1*219b2ee8SDavid du Colombier /* 2*219b2ee8SDavid du Colombier * 3*219b2ee8SDavid du Colombier * postreverse - reverse the page order in certain PostScript files. 4*219b2ee8SDavid du Colombier * 5*219b2ee8SDavid du Colombier * Page reversal relies on being able to locate sections of a document using file 6*219b2ee8SDavid du Colombier * structuring comments defined by Adobe (ie. the 1.0 and now 2.0 conventions) and 7*219b2ee8SDavid du Colombier * a few I've added. Among other things a minimally conforming document, according 8*219b2ee8SDavid du Colombier * to the 1.0 conventions, 9*219b2ee8SDavid du Colombier * 10*219b2ee8SDavid du Colombier * 1) Marks the end of the prologue with an %%EndProlog comment. 11*219b2ee8SDavid du Colombier * 12*219b2ee8SDavid du Colombier * 2) Starts each page with a %%Page: comment. 13*219b2ee8SDavid du Colombier * 14*219b2ee8SDavid du Colombier * 3) Marks the end of all the pages %%Trailer comment. 15*219b2ee8SDavid du Colombier * 16*219b2ee8SDavid du Colombier * 4) Obeys page independence (ie. pages can be arbitrarily rearranged). 17*219b2ee8SDavid du Colombier * 18*219b2ee8SDavid du Colombier * The most important change (at least for this program) that Adobe made in going 19*219b2ee8SDavid du Colombier * from the 1.0 to the 2.0 structuring conventions was in the prologue. They now 20*219b2ee8SDavid du Colombier * say the prologue should only define things, and the global initialization that 21*219b2ee8SDavid du Colombier * was in the prologue (1.0 conventions) should now come after the %%EndProlog 22*219b2ee8SDavid du Colombier * comment but before the first %%Page: comment and be bracketed by %%BeginSetup 23*219b2ee8SDavid du Colombier * and %%EndSetup comments. So a document that conforms to Adobe's 2.0 conventions, 24*219b2ee8SDavid du Colombier * 25*219b2ee8SDavid du Colombier * 1) Marks the end of the prologue (only definitions) with %%EndProlog. 26*219b2ee8SDavid du Colombier * 27*219b2ee8SDavid du Colombier * 2) Brackets global initialization with %%BeginSetup and %%EndSetup comments 28*219b2ee8SDavid du Colombier * which come after the prologue but before the first %Page: comment. 29*219b2ee8SDavid du Colombier * 30*219b2ee8SDavid du Colombier * 3) Starts each page with a %%Page: comment. 31*219b2ee8SDavid du Colombier * 32*219b2ee8SDavid du Colombier * 4) Marks the end of all the pages with a %%Trailer comment. 33*219b2ee8SDavid du Colombier * 34*219b2ee8SDavid du Colombier * 5) Obeys page independence. 35*219b2ee8SDavid du Colombier * 36*219b2ee8SDavid du Colombier * postreverse can handle documents that follow the 1.0 or 2.0 conventions, but has 37*219b2ee8SDavid du Colombier * also been extended slightly so it works properly with the translators (primarily 38*219b2ee8SDavid du Colombier * dpost) supplied with this package. The page independence requirement has been 39*219b2ee8SDavid du Colombier * relaxed some. In particular definitions exported to the global environment from 40*219b2ee8SDavid du Colombier * within a page should be bracketed by %%BeginGlobal and %%EndGlobal comments. 41*219b2ee8SDavid du Colombier * postreverse pulls them out of each page and inserts them in the setup section 42*219b2ee8SDavid du Colombier * of the document, immediately before it writes the %%EndProlog (for version 1.0) 43*219b2ee8SDavid du Colombier * or %%EndSetup (for version 2.0) comments. 44*219b2ee8SDavid du Colombier * 45*219b2ee8SDavid du Colombier * In addition postreverse accepts documents that choose to mark the end of each 46*219b2ee8SDavid du Colombier * page with a %%EndPage: comment, which from a translator's point of view is often 47*219b2ee8SDavid du Colombier * a more natural approach. Both page boundary comments (ie. Page: and %%EndPage:) 48*219b2ee8SDavid du Colombier * are also accepted, but be warned that everything between consecutive %%EndPage: 49*219b2ee8SDavid du Colombier * and %%Page: comments will be ignored. 50*219b2ee8SDavid du Colombier * 51*219b2ee8SDavid du Colombier * So a document that will reverse properly with postreverse, 52*219b2ee8SDavid du Colombier * 53*219b2ee8SDavid du Colombier * 1) Marks the end of the prologue with %%EndProlog. 54*219b2ee8SDavid du Colombier * 55*219b2ee8SDavid du Colombier * 2) May have a %%BeginSetup/%%EndSetup comment pair before the first %%Page: 56*219b2ee8SDavid du Colombier * comment that brackets any global initialization. 57*219b2ee8SDavid du Colombier * 58*219b2ee8SDavid du Colombier * 3) Marks the start of each page with a %%Page: comment, or the end of each 59*219b2ee8SDavid du Colombier * page with a %%EndPage: comment. Both page boundary comments are allowed. 60*219b2ee8SDavid du Colombier * 61*219b2ee8SDavid du Colombier * 4) Marks the end of all the pages with a %%Trailer comment. 62*219b2ee8SDavid du Colombier * 63*219b2ee8SDavid du Colombier * 5) Obeys page independence or violates it to a rather limited extent and 64*219b2ee8SDavid du Colombier * marks the violations with %%BeginGlobal and %%EndGlobal comments. 65*219b2ee8SDavid du Colombier * 66*219b2ee8SDavid du Colombier * If no file arguments are given postreverse copies stdin to a temporary file and 67*219b2ee8SDavid du Colombier * then processes that file. That means the input is read three times (rather than 68*219b2ee8SDavid du Colombier * two) whenever we handle stdin. That's expensive, and shouldn't be too difficult 69*219b2ee8SDavid du Colombier * to fix, but I haven't gotten around to it yet. 70*219b2ee8SDavid du Colombier * 71*219b2ee8SDavid du Colombier */ 72*219b2ee8SDavid du Colombier 73*219b2ee8SDavid du Colombier #include <stdio.h> 74*219b2ee8SDavid du Colombier #include <signal.h> 75*219b2ee8SDavid du Colombier #include <sys/types.h> 76*219b2ee8SDavid du Colombier #include <fcntl.h> 77*219b2ee8SDavid du Colombier 78*219b2ee8SDavid du Colombier #include "comments.h" /* PostScript file structuring comments */ 79*219b2ee8SDavid du Colombier #include "gen.h" /* general purpose definitions */ 80*219b2ee8SDavid du Colombier #include "path.h" /* for temporary directory */ 81*219b2ee8SDavid du Colombier #include "ext.h" /* external variable declarations */ 82*219b2ee8SDavid du Colombier #include "postreverse.h" /* a few special definitions */ 83*219b2ee8SDavid du Colombier 84*219b2ee8SDavid du Colombier int page = 1; /* current page number */ 85*219b2ee8SDavid du Colombier int forms = 1; /* forms per page in the input file */ 86*219b2ee8SDavid du Colombier 87*219b2ee8SDavid du Colombier char *temp_dir = TEMPDIR; /* temp directory for copying stdin */ 88*219b2ee8SDavid du Colombier 89*219b2ee8SDavid du Colombier Pages pages[1000]; /* byte offsets for all pages */ 90*219b2ee8SDavid du Colombier int next_page = 0; /* next page goes here */ 91*219b2ee8SDavid du Colombier long start; /* starting offset for next page */ 92*219b2ee8SDavid du Colombier long endoff = -1; /* offset where TRAILER was found */ 93*219b2ee8SDavid du Colombier int noreverse = FALSE; /* don't reverse pages if TRUE */ 94*219b2ee8SDavid du Colombier char *endprolog = ENDPROLOG; /* occasionally changed to ENDSETUP */ 95*219b2ee8SDavid du Colombier 96*219b2ee8SDavid du Colombier double version = 3.3; /* of the input file */ 97*219b2ee8SDavid du Colombier int ignoreversion = FALSE; /* ignore possible forms.ps problems */ 98*219b2ee8SDavid du Colombier 99*219b2ee8SDavid du Colombier char buf[2048]; /* line buffer for input file */ 100*219b2ee8SDavid du Colombier 101*219b2ee8SDavid du Colombier FILE *fp_in; /* stuff is read from this file */ 102*219b2ee8SDavid du Colombier FILE *fp_out = stdout; /* and written here */ 103*219b2ee8SDavid du Colombier 104*219b2ee8SDavid du Colombier /*****************************************************************************/ 105*219b2ee8SDavid du Colombier 106*219b2ee8SDavid du Colombier main(agc, agv) 107*219b2ee8SDavid du Colombier 108*219b2ee8SDavid du Colombier int agc; 109*219b2ee8SDavid du Colombier char *agv[]; 110*219b2ee8SDavid du Colombier 111*219b2ee8SDavid du Colombier { 112*219b2ee8SDavid du Colombier 113*219b2ee8SDavid du Colombier /* 114*219b2ee8SDavid du Colombier * 115*219b2ee8SDavid du Colombier * A simple program that reverses the pages in specially formatted PostScript 116*219b2ee8SDavid du Colombier * files. Will work with all the translators in this package, and should handle 117*219b2ee8SDavid du Colombier * any document that conforms to Adobe's version 1.0 or 2.0 file structuring 118*219b2ee8SDavid du Colombier * conventions. Only one input file is allowed, and it can either be a named (on 119*219b2ee8SDavid du Colombier * the command line) file or stdin. 120*219b2ee8SDavid du Colombier * 121*219b2ee8SDavid du Colombier */ 122*219b2ee8SDavid du Colombier 123*219b2ee8SDavid du Colombier argc = agc; /* other routines may want them */ 124*219b2ee8SDavid du Colombier argv = agv; 125*219b2ee8SDavid du Colombier 126*219b2ee8SDavid du Colombier prog_name = argv[0]; /* just for error messages */ 127*219b2ee8SDavid du Colombier 128*219b2ee8SDavid du Colombier init_signals(); /* sets up interrupt handling */ 129*219b2ee8SDavid du Colombier options(); /* first get command line options */ 130*219b2ee8SDavid du Colombier arguments(); /* then process non-option arguments */ 131*219b2ee8SDavid du Colombier done(); /* and clean things up */ 132*219b2ee8SDavid du Colombier 133*219b2ee8SDavid du Colombier exit(x_stat); /* not much could be wrong */ 134*219b2ee8SDavid du Colombier 135*219b2ee8SDavid du Colombier } /* End of main */ 136*219b2ee8SDavid du Colombier 137*219b2ee8SDavid du Colombier /*****************************************************************************/ 138*219b2ee8SDavid du Colombier 139*219b2ee8SDavid du Colombier init_signals() 140*219b2ee8SDavid du Colombier 141*219b2ee8SDavid du Colombier { 142*219b2ee8SDavid du Colombier 143*219b2ee8SDavid du Colombier /* 144*219b2ee8SDavid du Colombier * 145*219b2ee8SDavid du Colombier * Makes sure we handle interrupts properly. 146*219b2ee8SDavid du Colombier * 147*219b2ee8SDavid du Colombier */ 148*219b2ee8SDavid du Colombier 149*219b2ee8SDavid du Colombier if ( signal(SIGINT, interrupt) == SIG_IGN ) { 150*219b2ee8SDavid du Colombier signal(SIGINT, SIG_IGN); 151*219b2ee8SDavid du Colombier signal(SIGQUIT, SIG_IGN); 152*219b2ee8SDavid du Colombier signal(SIGHUP, SIG_IGN); 153*219b2ee8SDavid du Colombier } else { 154*219b2ee8SDavid du Colombier signal(SIGHUP, interrupt); 155*219b2ee8SDavid du Colombier signal(SIGQUIT, interrupt); 156*219b2ee8SDavid du Colombier } /* End else */ 157*219b2ee8SDavid du Colombier 158*219b2ee8SDavid du Colombier signal(SIGTERM, interrupt); 159*219b2ee8SDavid du Colombier 160*219b2ee8SDavid du Colombier } /* End of init_signals */ 161*219b2ee8SDavid du Colombier 162*219b2ee8SDavid du Colombier /*****************************************************************************/ 163*219b2ee8SDavid du Colombier 164*219b2ee8SDavid du Colombier options() 165*219b2ee8SDavid du Colombier 166*219b2ee8SDavid du Colombier { 167*219b2ee8SDavid du Colombier 168*219b2ee8SDavid du Colombier int ch; /* return value from getopt() */ 169*219b2ee8SDavid du Colombier char *optnames = "n:o:rvT:DI"; 170*219b2ee8SDavid du Colombier 171*219b2ee8SDavid du Colombier extern char *optarg; /* used by getopt() */ 172*219b2ee8SDavid du Colombier extern int optind; 173*219b2ee8SDavid du Colombier 174*219b2ee8SDavid du Colombier /* 175*219b2ee8SDavid du Colombier * 176*219b2ee8SDavid du Colombier * Reads and processes the command line options. The -r option (ie. the one that 177*219b2ee8SDavid du Colombier * turns page reversal off) is really only useful if you want to take dpost output 178*219b2ee8SDavid du Colombier * and produce a page independent output file. In that case global definitions 179*219b2ee8SDavid du Colombier * made within pages and bracketed by %%BeginGlobal/%%EndGlobal comments will be 180*219b2ee8SDavid du Colombier * moved into the prologue or setup section of the document. 181*219b2ee8SDavid du Colombier * 182*219b2ee8SDavid du Colombier */ 183*219b2ee8SDavid du Colombier 184*219b2ee8SDavid du Colombier while ( (ch = getopt(argc, argv, optnames)) != EOF ) { 185*219b2ee8SDavid du Colombier switch ( ch ) { 186*219b2ee8SDavid du Colombier case 'n': /* forms per page */ 187*219b2ee8SDavid du Colombier if ( (forms = atoi(optarg)) <= 0 ) 188*219b2ee8SDavid du Colombier error(FATAL, "illegal forms request %s", optarg); 189*219b2ee8SDavid du Colombier break; 190*219b2ee8SDavid du Colombier 191*219b2ee8SDavid du Colombier case 'o': /* output page list */ 192*219b2ee8SDavid du Colombier out_list(optarg); 193*219b2ee8SDavid du Colombier break; 194*219b2ee8SDavid du Colombier 195*219b2ee8SDavid du Colombier case 'r': /* don't reverse the pages */ 196*219b2ee8SDavid du Colombier noreverse = TRUE; 197*219b2ee8SDavid du Colombier break; 198*219b2ee8SDavid du Colombier 199*219b2ee8SDavid du Colombier case 'v': /* ignore possible forms.ps problems */ 200*219b2ee8SDavid du Colombier ignoreversion = TRUE; 201*219b2ee8SDavid du Colombier break; 202*219b2ee8SDavid du Colombier 203*219b2ee8SDavid du Colombier case 'T': /* temporary file directory */ 204*219b2ee8SDavid du Colombier temp_dir = optarg; 205*219b2ee8SDavid du Colombier break; 206*219b2ee8SDavid du Colombier 207*219b2ee8SDavid du Colombier case 'D': /* debug flag */ 208*219b2ee8SDavid du Colombier debug = ON; 209*219b2ee8SDavid du Colombier break; 210*219b2ee8SDavid du Colombier 211*219b2ee8SDavid du Colombier case 'I': /* ignore FATAL errors */ 212*219b2ee8SDavid du Colombier ignore = ON; 213*219b2ee8SDavid du Colombier break; 214*219b2ee8SDavid du Colombier 215*219b2ee8SDavid du Colombier case '?': /* don't understand the option */ 216*219b2ee8SDavid du Colombier error(FATAL, ""); 217*219b2ee8SDavid du Colombier break; 218*219b2ee8SDavid du Colombier 219*219b2ee8SDavid du Colombier default: /* don't know what to do for ch */ 220*219b2ee8SDavid du Colombier error(FATAL, "missing case for option %c\n", ch); 221*219b2ee8SDavid du Colombier break; 222*219b2ee8SDavid du Colombier } /* End switch */ 223*219b2ee8SDavid du Colombier } /* End while */ 224*219b2ee8SDavid du Colombier 225*219b2ee8SDavid du Colombier argc -= optind; /* get ready for non-option args */ 226*219b2ee8SDavid du Colombier argv += optind; 227*219b2ee8SDavid du Colombier 228*219b2ee8SDavid du Colombier } /* End of options */ 229*219b2ee8SDavid du Colombier 230*219b2ee8SDavid du Colombier /*****************************************************************************/ 231*219b2ee8SDavid du Colombier 232*219b2ee8SDavid du Colombier arguments() 233*219b2ee8SDavid du Colombier 234*219b2ee8SDavid du Colombier { 235*219b2ee8SDavid du Colombier 236*219b2ee8SDavid du Colombier char *name; /* name of the input file */ 237*219b2ee8SDavid du Colombier 238*219b2ee8SDavid du Colombier /* 239*219b2ee8SDavid du Colombier * 240*219b2ee8SDavid du Colombier * postreverse only handles one input file at a time, so if there's more than one 241*219b2ee8SDavid du Colombier * argument left when we get here we'll quit. If none remain we copy stdin to a 242*219b2ee8SDavid du Colombier * temporary file and process that file. 243*219b2ee8SDavid du Colombier * 244*219b2ee8SDavid du Colombier */ 245*219b2ee8SDavid du Colombier 246*219b2ee8SDavid du Colombier if ( argc > 1 ) /* can't handle more than one file */ 247*219b2ee8SDavid du Colombier error(FATAL, "too many arguments"); 248*219b2ee8SDavid du Colombier 249*219b2ee8SDavid du Colombier if ( argc == 0 ) /* copy stdin to a temporary file */ 250*219b2ee8SDavid du Colombier name = copystdin(); 251*219b2ee8SDavid du Colombier else name = *argv; 252*219b2ee8SDavid du Colombier 253*219b2ee8SDavid du Colombier if ( (fp_in = fopen(name, "r")) == NULL ) 254*219b2ee8SDavid du Colombier error(FATAL, "can't open %s", name); 255*219b2ee8SDavid du Colombier 256*219b2ee8SDavid du Colombier reverse(); 257*219b2ee8SDavid du Colombier 258*219b2ee8SDavid du Colombier } /* End of arguments */ 259*219b2ee8SDavid du Colombier 260*219b2ee8SDavid du Colombier /*****************************************************************************/ 261*219b2ee8SDavid du Colombier 262*219b2ee8SDavid du Colombier done() 263*219b2ee8SDavid du Colombier 264*219b2ee8SDavid du Colombier { 265*219b2ee8SDavid du Colombier 266*219b2ee8SDavid du Colombier /* 267*219b2ee8SDavid du Colombier * 268*219b2ee8SDavid du Colombier * Cleans things up after we've finished reversing the pages in the input file. 269*219b2ee8SDavid du Colombier * All that's really left to do is remove the temp file, provided we used one. 270*219b2ee8SDavid du Colombier * 271*219b2ee8SDavid du Colombier */ 272*219b2ee8SDavid du Colombier 273*219b2ee8SDavid du Colombier if ( temp_file != NULL ) 274*219b2ee8SDavid du Colombier unlink(temp_file); 275*219b2ee8SDavid du Colombier 276*219b2ee8SDavid du Colombier } /* End of done */ 277*219b2ee8SDavid du Colombier 278*219b2ee8SDavid du Colombier /*****************************************************************************/ 279*219b2ee8SDavid du Colombier 280*219b2ee8SDavid du Colombier char *copystdin() 281*219b2ee8SDavid du Colombier 282*219b2ee8SDavid du Colombier { 283*219b2ee8SDavid du Colombier 284*219b2ee8SDavid du Colombier int fd_out; /* for the temporary file */ 285*219b2ee8SDavid du Colombier int fd_in; /* for stdin */ 286*219b2ee8SDavid du Colombier int count; /* number of bytes put in buf[] */ 287*219b2ee8SDavid du Colombier 288*219b2ee8SDavid du Colombier /* 289*219b2ee8SDavid du Colombier * 290*219b2ee8SDavid du Colombier * Copies stdin to a temporary file and returns the pathname of that file to the 291*219b2ee8SDavid du Colombier * caller. It's an expensive way of doing things, because it means we end up 292*219b2ee8SDavid du Colombier * reading the input file three times - rather than just twice. Could probably be 293*219b2ee8SDavid du Colombier * fixed by creating the temporary file on the fly as we read the file the first 294*219b2ee8SDavid du Colombier * time. 295*219b2ee8SDavid du Colombier * 296*219b2ee8SDavid du Colombier */ 297*219b2ee8SDavid du Colombier 298*219b2ee8SDavid du Colombier if ( (temp_file = tempnam(temp_dir, "post")) == NULL ) 299*219b2ee8SDavid du Colombier error(FATAL, "can't generate temp file name"); 300*219b2ee8SDavid du Colombier 301*219b2ee8SDavid du Colombier if ( (fd_out = creat(temp_file, 0660)) == -1 ) 302*219b2ee8SDavid du Colombier error(FATAL, "can't open %s", temp_file); 303*219b2ee8SDavid du Colombier 304*219b2ee8SDavid du Colombier fd_in = fileno(stdin); 305*219b2ee8SDavid du Colombier 306*219b2ee8SDavid du Colombier while ( (count = read(fd_in, buf, sizeof(buf))) > 0 ) 307*219b2ee8SDavid du Colombier if ( write(fd_out, buf, count) != count ) 308*219b2ee8SDavid du Colombier error(FATAL, "error writing to %s", temp_file); 309*219b2ee8SDavid du Colombier 310*219b2ee8SDavid du Colombier close(fd_out); 311*219b2ee8SDavid du Colombier 312*219b2ee8SDavid du Colombier return(temp_file); 313*219b2ee8SDavid du Colombier 314*219b2ee8SDavid du Colombier } /* End of copystdin */ 315*219b2ee8SDavid du Colombier 316*219b2ee8SDavid du Colombier /*****************************************************************************/ 317*219b2ee8SDavid du Colombier 318*219b2ee8SDavid du Colombier reverse() 319*219b2ee8SDavid du Colombier 320*219b2ee8SDavid du Colombier { 321*219b2ee8SDavid du Colombier 322*219b2ee8SDavid du Colombier /* 323*219b2ee8SDavid du Colombier * 324*219b2ee8SDavid du Colombier * Begins by looking for the ENDPROLOG comment in the input file. Everything up to 325*219b2ee8SDavid du Colombier * that comment is copied to the output file. If the comment isn't found the entire 326*219b2ee8SDavid du Colombier * input file is copied and moreprolog() returns FALSE. Otherwise readpages() reads 327*219b2ee8SDavid du Colombier * the rest of the input file and remembers (in pages[]) where each page starts and 328*219b2ee8SDavid du Colombier * ends. In addition everything bracketed by %%BeginGlobal and %%EndGlobal comments 329*219b2ee8SDavid du Colombier * is immediately added to the new prologue (or setup section) and ends up being 330*219b2ee8SDavid du Colombier * removed from the individual pages. When readpages() finds the TRAILER comment 331*219b2ee8SDavid du Colombier * or gets to the end of the input file we go back to the pages[] array and use 332*219b2ee8SDavid du Colombier * the saved offsets to write the pages out in reverse order. Finally everything 333*219b2ee8SDavid du Colombier * from the TRAILER comment to the end of the input file is copied to the output 334*219b2ee8SDavid du Colombier * file. 335*219b2ee8SDavid du Colombier * 336*219b2ee8SDavid du Colombier */ 337*219b2ee8SDavid du Colombier 338*219b2ee8SDavid du Colombier if ( moreprolog(ENDPROLOG) == TRUE ) { 339*219b2ee8SDavid du Colombier readpages(); 340*219b2ee8SDavid du Colombier writepages(); 341*219b2ee8SDavid du Colombier trailer(); 342*219b2ee8SDavid du Colombier } /* End if */ 343*219b2ee8SDavid du Colombier 344*219b2ee8SDavid du Colombier } /* End of reverse */ 345*219b2ee8SDavid du Colombier 346*219b2ee8SDavid du Colombier /*****************************************************************************/ 347*219b2ee8SDavid du Colombier 348*219b2ee8SDavid du Colombier moreprolog(str) 349*219b2ee8SDavid du Colombier 350*219b2ee8SDavid du Colombier char *str; /* copy everything up to this string */ 351*219b2ee8SDavid du Colombier 352*219b2ee8SDavid du Colombier { 353*219b2ee8SDavid du Colombier 354*219b2ee8SDavid du Colombier int len; /* length of FORMSPERPAGE string */ 355*219b2ee8SDavid du Colombier int vlen; /* length of VERSION string */ 356*219b2ee8SDavid du Colombier 357*219b2ee8SDavid du Colombier /* 358*219b2ee8SDavid du Colombier * 359*219b2ee8SDavid du Colombier * Looks for string *str at the start of a line and copies everything up to that 360*219b2ee8SDavid du Colombier * string to the output file. If *str isn't found the entire input file will end 361*219b2ee8SDavid du Colombier * up being copied to the output file and FALSE will be returned to the caller. 362*219b2ee8SDavid du Colombier * The first call (made from reverse()) looks for ENDPROLOG. Any other call comes 363*219b2ee8SDavid du Colombier * from readpages() and will be looking for the ENDSETUP comment. 364*219b2ee8SDavid du Colombier * 365*219b2ee8SDavid du Colombier */ 366*219b2ee8SDavid du Colombier 367*219b2ee8SDavid du Colombier len = strlen(FORMSPERPAGE); 368*219b2ee8SDavid du Colombier vlen = strlen(VERSION); 369*219b2ee8SDavid du Colombier 370*219b2ee8SDavid du Colombier while ( fgets(buf, sizeof(buf), fp_in) != NULL ) { 371*219b2ee8SDavid du Colombier if ( strcmp(buf, str) == 0 ) 372*219b2ee8SDavid du Colombier return(TRUE); 373*219b2ee8SDavid du Colombier else if ( strncmp(buf, FORMSPERPAGE, len) == 0 ) 374*219b2ee8SDavid du Colombier forms = atoi(&buf[len+1]); 375*219b2ee8SDavid du Colombier else if ( strncmp(buf, VERSION, vlen) == 0 ) 376*219b2ee8SDavid du Colombier version = atof(&buf[vlen+1]); 377*219b2ee8SDavid du Colombier fprintf(fp_out, "%s", buf); 378*219b2ee8SDavid du Colombier } /* End while */ 379*219b2ee8SDavid du Colombier 380*219b2ee8SDavid du Colombier return(FALSE); 381*219b2ee8SDavid du Colombier 382*219b2ee8SDavid du Colombier } /* End of moreprolog */ 383*219b2ee8SDavid du Colombier 384*219b2ee8SDavid du Colombier /*****************************************************************************/ 385*219b2ee8SDavid du Colombier 386*219b2ee8SDavid du Colombier readpages() 387*219b2ee8SDavid du Colombier 388*219b2ee8SDavid du Colombier { 389*219b2ee8SDavid du Colombier 390*219b2ee8SDavid du Colombier int endpagelen; /* length of ENDPAGE */ 391*219b2ee8SDavid du Colombier int pagelen; /* and PAGE strings */ 392*219b2ee8SDavid du Colombier int sawendpage = TRUE; /* ENDPAGE equivalent marked last page */ 393*219b2ee8SDavid du Colombier int gotpage = FALSE; /* TRUE disables BEGINSETUP stuff */ 394*219b2ee8SDavid du Colombier 395*219b2ee8SDavid du Colombier /* 396*219b2ee8SDavid du Colombier * 397*219b2ee8SDavid du Colombier * Records starting and ending positions of the requested pages (usually all of 398*219b2ee8SDavid du Colombier * them), puts global definitions in the prologue, and remembers where the TRAILER 399*219b2ee8SDavid du Colombier * was found. 400*219b2ee8SDavid du Colombier * 401*219b2ee8SDavid du Colombier * Page boundaries are marked by the strings PAGE, ENDPAGE, or perhaps both. 402*219b2ee8SDavid du Colombier * Application programs will normally find one or the other more convenient, so 403*219b2ee8SDavid du Colombier * in most cases only one kind of page delimiter will be found in a particular 404*219b2ee8SDavid du Colombier * document. 405*219b2ee8SDavid du Colombier * 406*219b2ee8SDavid du Colombier */ 407*219b2ee8SDavid du Colombier 408*219b2ee8SDavid du Colombier pages[0].start = ftell(fp_in); /* first page starts after ENDPROLOG */ 409*219b2ee8SDavid du Colombier endprolog = ENDPROLOG; 410*219b2ee8SDavid du Colombier 411*219b2ee8SDavid du Colombier endpagelen = strlen(ENDPAGE); 412*219b2ee8SDavid du Colombier pagelen = strlen(PAGE); 413*219b2ee8SDavid du Colombier 414*219b2ee8SDavid du Colombier while ( fgets(buf, sizeof(buf), fp_in) != NULL ) 415*219b2ee8SDavid du Colombier if ( buf[0] != '%' ) 416*219b2ee8SDavid du Colombier continue; 417*219b2ee8SDavid du Colombier else if ( strncmp(buf, ENDPAGE, endpagelen) == 0 ) { 418*219b2ee8SDavid du Colombier if ( in_olist(page++) == ON ) { 419*219b2ee8SDavid du Colombier pages[next_page].empty = FALSE; 420*219b2ee8SDavid du Colombier pages[next_page++].stop = ftell(fp_in); 421*219b2ee8SDavid du Colombier } /* End if */ 422*219b2ee8SDavid du Colombier pages[next_page].start = ftell(fp_in); 423*219b2ee8SDavid du Colombier sawendpage = TRUE; 424*219b2ee8SDavid du Colombier gotpage = TRUE; 425*219b2ee8SDavid du Colombier } else if ( strncmp(buf, PAGE, pagelen) == 0 ) { 426*219b2ee8SDavid du Colombier if ( sawendpage == FALSE && in_olist(page++) == ON ) { 427*219b2ee8SDavid du Colombier pages[next_page].empty = FALSE; 428*219b2ee8SDavid du Colombier pages[next_page++].stop = ftell(fp_in) - strlen(buf); 429*219b2ee8SDavid du Colombier } /* End if */ 430*219b2ee8SDavid du Colombier pages[next_page].start = ftell(fp_in) - strlen(buf); 431*219b2ee8SDavid du Colombier sawendpage = FALSE; 432*219b2ee8SDavid du Colombier gotpage = TRUE; 433*219b2ee8SDavid du Colombier } else if ( gotpage == FALSE && strcmp(buf, BEGINSETUP) == 0 ) { 434*219b2ee8SDavid du Colombier fprintf(fp_out, "%s", endprolog); 435*219b2ee8SDavid du Colombier fprintf(fp_out, "%s", BEGINSETUP); 436*219b2ee8SDavid du Colombier moreprolog(ENDSETUP); 437*219b2ee8SDavid du Colombier endprolog = ENDSETUP; 438*219b2ee8SDavid du Colombier } else if ( strcmp(buf, BEGINGLOBAL) == 0 ) { 439*219b2ee8SDavid du Colombier moreprolog(ENDGLOBAL); 440*219b2ee8SDavid du Colombier } else if ( strcmp(buf, TRAILER) == 0 ) { 441*219b2ee8SDavid du Colombier if ( sawendpage == FALSE ) 442*219b2ee8SDavid du Colombier pages[next_page++].stop = ftell(fp_in) - strlen(buf); 443*219b2ee8SDavid du Colombier endoff = ftell(fp_in); 444*219b2ee8SDavid du Colombier break; 445*219b2ee8SDavid du Colombier } /* End if */ 446*219b2ee8SDavid du Colombier 447*219b2ee8SDavid du Colombier } /* End of readpages */ 448*219b2ee8SDavid du Colombier 449*219b2ee8SDavid du Colombier /*****************************************************************************/ 450*219b2ee8SDavid du Colombier 451*219b2ee8SDavid du Colombier writepages() 452*219b2ee8SDavid du Colombier 453*219b2ee8SDavid du Colombier { 454*219b2ee8SDavid du Colombier 455*219b2ee8SDavid du Colombier int i, j, k; /* loop indices */ 456*219b2ee8SDavid du Colombier 457*219b2ee8SDavid du Colombier /* 458*219b2ee8SDavid du Colombier * 459*219b2ee8SDavid du Colombier * Goes through the pages[] array, usually from the bottom up, and writes out all 460*219b2ee8SDavid du Colombier * the pages. Documents that print more than one form per page cause things to get 461*219b2ee8SDavid du Colombier * a little more complicated. Each physical page has to have its subpages printed 462*219b2ee8SDavid du Colombier * in the correct order, and we have to build a few dummy subpages for the last 463*219b2ee8SDavid du Colombier * (and now first) sheet of paper, otherwise things will only occasionally work. 464*219b2ee8SDavid du Colombier * 465*219b2ee8SDavid du Colombier */ 466*219b2ee8SDavid du Colombier 467*219b2ee8SDavid du Colombier fprintf(fp_out, "%s", endprolog); 468*219b2ee8SDavid du Colombier 469*219b2ee8SDavid du Colombier if ( noreverse == FALSE ) /* fill out the first page */ 470*219b2ee8SDavid du Colombier for ( i = (forms - next_page % forms) % forms; i > 0; i--, next_page++ ) 471*219b2ee8SDavid du Colombier pages[next_page].empty = TRUE; 472*219b2ee8SDavid du Colombier else forms = next_page; /* turns reversal off in next loop */ 473*219b2ee8SDavid du Colombier 474*219b2ee8SDavid du Colombier for ( i = next_page - forms; i >= 0; i -= forms ) 475*219b2ee8SDavid du Colombier for ( j = i, k = 0; k < forms; j++, k++ ) 476*219b2ee8SDavid du Colombier if ( pages[j].empty == TRUE ) { 477*219b2ee8SDavid du Colombier if ( ignoreversion == TRUE || version > 3.1 ) { 478*219b2ee8SDavid du Colombier fprintf(fp_out, "%s 0 0\n", PAGE); 479*219b2ee8SDavid du Colombier fprintf(fp_out, "/saveobj save def\n"); 480*219b2ee8SDavid du Colombier fprintf(fp_out, "showpage\n"); 481*219b2ee8SDavid du Colombier fprintf(fp_out, "saveobj restore\n"); 482*219b2ee8SDavid du Colombier fprintf(fp_out, "%s 0 0\n", ENDPAGE); 483*219b2ee8SDavid du Colombier } else { 484*219b2ee8SDavid du Colombier fprintf(fp_out, "%s 0 0\n", PAGE); 485*219b2ee8SDavid du Colombier fprintf(fp_out, "save showpage restore\n"); 486*219b2ee8SDavid du Colombier fprintf(fp_out, "%s 0 0\n", ENDPAGE); 487*219b2ee8SDavid du Colombier } /* End else */ 488*219b2ee8SDavid du Colombier } else copypage(pages[j].start, pages[j].stop); 489*219b2ee8SDavid du Colombier 490*219b2ee8SDavid du Colombier } /* End of writepages */ 491*219b2ee8SDavid du Colombier 492*219b2ee8SDavid du Colombier /*****************************************************************************/ 493*219b2ee8SDavid du Colombier 494*219b2ee8SDavid du Colombier copypage(start, stop) 495*219b2ee8SDavid du Colombier 496*219b2ee8SDavid du Colombier long start; /* starting from this offset */ 497*219b2ee8SDavid du Colombier long stop; /* and ending here */ 498*219b2ee8SDavid du Colombier 499*219b2ee8SDavid du Colombier { 500*219b2ee8SDavid du Colombier 501*219b2ee8SDavid du Colombier /* 502*219b2ee8SDavid du Colombier * 503*219b2ee8SDavid du Colombier * Copies the page beginning at offset start and ending at stop to the output 504*219b2ee8SDavid du Colombier * file. Global definitions are skipped since they've already been added to the 505*219b2ee8SDavid du Colombier * prologue. 506*219b2ee8SDavid du Colombier * 507*219b2ee8SDavid du Colombier */ 508*219b2ee8SDavid du Colombier 509*219b2ee8SDavid du Colombier fseek(fp_in, start, 0); 510*219b2ee8SDavid du Colombier 511*219b2ee8SDavid du Colombier while ( ftell(fp_in) < stop && fgets(buf, sizeof(buf), fp_in) != NULL ) 512*219b2ee8SDavid du Colombier if ( buf[0] == '%' && strcmp(buf, BEGINGLOBAL) == 0 ) 513*219b2ee8SDavid du Colombier while ( fgets(buf, sizeof(buf), fp_in) != NULL && strcmp(buf, ENDGLOBAL) != 0 ) ; 514*219b2ee8SDavid du Colombier else fprintf(fp_out, "%s", buf); 515*219b2ee8SDavid du Colombier 516*219b2ee8SDavid du Colombier } /* End of copypage */ 517*219b2ee8SDavid du Colombier 518*219b2ee8SDavid du Colombier /*****************************************************************************/ 519*219b2ee8SDavid du Colombier 520*219b2ee8SDavid du Colombier trailer() 521*219b2ee8SDavid du Colombier 522*219b2ee8SDavid du Colombier { 523*219b2ee8SDavid du Colombier 524*219b2ee8SDavid du Colombier /* 525*219b2ee8SDavid du Colombier * 526*219b2ee8SDavid du Colombier * Makes sure everything from the TRAILER string to EOF is copied to the output 527*219b2ee8SDavid du Colombier * file. 528*219b2ee8SDavid du Colombier * 529*219b2ee8SDavid du Colombier */ 530*219b2ee8SDavid du Colombier 531*219b2ee8SDavid du Colombier if ( endoff > 0 ) { 532*219b2ee8SDavid du Colombier fprintf(fp_out, "%s", TRAILER); 533*219b2ee8SDavid du Colombier fseek(fp_in, endoff, 0); 534*219b2ee8SDavid du Colombier while ( fgets(buf, sizeof(buf), fp_in) != NULL ) 535*219b2ee8SDavid du Colombier fprintf(fp_out, "%s", buf); 536*219b2ee8SDavid du Colombier } /* End if */ 537*219b2ee8SDavid du Colombier 538*219b2ee8SDavid du Colombier } /* End of trailer */ 539*219b2ee8SDavid du Colombier 540*219b2ee8SDavid du Colombier /*****************************************************************************/ 541*219b2ee8SDavid du Colombier 542