source: trunk/third/transcript/src/psparse.c @ 9212

Revision 9212, 62.8 KB checked in by ghudson, 28 years ago (diff)
From bert: Stuff that uses features really, really wants a PPD file. In order to make pslpr work, we use "default.ppd" if the PPD file we're looking for isn't found.
Line 
1#ifndef lint
2#define _NOTICE static char
3_NOTICE N1[] = "Copyright (c) 1990,1991,1992 Adobe Systems Incorporated";
4_NOTICE N2[] = "GOVERNMENT END USERS: See Notice file in TranScript library directory";
5_NOTICE N3[] = "-- probably /usr/lib/ps/Notice";
6_NOTICE RCSID[]="$Header: /afs/dev.mit.edu/source/repository/third/transcript/src/psparse.c,v 1.2 1996-10-14 05:00:53 ghudson Exp $";
7#endif
8/* psparse.c
9 *
10 * Copyright (C) 1990,1991,1992 Adobe Systems Incorporated. All rights
11 *  reserved.
12 * GOVERNMENT END USERS: See Notice file in TranScript library directory
13 * -- probably /usr/lib/ps/Notice
14 *
15 *
16 *
17 * $/Log: psparse.c,v/$
18 * Revision 3.20  1994/05/03  23:01:32  snichols
19 * Handle null in name of resource, and handle files with neither prolog
20 * nor setup comments.
21 *
22 * Revision 3.19  1994/02/16  00:31:48  snichols
23 * support for Orientation comment
24 *
25 * Revision 3.18  1993/12/21  23:43:08  snichols
26 * cast strlen for Solaris.
27 *
28 * Revision 3.17  1993/12/01  21:04:27  snichols
29 * initialize some variables, and loop looking for resource files.
30 *
31 * Revision 3.16  1993/11/17  22:33:32  snichols
32 * make sure that null bytes in the data don't prematurely terminate
33 * the output.
34 *
35 * Revision 3.15  1993/08/06  22:56:51  snichols
36 * fixed typos.
37 *
38 * Revision 3.14  1993/08/06  22:55:15  snichols
39 * pname should be static.
40 *
41 * Revision 3.13  1993/07/27  17:50:17  snichols
42 * Corrected a typo.
43 *
44 * Revision 3.12  1993/05/25  21:38:59  snichols
45 * cleanup for Solaris.
46 *
47 * Revision 3.11  1992/08/21  16:26:32  snichols
48 * Release 4.0
49 *
50 * Revision 3.10  1992/08/20  00:38:41  snichols
51 * Even if noparse is desired, should check for file type and conformance,
52 * so clients can decide what to do.
53 *
54 * Revision 3.9  1992/07/27  20:02:19  snichols
55 * Added support for BINARYOK environment variable, to allow control over
56 * whether or not ASCII85 encoding is done after LZW compression.
57 *
58 * Revision 3.8  1992/07/14  22:37:51  snichols
59 * Updated copyright.
60 *
61 * Revision 3.7  1992/06/29  23:57:31  snichols
62 * line wrapped when I didn't want it to.
63 *
64 * Revision 3.6  1992/06/29  19:49:45  snichols
65 * handle RequiresPageRegion, and warn user CustomPageSize isn't
66 * supported.
67 *
68 * Revision 3.5  1992/06/23  19:41:28  snichols
69 * fixed up problem where sometimes psparse was trying to open a null pathname.
70 *
71 * Revision 3.4  1992/05/28  21:20:04  snichols
72 * support for handling Multiple Master fonts.
73 *
74 * Revision 3.3  1992/05/18  21:51:13  snichols
75 * removed unnecessary debugging statement.
76 *
77 * Revision 3.2  1992/05/18  20:07:57  snichols
78 * Added support for shrink to fit, and for translating by page length on
79 * landscape as well as translating by page width.  Also has support for
80 * long lines, as long as they aren't comments.
81 *
82 * Revision 3.1  1992/05/05  22:10:34  snichols
83 * support for adding showpage to end of file.
84 *
85 * Revision 3.0  1991/06/17  16:59:26  snichols
86 * Release 3.0
87 *
88 * Revision 1.29  1991/06/17  16:58:33  snichols
89 * add more checks to make sure array limits aren't exceeded, and
90 * increase array limits.
91 *
92 * Revision 1.28  1991/05/31  21:13:10  snichols
93 * Since we're strncat'ing rather than strncpy'ing in StrCap, we need to
94 * zero out r each time.
95 *
96 * Revision 1.27  1991/05/14  23:16:52  snichols
97 * fixed bug in comment stripping code which was stripping out the prolog.
98 *
99 * Revision 1.26  1991/05/14  19:20:47  snichols
100 * make sure command line feature code gets inserted properly.
101 *
102 * Revision 1.25  1991/05/13  20:50:39  snichols
103 * The array that StrCap returns should be static.
104 *
105 * Revision 1.24  1991/04/29  22:52:44  snichols
106 * if we get to end of CheckPrinter, return null, since we're checking for
107 * null on the other end.
108 *
109 * Revision 1.23  1991/04/23  19:29:16  snichols
110 * GetName would loop infinitely on names with ('s.
111 *
112 * Revision 1.22  1991/03/28  23:47:32  snichols
113 * isolated code for finding PPD files to one routine, in psutil.c.
114 *
115 * Revision 1.21  1991/03/27  01:03:18  snichols
116 * command line feature requests should override feature requests in file.
117 *
118 * Revision 1.20  1991/03/25  23:15:19  snichols
119 * moved CheckForTray to appear before invocation.
120 *
121 * Revision 1.19  1991/03/21  22:58:02  snichols
122 * if manual feed and no page specified anywhere else, use the one in
123 * the PPD file as the default.
124 *
125 * Revision 1.18  1991/03/21  18:53:15  snichols
126 * if printername is > 10 characters and can't find ppd, truncate to 10 and
127 * check again.
128 *
129 * Revision 1.17  1991/03/06  21:54:54  snichols
130 * missing arg to fprintf.
131 *
132 * Revision 1.16  1991/03/01  15:10:44  snichols
133 * needed to declare ResourceDir extern.
134 *
135 * Revision 1.15  91/03/01  14:42:04  snichols
136 * don't die if procset doesn't have version and revision.
137 *
138 * Revision 1.14  91/02/19  16:46:45  snichols
139 * support for additional resource types other than the currently defined ones,
140 * new resource location package, and general clean-up for readability.
141 *
142 * Revision 1.13  91/02/07  13:49:53  snichols
143 * fixed landscape bugs.
144 *
145 * Revision 1.12  91/01/30  14:32:21  snichols
146 * fixed some bugs with parsing version and revision numbers on procsets.
147 *
148 * Revision 1.11  91/01/23  16:32:25  snichols
149 * Added support for landscape, cleaned up some defaults, and
150 * handled *PageRegion features better.
151 *
152 * Revision 1.10  91/01/17  13:23:08  snichols
153 * extra debugging stuff.
154 *
155 * Revision 1.9  91/01/16  16:46:15  snichols
156 * SysV doesn't like union wait.
157 *
158 * Revision 1.8  91/01/16  14:14:07  snichols
159 * Added support for LZW compression and ascii85 encoding for Level 2 printers.
160 *
161 * Revision 1.7  91/01/02  16:34:40  snichols
162 * conditional compile for XPG3 to use SEEK_SET instead of L_SET in lseek.
163 *
164 * Revision 1.6  90/12/12  10:29:36  snichols
165 * new configuration stuff.
166 *
167 * Revision 1.5  90/12/03  16:52:40  snichols
168 * handled nested documents better.
169 *
170 * Revision 1.4  90/11/16  14:45:22  snichols
171 * Support for range printing: only download resource if it's going to be
172 * used within the range.
173 *
174 * Revision 1.2  90/09/17  17:46:54  snichols
175 * Added support for PPD features; cleaned up output considerably
176 * Now puts fonts, procsets in correct places (setup or prolog)
177 * outputs appropriate setup and prolog comments.
178 *
179 *
180 */
181
182
183#include <stdio.h>
184#ifdef XPG3
185#include <unistd.h>
186#endif
187#include <sys/types.h>
188#include <sys/wait.h>
189#include <sys/file.h>
190#include <string.h>
191#include <ctype.h>
192#include "transcript.h"
193#include "docman.h"
194#include "psparse.h"
195#include "PSres.h"
196
197
198#ifdef XPG3
199#define SEEKING SEEK_SET
200#else
201#define SEEKING L_SET
202#endif
203
204int SetupCompression();
205
206static struct resource resources[MAXRESOURCES];  /* one entry per resource */
207
208static struct dtable dloads[MAXRESOURCES];  /* one per potential download */
209
210static struct feature features[MAXRESOURCES]; /* one per feature */
211
212static int neededResources[MAXRESTYPES][MAXRESOURCES];  /* list by type of resouces
213                                                 not supplied, points into
214                                                 resources  */
215static int suppliedResources[MAXRESTYPES][MAXRESOURCES]; /* list by type of resources
216                                                  supplied, points into
217                                                  resources  */
218
219static long remcomment[MAXREM];  /* location of comments to be
220                                          removed from the original */
221
222static int ndloads = 0;               /* counters for above data structures */
223static int nresources = 0;
224static int nfeatures = 0;
225static int numrestypes = 6;
226static int nNR[MAXRESTYPES];
227static int nSR[MAXRESTYPES];
228static int nrem = 0;
229
230
231static int seenHeaderComment[HEADCOM]; /* only first header comment per
232                                          type is interesting, so if we've
233                                          seen one, we want to ignore rest */
234
235
236
237static FILE *ppd;
238static int noppd = FALSE;
239
240static int alreadycompressed = FALSE;
241
242static char docpagesize[50];
243static char specialhandled = FALSE;
244
245static int version;  /* version of DSC used */
246
247static long endlast = -1; 
248static long endpro = -1;
249static int npages = 0;
250static int ordered = TRUE;
251
252static int defaultSection = FALSE;
253
254static struct pageinfo {
255    long location;
256    char label[20];
257    int  pageno;
258} ptable[2000];
259
260
261static long prologend = -1;
262static long prologbegin = -1;
263static long setupbegin = -1;
264static long firstpages = -1;
265static long setupend = -1;
266static long vmtotal = 0;
267static int exitonerror = FALSE;
268
269int fd1pipe[2];
270int fd2pipe[2];
271
272
273static void VMUsage(min,max,fp)
274    long *min, *max;
275    FILE *fp;
276{
277    char buf[255];
278    char *p, *q;
279   
280    while (fgets(buf,255,fp))
281        if (!strncmp(buf,"%%VMusage:",10)) {
282        p = strchr(buf,':');
283        p++;
284        while (*p == ' ') p++;
285        q = strchr(p,' ');
286        *q++ = '\0';
287        *min = atol(p);
288        p = strchr(q,'\n');
289        if (p) *p = '\0';
290        *max = atol(q);
291        return;
292    }
293}
294
295static int IncRemIndex()
296{
297    int old;
298    if (nrem >= MAXREM) {
299        fprintf(stderr,"psparse: too many comments to remove.\n");
300        exit(2);
301    }
302    old = nrem++;
303    return old;
304}
305
306static char *DecodeType(type)
307    int type;
308{
309    if (!strcmp(resmap[type],"font"))
310        return PSResFontOutline;
311    if (!strcmp(resmap[type],"form"))
312        return PSResForm;
313    if (!strcmp(resmap[type],"pattern"))
314        return PSResPattern;
315    if (!strcmp(resmap[type],"encoding"))
316        return PSResEncoding;
317    if (!strcmp(resmap[type],"procset"))
318        return PSResProcSet;
319    return resmap[type];
320}
321
322   
323
324static char *FindResource(resname,type, resourcepath, minvm, maxvm)
325    char *resname;
326    int type;
327    char *resourcepath;
328    long *minvm, *maxvm;
329{
330    FILE *tfp;
331    char **pathnames;
332    char **names;
333    static char pname[TSPATHSIZE];
334    char *r,*q;
335    int cnt;
336    char mmname[255];
337    char *tmpresname;
338    int i;
339
340    if (type == RFILE) {
341        /* if it's a file, just use file name. */
342        strncpy(pname,resname,PSBUFSIZ);
343        if ((tfp = fopen(pname,"r")) == NULL)
344            return NULL;
345        else {
346            fclose(tfp);
347            return pname;
348        }
349    }
350    else {
351        tmpresname = resname;
352        if (type == FONT) {
353            /* might be a multiple master font, and if it is, we need to
354               strip down to the real name */
355            strcpy(mmname, resname);
356            r = strchr(mmname, '_');
357            if (r) {
358                /* it is a multiple master font! */
359                *r = '\0';
360                tmpresname = mmname;
361            }
362        }
363               
364        cnt = ListPSResourceFiles(resourcepath, ResourceDir,
365                                  DecodeType(type), tmpresname, &names,
366                                  &pathnames);
367        if (cnt == 0)
368            return NULL;
369        if (cnt > 1)
370            fprintf(stderr,"Warning: more than one filename found for resource %s\n",
371                    resname);
372        for (i = 0; i < cnt; i++) {
373            if ((tfp = fopen(pathnames[i],"r")) != NULL) {
374                VMUsage(minvm,maxvm,tfp);
375                fclose(tfp);
376                return pathnames[0];
377            }
378        }
379    }
380    return NULL;
381}
382
383static void InitPrinterInfo(printer)
384    char *printer;
385{
386    char ppdfile[255];
387
388    ppd = GetPPD(printer);
389    /* On Athena, we want to have a default printer description, so we
390     * don't have to maintain a file for every single printer...
391     * "default.ppd" is as good a name as any.
392     * --bert 15apr1996
393     */
394    if (ppd == NULL)  ppd = GetPPD("default");
395
396    if (ppd == NULL)
397        noppd = TRUE;
398    else
399        noppd = FALSE;
400}
401
402   
403
404static char *CheckPrinter(resname,type,printer)
405    char *resname;
406    int type;
407    char *printer;
408{
409    char *q;
410    int i;
411
412    if (noppd) {
413        if (type == FONT) {
414            for (i=0;i<35;i++) {
415                if (!strcmp(standardfonts[i],resname))
416                    return standardfonts[i];
417            }
418        }
419        return NULL;
420    }
421    else {
422        if (type == FONT) {
423            rewind(ppd);
424            q = parseppd(ppd,"*Font",resname);
425            return q;
426        }
427    }
428    return NULL;
429}
430
431static int NeededComment(comment)
432    enum comtypes comment;
433{
434    if (comment == docneedfont || comment == docneedfile || comment ==
435        docneedproc || comment == docneedres)
436        return TRUE;
437    return FALSE;
438}
439
440static int SuppliedComment(comment)
441    enum comtypes comment;
442{
443    if (comment == docsupfont || comment == docsupfile || comment ==
444        docsupproc || comment == docsupres)
445        return TRUE;
446    return FALSE;
447}
448
449static int BeginComment(comment)
450    enum comtypes comment;
451{
452    if (comment == begfont || comment == begfile || comment == begproc ||
453        comment == begres)
454        return TRUE;
455    return FALSE;
456}
457
458static int IncComment(comment)
459    enum comtypes comment;
460{
461    if (comment == incfont || comment == incfile || comment == incproc ||
462        comment == incres)
463        return TRUE;
464    return FALSE;
465}
466
467static int DocComment(comment)
468    enum comtypes comment;
469{
470    if (comment == docfont || comment == docproc)
471        return TRUE;
472    return FALSE;
473}
474
475static int PageComment(comment)
476    enum comtypes comment;
477{
478    if (comment == pagefont || comment == pagefile || comment == pageres)
479        return TRUE;
480    return FALSE;
481}
482
483static int ResourceType(q)
484    char *q;
485{
486    int i;
487
488    for (i=0; i<numrestypes; i++)
489        if (!strcmp(q, resmap[i]))
490            return i;
491    /* new kind of resource */
492    if (numrestypes == MAXRESTYPES) {
493        fprintf(stderr,"psparse: too many different types of resources requested!\n");
494        exit(10);
495    }
496    strncpy(resmap[numrestypes++],q,30);
497    return numrestypes-1;
498}
499
500static int ResourceChange(q)
501    char *q;
502{
503    int i;
504
505    for (i=0; i<numrestypes; i++)
506        if (!strcmp(q, resmap[i]))
507            return TRUE;
508    return FALSE;
509}
510
511static void FillInResource(ndex,path,name,type,state,comment,minvm,maxvm,ver,rev)
512    int ndex;
513    char *path;
514    char *name;
515    int type;
516    enum resstates state;
517    enum comtypes comment;
518    long minvm, maxvm;
519    float ver;
520    int rev;
521{
522    enum rangestates rangeinfo;
523
524    if (ndex >= MAXRESOURCES) {
525        fprintf(stderr,"psparse: too many resource requests.\n");
526        exit(2);
527    }
528    if (DocComment(comment) || NeededComment(comment))
529        rangeinfo = header;
530    else if (defaultSection)
531        rangeinfo = defaults;
532    else if (PageComment(comment))
533        rangeinfo = pageinrange;
534    else rangeinfo = undefined;
535    if (path)
536        strncpy(resources[ndex].path,path,PSBUFSIZ);
537    else resources[ndex].path[0] = '\0';
538    if (name)
539        strncpy(resources[ndex].name,name,PSBUFSIZ);
540    else resources[ndex].name[0] = '\0';
541    resources[ndex].type = type;
542    resources[ndex].state = state;
543    resources[ndex].comment = comment;
544    resources[ndex].rangeinfo = rangeinfo;
545    resources[ndex].inrange = FALSE;
546    resources[ndex].minvm = minvm;
547    resources[ndex].maxvm = maxvm;
548    vmtotal += maxvm;
549    resources[ndex].version = ver;
550    resources[ndex].rev = rev;
551}
552
553static void FillInDLoad(ndex,location,type,rndex,comment)
554    int ndex;
555    long location;
556    int type;
557    int rndex;
558    enum comtypes comment;
559{
560    if (ndex >= MAXRESOURCES) {
561        fprintf(stderr,"psparse: too many download requests.\n");
562        exit(2);
563    }
564    dloads[ndex].location = location;
565    dloads[ndex].type = type;
566    dloads[ndex].index = rndex;
567    dloads[ndex].comment = comment;
568}
569   
570
571static long checkatend(type)
572    int type;
573{
574    int i;
575    for (i=0;i<ndloads;i++)
576        if (dloads[i].index == -1 && dloads[i].type == type)
577            return dloads[i].location;
578    return -1;
579}
580
581static int AlreadySupplied(ndex,type)
582    int ndex;
583    int type;
584{
585    int i;
586    for (i=0; i<nSR[type];i++)
587        if (suppliedResources[type][i] == ndex)
588            return TRUE;
589    return FALSE;
590}
591
592static VOID MarkHeaderComment(comment)
593    enum comtypes comment;
594{
595    /* this (and the following routine) are done this way because non-ANSI
596       C compilers won't allow the use of enum's as array indices */
597
598    switch (comment) {
599    case docfont:
600        seenHeaderComment[0]++;
601        break;
602    case docneedfont:
603        seenHeaderComment[1]++;
604        break;
605    case docsupfont:
606        seenHeaderComment[2]++;
607        break;
608    case docneedres:
609        seenHeaderComment[3]++;
610        break;
611    case docsupres:
612        seenHeaderComment[4]++;
613        break;
614    case docneedfile:
615        seenHeaderComment[5]++;
616        break;
617    case docsupfile:
618        seenHeaderComment[6]++;
619        break;
620    case docproc:
621        seenHeaderComment[7]++;
622        break;
623    case docneedproc:
624        seenHeaderComment[8]++;
625        break;
626    case docsupproc:
627        seenHeaderComment[9]++;
628        break;
629    default: break;
630    }
631}
632       
633
634
635static int RepeatedHeaderComment(comment)
636    enum comtypes comment;
637{
638    switch (comment) {
639    case docfont:
640        if (seenHeaderComment[0]) return TRUE;
641        break;
642    case docneedfont:
643        if (seenHeaderComment[1]) return TRUE;
644        break;
645    case docsupfont:
646        if (seenHeaderComment[2]) return TRUE;
647        break;
648    case docneedres:
649        if (seenHeaderComment[3]) return TRUE;
650        break;
651    case docsupres:
652        if (seenHeaderComment[4]) return TRUE;
653        break;
654    case docneedfile:
655        if (seenHeaderComment[5]) return TRUE;
656        break;
657    case docsupfile:
658        if (seenHeaderComment[6]) return TRUE;
659        break;
660    case docproc:
661        if (seenHeaderComment[7]) return TRUE;
662        break;
663    case docneedproc:
664        if (seenHeaderComment[8]) return TRUE;
665        break;
666    case docsupproc:
667        if (seenHeaderComment[9]) return TRUE;
668        break;
669    default:
670        return FALSE;
671        break;
672    }
673    return FALSE;
674}
675
676static int InRange(pagenum, ranges)
677    int pagenum;
678    struct range ranges[];
679{
680    int i;
681
682    /* if *no* ranges specified, i.e. all pages in range, return true */
683    if (ranges[0].begin == 0 && ranges[0].end == 0)
684        return TRUE;
685    for (i = 0; i < MAXRANGES && ranges[i].begin > 0; i++)
686        if (pagenum >= ranges[i].begin && pagenum <= ranges[i].end)
687            return TRUE;
688    return FALSE;
689}
690
691static char *GetName(str)
692    char **str;
693{
694    char *q, *p;
695    char *name;
696    int depth = 0;
697
698    if (*str == NULL || **str == '\0') return NULL;
699    while (**str == ' ') (*str)++;
700    q = strchr(*str,'\n');
701    if (q) *q = '\0';
702    p = *str;
703    name = p;
704    if (*p == '(') {
705        depth++;
706        p++;
707        while (q = strchr(p,'(')) {
708            depth++;
709            p = q;
710            p++;
711        }
712        while (q = strchr(p,')')) {
713            depth--;
714            p = q;
715            p++;
716        }
717        if (depth) {
718            fprintf(stderr,"psparse: mismatched parentheses in %s.\n",name);
719            if (exitonerror)
720                exit(2);
721        }
722    }
723    else
724        p = strchr(*str,' ');
725    if (p) *p++ = '\0';
726    *str = p;
727    return name;
728}
729       
730   
731
732static int CheckResources(reslist, kind, location, state, comment, printer,
733                          resourcepath, cont, control)
734    char *reslist;
735    int kind;
736    long location;
737    enum resstates state;
738    enum comtypes comment;
739    char *printer;
740    char *resourcepath;
741    int cont;
742    struct controlswitches control;
743{
744    char *p,*q;
745    char *name;
746    int i,j;
747    long loc;
748    long minvm = 0, maxvm = 0;
749    int depth = 0;
750    int first = TRUE;
751    float version = 0.0;
752    int rev = 0;
753   
754    if (RepeatedHeaderComment(comment) && !cont)
755        return;
756    p = reslist;
757    while (name = GetName(&p)) {
758        if (name[0] == '\0') continue;
759        if (kind == UNKNOWN) {
760            kind = ResourceType(name);
761            if (p == NULL) break;
762            continue;
763        }
764        if (!strncmp(name,"(atend)",7)) {
765            /* need to save this location away, in case we need it again */
766            /* don't need to do this for pagefont, pagefile, etc. since */
767            /* we won't need it again */
768            if (!PageComment(comment))
769                FillInDLoad(ndloads++,location,kind,-1,comment);
770            return;
771        }
772        /* is this a proc set?  if so, grab version and revision off input
773           now, unless we've run out of line, in which case we have to
774           assume that there isn't a version and revision */
775        if (kind == PROCSET && p != NULL) {
776            while (*p == ' ') p++;
777            sscanf(p,"%f %d",&version, &rev);
778            /* now, skip over those two */
779            q = strchr(p,' ');
780            if (q) {
781                p = q; p++;
782                q = strchr(p,' ');
783                if (q) {
784                    p = q; p++;
785                }
786                else {
787                    /* end of line */
788                    *p = '\0';
789                }
790            }
791        }
792        /* mark header comments as seen here, after the (atend) check */
793        /* we don't want to ignore second one if first one was (atend) */
794        MarkHeaderComment(comment);
795        if (ResourceChange(name))
796            kind = ResourceType(name);
797        /* have we seen this resource before? */
798        for (i=0;i<nresources;i++) {
799            if (!strcmp(resources[i].name,name)) {
800                /* begin comments */
801                /* previously seen in a supplied comment, or even a
802                   previous begin */
803                if (BeginComment(comment)) {
804                    if (resources[i].state != indocument) {
805                        /* first time we've seen this in a begin */
806                        resources[i].state = indocument;
807                        suppliedResources[kind][nSR[kind]++] = i;
808                    }
809                    break;
810                }
811                if (IncComment(comment)) {
812                    /* include comm */
813                    /* previously seen in a needed comment, or previous
814                       include */
815                    /* if resource is in printer, we're done with this one */
816                    if (resources[i].state == inprinter) {
817                        resources[i].comment = comment;
818                        break;
819                    }
820                    /* if it's not in the printer, we're going to download
821                       it, so get rid of the comment */
822                    remcomment[IncRemIndex()] = location;
823                    /* could have also been seen in a docfont or docproc,
824                       so need to check for that */
825                    for (j = 0; j < ndloads; j++) {
826                        if (dloads[j].comment == docfont && dloads[j].index
827                            == i) {
828                            dloads[j].location = location;
829                            dloads[j].comment = comment;
830                            break;
831                        }
832                        if (dloads[j].comment == docproc && dloads[j].index
833                            == i) {
834                            dloads[j].location = location;
835                            dloads[j].comment = comment;
836                            break;
837                        }
838                    }
839                    if (j != ndloads) {
840                        break;
841                    }
842                    /* if there had been a doc{font,proc}, all this is
843                       already filled in */
844                    resources[i].state = download;
845                    if (!AlreadySupplied(i,kind))
846                        suppliedResources[kind][nSR[kind]++] = i;
847                    FillInDLoad(ndloads++,location,kind,i,comment);
848                    break;
849                }
850                if (comment == pagefont || comment == pagefile || comment
851                    == pageres) {
852                    if (defaultSection)
853                        resources[i].rangeinfo = defaults;
854                    else {
855                        if (resources[i].rangeinfo == defaults)
856                            break;
857                        if (InRange(ptable[npages - 1].pageno,control.ranges))
858                            resources[i].rangeinfo = pageinrange;
859                        else
860                            resources[i].rangeinfo = undefined;
861                    }
862                    break;
863                }
864                break;
865            }
866        }
867        if (i != nresources) {
868            if (p == NULL) return;
869            continue;
870        }
871        /* parse ppd file to check existence of resource in printer */
872        q = CheckPrinter(name,kind,printer);
873        if (q) {
874            FillInResource(nresources, (char *)NULL, name, kind, inprinter,
875                           comment, minvm, maxvm, version, rev);
876            if (nNR[kind] >= MAXRESOURCES) {
877                fprintf(stderr,"psparse: too many needed resources.\n");
878                exit(2);
879            }
880            neededResources[kind][nNR[kind]++] = nresources++;
881            if (p == NULL) return;
882            continue;
883        }
884        /* check along resource path for existence of resource */
885        q = FindResource(name,kind,resourcepath,&minvm,&maxvm);
886        if (q == NULL) {
887            if (NeededComment(comment) || IncComment(comment)) {
888                fprintf(stderr,"psparse: Couldn't find resource %s\n",name);
889                if (exitonerror)
890                    exit(2);
891            }
892            if (DocComment(comment)) {
893                FillInResource(nresources++, (char *)NULL, name, kind,
894                               nowhere, comment, minvm, maxvm, version, rev);
895            }
896            if (SuppliedComment(comment)) {
897                FillInResource(nresources++, (char *)NULL, name, kind,
898                               verify, comment, minvm, maxvm, version, rev);
899            }
900            if (BeginComment(comment)) {
901                FillInResource(nresources, (char *)NULL, name, kind,
902                               indocument, comment, minvm, maxvm, version,
903                               rev);
904                if (nSR[kind] >= MAXRESOURCES) {
905                    fprintf(stderr,"psparse: too many supplied resources.\n");
906                    exit(2);
907                }
908                suppliedResources[kind][nSR[kind]++] = nresources++;
909            }
910            if (p == NULL) return;
911            continue;
912        }
913        /* it's not in the printer, we found it, we've never seen it before */
914        FillInResource(nresources, q, name, kind, state, comment, minvm,
915                       maxvm, version, rev);
916        if (state == download) {
917            /* need to download here */
918            suppliedResources[kind][nSR[kind]++] = nresources;
919            /* if it's an inc, don't need to check atends, just dload here */
920            if (IncComment(comment)) {
921                FillInDLoad(ndloads++,location,kind,nresources,comment);
922                remcomment[IncRemIndex()] = location;
923            }
924            if (DocComment(comment)) {
925                 /* check for atend entries */
926                loc = checkatend(kind);
927                if (loc > 0) location = loc;
928                FillInDLoad(ndloads++,location,kind,nresources,comment);
929            }
930        }
931        nresources++;
932        if (p == NULL) return;
933    }
934    return;
935}
936
937static char *StrCap(str)
938    char *str;
939{
940    char *q,*p;
941    static char r[30];
942    int i;
943
944    if (str == NULL || *str == '\0') return NULL;
945    for (i = 0; i < 30; i++) r[i] = '\0';
946    p = str;
947    q = str;
948    q++;
949    r[0] = toupper(*p);
950    strncat(r,q,30);
951    return r;
952}
953
954static void PrologAndSetup()
955{
956    int i;
957
958    if (setupbegin == -1) {
959        if (prologend != -1)
960            setupbegin = prologend;
961        else
962            setupbegin = firstpages;
963    }
964    if (setupend == -1) {
965        if (prologend != -1)
966            setupend = prologend;
967        else
968            setupend = firstpages;
969    }
970    if (prologend == -1) return;
971    for (i=0;i<ndloads;i++) {
972        /* check procsets to make sure they're within prolog boundaries */
973        if (dloads[i].type == PROCSET) {
974            if (dloads[i].location < prologbegin)
975                dloads[i].location = prologbegin;
976            if (dloads[i].location > prologend)
977                dloads[i].location = prologend;
978        }
979        /* check fonts to make sure they're within setup boundaries */
980        if (dloads[i].type == FONT)
981            /* only check begin, because vm considerations may put a font
982               outside setup boundaries */
983            if (dloads[i].location < setupbegin)
984                dloads[i].location = setupbegin;
985    }
986}
987
988static int realcnt[MAXRESTYPES];
989
990static void RangeResources()
991{
992    int i, j;
993
994    for (i = 0; i < MAXRESTYPES; i++)
995        realcnt[i] =0;
996    for (i = 0; i< nresources; i++) {
997        if (resources[i].rangeinfo == pageinrange || resources[i].rangeinfo
998            == defaults) {
999            resources[i].inrange = TRUE;
1000            realcnt[resources[i].type]++;
1001        }
1002    }
1003    for (i = 0; i < numrestypes; i++) {
1004        if (realcnt[i] == 0) {
1005            /* didn't find %%PageResources for this type in either the
1006               defaults or the pages in the range, so must use everything
1007               in header  */
1008            for (j = 0; j < nresources; j++) {
1009                if (resources[j].type == i)
1010                    resources[j].inrange = TRUE;
1011            }
1012        }
1013    }
1014}
1015           
1016
1017
1018static void ReArrange(printer)
1019    char *printer;
1020{
1021    long printervm;
1022    char *value;
1023    int i;
1024    int moved[MAXRESOURCES];
1025
1026    if (noppd)
1027        return;
1028    if (prologend == -1) return;
1029    for (i=0;i<MAXRESOURCES;i++)
1030        moved[i] = 0;
1031    rewind(ppd);
1032    value = parseppd(ppd,"*FreeVM",(char *)NULL);
1033    if (value == NULL) return;
1034    printervm = atol(value);
1035    if ((printervm - vmtotal) > 100000) {
1036        /* perhaps some rearranging? */
1037        for (i=0;i<ndloads;i++) {
1038            if (dloads[i].type == FONT) {
1039                if (dloads[i].location > setupend) {
1040                    if (moved[dloads[i].index] > 0)
1041                        dloads[i].index = -1;
1042                    dloads[i].location = setupbegin;
1043                    moved[dloads[i].index]++;
1044                }
1045            }
1046        }
1047    }
1048}
1049   
1050   
1051static void DownLoadResource(resindex,output,strip)
1052    int resindex;
1053    FILE *output;
1054    int strip;
1055{
1056    FILE *fp;
1057    char buf[BUFSIZ];
1058
1059    if (resources[resindex].state != download)
1060        return;
1061    if (resources[resindex].inrange != TRUE)
1062        return;
1063    if (resources[resindex].path[0] == '\0') {
1064        fprintf(stderr, "psparse: couldn't find resource file for %s\n",
1065                resources[resindex].name);
1066        if (exitonerror)
1067            exit(2);
1068    }
1069    else {
1070        if ((fp = fopen(resources[resindex].path, "r")) == NULL) {
1071            fprintf(stderr, "Couldn't open resource file %s.\n",
1072                    resources[resindex].path);
1073            if (exitonerror)
1074                exit(2);
1075        }
1076        if (!strip) {
1077            if (version == VERS3) {
1078                fprintf(output, "%%%%BeginResource: ");
1079                fprintf(output, "%s ", resmap[resources[resindex].type]);
1080                fprintf(output, "%s", resources[resindex].name);
1081                if (resources[resindex].type == PROCSET)
1082                    fprintf(output,"%5.1f %d", resources[resindex].version,
1083                            resources[resindex].rev);
1084                fprintf(output,"\n");
1085            }
1086            else {
1087                fprintf(output, "%%%%Begin");
1088                fprintf(output, "%s: ", StrCap(resmap[resources[resindex].type]));
1089                fprintf(output, "%s", resources[resindex].name);
1090                if (resources[resindex].type == PROCSET)
1091                    fprintf(output,"%5.1f %d", resources[resindex].version,
1092                            resources[resindex].rev);
1093                fprintf(output, "\n");
1094            }
1095        }
1096        while (fgets(buf, BUFSIZ, fp))
1097            fputs(buf, output);
1098        if (!strip) {
1099            if (version == VERS3)
1100                fprintf(output, "%%%%EndResource\n");
1101            else {
1102                fprintf(output, "%%%%End");
1103                fprintf(output, "%s\n",
1104                        StrCap(resmap[resources[resindex].type]));
1105            }
1106        }
1107    }
1108}
1109
1110static void OutputInclude(output,ndex, type)
1111    FILE *output;
1112    int ndex;
1113    int type;
1114{
1115    if (version > VERS21) {
1116        fprintf(output, "%%%%IncludeResource: ");
1117        fprintf(output,"%s ",resmap[type]);
1118    }
1119    else {
1120        fprintf(output, "%%%%Include");
1121        fprintf(output,"%s: ",StrCap(resmap[type]));
1122    }
1123    fprintf(output,"%s\n",resources[ndex].name);
1124}
1125
1126static void CheckIncludes(output)
1127    FILE *output;
1128{
1129    int i;
1130
1131    for (i=0;i<nresources;i++) {
1132        if (resources[i].state == inprinter) {
1133            if (NeededComment(resources[i].comment) || DocComment(resources[i].comment))
1134                OutputInclude(output,i,resources[i].type);
1135        }
1136    }
1137}
1138
1139static void NewLine(output,count,s)
1140    FILE *output;
1141    int *count;
1142    char *s;
1143{
1144    fprintf(output,"\n%%%%+ ");
1145    *count = 3;
1146    if (s) {
1147        fprintf(output,"%s ",s);
1148        *count += strlen(s);
1149    }
1150}
1151
1152static void OutputComments(output)
1153    FILE *output;
1154{
1155    int i;
1156    int k;
1157    int count = 0;
1158    int prev = FALSE;
1159    char *str;
1160
1161    if (version == VERS3) {
1162        for (k = 0; k < numrestypes; k++) {
1163            if (nNR[k] > 0) {
1164                if (!prev) {
1165                    fprintf(output, "%%%%DocumentNeededResources: ");
1166                    prev = TRUE;
1167                    count = 27;
1168                }
1169                else {
1170                    fprintf(output, "\n%%%%+ ");
1171                    count = 4;
1172                }
1173                str = resmap[k];
1174                fprintf(output, "%s ", str);
1175                count += strlen(str) + 1;
1176                for (i = 0; i < nNR[k]; i++) {
1177                    if (neededResources[k][i] >= 0 &&
1178                      resources[neededResources[k][i]].inrange) {
1179                        count += strlen(resources[neededResources[k][i]].name);
1180                        if (k == PROCSET) {
1181                            count += 10;
1182                            if (count > PSBUFSIZ)
1183                                NewLine(output, &count, str);
1184                            fprintf(output, "%s %5.1f %d ",
1185                                    resources[neededResources[k][i]].name,
1186                                    resources[neededResources[k][i]].version,
1187                                    resources[neededResources[k][i]].rev);
1188                        }
1189                        else {
1190                            if (count > PSBUFSIZ)
1191                                NewLine(output, &count, str);
1192                            fprintf(output, "%s ",
1193                                    resources[neededResources[k][i]].name);
1194                        }
1195                    }
1196                }
1197            }
1198        }
1199        if (prev)
1200            fprintf(output, "\n");
1201        prev = FALSE;
1202        for (k = 0; k < numrestypes; k++) {
1203            if (nSR[k] > 0) {
1204                if (!prev) {
1205                    fprintf(output, "%%%%DocumentSuppliedResources: ");
1206                    prev = TRUE;
1207                    count = 29;
1208                }
1209                else {
1210                    fprintf(output, "\n%%%%+ ");
1211                    count = 4;
1212                }
1213                str = resmap[k];
1214                fprintf(output, "%s ", str );
1215                count += strlen(str) + 1;
1216                for (i = 0; i < nSR[k]; i++) {
1217                    if (suppliedResources[k][i] >= 0) {
1218                        if (resources[suppliedResources[k][i]].state ==
1219                          download) {
1220                            if (!resources[suppliedResources[k][i]].inrange)
1221                                continue;
1222                        }
1223                        count += strlen(resources[suppliedResources[k][i]].name);
1224                        if (k == PROCSET) {
1225                            count += 10;
1226                            if (count > PSBUFSIZ)
1227                                NewLine(output, &count, str);
1228                            fprintf(output, "%s %5.1f %d ",
1229                                    resources[suppliedResources[k][i]].name,
1230                                    resources[suppliedResources[k][i]].version,
1231                                    resources[suppliedResources[k][i]].rev);
1232                        }
1233                        else {
1234                            if (count > PSBUFSIZ)
1235                                NewLine(output, &count, str);
1236                            fprintf(output, "%s ",
1237                                    resources[suppliedResources[k][i]].name);
1238                        }
1239                    }
1240                }
1241            }
1242        }
1243        if (prev)
1244            fprintf(output, "\n");
1245    }
1246    else {
1247        for (k = 0; k <= PROCSET; k++) {
1248            if (nNR[k] > 0) {
1249                fprintf(output, "%%%%DocumentNeeded");
1250                count = 16;
1251                str = StrCap(resmap[k]);
1252                fprintf(output, "%ss: ", str);
1253                count += strlen(str) + 3;
1254                for (i = 0; i < nNR[k]; i++) {
1255                    if (neededResources[k][i] >= 0) {
1256                        count += strlen(resources[neededResources[k][i]].name);
1257                        if (k == PROCSET) {
1258                            count += 10;
1259                            if (count > PSBUFSIZ)
1260                                NewLine(output, &count, str);
1261                            fprintf(output, "%s %5.1f %d ",
1262                                    resources[neededResources[k][i]].name,
1263                                    resources[neededResources[k][i]].version,
1264                                    resources[neededResources[k][i]].rev);
1265                        }
1266                        else {
1267                            if (count > PSBUFSIZ)
1268                                NewLine(output, &count, "");
1269                            fprintf(output, "%s ",
1270                                    resources[neededResources[k][i]].name);
1271                        }
1272                    }
1273                }
1274                fprintf(output, "\n");
1275                count = 0;
1276            }
1277        }
1278        for (k = 0; k < PROCSET; k++) {
1279            if (nSR[k] > 0) {
1280                fprintf(output, "%%%%DocumentSupplied");
1281                count = 18;
1282                str = StrCap(resmap[k]);
1283                fprintf(output, "%ss: ", str);
1284                count += strlen(str) + 3;
1285                for (i = 0; i < nSR[k]; i++) {
1286                    if (suppliedResources[k][i] >= 0) {
1287                        count += strlen(resources[suppliedResources[k][i]].name);
1288                        if (k == PROCSET) {
1289                            count += 10;
1290                            if (count > PSBUFSIZ)
1291                                NewLine(output, &count, str);
1292                            fprintf(output, "%s %5.1f %d ",
1293                                    resources[suppliedResources[k][i]].name,
1294                                    resources[suppliedResources[k][i]].version,
1295                                    resources[suppliedResources[k][i]].rev);
1296                        }
1297                        else {
1298                            if (count > PSBUFSIZ)
1299                                NewLine(output, &count, "");
1300                            fprintf(output, "%s ",
1301                                    resources[suppliedResources[k][i]].name);
1302                        }
1303                    }
1304                }
1305                fprintf(output, "\n");
1306                count = 0;
1307            }
1308        }
1309    }
1310}
1311
1312int dcompar(a,b)
1313#ifdef __STDC__
1314    const void *a, *b;
1315#else
1316    void *a, *b;
1317#endif   
1318{
1319    return(((struct dtable *)a)->location -
1320           ((struct dtable *)b)->location);
1321}
1322
1323int rcompar(a,b)
1324#ifdef __STDC__
1325    const void *a, *b;
1326#else
1327    void *a, *b;
1328#endif   
1329{
1330    return (*(long *)a - *(long *)b);
1331}
1332
1333int fcompar(a,b)
1334#ifdef __STDC__
1335    const void *a, *b;
1336#else
1337    void *a, *b;
1338#endif   
1339{
1340    return(((struct feature *)a)->location -
1341           ((struct feature *)b)->location);
1342}
1343
1344static void BuildDownLoadTable()
1345{
1346/* sort download table for easier downloading */
1347    qsort((void *)dloads,ndloads,sizeof(struct dtable),dcompar);
1348    qsort((void *)remcomment,nrem,sizeof(long),rcompar);
1349    qsort((void *)features,nfeatures,sizeof(struct feature),fcompar);
1350}
1351
1352static long finddloc(loc)
1353    long loc;
1354{
1355    int i;
1356
1357    for (i = 0;i<ndloads;i++)
1358        if (dloads[i].location >= loc)
1359            return i;
1360    return -1;
1361}
1362
1363static long findrloc(loc)
1364    long loc;
1365{
1366    int i;
1367
1368    for (i = 0;i<nrem;i++)
1369        if (remcomment[i] >= loc)
1370            return i;
1371    return -1;
1372}
1373
1374static long findfloc(loc)
1375    long loc;
1376{
1377    int i;
1378
1379    for(i=0;i<nfeatures;i++)
1380        if (features[i].location >= loc)
1381            return i;
1382    return -1;
1383}
1384
1385static char *PageSizeGiven();
1386
1387static int CheckForSpecial(feats, nfeats)
1388    struct comfeatures feats[];
1389    int nfeats;
1390{
1391    int i;
1392    for (i=0; i<nfeats; i++) {
1393        if (strncmp(feats[i].keyword,"*InputSlot",10) == 0)
1394            return TRUE;
1395        if (strncmp(feats[i].keyword, "*ManualFeed", 11) == 0)
1396            return TRUE;
1397    }
1398    return FALSE;
1399}
1400
1401static int CheckOverrides(request, feats, nfeats)
1402    char *request;
1403    struct comfeatures feats[];
1404    int nfeats;
1405{
1406    int i;
1407
1408    for (i = 0; i < nfeats; i++) {
1409        if (!strcmp(request, feats[i].keyword)) {
1410            /* a match */
1411            return TRUE;
1412        }
1413    }
1414    return FALSE;
1415}
1416                         
1417   
1418
1419static void HandleFeatures(buf,location,command,control)
1420    char *buf;                  /* string containing feature */
1421    long location;              /* where this feature should go */
1422    int command;                /* was this requested on command line? */
1423    struct controlswitches control;
1424{
1425    char *feature, *option, *p;
1426    char *value;
1427    char defaultvalue[255];
1428    char *size;
1429    int doregion = FALSE;
1430
1431
1432    if (noppd) {
1433        fprintf(stderr,"psparse: can't include printer specific feature without PPD file!\n");
1434        if (exitonerror)
1435            exit(2);
1436        return;
1437    }
1438    if (nfeatures >= MAXRESOURCES) {
1439        fprintf(stderr,"psparse: too many feature requests.\n");
1440        exit(2);
1441    }
1442   
1443    feature = buf;
1444    while (*feature == ' ') feature++;
1445      p = strrchr(feature,'\n');
1446    if (p) *p = '\0';
1447    option = strchr(feature,' ');
1448    if (option) {
1449        *option = '\0';
1450        option++;
1451    }
1452    if (!command) {
1453        /* check for overrides; command line takes precedence */
1454        if (CheckOverrides(feature, control.features, control.nfeatures))
1455            return;
1456    }
1457    if (strcmp(feature, "*CustomPageSize") == 0 && strcmp(option, "False")
1458        != 0) {
1459        /* feature is CustomPageSize, and it's not set to False */
1460        fprintf(stderr, "psparse: CustomPageSize is not ");
1461        fprintf(stderr, "supported in this print manager\n");
1462        if (exitonerror)
1463            exit(2);
1464        return;
1465    }
1466   
1467    /* check default first */
1468    p = feature; p++;
1469    if (option) {
1470        strncpy(defaultvalue,"*Default",255);
1471        strncat(defaultvalue,p,255);
1472        rewind(ppd);
1473        value = parseppd(ppd,defaultvalue,(char *)NULL);
1474        if (value) {
1475            if (!strcmp(value,option)) {
1476                if (!strncmp(feature,"*PageSize",9))
1477                    strncpy(docpagesize,option,50);
1478                return;
1479            }
1480        }
1481    }
1482    rewind(ppd);
1483    value = parseppd(ppd,feature,option);
1484    if (value) {
1485        if (!strncmp(feature,"*PageSize",9)) {
1486            strncpy(docpagesize,option,50);
1487            /* need to see if input tray or manual feed is or has been
1488               requested */
1489            /* if it has, then page size code is handled there with
1490               *PageRegion, so we don't put in *PageSize code */
1491            if (specialhandled)
1492                /* already seen a tray or manual feed request */
1493                return;
1494            if (CheckForSpecial(control.features, control.nfeatures))
1495                /* will see a tray or manual feed request */
1496                return;
1497        }
1498        strncpy(features[nfeatures].name,feature,255);
1499        if (option)
1500            strncpy(features[nfeatures].option,option,255);
1501        else
1502            features[nfeatures].option[0] = '\0';
1503        features[nfeatures].code = value;
1504        features[nfeatures++].location = location;
1505        if (!command)
1506            remcomment[IncRemIndex()] = location;
1507        if (!strncmp(feature,"*ManualFeed",11) &&
1508            !strncmp(option,"True",4) && command) {
1509            /* if manual feed is requested, need to use PageRegion as well */
1510            specialhandled = TRUE;
1511            size = PageSizeGiven(control.features,control.nfeatures);
1512            if (size) {
1513                rewind(ppd);
1514                value = parseppd(ppd,"*PageRegion",size);
1515                if (value) {
1516                    strncpy(features[nfeatures].name,"*PageRegion",255);
1517                    strncpy(features[nfeatures].option,size,255);
1518                    features[nfeatures].code = value;
1519                    features[nfeatures++].location = location;
1520                }
1521                else {
1522                    fprintf(stderr,"psparse: no PageRegion of size %s available.\n",
1523                            size);
1524                    if (exitonerror)
1525                        exit(2);
1526                }
1527            }
1528            else {
1529                fprintf(stderr,"psparse: size must be provided for manual feed.\n");
1530                if (exitonerror)
1531                    exit(2);
1532            }
1533        }
1534        if (!strncmp(feature,"*InputSlot",10) && command) {
1535            /* if input tray is requested, may need to use PageRegion as
1536               well */
1537            specialhandled = TRUE;
1538            rewind(ppd);
1539            value = parseppd(ppd, "*RequiresPageRegion", option);
1540            if (value) {
1541                if (strcmp(value, "True") == 0) {
1542                    doregion = TRUE;
1543                }
1544                else {
1545                    doregion = FALSE;
1546                }
1547            }
1548            else {
1549                rewind(ppd);
1550                value = parseppd(ppd, "*RequiresPageRegion", "All");
1551                if (value) {
1552                    if (strcmp(value, "True") == 0) {
1553                        doregion = TRUE;
1554                    }
1555                    else {
1556                        doregion = FALSE;
1557                    }
1558                }
1559                else doregion = FALSE;
1560            }
1561            if (doregion) {
1562                doregion = FALSE;
1563                size = PageSizeGiven(control.features,control.nfeatures);
1564                if (size) {
1565                    rewind(ppd);
1566                    value = parseppd(ppd,"*PageRegion",size);
1567                    if (value) {
1568                        strncpy(features[nfeatures].name,
1569                                "*PageRegion",255);
1570                        strncpy(features[nfeatures].option,size,255);
1571                        features[nfeatures].code = value;
1572                        features[nfeatures++].location = location;
1573                    }
1574                    else {
1575                        fprintf(stderr,
1576                                "psparse: no PageRegion of size %s available.\n", size);
1577                        if (exitonerror)
1578                            exit(2);
1579                    }
1580                }
1581                else {
1582                    fprintf(stderr,
1583                            "psparse: size must be provided for input slot.\n");
1584                    if (exitonerror)
1585                        exit(2);
1586                }
1587            }
1588        }
1589    }
1590    else {
1591        fprintf(stderr,"psparse: Unsupported printer feature: %s ",feature);
1592        if (option)
1593            fprintf(stderr,"%s.\n",option);
1594        else fprintf(stderr,".\n");
1595        if (exitonerror) exit(2);
1596    }
1597}
1598
1599static void IncludeFeature(output,ndex,strip)
1600    FILE *output;
1601    int ndex;
1602    int strip;
1603{
1604    if (!strip) {
1605        fprintf(output,"%%%%BeginFeature: %s ",features[ndex].name);
1606        if (features[ndex].option)
1607            fprintf(output,"%s\n",features[ndex].option);
1608        else fprintf(output,"\n");
1609    }
1610    fputs(features[ndex].code,output);
1611    fprintf(output,"\n");
1612    if (!strip)
1613        fprintf(output,"%%%%EndFeature\n");
1614}
1615
1616static void CommandLineFeatures(control)
1617    struct controlswitches control;
1618{
1619    int i;
1620    long loc;
1621    char tmp[100];
1622
1623    if (setupbegin > -1)
1624        loc = setupbegin;
1625    else if (endpro > -1)
1626        loc = endpro;
1627    else loc = 0;
1628
1629    for (i = 0; i < control.nfeatures; i++) {
1630        strncpy(tmp,control.features[i].keyword,100);
1631        if (control.features[i].option) {
1632            strncat(tmp," ",100);
1633            strncat(tmp,control.features[i].option,100);
1634        }
1635        HandleFeatures(tmp,loc,TRUE,control);
1636    }
1637}
1638   
1639static void CheckPrinterLevel(level,printer)
1640    int level;
1641    char *printer;
1642{
1643    char *q;
1644    int plevel;
1645
1646
1647    if (!noppd) {
1648        rewind(ppd);
1649        q = parseppd(ppd,"*LanguageLevel",NULL);
1650        if (q)
1651            plevel = atoi(q);
1652        else
1653            plevel = 1;
1654        if (level > plevel) {
1655            fprintf(stderr,"Warning: document language level greater than printer language level!\n");
1656            if (exitonerror)
1657                exit(2);
1658        }
1659    }
1660}
1661
1662static int Level2()
1663{
1664    char *q;
1665    int level;
1666
1667    if (!noppd) {
1668        rewind(ppd);
1669        q = parseppd(ppd,"*LanguageLevel",NULL);
1670        if (q) {
1671            level = atoi(q);
1672            if (level == 2)
1673                return TRUE;
1674        }
1675    }
1676    return FALSE;
1677}
1678
1679static void CheckSize(p)
1680    char *p;
1681{
1682    char *q;
1683   
1684    while (*p++ == ' ');
1685    q = strchr(p,' ');
1686    if (q) {
1687        *q++ = '\0';
1688        if (!strncmp(p,"*PageSize",9)) {
1689            p = strchr(q,'\n');
1690            *p = '\0';
1691            strncpy(docpagesize,q,50);
1692        }
1693    }
1694}
1695
1696
1697static char *PageSizeGiven(feats, nfeats)
1698    struct comfeatures feats[];
1699    int nfeats;
1700{
1701    int i;
1702    char *size;
1703
1704    for (i=0; i<nfeats; i++) {
1705        if (strncmp(feats[i].keyword,"*PageSize",9) == 0)
1706            return feats[i].option;
1707        if (strncmp(feats[i].keyword, "*PageRegion", 11) == 0)
1708            return feats[i].option;
1709    }
1710    if (docpagesize[0] != '\0')
1711        return docpagesize;
1712    if (!noppd) {
1713        rewind(ppd);
1714        size = parseppd(ppd,"*DefaultPageSize", NULL);
1715        if (size) {
1716            strncpy(docpagesize, size, 50);
1717            return docpagesize;
1718        }
1719    }
1720    return NULL;
1721}
1722static void ShrinkToFit(out, control)
1723    FILE *out;
1724    struct controlswitches control;
1725{
1726    float x, y;
1727    float scale;
1728    char *str;
1729    char *size;
1730
1731    if (noppd) {
1732        fprintf(stderr, "psparse: must specify a printer for squeezing.\n");
1733        if (exitonerror)
1734            exit(2);
1735    }
1736    else {
1737        rewind(ppd);
1738        size = PageSizeGiven(control.features, control.nfeatures);
1739        if (size) {
1740            rewind(ppd);
1741            str = parseppd(ppd, "*PaperDimension", size);
1742            if (str) {
1743                sscanf(str, "%f %f", &x, &y);
1744                scale = x/y;
1745                fprintf(out, "%5.1f %5.1f scale\n", scale, scale);
1746            }
1747            else {
1748                fprintf(stderr,
1749                        "psparse: no *PaperDimension entry! using default.\n");
1750                scale = 612.0/792.0;
1751                fprintf(out, "%5.1f %5.1f scale\n", scale, scale);
1752            }
1753        }
1754        else {
1755            fprintf(stderr,
1756                    "psparse: must specify a page size for squeezing.\n");
1757            if (exitonerror)
1758                exit(2);
1759        }
1760    }
1761}
1762               
1763static void DoLandscape(out,control)
1764    FILE *out;
1765    struct controlswitches control;
1766{
1767    float x, y;
1768    char *str;
1769    char *size;
1770
1771    if (!noppd) {
1772        rewind(ppd);
1773        size = PageSizeGiven(control.features, control.nfeatures);
1774        if (size) {
1775            rewind(ppd);
1776            str = parseppd(ppd,"*PaperDimension",size);
1777            if (str) {
1778                sscanf(str,"%f %f",&x,&y);
1779                if (control.upper)
1780                    fprintf(out,"90 rotate 0 %5.1f translate\n",-y);
1781                else
1782                    fprintf(out,"90 rotate 0 %5.1f translate\n",-x);
1783            }
1784            else {
1785                fprintf(stderr,
1786                        "psparse: no *PaperDimension entry! using defaults.\n");
1787                if (control.upper)
1788                    fprintf(out,"90 rotate 0 %5.1f translate\n",-612);
1789                else
1790                    fprintf(out,"90 rotate 0 %5.1f translate\n",-792);
1791               
1792            }
1793        }
1794        else {
1795            fprintf(stderr,
1796                    "psparse: must specify a page size for landscape.\n");
1797            if (exitonerror)
1798                exit(2);
1799        }
1800    }
1801    else {
1802        fprintf(stderr,"psparse: must specify a printer for landscape.\n");
1803        if (exitonerror)
1804            exit(2);
1805    }
1806}
1807               
1808
1809static enum comtypes ParseComment(line)
1810    char *line;
1811{
1812    if (!strncmp(line,"%%LanguageLevel:",16))
1813        return langlevel;
1814    if (!strncmp(line,"%%DocumentFonts:",16))
1815        return docfont;
1816    if (!strncmp(line,"%%Page:",7))
1817        return page;
1818    if (!strncmp(line, "%%Pages:", 8))
1819        return pages;
1820    if (!strncmp(line,"%%Trailer",9))
1821        return trailer;
1822    if (!strncmp(line,"%%BeginDocument",15))
1823        return begdoc;
1824    if (!strncmp(line,"%%EndDocument",13))
1825        return enddoc;
1826        /* version 2.0 (2.1?) comments */
1827    if (!strncmp(line,"%%DocumentNeededFonts:",22))
1828        return docneedfont;
1829    if (!strncmp(line,"%%DocumentSuppliedFonts:",24))
1830        return docsupfont;
1831    if (!strncmp(line,"%%IncludeFont:",14))
1832        return incfont;
1833    if (!strncmp(line,"%%BeginFont:",12))
1834        return begfont;
1835    if (!strncmp(line,"%%EndFont",9))
1836        return endfont;
1837    if (!strncmp(line,"%%PageFonts:", 12))
1838        return pagefont;
1839    if (!strncmp(line,"%%DocumentNeededFiles:",22))
1840        return docneedfile;
1841    if (!strncmp(line,"%%DocumentSuppliedFiles:",24))
1842        return docsupfile;
1843    if (!strncmp(line,"%%PageFiles:",12))
1844        return pagefile;
1845    if (!strncmp(line,"%%IncludeFile:",14))
1846        return incfile;
1847    if (!strncmp(line,"%%BeginFile:",12))
1848        return begfile;
1849    if (!strncmp(line,"%%EndFile",9))
1850        return endfile;
1851    if (!strncmp(line,"%%DocumentProcSets:",19))
1852        return docproc;
1853    if (!strncmp(line,"%%DocumentNeededProcSets:",25))
1854        return docneedproc;
1855    if (!strncmp(line,"%%DocumentSuppliedProcSets:",27))
1856        return docsupproc;
1857    if (!strncmp(line,"%%IncludeProcSet:",17))
1858        return incproc;
1859    if (!strncmp(line,"%%BeginProcSet:",15))
1860        return begproc;
1861    if (!strncmp(line,"%%EndProcSet",12))
1862        return endproc;
1863       /* version 3 comments */
1864    if (!strncmp(line,"%%DocumentNeededResources:",26))
1865        return docneedres;
1866    if (!strncmp(line,"%%DocumentSuppliedResources:",28))
1867        return docsupres;
1868    if (!strncmp(line,"%%PageResources:",16))
1869        return pageres;
1870    if (!strncmp(line,"%%IncludeResource:",18))
1871        return incres;
1872    if (!strncmp(line,"%%BeginResource:",15))
1873        return begres;
1874    if (!strncmp(line,"%%EndResource",13))
1875        return endres;
1876    if (!strncmp(line,"%%IncludeFeature:",17))
1877        return incfeature;
1878    if (!strncmp(line,"%%Feature:",10))
1879        return incfeature;
1880    if (!strncmp(line,"%%BeginFeature:",15))
1881        return begfeature;
1882    if (!strncmp(line,"%%EndFeature",12))
1883        return endfeature;
1884    if (!strncmp(line,"%%BeginBinary",13))
1885        return begbin;
1886    if (!strncmp(line,"%%EndBinary",11))
1887        return endbin;
1888    if (!strncmp(line,"%%BeginData",11))
1889        return begdata;
1890    if (!strncmp(line,"%%EndData",9))
1891        return enddata;
1892    if (!strncmp(line,"%%BeginProlog", 13))
1893        return begprolog;
1894    if (!strncmp(line,"%%EndProlog",11))
1895        return endprolog;
1896    if (!strncmp(line,"%%BeginSetup",12))
1897        return begsetup;
1898    if (!strncmp(line,"%%EndSetup",10))
1899        return endsetup;
1900    if (!strncmp(line,"%%EndComments",13))
1901        return endcomment;
1902    if (!strncmp(line,"%%PageOrder:",11))
1903        return pageorder;
1904    if (!strncmp(line,"%%BeginDefaults",15))
1905        return begdef;
1906    if (!strncmp(line,"%%EndDefaults",13))
1907        return enddef;
1908    if (!strncmp(line, "%%Orientation:", 14))
1909        return orient;
1910    return invalid;
1911}
1912
1913enum status HandleComments(input,printer,resourcepath,control)
1914    FILE *input;
1915    char *printer;
1916    char *resourcepath;
1917    struct controlswitches control;
1918{
1919    char buf[PSBUFSIZ];
1920    int i;
1921    long location;
1922    char *p,*q;
1923    enum comtypes context;
1924    int skip = 0;
1925    int dontchecklength = 0;
1926    int continuation = FALSE;
1927    int level;
1928    char tempstr[20];
1929
1930
1931    InitPrinterInfo(printer);
1932    exitonerror = !(control.force);
1933    fgets(buf,PSBUFSIZ,input);
1934    if (strncmp(buf,"%!",2))
1935        return notps;
1936    if (strncmp(buf,"%!PS-Adobe-",11))
1937        return notcon;
1938    if (control.noparse) return success;
1939
1940    for (i = 0; i < MAXRESTYPES; i++)
1941        nNR[i] = nSR[i] = 0;
1942
1943    /* okay, we've got a conforming file, let's find out the version */
1944    for (i = 11; buf[i] != ' ' && buf[i] != '\n'; i++)
1945        if (buf[i] != '.')
1946            version = version * 10 + buf[i] - '0';
1947
1948    /* parse on! */
1949    CommandLineFeatures(control);
1950    location = ftell(input);
1951    while (fgets(buf,PSBUFSIZ,input)) {
1952        if ((p = strchr(buf, '\n')) == NULL) {
1953            /* tolerate long lines, except on comments */
1954            if (buf[0] == '%') {
1955                fprintf(stderr,
1956                        "psparse: comment line too long!\n");
1957                if (exitonerror)
1958                    exit(2);
1959            }
1960            else {
1961                fprintf(stderr,
1962                        "psparse: line longer than 255 characters\n");
1963                fprintf(stderr, "psparse: proceeding anyway\n");
1964                while (fgets(buf, PSBUFSIZ, input)) {
1965                    if ((p = strchr(buf, '\n')) != NULL)
1966                        break;
1967                }
1968            }
1969        }
1970        if (!strncmp(buf,"%%%NOPARSE",10))
1971            return handled;
1972        if (!strncmp(buf,"%%%PARSED:",10)) {
1973            /* check printer: might have been handled for different printer */
1974            p = strchr(buf,':'); p++;
1975            while (*p == ' ') p++;
1976            if (!strcmp(printer,p))
1977                return handled;
1978        }
1979        if (!strncmp(buf,"%%%CMP",6))
1980            alreadycompressed = TRUE;
1981        if (prologbegin == -1)
1982            if (buf[0] != '%' || !strncmp(buf,"% ",2) ||
1983                !strncmp(buf,"%\n",2) || !strncmp(buf,"%\t",2)) {
1984                prologbegin = location;
1985            }
1986        if (strncmp(buf,"%%",2)) {
1987            location = ftell(input);
1988            continue;
1989        }
1990        p = strchr(buf,':');
1991        if (p) p++;
1992        if (strncmp(buf,"%%+",3)) {
1993            context = ParseComment(buf);
1994            continuation = FALSE;
1995        }
1996        else {
1997            continuation = TRUE;
1998            p = strchr(buf,'+');
1999            p++;
2000        }
2001        switch (context) {
2002        case begdef:
2003            defaultSection = TRUE;
2004            break;
2005        case enddef:
2006            defaultSection = FALSE;
2007            break;
2008        case langlevel:
2009            q = strrchr(p,'\n');
2010            if (q) *q = '\0';
2011            level = atoi(p);
2012            CheckPrinterLevel(level,printer);
2013            break;
2014        case pageorder:
2015            if (!strncmp(p,"(atend)",7))
2016                break;
2017            if (!strncmp(p,"Special",7))
2018                ordered = FALSE;
2019            break;
2020        case pages:
2021            if (firstpages == -1)
2022                firstpages = location;
2023            break;
2024        case page:
2025            if (!skip) {
2026                ptable[npages].location = location;
2027                sscanf(buf,"%s %s %d",tempstr, ptable[npages].label,
2028                       &ptable[npages].pageno);
2029                npages++;
2030                if (endpro == -1) endpro = location;
2031            }
2032            break;
2033        case trailer:
2034            if (!skip) {
2035                endlast = location;
2036                ptable[npages].location = location;
2037            }
2038            break;
2039        case begdoc:
2040            skip++;
2041            break;
2042        case enddoc:
2043            skip--;
2044            break;
2045        case incfeature:
2046            HandleFeatures(p,location, FALSE, control);
2047        case begfeature:
2048            CheckSize(p);
2049        case orient:
2050            /* check to see if it matches what we want */
2051            /* we're only going to modify things if control.landscape is
2052               true *and* the Orientation comment says Portrait.  If
2053               control.landscape is false, we're not changing the
2054               orientation of the original document, so we shouldn't change
2055               the comment */
2056            if (control.landscape) {
2057                if (strncmp(p, "Portrait", 8) == 0) {
2058                    /* it's not what we want */
2059                    remcomment[IncRemIndex()] = location;
2060                }
2061            }
2062            break;
2063        case begsetup:
2064            if (!skip) {
2065                remcomment[IncRemIndex()] = location;
2066                setupbegin = location;
2067            }
2068            break;
2069        case endsetup:
2070            if (!skip) {
2071                remcomment[IncRemIndex()] = location;
2072                setupend = location;
2073            }
2074            break;
2075        case endcomment:
2076        case begprolog:
2077            if (!skip) {
2078                remcomment[IncRemIndex()] = location;
2079                prologbegin = location;
2080            }
2081            break;
2082        case endprolog:
2083            if (!skip) {
2084                remcomment[IncRemIndex()] = location;
2085                prologend = location;
2086            }
2087            break;
2088        case docfont:
2089            if (skip) break;
2090            CheckResources(p, FONT, location, download, context, printer,
2091                           resourcepath, continuation, control);
2092            remcomment[IncRemIndex()] = location;
2093            break;
2094        case docneedfont:
2095            if (skip) break;
2096            CheckResources(p, FONT, location, future, context, printer,
2097                           resourcepath, continuation, control);
2098            remcomment[IncRemIndex()] = location;
2099            break;
2100        case docsupfont:
2101            if (skip) break;
2102            CheckResources(p, FONT, location, verify, context, printer,
2103                           resourcepath, continuation, control);
2104            remcomment[IncRemIndex()] = location;
2105            break;
2106        case pagefont:
2107            if (skip) break;
2108            CheckResources(p, FONT, location, future, context, printer,
2109                           resourcepath, continuation, control);
2110            break;
2111        case incfont:
2112            if (skip) break;
2113            CheckResources(p, FONT, location, download, context, printer,
2114                           resourcepath, continuation, control);
2115            break;
2116        case begfont:
2117            if (skip) break;
2118            CheckResources(p, FONT, location, indocument, context, printer,
2119                           resourcepath, continuation, control);
2120            break;
2121        case endfont:
2122            break;
2123        case docneedfile:
2124            if (skip) break;
2125            CheckResources(p, RFILE, location, future, context, printer,
2126                           resourcepath, continuation, control);
2127            remcomment[IncRemIndex()] = location;
2128            break;
2129        case docsupfile:
2130            if (skip) break;
2131            CheckResources(p, RFILE, location, verify, context, printer,
2132                           resourcepath, continuation, control);
2133            remcomment[IncRemIndex()] = location;
2134            break;
2135        case pagefile:
2136            if (skip) break;
2137            CheckResources(p, RFILE, location, future, context, printer,
2138                           resourcepath, continuation, control);
2139            break;
2140        case incfile:
2141            CheckResources(p, RFILE, location, download, context, printer,
2142                           resourcepath, continuation, control);
2143            break;
2144        case begfile:
2145            if (skip) break;
2146            CheckResources(p, RFILE, location, indocument, context,
2147                           printer, resourcepath, continuation, control);
2148            break;
2149        case endfile:
2150            break;
2151        case docproc:
2152            if (skip) break;
2153            CheckResources(p, PROCSET, location, download, context,
2154                           printer, resourcepath, continuation, control);
2155            remcomment[IncRemIndex()] = location;
2156            break;
2157        case docneedproc:
2158            if (skip) break;
2159            CheckResources(p, PROCSET, location,  future,  context,
2160                           printer, resourcepath, continuation, control);
2161            remcomment[IncRemIndex()] = location;
2162            break;
2163        case docsupproc:
2164            if (skip) break;
2165            CheckResources(p, PROCSET, location, verify, context, printer,
2166                           resourcepath, continuation, control);
2167            remcomment[IncRemIndex()] = location;
2168            break;
2169        case incproc:
2170            CheckResources(p, PROCSET, location, download, context,
2171                           printer, resourcepath, continuation, control);
2172            break;
2173        case begproc:
2174            if (skip) break;
2175            CheckResources(p, PROCSET, location, indocument, context,
2176                           printer, resourcepath, continuation, control);
2177            break;
2178        case endproc:
2179            break;
2180        case docneedres:
2181            if (skip) break;
2182            CheckResources(p, UNKNOWN, location, future, context, printer,
2183                           resourcepath, continuation, control);
2184            remcomment[IncRemIndex()] = location;
2185            break;
2186        case docsupres:
2187            if (skip) break;
2188            CheckResources(p, UNKNOWN, location, verify, context, printer,
2189                           resourcepath, continuation, control);
2190            remcomment[IncRemIndex()] = location;
2191            break;
2192        case pageres:
2193            if (skip) break;
2194            CheckResources(p, UNKNOWN, location, future, context, printer,
2195                           resourcepath, continuation, control);
2196            break;
2197        case incres:
2198            CheckResources(p, UNKNOWN, location, download, context,
2199                           printer, resourcepath, continuation, control);
2200            break;
2201        case begres:
2202            if (skip) break;
2203            CheckResources(p, UNKNOWN, location, indocument, context,
2204                           printer, resourcepath, continuation, control);
2205            break;
2206        case begbin:
2207        case begdata:
2208            dontchecklength++;
2209            break;
2210        case endbin:
2211        case enddata:
2212            dontchecklength--;
2213            break;
2214        case endres: break;
2215        case invalid: break;
2216        default: break;
2217        }
2218        location = ftell(input);
2219    }
2220    location = ftell(input);
2221    if (endlast == -1) ptable[npages].location = location;
2222    if (!control.norearrange) {
2223        PrologAndSetup();
2224        ReArrange(printer);
2225    }
2226    BuildDownLoadTable();
2227    RangeResources();
2228    return success;
2229}
2230
2231static int CheckOrientation(buffer, output, landscape)
2232    char *buffer;
2233    FILE *output;
2234{
2235    if (strncmp(buffer, "%%Orientation:", 14) == 0) {
2236        /* we already know that this orientation comment doesn't match what
2237           we want, or we wouldn't be here, so put out correct comment.  We
2238           also know that we're only changing to Landscape. */
2239        if (landscape) {
2240            fprintf(output, "%%%%Orientation: Landscape\n");
2241        }
2242        return TRUE;
2243    }
2244    return FALSE;
2245}
2246           
2247
2248static void PutBuf(buffer, output)
2249    char *buffer;
2250    FILE *output;
2251{
2252    char *p;
2253    int i;
2254
2255    p = strchr(buffer, '\n');
2256    if (((int) strlen(buffer) < PSBUFSIZ - 1) && !p) {
2257        for (i = 0; i < PSBUFSIZ - 1; i++) {
2258            fputc(buffer[i], output);
2259            if (buffer[i] == '\n')
2260                break;
2261        }
2262    }
2263    else
2264        fputs(buffer, output);
2265    memset(buffer, 0, PSBUFSIZ);
2266}
2267           
2268
2269void HandleOutput(input, output, printer, control)
2270    FILE *input, *output;
2271    char *printer;
2272    struct controlswitches control;
2273{
2274    int downndx, remndx, pagendx, featndx;
2275    char buf[PSBUFSIZ];
2276    long location;
2277    int i;
2278    int reverse;
2279    int fdin, fdout;
2280    FILE *out;
2281    int cnt;
2282    char bigbuf[TSBUFSIZE];
2283    int status;
2284    int filtering = FALSE;
2285    int dolandscape = FALSE;
2286
2287    /* now, let's ship result to output */
2288    fdin = fileno(input);
2289    if (!(filtering = SetupCompression(&out,fileno(output), control)))
2290        out = output;
2291    reverse = control.reverse;
2292    if (endpro == -1 || npages == 0)
2293        reverse = FALSE;
2294    downndx = remndx = featndx = 0;
2295    if (reverse)
2296        pagendx = npages - 1;
2297    else pagendx = 0;
2298    if (!control.noparse) {
2299        fgets(buf, PSBUFSIZ, input);
2300        if (control.strip) {
2301            sprintf(buf, "%%!\n");
2302            PutBuf(buf, out);
2303        }
2304        else {
2305            if (version == VERS1)
2306                sprintf(buf, "%%!PS-Adobe-2.1\n");
2307            PutBuf(buf, out);
2308            if (printer)
2309                fprintf(out, "%%%%%%PARSED: %s\n", printer);
2310            OutputComments(out);
2311        }
2312        location = ftell(input);
2313        while (fgets(buf, PSBUFSIZ, input)) {
2314            if (location == prologbegin && !control.strip && prologend > -1)
2315                fprintf(out, "%%%%BeginProlog\n");
2316            /* check for procsets to download */
2317            if (downndx < ndloads) {
2318                if (location == dloads[downndx].location) {
2319                    for (i = downndx; location == dloads[i].location; i++)
2320                        if (dloads[i].index >= 0 &&
2321                            dloads[i].type == PROCSET)
2322                            DownLoadResource(dloads[i].index, out, control.strip);
2323                }
2324            }
2325            if (location == prologend && !control.strip)
2326                fprintf(out, "%%%%EndProlog\n");
2327            if (location == setupbegin) {
2328                if (!control.strip) {
2329                    fprintf(out, "%%%%BeginSetup\n");
2330                    CheckIncludes(out);
2331                }
2332                if (featndx < nfeatures && features[featndx].location == 0) {
2333                    /* features specified on command line that don't replace
2334                       something specified in document */
2335                    for (; features[featndx].location == 0 && featndx <
2336                         nfeatures; featndx++)
2337                        if (features[featndx].code)
2338                            IncludeFeature(out, featndx, control.strip);
2339                }
2340            }
2341            if (reverse) {
2342                if (location == endpro && pagendx > 0) {
2343                    fseek(input, ptable[pagendx].location, 0);
2344                    location = ftell(input);
2345                    downndx = finddloc(location);
2346                    remndx = findrloc(location);
2347                    featndx = findfloc(location);
2348                    continue;
2349                }
2350                if (location == ptable[pagendx].location && pagendx >= 0) {
2351                    if (!InRange(ptable[pagendx].pageno,control.ranges)) {
2352                        /* outside range, skip to next page */
2353                        if (pagendx == 0) {
2354                            fseek(input,endlast, 0);
2355                            pagendx--;
2356                        }
2357                        else
2358                            fseek(input,ptable[--pagendx].location,0);
2359                        location = ftell(input);
2360                        downndx = finddloc(location);
2361                        remndx = findrloc(location);
2362                        featndx = findfloc(location);
2363                        continue;
2364                    }
2365                    if (control.landscape)
2366                        dolandscape = TRUE;
2367                }
2368                if (location == ptable[pagendx + 1].location && pagendx >= 0) {
2369                    if (pagendx == 0) {
2370                        fseek(input, endlast, 0);
2371                        pagendx--;
2372                    }
2373                    else
2374                        fseek(input, ptable[--pagendx].location, 0);
2375                    location = ftell(input);
2376                    downndx = finddloc(location);
2377                    remndx = findrloc(location);
2378                    featndx = findfloc(location);
2379                    continue;
2380                }
2381            }
2382            else {
2383                if (location == ptable[pagendx].location && pagendx != npages) {
2384                    if (!InRange(ptable[pagendx].pageno, control.ranges)) {
2385                        /* outside the range, skip to next page */
2386                        fseek(input,ptable[++pagendx].location,0);
2387                        location = ftell(input);
2388                        downndx = finddloc(location);
2389                        remndx = findrloc(location);
2390                        featndx = findfloc(location);
2391                        continue;
2392                    }
2393                    else {
2394                        /* inside the range, keep on going */
2395                        pagendx++;
2396                        if (control.landscape)
2397                            dolandscape = TRUE;
2398                    }
2399                }
2400            }
2401            if (downndx < ndloads) {
2402                if (location == dloads[downndx].location) {
2403                    for (; location == dloads[downndx].location; downndx++)
2404                        if (dloads[downndx].index >= 0 &&
2405                            dloads[downndx].type != PROCSET)
2406                            DownLoadResource(dloads[downndx].index, out, control.strip);
2407                }
2408            }
2409            if (featndx < nfeatures) {
2410                if (location == features[featndx].location) {
2411                    for (; location == features[featndx].location; featndx++)
2412                        if (features[featndx].code)
2413                            IncludeFeature(out, featndx, control.strip);
2414                }
2415            }
2416            if (location == setupend && !control.strip)
2417                fprintf(out, "%%%%EndSetup\n");
2418            if (remndx < nrem) {
2419                if (location == remcomment[remndx]) {
2420                    if (!CheckOrientation(buf, out, control.landscape))
2421                        remndx++;
2422                }
2423                else if (!(control.strip && *buf == '%'))
2424                    PutBuf(buf, out);
2425            }
2426            else if (!(control.strip && *buf == '%'))
2427                PutBuf(buf, out);
2428            if (dolandscape) {
2429                DoLandscape(out, control);
2430                dolandscape = FALSE;
2431                if (control.squeeze)
2432                    ShrinkToFit(out, control);
2433            }
2434            location = ftell(input);
2435        }
2436        if (control.addshowpage) {
2437            fprintf(out, "\nshowpage\n");
2438        }
2439        fflush(out);
2440    }
2441    else {
2442        fgets(buf,PSBUFSIZ,input);
2443        cnt = strlen(buf);
2444        PutBuf(buf,out);
2445        fprintf(out,"%%%%%%NOPARSE\n");
2446        fflush(out);
2447        fdout = fileno(out);
2448        lseek(fdin,cnt,SEEKING);
2449        while ((cnt = read(fdin,bigbuf,BUFSIZ)) > 0)
2450            write(fdout,bigbuf,cnt);
2451    }
2452    if (filtering) {
2453        fclose(out);
2454        wait(&status);
2455    }
2456}
2457
2458int SetupCompression(fptr, outfd, control)
2459    FILE **fptr;
2460    int outfd;
2461    struct controlswitches control;
2462{
2463    int fpid;
2464    int f2pid;
2465    char pathname[TSPATHSIZE];
2466    FILE *outptr;
2467    int binok = FALSE;
2468    char *value;
2469
2470    if (alreadycompressed)
2471        return FALSE;
2472    if (value = getenv("BINARYOK")) {
2473        if (strcmp(value, "1") == 0) {
2474            binok = TRUE;
2475        }
2476    }
2477    /* if it's a Level 2 printer, can compress */
2478    if ((Level2() && control.compress) || (control.compress && control.force)) {
2479        outptr = fdopen(outfd, "w");
2480        fprintf(outptr, "%%!\n");
2481        fprintf(outptr, "%%%%%%CMP\n");
2482        if (!binok) {
2483            fprintf(outptr, "currentfile /ASCII85Decode filter ");
2484        }
2485        else {
2486            fprintf(outptr, "currentilfe ");
2487        }
2488        fprintf(outptr, "/LZWDecode filter cvx exec\n");
2489        fflush(outptr);
2490        if (pipe(fd1pipe)) {
2491            fprintf(stderr,"Error in pipe.\n");
2492            perror("");
2493        }
2494        if (!binok) {
2495            if (pipe(fd2pipe)) {
2496                fprintf(stderr,"Error in 2nd pipe.\n");
2497                perror("");
2498                exit(2);
2499            }
2500        }
2501        if ((fpid = fork()) < 0) {
2502            fprintf(stderr, "Error in compression fork.\n");
2503            perror("");
2504            exit(2);
2505        }
2506        if (fpid == 0) {
2507            /* compression fork */
2508            if (!binok) {
2509                /* need to encode the binary */
2510                if ((f2pid = fork()) < 0) {
2511                    fprintf(stderr, "Error in encoding fork.\n");
2512                    perror("");
2513                    exit(2);
2514                }
2515                if (f2pid == 0) {
2516                    /* encoding fork */
2517                    if (dup2(outfd, 1) < 0) {
2518                        fprintf(stderr, "Error connecting output.\n");
2519                        perror("");
2520                        exit(2);
2521                    }
2522                    if ((dup2(fd2pipe[0], 0) < 0) || close(fd2pipe[0]) ||
2523                        close(fd2pipe[1]) || close(fd1pipe[0]) ||
2524                        close(fd1pipe[1])) {
2525                        fprintf(stderr, "Error in encoding child.\n");
2526                        perror("");
2527                        exit(2);
2528                    }
2529                    sprintf(pathname, "%s/asc85ec", PSLibDir);
2530                    execl(pathname, (char *) 0);
2531                    fprintf(stderr, "Error exec'ing %s\n", pathname);
2532                    perror("");
2533                    exit(2);
2534                }
2535                if ((dup2(fd2pipe[1], 1) < 0) || close(fd2pipe[1]) ||
2536                    close(fd2pipe[0])) {
2537                    fprintf(stderr,
2538                            "Error in compressing child (output pipe)\n");
2539                    perror("");
2540                    exit(2);
2541                }
2542            }
2543            else {
2544                /* don't need to encode */
2545                if (dup2(outfd, 1) < 0) {
2546                    fprintf(stderr,
2547                            "Error in compressing child (output)\n");
2548                    perror("");
2549                    exit(2);
2550                }
2551            }
2552            if ((dup2(fd1pipe[0], 0) < 0) || close(fd1pipe[0]) ||
2553                close(fd1pipe[1])) {
2554                fprintf(stderr, "Error in compressing child (input).\n");
2555                perror("");
2556                exit(2);
2557            }
2558            sprintf(pathname, "%s/lzwec", PSLibDir);
2559            execl(pathname, (char *) 0);
2560            fprintf(stderr, "Error exec'ing %s\n", pathname);
2561            perror("");
2562            exit(2);
2563        }
2564        *fptr = fdopen(fd1pipe[1], "w");
2565        if (!binok) {
2566            close(fd2pipe[0]); close(fd2pipe[1]);
2567        }
2568        close(fd1pipe[0]);
2569        return TRUE;
2570    }
2571    return FALSE;
2572}
Note: See TracBrowser for help on using the repository browser.