xref: /csrg-svn/local/transcript/src/psrev.c (revision 64050)
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,&params);
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], &params)) {
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