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

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