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