home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1997 February / PCWK0297.iso / technika / simic / pspage.c < prev    next >
Text File  |  1993-11-10  |  11KB  |  348 lines

  1. /* ======== PSpage - a page manipulation program ======== */
  2. /*
  3.  * Copyright 1991, 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * This file may be freely copied and redistributed as long as:
  6.  *   1) This entire notice continues to be included in the file, 
  7.  *   2) If the file has been modified in any way, a notice of such
  8.  *      modification is conspicuously indicated.
  9.  *
  10.  * PostScript, Display PostScript, and Adobe are registered trademarks of
  11.  * Adobe Systems Incorporated.
  12.  * 
  13.  * ************************************************************************
  14.  * THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
  15.  * NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
  16.  * INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR 
  17.  * LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY 
  18.  * KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION, 
  19.  * AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  20.  * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
  21.  * ************************************************************************
  22.  */
  23.  
  24. /*
  25.  * SUMMARY:
  26.  * This program will manipulate a properly formatted PostScript document,
  27.  * that is, one that complies with the Adobe Document Structuring Conventions.
  28.  * Given the simplicity of this program, it is really only interested in the
  29.  * following comments;
  30.  *     %!PS-Adobe-X.x
  31.  *     %%EndSetup
  32.  *     %%Page:
  33.  *     %%Trailer
  34.  * 
  35.  * OPTIONS:
  36.  * p - allows a range of pages to be specified in the form
  37.  *     of a list separated by commas.  E.g. 4,5-13,22
  38.  *     Ranges can be specified forwards, e.g. 5-13, or backwards, e.g. 13-5
  39.  * r - will cause PSpage to page reverse the document.
  40.  * 
  41.  * DEFAULTS:
  42.  * If options are not specified, all pages are output without page reversal.
  43.  * 
  44.  * KNOWN BUGS:
  45.  * For page reversal: PSpage does not check the %%Pages: comment to see if
  46.  * the second argument is a 0, which indicates that page order should not
  47.  * be changed.
  48.  * 
  49.  * PSpage does not handle included documents, that would be better serviced
  50.  * by a proper state machine implementation.
  51.  * 
  52.  * Specifying an open range (e.g. 5-) to indicate that the current page until
  53.  * the end of the document is desired but is not supported.
  54.  * 
  55.  * THINGS TO TWEAK:
  56.  * ** MAXPAGES defines the maximum number of pages that can be reversed
  57.  * ** MAXRANGES defines the maximum number of ranges that can be specified
  58.  * ** In the #include section, the file <stdarg.h> may be <varargs.h> or 
  59.  * <sys/varagrs.h> on your system.
  60.  *
  61.  * CHANGE HISTORY:
  62.  *   90-June-01    orthlieb    created
  63.  *   91-June-05    mackay        incorporated comments; made lines < 80 chars;
  64.  *   91-Sept-26 mackay        added comment on #include <stdarg.h>
  65.  */
  66.  
  67.  
  68. /* ----------------------- includes ----------------------*/
  69. #include <stdio.h>
  70. #include <string.h>
  71. #include <stdarg.h>
  72. /* ------------------------ defines ----------------------*/
  73. #define TRUE 1
  74. #define FALSE 0
  75. #define VERBOSE TRUE
  76. #define TERSE FALSE
  77. #define error printf
  78.  
  79. /* MAXPAGES defines the maximum number of pages that can be reversed */
  80. #define MAXPAGES 100
  81.  
  82. /* MAXRANGES defines the maximum number of ranges that can be specified */
  83. #define MAXRANGES 25
  84.  
  85. /* ----------------------- typedefs --------------------- */
  86. typedef char bool;
  87.  
  88. /* ------------------------ globals ----------------------*/
  89. long pageloc[MAXPAGES];
  90. int  numpages;
  91. bool pagereverse = FALSE;    /* Default: No page reversal */
  92. char *pageranges[MAXRANGES];
  93. int numranges = 0;
  94. FILE *infile, *outfile;
  95.  
  96. /* ------------------------ externs ----------------------*/
  97. extern void find_page_locations(FILE *thefile);
  98. extern void output_document(FILE *infile, FILE *outfile);
  99. extern void check_args(int numargs, char **args);
  100.  
  101. /* ----------------------- mainline ----------------------*/
  102. void main (int argc, char **argv)
  103. {
  104.  
  105.   /* Setup page ranges */
  106.   numranges = 1;
  107.   pageranges[0] = "*";
  108.   pageranges[1] = NULL;
  109.  
  110.   check_args(argc, argv);
  111.   find_page_locations(infile);
  112.   rewind(infile);
  113.   output_document(infile, outfile);
  114. }
  115.  
  116. void print_instructions(bool howlong)
  117. {
  118.    error("PSpage [-p <pages>] [-r] <infile> <outfile>\n");
  119.    if (howlong == TERSE) return;
  120.    error("This program will manipulate a properly formatted PostScript\n");
  121.    error("document, that is, one that complies with the Adobe Document\n");
  122.    error("Structuring Conventions. \n\n");
  123.    error("Options:\n");
  124.    error("p - allows a range of pages to be specified in the form\n");
  125.    error("    of a list separated by commas.  E.g. 4,5-13,22\n");
  126.    error("    Ranges can be specified forwards, e.g. 5-13,\n");
  127.    error("    or backwards, e.g. 13-5\n");
  128.    error("r - will cause PSpage to page reverse the document.\n\n");
  129.    error("Defaults:\n");
  130.    error("If options are not specified, all pages are output");
  131.    error(" without page reversal\n\n");
  132.    error("Known Bugs:\n");
  133.    error("For page reversal: PSpage does not check the %%Pages: comment\n");
  134.    error("to see if the second argument is a 0, which indicates that page\n");
  135.    error("order should not be changed.\n");
  136.    error("PSpage does not handle included documents, that would be better\n");
  137.    error("serviced by a proper state machine implementation.\n");
  138. }
  139.  
  140. void check_args(int numargs, char **arg)
  141. {
  142.    int  mark;
  143.    char *cmd;
  144.  
  145.    /* Check to see if long instructions are desired */
  146.    if (numargs < 2 || arg[1][0] == '?') {
  147.       print_instructions(VERBOSE);
  148.       exit(0);
  149.    }
  150.    if (numargs < 3) {
  151.       error("PSpage ERROR: Not enough arguments\n");
  152.       print_instructions(TERSE);
  153.       exit(0);
  154.    }
  155.  
  156.    mark = 1;
  157.    while(mark < numargs) {
  158.       /* If we've found a command */
  159.       if (arg[mark][0] == '-') {
  160.      for (cmd = &arg[mark][1]; *cmd != '\0'; cmd++) {
  161.             /* Scan the arguments */
  162.         switch (*cmd) {
  163.               case 'p': /* Page number list */
  164.               error("PSpage STATUS: using page range option.\n");
  165.                   /* The next argument must be a list of page ranges */
  166.                   /* Breakout the page ranges into individual tokens */
  167.                   numranges = 0;
  168.                   pageranges[numranges++] = strtok(arg[mark+1],",");
  169.                   while ((pageranges[numranges++] = strtok(NULL,",")) != NULL);
  170.                   numranges--; /* Reset to reflect actual number of ranges */
  171.                   mark++;   /* move to next token */
  172.                break;
  173.                case 'r': /* Page reversal desired */
  174.               error("PSpage STATUS: performing page reversal.\n");
  175.                   pagereverse = TRUE;
  176.            break;
  177.                default:
  178.                   error("PSpage ERROR: invalid option\n");
  179.               print_instructions(TERSE);
  180.               exit(-1);
  181.                break;
  182.             }
  183.          }
  184.       }
  185.       else {
  186.          if (infile == NULL) {
  187.         if ((infile = fopen(arg[mark],"rb")) == NULL) {
  188.            error("PSpage ERROR: cannot open input file %s.\n",arg[mark]);
  189.            exit(-1);
  190.         }
  191.      }
  192.          else {
  193.         if ((outfile = fopen(arg[mark],"wb")) == NULL) {
  194.            error("PSpage ERROR: cannot open output file %s.\n",arg[mark]);
  195.            exit(-1);
  196.         }
  197.      }
  198.       }
  199.       mark++;
  200.    }
  201. }
  202.  
  203. int check_comment(char *str, int numargs, ...)
  204. {
  205.   va_list ap;
  206.   char    *comment;
  207.  
  208.   va_start(ap, numargs);
  209.  
  210.   while (numargs-- > 0) {
  211.     comment = va_arg(ap, char *);
  212.     if (strncmp(str, comment, strlen(comment)) == 0) {
  213.       va_end(ap);
  214.       return TRUE;
  215.     }
  216.   }
  217.   va_end(ap);
  218.   return FALSE;
  219. }
  220.  
  221. void find_page_locations(FILE *thefile)
  222. {
  223.   int  i;
  224.   bool endoffile = FALSE;
  225.   long oldpos = 0;
  226.   char buf[256];
  227.   char *junk;
  228.  
  229.   while (endoffile == FALSE) {
  230.     /* Save our current position */
  231.     oldpos = ftell(thefile);
  232.  
  233.     /* Get a line from the file */
  234.     if (fgets(buf, 256, thefile) == NULL) {
  235.       /* No %%Trailer, No %%EOF */
  236.       if (!pageloc[numpages]) pageloc[numpages] = oldpos;
  237.       endoffile = TRUE;
  238.     }
  239.     else {
  240.       /* Check to see if we've found a comment */
  241.       if (buf[0] == '%' && buf[1] == '%') {
  242.     /* Check for the Page comment, record the location */
  243.     if (check_comment(buf, 1, "%%Page:") == TRUE) {
  244.       /* Note the location of this page */
  245.       pageloc[numpages++] = oldpos;
  246.     }
  247.     /* Check for the trailer or EOF to see if it's time to leave */
  248.     if (check_comment(buf, 2, "%%Trailer", "%%EOF") == TRUE) {
  249.       /* End of the last page */
  250.       pageloc[numpages] = oldpos;
  251.       endoffile = TRUE; /* No use searching any more */
  252.     }
  253.       }
  254.     }
  255.   }
  256.   if (numpages == 0) {
  257.     error("PSpage ERROR: No %%%%Page: comments in this document.\n");
  258.     exit(-2);
  259.   } else {
  260.     error("PSpage STATUS: This document has %d pages.\n", numpages);
  261.   }
  262. }
  263.  
  264. void find_page_parms(char *range, int *start, int *end)
  265. {
  266.    char *pdash = NULL;
  267.    int  temp;
  268.  
  269.    if (range[0] == '*') {
  270.      *start = 1;
  271.      *end = numpages;
  272.    }
  273.    /* Single number */
  274.    else if ((pdash = strchr(range,'-')) == NULL) {
  275.       *start = *end = atoi(range);
  276.    }
  277.    else {
  278.    /* Range of numbers */
  279.       *pdash++ = '\0';
  280.       *start = atoi(range); *end = atoi(pdash);
  281.    }
  282.  
  283.    if (*start < 1 | *end < 1 | *start > numpages | *end > numpages) {
  284.       error("PSpage ERROR: page range is invalid [%d-%d].\n", start, end);
  285.       exit(-3);
  286.    }
  287.    (*start)--; (*end)--;
  288.  
  289.    /* Pull a little sneaky to help with page reversal */
  290.    if (pagereverse == TRUE) {
  291.       temp = *start; *start = *end; *end = temp;
  292.    }
  293. }
  294.  
  295. void print_page(FILE *infile, FILE *outfile, int page)
  296. {
  297.    long i;
  298.  
  299.    if (fseek(infile, pageloc[page], SEEK_SET) != 0) {
  300.       error("PSpage ERROR: Seek at position %d, page %d\n", 
  301.         pageloc[page], page+1);
  302.       exit(-2);
  303.    }
  304.    for (i = pageloc[page]; i < pageloc[page+1]; i++)
  305.       fputc(fgetc(infile), outfile);
  306. }
  307.  
  308. void output_document(FILE *infile, FILE *outfile)
  309. {
  310.    char c;
  311.    int  pagestart, pageend, pageincr, rangeindex, rangeincr;
  312.    long i;
  313.    register int r, p;
  314.  
  315.    /* Print out the top of the file */
  316.    for (i = 0; i < pageloc[0]; i++)
  317.       fputc(fgetc(infile),outfile);
  318.  
  319.    /* Now start the page manipulations */
  320.    /* Flip the order of ranges for page reversal */
  321.    rangeincr = 1; rangeindex = 0;
  322.    if (pagereverse == TRUE) {
  323.       rangeincr = -1;
  324.       rangeindex = numranges - 1;
  325.    }
  326.  
  327.    for (r = rangeindex; r < numranges && r >= 0; r += rangeincr) {
  328.       find_page_parms(pageranges[r], &pagestart, &pageend);
  329.       /* Print out each individual page */
  330.       if (pagestart > pageend)
  331.      for (p = pagestart; p >= pageend;p--)
  332.             print_page(infile, outfile, p);
  333.       else
  334.      for (p = pagestart; p <= pageend; p++)
  335.             print_page(infile, outfile, p);
  336.    }
  337.  
  338.    /* Now print out the end of the file */
  339.    if (fseek(infile, pageloc[numpages], SEEK_SET) != 0) {
  340.      error("PSpage ERROR: Seek at position %d while writing trailer %d\n",
  341.          pageloc[numpages]);
  342.      exit(-2);
  343.    }
  344.    while ((c = fgetc(infile)) != EOF)
  345.      fputc(c,outfile);
  346. }
  347.  
  348.