#ifndef lint static char Notice[] = "Copyright (c) 1985 Adobe Systems Incorporated"; static char *RCSID="$Header: psrev.c,v 2.1 85/11/24 11:51:02 shore Rel $"; #endif /* psrev.c * * Copyright (c) 1985 Adobe Systems Incorporated * * page reversal and selection filter * * Original Version: Tom Malloy * Edit History: * Andrew Shore: Fri Nov 22 11:20:20 1985 * End Edit History. * * RCSLOG: * $Log: psrev.c,v $ * Revision 2.1 85/11/24 11:51:02 shore * Product Release 2.0 * * Revision 1.4 85/11/22 11:31:05 shore * Last line of trailer was dropped if it didn't end in a newline * * Revision 1.3 85/11/20 00:52:21 shore * Support for System V * getopt! * made lint a little happier * * Revision 1.2 85/05/14 11:26:38 shore * * * */ #include #include #include #include #include #include "transcript.h" #define SCVERID "%!PS-Adobe-" #define ichMaxPage 7 #define SCPAGE "%%Page:" #define ichMaxTrailer 9 #define SCTRAILER "%%Trailer" #define ipgMax 2000 /* Maximum number of pages - first page index is 0 */ #define irngMax 30 /* Maximum number of intervals in a page range spec */ struct Range /* continuous interval of pages to be printed */ /* from a page range specification (i.e. -s) */ /* page numbers match the second parameter */ /* of the "%%Page: " comment */ { int pgnFst; int pgnLst; }; struct Params /* interesting info collected from command line */ { int fReverse; /* true => reverse page order */ int fRemove; /* true => remove input file */ char *scSrcFile; /* c-string containing source file name */ char *scDstFile; /* c-string containing destination file name */ int irngMac; /* number of intervals in rgrange */ struct Range rgrange[irngMax]; /* array of intervals of pages */ /* to be printed. One entry per */ /* entry in the "-s" parameter */ }; struct Psd /* PS file descriptor */ { FILE *fp; /* unix file descriptor of source */ FILE *fpTemp;/* temp file descriptor. Contains a copy of source when fd is not a regular file */ long int posLineFst, posMac; /* file positions - current, beginning of line, eof */ }; private struct stat S; private char *prog; /* Reads a signed integer from c-string */ /* Input is a pointer to pointer to string */ /* On return, it points to first character following the parsed numeral */ private IntGet(prgch) char **prgch; { int i, fNeg; char *rgch, ch; i = 0; rgch = *prgch; if ((ch = *rgch) == '-') { fNeg = TRUE; rgch++;} else { if (ch == '+') rgch++; fNeg = FALSE;} while (((ch = *rgch) >= '0') && (ch <= '9')) { rgch++; i = 10*i + (ch - '0');} *prgch = rgch; return(fNeg ? -i : i); } /* Parses the "-s" parameter. Fills the array params.rgrange */ /* with a page interval range for each entry int the comma separated list */ /* *prgch points at the character following the "s" command */ private SetPageRanges(rgch, pparams) char *rgch; struct Params *pparams; { char ch; char *scError; struct Range *rgrange; #define pgnMax 30000 scError = "Syntax error in page range specification while parsing "; rgrange = pparams->rgrange; while (TRUE) { if ((ch = *rgch) == '-') { rgrange[pparams->irngMac].pgnFst = 1; rgch++; rgrange[pparams->irngMac].pgnLst = IntGet(&rgch); } else { rgrange[pparams->irngMac].pgnFst = IntGet(&rgch); if ((ch = *rgch) == '-') { rgch++; if ((( ch = *rgch) == ',') || (ch == '\0')) rgrange[pparams->irngMac].pgnLst = pgnMax; else rgrange[pparams->irngMac].pgnLst = IntGet(&rgch); } else if ((( ch = *rgch) == ',') || (ch == '\0')) { rgrange[pparams->irngMac].pgnLst = rgrange[pparams->irngMac].pgnFst; } else if (rgrange[pparams->irngMac].pgnFst > 0) { fprintf(stderr, "%s%s\n", scError, rgch); exit(4); } } if ((rgrange[pparams->irngMac].pgnFst == 0) || (rgrange[pparams->irngMac].pgnLst == 0)) { fprintf(stderr, "%s%s\n", scError, rgch); exit(4); } if (++pparams->irngMac >= irngMax) { fprintf(stderr, "Too many intervals in page range specificaiton\n"); exit(4); } if ((ch = *rgch) == ',') rgch++; else if (ch == '\0') break; else return; } } /* Returns TRUE if ipg is to be printed; i.e. if it is in one of the intervals in pparams->rgrange[0..pparams->irngMac) */ private FPageInRange(pgn, pparams) int pgn; struct Params *pparams; { int irng; struct Range *rgrange; #define ichTMax 50 #define ichColon 6 if (pparams->irngMac == 0) return(TRUE); rgrange = pparams->rgrange; for (irng = 0; irng < pparams->irngMac; irng++) { if ((pgn >= rgrange[irng].pgnFst) && (pgn <= rgrange[irng].pgnLst)) return(TRUE); } return(FALSE); } /* Reads a line from the source PS file */ /* Fills the c-string, scDst, with the first ichMacRead characters */ /* of the line. Returns TRUE if it hits end of file, FALSE otherwise */ private FEofReadSc(scDst, ichMacRead, ppsd) char scDst[]; int ichMacRead; struct Psd *ppsd; { int ich; int ch; static int ateof = FALSE; scDst[0] = '\0'; ppsd->posLineFst = ftell(ppsd->fp); if (ateof) return(TRUE); for (ich = 0; ich < ichMacRead; ich++) { scDst[ich] = ch = getc(ppsd->fp); if ((ch == '\n') || (ch == EOF)) break; } scDst[ich] = '\0'; while ((ch != '\n') && (ch != EOF)) { ch = getc(ppsd->fp); } if (ch == EOF) { ateof = TRUE; return (ich == 0); } return(FALSE); } /* Returns TRUE if the source is a conforming PS file; */ /* i.e. first line of the source PS file contains "%!PS-Adobe-" */ private FConforming(ppsd) struct Psd *ppsd; { #define ichMaxVerId 11 char scVerIdT[ichMaxVerId+1]; if (!FEofReadSc(scVerIdT, ichMaxVerId, ppsd)) { if (strcmp(scVerIdT, SCVERID) == 0) return(TRUE); } return(FALSE); } /* Finds the beginning of pages. Loads rgposPage with the file position */ /* of the "%%Page:" comment line */ private FindPageStarts(ppsd, rgposPage, rgpgnPage, pipgMac) struct Psd *ppsd; long rgposPage[]; int rgpgnPage[]; int *pipgMac; { #define ichMaxScT 40 char scT[ichMaxScT+1]; char *scT1; while (1) { if (FEofReadSc(scT, ichMaxScT, ppsd)) { rgposPage[*pipgMac] = ppsd->posLineFst; break;} if (strncmp(scT, SCPAGE, ichMaxPage) == 0) { rgposPage[*pipgMac] = ppsd->posLineFst; scT1 = &scT[ichColon+1]; /* skip blanks */ while (*scT1 == ' ') scT1++; /* skip label */ while ((*scT1 != ' ') && (*scT1 != '\n')) scT1++; /* skip blanks */ while (*scT1 == ' ') scT1++; rgpgnPage[*pipgMac] = IntGet(&scT1); if ((*pipgMac) < (ipgMax-1)) (*pipgMac)++; else break; } else if (strncmp(scT, SCTRAILER, ichMaxTrailer) == 0) { rgposPage[*pipgMac] = ppsd->posLineFst; break; } } while (! FEofReadSc(scT, 1, ppsd)) ; ppsd->posMac = ppsd->posLineFst; } /* Move the bytes from posFst to posLim from source to destination PS file */ private MovePage(fdPsSrc, posFst, posLim, fdPsDst) int fdPsSrc; long int posFst, posLim; int fdPsDst; { #define ichMaxBuf 4096 char rgchBuf[ichMaxBuf]; int cchRead, cchMove, cchWrite; register unsigned nbr; VOIDC lseek(fdPsSrc, posFst, 0); cchMove = posLim - posFst; while (cchMove > 0) { nbr = (unsigned) (cchMove < ichMaxBuf) ? cchMove : ichMaxBuf; cchRead = read(fdPsSrc, rgchBuf, nbr); if ((cchRead != ichMaxBuf) && (cchRead != cchMove)) { fprintf(stderr,"%s: problem reading source file\n",prog); exit(2); } cchWrite = write(fdPsDst, rgchBuf, (unsigned) cchRead); if (cchWrite != cchRead) { fprintf(stderr,"%s: problem writing new file\n",prog); exit(2); } cchMove = cchMove - cchRead; } } #define ARGS "Rrp:s:" main(argc, argv) int argc; char *argv[]; { int ipgMac, ipgT; struct Psd psd; struct Params params; long rgposPage[ipgMax+1]; int rgpgnPage[ipgMax+1]; FILE *fpPsDst; char scTemp[50], *tempdir; int fSpooledPage; int fdPsSrc, fdPsDst; int ch; register int argp; extern int optind; extern char *optarg; prog = *argv; if ((tempdir = envget("PSTEMPDIR")) == NULL) tempdir = TempDir; VOIDC mstrcat(scTemp, tempdir, REVTEMP,sizeof scTemp); ipgMac = 0; params.scSrcFile = NULL; params.scDstFile = NULL; params.fReverse = TRUE; params.fRemove = FALSE; params.irngMac = 0; psd.fp = NULL; psd.fpTemp = NULL; /* process the command line arguments */ while ((argp = getopt(argc,argv,ARGS)) != EOF) { switch (argp) { case 'r': params.fRemove = TRUE; break; case 'R': params.fReverse = FALSE; break; case 'p': params.scDstFile = optarg; break; case 's': SetPageRanges(optarg,¶ms); break; case '?': default: fprintf(stderr,"%s: unknown option -%c\n",prog,argp); exit(2); } } if (optind < argc) { params.scSrcFile = argv[optind]; if ((psd.fp = fopen(argv[optind],"r")) == NULL) { fprintf(stderr,"%s: can't open %s\n",prog,params.scSrcFile); exit(2); } } else psd.fp = stdin; VOIDC fstat(fileno(psd.fp), &S); /* if its not a regular file then copy it to a temp file and use */ /* the temp from now on */ if ((S.st_mode & S_IFMT) != S_IFREG) { VOIDC mktemp(scTemp); if ((psd.fpTemp = fopen(scTemp, "w")) == NULL) { fprintf(stderr,"%s: could not open temp file\n",prog); exit(2); } while ((ch = getc(psd.fp)) != EOF) putc(ch, psd.fpTemp); VOIDC fclose(psd.fpTemp); psd.fpTemp = fopen(scTemp, "r"); VOIDC unlink(scTemp); psd.fp = psd.fpTemp; } if (FConforming(&psd)) { FindPageStarts(&psd, rgposPage, rgpgnPage, &ipgMac); if (ipgMac == ipgMax) { fprintf(stderr, "%s: Too many pages in PS file, sorry\n",prog); exit(1); } if (rgposPage[ipgMac] == psd.posMac) { fprintf(stderr,"%s: PS file does not contain a conforming trailer\n",prog); exit(1); } /* remove the input file if it was requested from */ /* command line */ if (params.fRemove) { VOIDC unlink(params.scSrcFile); params.scSrcFile = NULL; } if (params.scDstFile == NULL) { fpPsDst = stdout; } else { /* remove the input file if output file = input file */ if ((params.scSrcFile != NULL) && (strcmp(params.scSrcFile, params.scDstFile) == 0)) VOIDC unlink(params.scSrcFile); fpPsDst = fopen(params.scDstFile, "w"); if (fpPsDst == NULL) { fprintf(stderr, "%s: could not open output file %s\n", prog, params.scDstFile); exit(1); } } fdPsSrc = fileno(psd.fp); fdPsDst = fileno(fpPsDst); MovePage(fdPsSrc, 0L, rgposPage[0], fdPsDst); fSpooledPage = FALSE; ipgT = params.fReverse ? ipgMac - 1 : 0; while (TRUE) { if (FPageInRange(rgpgnPage[ipgT], ¶ms)) { fSpooledPage = TRUE; MovePage(fdPsSrc,rgposPage[ipgT], rgposPage[ipgT+1], fdPsDst); } if (params.fReverse) { if (ipgT == 0) break; ipgT--; } else { ipgT++; if (ipgT == ipgMac) break; } } if (!fSpooledPage) fprintf(stderr, "%s: No pages in specified range!\n",prog); MovePage(fdPsSrc, rgposPage[ipgMac], psd.posMac, fdPsDst); VOIDC fclose(fpPsDst); if (psd.fpTemp != NULL) VOIDC fclose(psd.fpTemp); else VOIDC fclose(psd.fp); exit(0); } fprintf(stderr,"%s: PS file does not begin with a version identifier\n", prog); exit(1); }