xref: /csrg-svn/local/transcript/src/psrev.c (revision 45148)
1*45148Skarels #ifndef lint
2*45148Skarels static char Notice[] = "Copyright (c) 1985 Adobe Systems Incorporated";
3*45148Skarels static char *RCSID="$Header: psrev.c,v 2.1 85/11/24 11:51:02 shore Rel $";
4*45148Skarels #endif
5*45148Skarels /* psrev.c
6*45148Skarels  *
7*45148Skarels  * Copyright (c) 1985 Adobe Systems Incorporated
8*45148Skarels  *
9*45148Skarels  * page reversal and selection filter
10*45148Skarels  *
11*45148Skarels  * Original Version: Tom Malloy
12*45148Skarels  * Edit History:
13*45148Skarels  * Andrew Shore: Fri Nov 22 11:20:20 1985
14*45148Skarels  * End Edit History.
15*45148Skarels  *
16*45148Skarels  * RCSLOG:
17*45148Skarels  * $Log:	psrev.c,v $
18*45148Skarels  * Revision 2.1  85/11/24  11:51:02  shore
19*45148Skarels  * Product Release 2.0
20*45148Skarels  *
21*45148Skarels  * Revision 1.4  85/11/22  11:31:05  shore
22*45148Skarels  * Last line of trailer was dropped if it didn't end in a newline
23*45148Skarels  *
24*45148Skarels  * Revision 1.3  85/11/20  00:52:21  shore
25*45148Skarels  * Support for System V
26*45148Skarels  * getopt!
27*45148Skarels  * made lint a little happier
28*45148Skarels  *
29*45148Skarels  * Revision 1.2  85/05/14  11:26:38  shore
30*45148Skarels  *
31*45148Skarels  *
32*45148Skarels  *
33*45148Skarels  */
34*45148Skarels 
35*45148Skarels #include <stdio.h>
36*45148Skarels #include <ctype.h>
37*45148Skarels #include <pwd.h>
38*45148Skarels #include <sys/types.h>
39*45148Skarels #include <sys/stat.h>
40*45148Skarels #include "transcript.h"
41*45148Skarels 
42*45148Skarels #define SCVERID "%!PS-Adobe-"
43*45148Skarels #define ichMaxPage 7
44*45148Skarels #define SCPAGE "%%Page:"
45*45148Skarels #define ichMaxTrailer 9
46*45148Skarels #define SCTRAILER "%%Trailer"
47*45148Skarels 
48*45148Skarels #define ipgMax 2000	/* Maximum number of pages - first page index is 0 */
49*45148Skarels #define irngMax 30	/* Maximum number of intervals in a page range spec */
50*45148Skarels 
51*45148Skarels private struct Range	/* continuous interval of pages to be printed */
52*45148Skarels 			/* from a page range specification (i.e. -s) */
53*45148Skarels 			/* page numbers match the second parameter */
54*45148Skarels 			/* of the "%%Page: " comment */
55*45148Skarels     { int	pgnFst;
56*45148Skarels     int		pgnLst;
57*45148Skarels     };
58*45148Skarels private struct Params	/* interesting info collected from command line */
59*45148Skarels     { int	fReverse; /* true => reverse page order */
60*45148Skarels     int		fRemove;  /* true => remove input file */
61*45148Skarels     char	*scSrcFile; /* c-string containing source file name */
62*45148Skarels     char	*scDstFile; /* c-string containing destination file name */
63*45148Skarels     int		irngMac;  /* number of intervals in rgrange */
64*45148Skarels     struct Range rgrange[irngMax]; /* array of intervals of pages */
65*45148Skarels                                      /* to be printed.  One entry per */
66*45148Skarels                                      /* entry in the "-s" parameter */
67*45148Skarels     };
68*45148Skarels 
69*45148Skarels private struct Psd	/* PS file descriptor */
70*45148Skarels     { FILE	*fp;	/* unix file descriptor  of source */
71*45148Skarels     FILE	*fpTemp;/* temp file descriptor.  Contains a
72*45148Skarels 			   copy of source when fd is not a regular file */
73*45148Skarels     long int	posLineFst, posMac;
74*45148Skarels 			/* file positions - current, beginning of line, eof */
75*45148Skarels     };
76*45148Skarels 
77*45148Skarels private struct stat S;
78*45148Skarels private char *prog;
79*45148Skarels 
80*45148Skarels 
81*45148Skarels /* Reads a signed integer from c-string */
82*45148Skarels /* Input is a pointer to pointer to string */
83*45148Skarels /* On return, it points to first character following the parsed numeral */
84*45148Skarels private IntGet(prgch)
85*45148Skarels char	**prgch;
86*45148Skarels { int	i, fNeg;
87*45148Skarels char	*rgch, ch;
88*45148Skarels 
89*45148Skarels i = 0; rgch = *prgch;
90*45148Skarels if ((ch = *rgch) == '-')
91*45148Skarels      { fNeg = TRUE; rgch++;}
92*45148Skarels else { if (ch == '+') rgch++; fNeg = FALSE;}
93*45148Skarels while (((ch = *rgch) >= '0') && (ch <= '9'))
94*45148Skarels     { rgch++; i = 10*i + (ch - '0');}
95*45148Skarels *prgch = rgch;
96*45148Skarels return(fNeg ? -i : i);
97*45148Skarels }
98*45148Skarels 
99*45148Skarels 
100*45148Skarels /* Parses the "-s" parameter.  Fills the array params.rgrange */
101*45148Skarels /* with a page interval range for each entry int the comma separated list */
102*45148Skarels /* *prgch points at the character following the "s" command */
103*45148Skarels private SetPageRanges(rgch, pparams)
104*45148Skarels char	*rgch;
105*45148Skarels struct Params *pparams;
106*45148Skarels { char	ch;
107*45148Skarels char	*scError;
108*45148Skarels struct Range *rgrange;
109*45148Skarels #define pgnMax 30000
110*45148Skarels 
111*45148Skarels scError = "Syntax error in page range specification while parsing ";
112*45148Skarels rgrange = pparams->rgrange;
113*45148Skarels while (TRUE)
114*45148Skarels     {
115*45148Skarels     if ((ch = *rgch) == '-')
116*45148Skarels         { rgrange[pparams->irngMac].pgnFst = 1;
117*45148Skarels         rgch++;
118*45148Skarels         rgrange[pparams->irngMac].pgnLst = IntGet(&rgch);
119*45148Skarels         }
120*45148Skarels     else
121*45148Skarels         {
122*45148Skarels         rgrange[pparams->irngMac].pgnFst = IntGet(&rgch);
123*45148Skarels         if ((ch = *rgch) == '-')
124*45148Skarels             { rgch++;
125*45148Skarels             if ((( ch = *rgch) == ',') || (ch == '\0'))
126*45148Skarels                  rgrange[pparams->irngMac].pgnLst = pgnMax;
127*45148Skarels             else rgrange[pparams->irngMac].pgnLst = IntGet(&rgch);
128*45148Skarels             }
129*45148Skarels         else if ((( ch = *rgch) == ',') || (ch == '\0'))
130*45148Skarels              { rgrange[pparams->irngMac].pgnLst =
131*45148Skarels                      rgrange[pparams->irngMac].pgnFst;
132*45148Skarels 	     }
133*45148Skarels         else if (rgrange[pparams->irngMac].pgnFst > 0)
134*45148Skarels              { fprintf(stderr, "%s%s\n", scError, rgch);
135*45148Skarels              exit(4);
136*45148Skarels              }
137*45148Skarels         }
138*45148Skarels     if ((rgrange[pparams->irngMac].pgnFst == 0) ||
139*45148Skarels         (rgrange[pparams->irngMac].pgnLst == 0))
140*45148Skarels             { fprintf(stderr, "%s%s\n",
141*45148Skarels                               scError, rgch);
142*45148Skarels              exit(4);
143*45148Skarels 	    }
144*45148Skarels     if (++pparams->irngMac >= irngMax)
145*45148Skarels         { fprintf(stderr, "Too many intervals in page range specificaiton\n");
146*45148Skarels         exit(4);
147*45148Skarels 	}
148*45148Skarels     if ((ch = *rgch) == ',')
149*45148Skarels         rgch++;
150*45148Skarels     else if (ch == '\0')
151*45148Skarels          break;
152*45148Skarels     else return;
153*45148Skarels     }
154*45148Skarels }
155*45148Skarels 
156*45148Skarels 
157*45148Skarels /* Returns TRUE if ipg is to be printed; i.e. if it is in one of the
158*45148Skarels    intervals in pparams->rgrange[0..pparams->irngMac) */
159*45148Skarels private FPageInRange(pgn, pparams)
160*45148Skarels int pgn;
161*45148Skarels struct Params *pparams;
162*45148Skarels { int	irng;
163*45148Skarels struct Range *rgrange;
164*45148Skarels #define ichTMax 50
165*45148Skarels #define ichColon 6
166*45148Skarels 
167*45148Skarels if (pparams->irngMac == 0) return(TRUE);
168*45148Skarels rgrange = pparams->rgrange;
169*45148Skarels for (irng = 0; irng < pparams->irngMac; irng++)
170*45148Skarels     { if ((pgn >= rgrange[irng].pgnFst)
171*45148Skarels             && (pgn <= rgrange[irng].pgnLst))
172*45148Skarels         return(TRUE);
173*45148Skarels     }
174*45148Skarels return(FALSE);
175*45148Skarels }
176*45148Skarels 
177*45148Skarels 
178*45148Skarels /* Reads a line from the source PS file */
179*45148Skarels /* Fills the c-string, scDst, with the first ichMacRead characters */
180*45148Skarels /* of the line.  Returns TRUE if it hits end of file, FALSE otherwise */
181*45148Skarels private FEofReadSc(scDst, ichMacRead, ppsd)
182*45148Skarels char	scDst[];
183*45148Skarels int	ichMacRead;
184*45148Skarels struct Psd *ppsd;
185*45148Skarels { int	ich;
186*45148Skarels int	ch;
187*45148Skarels static int ateof = FALSE;
188*45148Skarels 
189*45148Skarels scDst[0] = '\0';
190*45148Skarels ppsd->posLineFst = ftell(ppsd->fp);
191*45148Skarels if (ateof) return(TRUE);
192*45148Skarels for (ich = 0; ich < ichMacRead; ich++)
193*45148Skarels     { scDst[ich] = ch = getc(ppsd->fp);
194*45148Skarels     if ((ch == '\n') || (ch == EOF)) break;
195*45148Skarels     }
196*45148Skarels scDst[ich] = '\0';
197*45148Skarels while ((ch != '\n') && (ch != EOF))
198*45148Skarels     { ch = getc(ppsd->fp);
199*45148Skarels     }
200*45148Skarels if (ch == EOF) {
201*45148Skarels     ateof = TRUE;
202*45148Skarels     return (ich == 0);
203*45148Skarels }
204*45148Skarels return(FALSE);
205*45148Skarels }
206*45148Skarels 
207*45148Skarels /* Returns TRUE if the source is a conforming PS file; */
208*45148Skarels /* i.e. first line of the source PS file contains "%!PS-Adobe-" */
209*45148Skarels private FConforming(ppsd)
210*45148Skarels struct Psd *ppsd;
211*45148Skarels {
212*45148Skarels #define ichMaxVerId 11
213*45148Skarels char	scVerIdT[ichMaxVerId+1];
214*45148Skarels 
215*45148Skarels if (!FEofReadSc(scVerIdT, ichMaxVerId, ppsd)) {
216*45148Skarels     if (strcmp(scVerIdT, SCVERID) == 0) return(TRUE);
217*45148Skarels }
218*45148Skarels return(FALSE);
219*45148Skarels }
220*45148Skarels 
221*45148Skarels /* Finds the beginning of pages.  Loads rgposPage with the file position */
222*45148Skarels /* of the "%%Page:" comment line */
223*45148Skarels private FindPageStarts(ppsd, rgposPage, rgpgnPage, pipgMac)
224*45148Skarels struct Psd *ppsd;
225*45148Skarels long	rgposPage[];
226*45148Skarels int	rgpgnPage[];
227*45148Skarels int	*pipgMac;
228*45148Skarels {
229*45148Skarels #define ichMaxScT 40
230*45148Skarels char scT[ichMaxScT+1];
231*45148Skarels char *scT1;
232*45148Skarels 
233*45148Skarels while (1)
234*45148Skarels     { if (FEofReadSc(scT, ichMaxScT, ppsd))
235*45148Skarels         { rgposPage[*pipgMac] = ppsd->posLineFst; break;}
236*45148Skarels     if (strncmp(scT, SCPAGE, ichMaxPage) == 0)
237*45148Skarels         { rgposPage[*pipgMac] = ppsd->posLineFst;
238*45148Skarels         scT1 = &scT[ichColon+1];
239*45148Skarels         /* skip blanks */
240*45148Skarels         while (*scT1 == ' ') scT1++;
241*45148Skarels         /* skip label */
242*45148Skarels         while ((*scT1 != ' ') && (*scT1 != '\n')) scT1++;
243*45148Skarels         /* skip blanks */
244*45148Skarels         while (*scT1 == ' ') scT1++;
245*45148Skarels         rgpgnPage[*pipgMac] = IntGet(&scT1);
246*45148Skarels         if ((*pipgMac) < (ipgMax-1))
247*45148Skarels             (*pipgMac)++;
248*45148Skarels         else break;
249*45148Skarels         }
250*45148Skarels     else if (strncmp(scT, SCTRAILER, ichMaxTrailer) == 0)
251*45148Skarels         { rgposPage[*pipgMac] = ppsd->posLineFst;
252*45148Skarels         break;
253*45148Skarels 	}
254*45148Skarels     }
255*45148Skarels while (! FEofReadSc(scT, 1, ppsd)) ;
256*45148Skarels ppsd->posMac = ppsd->posLineFst;
257*45148Skarels }
258*45148Skarels 
259*45148Skarels /* Move the bytes from posFst to posLim from source to destination PS file */
260*45148Skarels private MovePage(fdPsSrc, posFst, posLim, fdPsDst)
261*45148Skarels int	fdPsSrc;
262*45148Skarels long int posFst, posLim;
263*45148Skarels int	fdPsDst;
264*45148Skarels {
265*45148Skarels #define ichMaxBuf 4096
266*45148Skarels char	rgchBuf[ichMaxBuf];
267*45148Skarels int cchRead, cchMove, cchWrite;
268*45148Skarels register unsigned nbr;
269*45148Skarels 
270*45148Skarels VOIDC lseek(fdPsSrc, posFst, 0);
271*45148Skarels cchMove = posLim - posFst;
272*45148Skarels while (cchMove > 0)
273*45148Skarels     {	nbr = (unsigned) (cchMove < ichMaxBuf) ? cchMove : ichMaxBuf;
274*45148Skarels 	cchRead = read(fdPsSrc, rgchBuf, nbr);
275*45148Skarels     if ((cchRead != ichMaxBuf) && (cchRead != cchMove))
276*45148Skarels         { fprintf(stderr,"%s: problem reading source file\n",prog);
277*45148Skarels 	  exit(2);
278*45148Skarels 	}
279*45148Skarels     cchWrite = write(fdPsDst, rgchBuf, (unsigned) cchRead);
280*45148Skarels     if (cchWrite != cchRead)
281*45148Skarels         { fprintf(stderr,"%s: problem writing new file\n",prog);
282*45148Skarels 	  exit(2);
283*45148Skarels 	}
284*45148Skarels     cchMove = cchMove - cchRead;
285*45148Skarels     }
286*45148Skarels }
287*45148Skarels 
288*45148Skarels #define ARGS "Rrp:s:"
289*45148Skarels 
290*45148Skarels main(argc, argv)
291*45148Skarels int	argc;
292*45148Skarels char  *argv[];
293*45148Skarels {
294*45148Skarels     int	ipgMac, ipgT;
295*45148Skarels     struct Psd psd;
296*45148Skarels     struct	Params	params;
297*45148Skarels     long rgposPage[ipgMax+1];
298*45148Skarels     int	rgpgnPage[ipgMax+1];
299*45148Skarels     FILE	*fpPsDst;
300*45148Skarels     char	scTemp[50], *tempdir;
301*45148Skarels     int	fSpooledPage;
302*45148Skarels     int	fdPsSrc, fdPsDst;
303*45148Skarels     int	ch;
304*45148Skarels     register int argp;
305*45148Skarels     extern int optind;
306*45148Skarels     extern char *optarg;
307*45148Skarels 
308*45148Skarels     prog = *argv;
309*45148Skarels     if ((tempdir = envget("PSTEMPDIR")) == NULL) tempdir = TempDir;
310*45148Skarels     VOIDC mstrcat(scTemp, tempdir, REVTEMP,sizeof scTemp);
311*45148Skarels     ipgMac = 0;
312*45148Skarels     params.scSrcFile = NULL;
313*45148Skarels     params.scDstFile = NULL;
314*45148Skarels     params.fReverse = TRUE;
315*45148Skarels     params.fRemove = FALSE;
316*45148Skarels     params.irngMac = 0;
317*45148Skarels 
318*45148Skarels     psd.fp = NULL;
319*45148Skarels     psd.fpTemp = NULL;
320*45148Skarels 
321*45148Skarels     /* process the command line arguments */
322*45148Skarels     while ((argp = getopt(argc,argv,ARGS)) != EOF) {
323*45148Skarels 	switch (argp) {
324*45148Skarels 	    case 'r':
325*45148Skarels 		params.fRemove = TRUE;
326*45148Skarels 		break;
327*45148Skarels 	    case 'R':
328*45148Skarels 		params.fReverse = FALSE;
329*45148Skarels 		break;
330*45148Skarels 	    case 'p':
331*45148Skarels 		params.scDstFile = optarg;
332*45148Skarels 		break;
333*45148Skarels 	    case 's':
334*45148Skarels 		SetPageRanges(optarg,&params);
335*45148Skarels 		break;
336*45148Skarels 	    case '?':
337*45148Skarels 	    default:
338*45148Skarels 		fprintf(stderr,"%s: unknown option -%c\n",prog,argp);
339*45148Skarels 		exit(2);
340*45148Skarels 	}
341*45148Skarels     }
342*45148Skarels     if (optind < argc) {
343*45148Skarels 	params.scSrcFile = argv[optind];
344*45148Skarels 	if ((psd.fp = fopen(argv[optind],"r")) == NULL) {
345*45148Skarels 	    fprintf(stderr,"%s: can't open %s\n",prog,params.scSrcFile);
346*45148Skarels 	    exit(2);
347*45148Skarels 	}
348*45148Skarels     }
349*45148Skarels     else psd.fp = stdin;
350*45148Skarels 
351*45148Skarels     VOIDC fstat(fileno(psd.fp), &S);
352*45148Skarels     /* if its not a regular file then copy it to a temp file and use */
353*45148Skarels     /* the temp from now on */
354*45148Skarels     if ((S.st_mode & S_IFMT) != S_IFREG) {
355*45148Skarels 	VOIDC mktemp(scTemp);
356*45148Skarels 	if ((psd.fpTemp = fopen(scTemp, "w")) == NULL) {
357*45148Skarels 	    fprintf(stderr,"%s: could not open temp file\n",prog);
358*45148Skarels 	    exit(2);
359*45148Skarels 	}
360*45148Skarels 	while ((ch = getc(psd.fp)) != EOF) putc(ch, psd.fpTemp);
361*45148Skarels 	VOIDC fclose(psd.fpTemp);
362*45148Skarels 	psd.fpTemp = fopen(scTemp, "r");
363*45148Skarels 	VOIDC unlink(scTemp);
364*45148Skarels 	psd.fp = psd.fpTemp;
365*45148Skarels     }
366*45148Skarels 
367*45148Skarels     if (FConforming(&psd)) {
368*45148Skarels 	FindPageStarts(&psd, rgposPage, rgpgnPage, &ipgMac);
369*45148Skarels 	if (ipgMac == ipgMax) {
370*45148Skarels 	    fprintf(stderr, "%s: Too many pages in PS file, sorry\n",prog);
371*45148Skarels 	    exit(1);
372*45148Skarels 	}
373*45148Skarels 	if (rgposPage[ipgMac] == psd.posMac) {
374*45148Skarels 	    fprintf(stderr,"%s: PS file does not contain a conforming trailer\n",prog);
375*45148Skarels 	    exit(1);
376*45148Skarels 	}
377*45148Skarels 	/* remove the input file if it was requested from */
378*45148Skarels 	/* command line */
379*45148Skarels 	if (params.fRemove) {
380*45148Skarels 	    VOIDC unlink(params.scSrcFile);
381*45148Skarels 	    params.scSrcFile = NULL;
382*45148Skarels 	}
383*45148Skarels 	if (params.scDstFile == NULL) {
384*45148Skarels 	    fpPsDst = stdout;
385*45148Skarels 	}
386*45148Skarels 	else {
387*45148Skarels 	    /* remove the input file if output file = input file */
388*45148Skarels 	    if ((params.scSrcFile != NULL)
389*45148Skarels 	    && (strcmp(params.scSrcFile, params.scDstFile) == 0))
390*45148Skarels 		VOIDC unlink(params.scSrcFile);
391*45148Skarels 	    fpPsDst = fopen(params.scDstFile, "w");
392*45148Skarels 	    if (fpPsDst == NULL) {
393*45148Skarels 		fprintf(stderr, "%s: could not open output file %s\n",
394*45148Skarels 			    prog, params.scDstFile);
395*45148Skarels 		exit(1);
396*45148Skarels 	    }
397*45148Skarels 	}
398*45148Skarels 	fdPsSrc = fileno(psd.fp);
399*45148Skarels 	fdPsDst = fileno(fpPsDst);
400*45148Skarels 	MovePage(fdPsSrc, 0L, rgposPage[0], fdPsDst);
401*45148Skarels 	fSpooledPage = FALSE;
402*45148Skarels 	ipgT = params.fReverse ? ipgMac - 1 : 0;
403*45148Skarels 	while (TRUE) {
404*45148Skarels 	    if (FPageInRange(rgpgnPage[ipgT], &params)) {
405*45148Skarels 		fSpooledPage = TRUE;
406*45148Skarels 		MovePage(fdPsSrc,rgposPage[ipgT], rgposPage[ipgT+1], fdPsDst);
407*45148Skarels 	    }
408*45148Skarels 	    if (params.fReverse) {
409*45148Skarels 		if (ipgT == 0) break;
410*45148Skarels 		ipgT--;
411*45148Skarels 	    }
412*45148Skarels 	    else {
413*45148Skarels 		ipgT++;
414*45148Skarels 		if (ipgT == ipgMac) break;
415*45148Skarels 	    }
416*45148Skarels 	}
417*45148Skarels 	if (!fSpooledPage)
418*45148Skarels 	    fprintf(stderr, "%s: No pages in specified range!\n",prog);
419*45148Skarels 	MovePage(fdPsSrc, rgposPage[ipgMac], psd.posMac, fdPsDst);
420*45148Skarels 	VOIDC fclose(fpPsDst);
421*45148Skarels 	if (psd.fpTemp != NULL) VOIDC fclose(psd.fpTemp);
422*45148Skarels 	else VOIDC fclose(psd.fp);
423*45148Skarels 	exit(0);
424*45148Skarels     }
425*45148Skarels     fprintf(stderr,"%s: PS file does not begin with a version identifier\n",
426*45148Skarels     	prog);
427*45148Skarels     exit(1);
428*45148Skarels }
429