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