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 */ 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 */ 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) */ 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 */ 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-" */ 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 */ 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 */ 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 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