145148Skarels #ifndef lint
245148Skarels static char Notice[] = "Copyright (c) 1985 Adobe Systems Incorporated";
345148Skarels static char *RCSID="$Header: psrev.c,v 2.1 85/11/24 11:51:02 shore Rel $";
445148Skarels #endif
545148Skarels /* psrev.c
645148Skarels *
745148Skarels * Copyright (c) 1985 Adobe Systems Incorporated
845148Skarels *
945148Skarels * page reversal and selection filter
1045148Skarels *
1145148Skarels * Original Version: Tom Malloy
1245148Skarels * Edit History:
1345148Skarels * Andrew Shore: Fri Nov 22 11:20:20 1985
1445148Skarels * End Edit History.
1545148Skarels *
1645148Skarels * RCSLOG:
1745148Skarels * $Log: psrev.c,v $
1845148Skarels * Revision 2.1 85/11/24 11:51:02 shore
1945148Skarels * Product Release 2.0
2045148Skarels *
2145148Skarels * Revision 1.4 85/11/22 11:31:05 shore
2245148Skarels * Last line of trailer was dropped if it didn't end in a newline
2345148Skarels *
2445148Skarels * Revision 1.3 85/11/20 00:52:21 shore
2545148Skarels * Support for System V
2645148Skarels * getopt!
2745148Skarels * made lint a little happier
2845148Skarels *
2945148Skarels * Revision 1.2 85/05/14 11:26:38 shore
3045148Skarels *
3145148Skarels *
3245148Skarels *
3345148Skarels */
3445148Skarels
3545148Skarels #include <stdio.h>
3645148Skarels #include <ctype.h>
3745148Skarels #include <pwd.h>
3845148Skarels #include <sys/types.h>
3945148Skarels #include <sys/stat.h>
4045148Skarels #include "transcript.h"
4145148Skarels
4245148Skarels #define SCVERID "%!PS-Adobe-"
4345148Skarels #define ichMaxPage 7
4445148Skarels #define SCPAGE "%%Page:"
4545148Skarels #define ichMaxTrailer 9
4645148Skarels #define SCTRAILER "%%Trailer"
4745148Skarels
4845148Skarels #define ipgMax 2000 /* Maximum number of pages - first page index is 0 */
4945148Skarels #define irngMax 30 /* Maximum number of intervals in a page range spec */
5045148Skarels
51*64050Sbostic struct Range /* continuous interval of pages to be printed */
5245148Skarels /* from a page range specification (i.e. -s) */
5345148Skarels /* page numbers match the second parameter */
5445148Skarels /* of the "%%Page: " comment */
5545148Skarels { int pgnFst;
5645148Skarels int pgnLst;
5745148Skarels };
58*64050Sbostic struct Params /* interesting info collected from command line */
5945148Skarels { int fReverse; /* true => reverse page order */
6045148Skarels int fRemove; /* true => remove input file */
6145148Skarels char *scSrcFile; /* c-string containing source file name */
6245148Skarels char *scDstFile; /* c-string containing destination file name */
6345148Skarels int irngMac; /* number of intervals in rgrange */
6445148Skarels struct Range rgrange[irngMax]; /* array of intervals of pages */
6545148Skarels /* to be printed. One entry per */
6645148Skarels /* entry in the "-s" parameter */
6745148Skarels };
6845148Skarels
69*64050Sbostic struct Psd /* PS file descriptor */
7045148Skarels { FILE *fp; /* unix file descriptor of source */
7145148Skarels FILE *fpTemp;/* temp file descriptor. Contains a
7245148Skarels copy of source when fd is not a regular file */
7345148Skarels long int posLineFst, posMac;
7445148Skarels /* file positions - current, beginning of line, eof */
7545148Skarels };
7645148Skarels
7745148Skarels private struct stat S;
7845148Skarels private char *prog;
7945148Skarels
8045148Skarels
8145148Skarels /* Reads a signed integer from c-string */
8245148Skarels /* Input is a pointer to pointer to string */
8345148Skarels /* On return, it points to first character following the parsed numeral */
IntGet(prgch)8445148Skarels private IntGet(prgch)
8545148Skarels char **prgch;
8645148Skarels { int i, fNeg;
8745148Skarels char *rgch, ch;
8845148Skarels
8945148Skarels i = 0; rgch = *prgch;
9045148Skarels if ((ch = *rgch) == '-')
9145148Skarels { fNeg = TRUE; rgch++;}
9245148Skarels else { if (ch == '+') rgch++; fNeg = FALSE;}
9345148Skarels while (((ch = *rgch) >= '0') && (ch <= '9'))
9445148Skarels { rgch++; i = 10*i + (ch - '0');}
9545148Skarels *prgch = rgch;
9645148Skarels return(fNeg ? -i : i);
9745148Skarels }
9845148Skarels
9945148Skarels
10045148Skarels /* Parses the "-s" parameter. Fills the array params.rgrange */
10145148Skarels /* with a page interval range for each entry int the comma separated list */
10245148Skarels /* *prgch points at the character following the "s" command */
SetPageRanges(rgch,pparams)10345148Skarels private SetPageRanges(rgch, pparams)
10445148Skarels char *rgch;
10545148Skarels struct Params *pparams;
10645148Skarels { char ch;
10745148Skarels char *scError;
10845148Skarels struct Range *rgrange;
10945148Skarels #define pgnMax 30000
11045148Skarels
11145148Skarels scError = "Syntax error in page range specification while parsing ";
11245148Skarels rgrange = pparams->rgrange;
11345148Skarels while (TRUE)
11445148Skarels {
11545148Skarels if ((ch = *rgch) == '-')
11645148Skarels { rgrange[pparams->irngMac].pgnFst = 1;
11745148Skarels rgch++;
11845148Skarels rgrange[pparams->irngMac].pgnLst = IntGet(&rgch);
11945148Skarels }
12045148Skarels else
12145148Skarels {
12245148Skarels rgrange[pparams->irngMac].pgnFst = IntGet(&rgch);
12345148Skarels if ((ch = *rgch) == '-')
12445148Skarels { rgch++;
12545148Skarels if ((( ch = *rgch) == ',') || (ch == '\0'))
12645148Skarels rgrange[pparams->irngMac].pgnLst = pgnMax;
12745148Skarels else rgrange[pparams->irngMac].pgnLst = IntGet(&rgch);
12845148Skarels }
12945148Skarels else if ((( ch = *rgch) == ',') || (ch == '\0'))
13045148Skarels { rgrange[pparams->irngMac].pgnLst =
13145148Skarels rgrange[pparams->irngMac].pgnFst;
13245148Skarels }
13345148Skarels else if (rgrange[pparams->irngMac].pgnFst > 0)
13445148Skarels { fprintf(stderr, "%s%s\n", scError, rgch);
13545148Skarels exit(4);
13645148Skarels }
13745148Skarels }
13845148Skarels if ((rgrange[pparams->irngMac].pgnFst == 0) ||
13945148Skarels (rgrange[pparams->irngMac].pgnLst == 0))
14045148Skarels { fprintf(stderr, "%s%s\n",
14145148Skarels scError, rgch);
14245148Skarels exit(4);
14345148Skarels }
14445148Skarels if (++pparams->irngMac >= irngMax)
14545148Skarels { fprintf(stderr, "Too many intervals in page range specificaiton\n");
14645148Skarels exit(4);
14745148Skarels }
14845148Skarels if ((ch = *rgch) == ',')
14945148Skarels rgch++;
15045148Skarels else if (ch == '\0')
15145148Skarels break;
15245148Skarels else return;
15345148Skarels }
15445148Skarels }
15545148Skarels
15645148Skarels
15745148Skarels /* Returns TRUE if ipg is to be printed; i.e. if it is in one of the
15845148Skarels intervals in pparams->rgrange[0..pparams->irngMac) */
FPageInRange(pgn,pparams)15945148Skarels private FPageInRange(pgn, pparams)
16045148Skarels int pgn;
16145148Skarels struct Params *pparams;
16245148Skarels { int irng;
16345148Skarels struct Range *rgrange;
16445148Skarels #define ichTMax 50
16545148Skarels #define ichColon 6
16645148Skarels
16745148Skarels if (pparams->irngMac == 0) return(TRUE);
16845148Skarels rgrange = pparams->rgrange;
16945148Skarels for (irng = 0; irng < pparams->irngMac; irng++)
17045148Skarels { if ((pgn >= rgrange[irng].pgnFst)
17145148Skarels && (pgn <= rgrange[irng].pgnLst))
17245148Skarels return(TRUE);
17345148Skarels }
17445148Skarels return(FALSE);
17545148Skarels }
17645148Skarels
17745148Skarels
17845148Skarels /* Reads a line from the source PS file */
17945148Skarels /* Fills the c-string, scDst, with the first ichMacRead characters */
18045148Skarels /* of the line. Returns TRUE if it hits end of file, FALSE otherwise */
FEofReadSc(scDst,ichMacRead,ppsd)18145148Skarels private FEofReadSc(scDst, ichMacRead, ppsd)
18245148Skarels char scDst[];
18345148Skarels int ichMacRead;
18445148Skarels struct Psd *ppsd;
18545148Skarels { int ich;
18645148Skarels int ch;
18745148Skarels static int ateof = FALSE;
18845148Skarels
18945148Skarels scDst[0] = '\0';
19045148Skarels ppsd->posLineFst = ftell(ppsd->fp);
19145148Skarels if (ateof) return(TRUE);
19245148Skarels for (ich = 0; ich < ichMacRead; ich++)
19345148Skarels { scDst[ich] = ch = getc(ppsd->fp);
19445148Skarels if ((ch == '\n') || (ch == EOF)) break;
19545148Skarels }
19645148Skarels scDst[ich] = '\0';
19745148Skarels while ((ch != '\n') && (ch != EOF))
19845148Skarels { ch = getc(ppsd->fp);
19945148Skarels }
20045148Skarels if (ch == EOF) {
20145148Skarels ateof = TRUE;
20245148Skarels return (ich == 0);
20345148Skarels }
20445148Skarels return(FALSE);
20545148Skarels }
20645148Skarels
20745148Skarels /* Returns TRUE if the source is a conforming PS file; */
20845148Skarels /* i.e. first line of the source PS file contains "%!PS-Adobe-" */
FConforming(ppsd)20945148Skarels private FConforming(ppsd)
21045148Skarels struct Psd *ppsd;
21145148Skarels {
21245148Skarels #define ichMaxVerId 11
21345148Skarels char scVerIdT[ichMaxVerId+1];
21445148Skarels
21545148Skarels if (!FEofReadSc(scVerIdT, ichMaxVerId, ppsd)) {
21645148Skarels if (strcmp(scVerIdT, SCVERID) == 0) return(TRUE);
21745148Skarels }
21845148Skarels return(FALSE);
21945148Skarels }
22045148Skarels
22145148Skarels /* Finds the beginning of pages. Loads rgposPage with the file position */
22245148Skarels /* of the "%%Page:" comment line */
FindPageStarts(ppsd,rgposPage,rgpgnPage,pipgMac)22345148Skarels private FindPageStarts(ppsd, rgposPage, rgpgnPage, pipgMac)
22445148Skarels struct Psd *ppsd;
22545148Skarels long rgposPage[];
22645148Skarels int rgpgnPage[];
22745148Skarels int *pipgMac;
22845148Skarels {
22945148Skarels #define ichMaxScT 40
23045148Skarels char scT[ichMaxScT+1];
23145148Skarels char *scT1;
23245148Skarels
23345148Skarels while (1)
23445148Skarels { if (FEofReadSc(scT, ichMaxScT, ppsd))
23545148Skarels { rgposPage[*pipgMac] = ppsd->posLineFst; break;}
23645148Skarels if (strncmp(scT, SCPAGE, ichMaxPage) == 0)
23745148Skarels { rgposPage[*pipgMac] = ppsd->posLineFst;
23845148Skarels scT1 = &scT[ichColon+1];
23945148Skarels /* skip blanks */
24045148Skarels while (*scT1 == ' ') scT1++;
24145148Skarels /* skip label */
24245148Skarels while ((*scT1 != ' ') && (*scT1 != '\n')) scT1++;
24345148Skarels /* skip blanks */
24445148Skarels while (*scT1 == ' ') scT1++;
24545148Skarels rgpgnPage[*pipgMac] = IntGet(&scT1);
24645148Skarels if ((*pipgMac) < (ipgMax-1))
24745148Skarels (*pipgMac)++;
24845148Skarels else break;
24945148Skarels }
25045148Skarels else if (strncmp(scT, SCTRAILER, ichMaxTrailer) == 0)
25145148Skarels { rgposPage[*pipgMac] = ppsd->posLineFst;
25245148Skarels break;
25345148Skarels }
25445148Skarels }
25545148Skarels while (! FEofReadSc(scT, 1, ppsd)) ;
25645148Skarels ppsd->posMac = ppsd->posLineFst;
25745148Skarels }
25845148Skarels
25945148Skarels /* Move the bytes from posFst to posLim from source to destination PS file */
MovePage(fdPsSrc,posFst,posLim,fdPsDst)26045148Skarels private MovePage(fdPsSrc, posFst, posLim, fdPsDst)
26145148Skarels int fdPsSrc;
26245148Skarels long int posFst, posLim;
26345148Skarels int fdPsDst;
26445148Skarels {
26545148Skarels #define ichMaxBuf 4096
26645148Skarels char rgchBuf[ichMaxBuf];
26745148Skarels int cchRead, cchMove, cchWrite;
26845148Skarels register unsigned nbr;
26945148Skarels
27045148Skarels VOIDC lseek(fdPsSrc, posFst, 0);
27145148Skarels cchMove = posLim - posFst;
27245148Skarels while (cchMove > 0)
27345148Skarels { nbr = (unsigned) (cchMove < ichMaxBuf) ? cchMove : ichMaxBuf;
27445148Skarels cchRead = read(fdPsSrc, rgchBuf, nbr);
27545148Skarels if ((cchRead != ichMaxBuf) && (cchRead != cchMove))
27645148Skarels { fprintf(stderr,"%s: problem reading source file\n",prog);
27745148Skarels exit(2);
27845148Skarels }
27945148Skarels cchWrite = write(fdPsDst, rgchBuf, (unsigned) cchRead);
28045148Skarels if (cchWrite != cchRead)
28145148Skarels { fprintf(stderr,"%s: problem writing new file\n",prog);
28245148Skarels exit(2);
28345148Skarels }
28445148Skarels cchMove = cchMove - cchRead;
28545148Skarels }
28645148Skarels }
28745148Skarels
28845148Skarels #define ARGS "Rrp:s:"
28945148Skarels
main(argc,argv)29045148Skarels main(argc, argv)
29145148Skarels int argc;
29245148Skarels char *argv[];
29345148Skarels {
29445148Skarels int ipgMac, ipgT;
29545148Skarels struct Psd psd;
29645148Skarels struct Params params;
29745148Skarels long rgposPage[ipgMax+1];
29845148Skarels int rgpgnPage[ipgMax+1];
29945148Skarels FILE *fpPsDst;
30045148Skarels char scTemp[50], *tempdir;
30145148Skarels int fSpooledPage;
30245148Skarels int fdPsSrc, fdPsDst;
30345148Skarels int ch;
30445148Skarels register int argp;
30545148Skarels extern int optind;
30645148Skarels extern char *optarg;
30745148Skarels
30845148Skarels prog = *argv;
30945148Skarels if ((tempdir = envget("PSTEMPDIR")) == NULL) tempdir = TempDir;
31045148Skarels VOIDC mstrcat(scTemp, tempdir, REVTEMP,sizeof scTemp);
31145148Skarels ipgMac = 0;
31245148Skarels params.scSrcFile = NULL;
31345148Skarels params.scDstFile = NULL;
31445148Skarels params.fReverse = TRUE;
31545148Skarels params.fRemove = FALSE;
31645148Skarels params.irngMac = 0;
31745148Skarels
31845148Skarels psd.fp = NULL;
31945148Skarels psd.fpTemp = NULL;
32045148Skarels
32145148Skarels /* process the command line arguments */
32245148Skarels while ((argp = getopt(argc,argv,ARGS)) != EOF) {
32345148Skarels switch (argp) {
32445148Skarels case 'r':
32545148Skarels params.fRemove = TRUE;
32645148Skarels break;
32745148Skarels case 'R':
32845148Skarels params.fReverse = FALSE;
32945148Skarels break;
33045148Skarels case 'p':
33145148Skarels params.scDstFile = optarg;
33245148Skarels break;
33345148Skarels case 's':
33445148Skarels SetPageRanges(optarg,¶ms);
33545148Skarels break;
33645148Skarels case '?':
33745148Skarels default:
33845148Skarels fprintf(stderr,"%s: unknown option -%c\n",prog,argp);
33945148Skarels exit(2);
34045148Skarels }
34145148Skarels }
34245148Skarels if (optind < argc) {
34345148Skarels params.scSrcFile = argv[optind];
34445148Skarels if ((psd.fp = fopen(argv[optind],"r")) == NULL) {
34545148Skarels fprintf(stderr,"%s: can't open %s\n",prog,params.scSrcFile);
34645148Skarels exit(2);
34745148Skarels }
34845148Skarels }
34945148Skarels else psd.fp = stdin;
35045148Skarels
35145148Skarels VOIDC fstat(fileno(psd.fp), &S);
35245148Skarels /* if its not a regular file then copy it to a temp file and use */
35345148Skarels /* the temp from now on */
35445148Skarels if ((S.st_mode & S_IFMT) != S_IFREG) {
35545148Skarels VOIDC mktemp(scTemp);
35645148Skarels if ((psd.fpTemp = fopen(scTemp, "w")) == NULL) {
35745148Skarels fprintf(stderr,"%s: could not open temp file\n",prog);
35845148Skarels exit(2);
35945148Skarels }
36045148Skarels while ((ch = getc(psd.fp)) != EOF) putc(ch, psd.fpTemp);
36145148Skarels VOIDC fclose(psd.fpTemp);
36245148Skarels psd.fpTemp = fopen(scTemp, "r");
36345148Skarels VOIDC unlink(scTemp);
36445148Skarels psd.fp = psd.fpTemp;
36545148Skarels }
36645148Skarels
36745148Skarels if (FConforming(&psd)) {
36845148Skarels FindPageStarts(&psd, rgposPage, rgpgnPage, &ipgMac);
36945148Skarels if (ipgMac == ipgMax) {
37045148Skarels fprintf(stderr, "%s: Too many pages in PS file, sorry\n",prog);
37145148Skarels exit(1);
37245148Skarels }
37345148Skarels if (rgposPage[ipgMac] == psd.posMac) {
37445148Skarels fprintf(stderr,"%s: PS file does not contain a conforming trailer\n",prog);
37545148Skarels exit(1);
37645148Skarels }
37745148Skarels /* remove the input file if it was requested from */
37845148Skarels /* command line */
37945148Skarels if (params.fRemove) {
38045148Skarels VOIDC unlink(params.scSrcFile);
38145148Skarels params.scSrcFile = NULL;
38245148Skarels }
38345148Skarels if (params.scDstFile == NULL) {
38445148Skarels fpPsDst = stdout;
38545148Skarels }
38645148Skarels else {
38745148Skarels /* remove the input file if output file = input file */
38845148Skarels if ((params.scSrcFile != NULL)
38945148Skarels && (strcmp(params.scSrcFile, params.scDstFile) == 0))
39045148Skarels VOIDC unlink(params.scSrcFile);
39145148Skarels fpPsDst = fopen(params.scDstFile, "w");
39245148Skarels if (fpPsDst == NULL) {
39345148Skarels fprintf(stderr, "%s: could not open output file %s\n",
39445148Skarels prog, params.scDstFile);
39545148Skarels exit(1);
39645148Skarels }
39745148Skarels }
39845148Skarels fdPsSrc = fileno(psd.fp);
39945148Skarels fdPsDst = fileno(fpPsDst);
40045148Skarels MovePage(fdPsSrc, 0L, rgposPage[0], fdPsDst);
40145148Skarels fSpooledPage = FALSE;
40245148Skarels ipgT = params.fReverse ? ipgMac - 1 : 0;
40345148Skarels while (TRUE) {
40445148Skarels if (FPageInRange(rgpgnPage[ipgT], ¶ms)) {
40545148Skarels fSpooledPage = TRUE;
40645148Skarels MovePage(fdPsSrc,rgposPage[ipgT], rgposPage[ipgT+1], fdPsDst);
40745148Skarels }
40845148Skarels if (params.fReverse) {
40945148Skarels if (ipgT == 0) break;
41045148Skarels ipgT--;
41145148Skarels }
41245148Skarels else {
41345148Skarels ipgT++;
41445148Skarels if (ipgT == ipgMac) break;
41545148Skarels }
41645148Skarels }
41745148Skarels if (!fSpooledPage)
41845148Skarels fprintf(stderr, "%s: No pages in specified range!\n",prog);
41945148Skarels MovePage(fdPsSrc, rgposPage[ipgMac], psd.posMac, fdPsDst);
42045148Skarels VOIDC fclose(fpPsDst);
42145148Skarels if (psd.fpTemp != NULL) VOIDC fclose(psd.fpTemp);
42245148Skarels else VOIDC fclose(psd.fp);
42345148Skarels exit(0);
42445148Skarels }
42545148Skarels fprintf(stderr,"%s: PS file does not begin with a version identifier\n",
42645148Skarels prog);
42745148Skarels exit(1);
42845148Skarels }
429