home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 2: PC / frozenfish_august_1995.bin / bbs / d07xx / d0797.lha / PSUtils / pstops.c < prev    next >
C/C++ Source or Header  |  1993-01-10  |  9KB  |  355 lines

  1. /* pstops.c
  2.  * AJCD 27/1/91
  3.  * rearrange pages in conforming PS file for printing in signatures
  4.  *
  5.  * Usage:
  6.  *       pstops [-q] [-b] [-w<dim>] [-h<dim>] <pagespecs> [infile [outfile]]
  7.  */
  8.  
  9. #include "psutil.h"
  10.  
  11. void usage()
  12. {
  13.    fprintf(stderr, "Usage: %s [-q] [-b] [-w<dim>] [-h<dim] <pagespecs> [infile [outfile]]\n",
  14.        prog);
  15.    fflush(stderr);
  16.    exit(1);
  17. }
  18.  
  19. void specusage()
  20. {
  21.    fprintf(stderr, "%s: page specification error:\n", prog);
  22.    fprintf(stderr, "  <pagespecs> = [modulo:]<spec>\n");
  23.    fprintf(stderr, "  <spec>      = [-]pageno[@scale][L|R|U][(xoff,yoff)][,spec|+spec]\n");
  24.    fprintf(stderr, "                modulo>=1, 0<=pageno<modulo\n");
  25.    fflush(stderr);
  26.    exit(1);
  27. }
  28.  
  29. static int modulo = 1;
  30. static int pagesperspec = 1;
  31. static double width = -1.0;
  32. static double height = -1.0;
  33.  
  34. /* pagespec flags */
  35. #define ADD_NEXT (0x01)
  36. #define ROTATE   (0x02)
  37. #define SCALE    (0x04)
  38. #define OFFSET   (0x08)
  39. #define GSAVE    (ROTATE|SCALE|OFFSET)
  40.  
  41. struct pagespec {
  42.    int reversed, pageno, flags, rotate;
  43.    double xoff, yoff, scale;
  44.    struct pagespec *next;
  45. };
  46.  
  47. struct pagespec *newspec()
  48. {
  49.    struct pagespec *temp = (struct pagespec *)malloc(sizeof(struct pagespec));
  50.    temp->reversed = temp->pageno = temp->flags = temp->rotate = 0;
  51.    temp->scale = 1.0;
  52.    temp->xoff = temp->yoff = 0.0;
  53.    temp->next = NULL;
  54.    return (temp);
  55. }
  56.  
  57. int parseint(sp)
  58.      char **sp;
  59. {
  60.    char *s;
  61.    int n = 0;
  62.  
  63.    for (s = *sp; isdigit(*s); s++)
  64.       n = n*10 + (*s-'0');
  65.    if (*sp == s) specusage();
  66.    *sp = s;
  67.    return (n);
  68. }
  69.  
  70. double parsedouble(sp)
  71.      char **sp;
  72. {
  73.    int n = parseint(sp);
  74.    char *s = *sp;
  75.    int d = 0, frac = 1;
  76.  
  77.    if (*s == '.') {
  78.       *sp = ++s;
  79.       for (; isdigit(*s); s++) {
  80.      d = d*10 + (*s-'0');
  81.      frac *= 10;
  82.       }
  83.       if (*sp == s) specusage();
  84.    }
  85.    *sp = s;
  86.    return ((double)n+(double)d/frac);
  87. }
  88.  
  89. double parsedimen(sp)
  90.      char **sp;
  91. {
  92.    double num = parsedouble(sp);
  93.    char *s = *sp;
  94.  
  95.    if (strncmp(s, "pt", 2) == 0) {
  96.       s += 2;
  97.    } else if (strncmp(s, "in", 2) == 0) {
  98.       num *= 72.0;
  99.       s += 2;
  100.    } else if (strncmp(s, "cm", 2) == 0) {
  101.       num *= 28.346456692913385211;
  102.       s += 2;
  103.    } else if (*s == 'w') {
  104.       if (width < 0.0) {
  105.      fprintf(stderr, "%s: width not initialised\n", prog);
  106.      fflush(stderr);
  107.      exit(1);
  108.       }
  109.       num *= width;
  110.       s++;
  111.    } else if (*s == 'h') {
  112.       if (height < 0.0) {
  113.      fprintf(stderr, "%s: height not initialised\n", prog);
  114.      fflush(stderr);
  115.      exit(1);
  116.       }
  117.       num *= height;
  118.       s++;
  119.    }
  120.    *sp = s;
  121.    return (num);
  122. }
  123.  
  124. struct pagespec *parsespecs(str)
  125.      char *str;
  126. {
  127.    char *t;
  128.    struct pagespec *head, *tail;
  129.    int other = 0;
  130.    int num = -1;
  131.  
  132.    head = tail = newspec();
  133.    while (*str) {
  134.       if (isdigit(*str)) {
  135.      num = parseint(&str);
  136.       } else {
  137.      switch (*str++) {
  138.      case ':':
  139.         if (other || head != tail || num < 1) specusage();
  140.         modulo = num;
  141.         num = -1;
  142.         break;
  143.      case '-':
  144.         tail->reversed = !tail->reversed;
  145.         break;
  146.      case '@':
  147.         if (num < 0) specusage();
  148.         tail->scale *= parsedouble(&str);
  149.         tail->flags |= SCALE;
  150.         break;
  151.      case 'l': case 'L':
  152.         tail->rotate += 90;
  153.         tail->flags |= ROTATE;
  154.         break;
  155.      case 'r': case 'R':
  156.         tail->rotate -= 90;
  157.         tail->flags |= ROTATE;
  158.         break;
  159.      case 'u': case 'U':
  160.         tail->rotate += 180;
  161.         tail->flags |= ROTATE;
  162.         break;
  163.      case '(':
  164.         tail->xoff += parsedimen(&str);
  165.         if (*str++ != ',') specusage();
  166.         tail->yoff += parsedimen(&str);
  167.         if (*str++ != ')') specusage();
  168.         tail->flags |= OFFSET;
  169.         break;
  170.      case '+':
  171.         tail->flags |= ADD_NEXT;
  172.      case ',':
  173.         if (num < 0 || num >= modulo) specusage();
  174.         if ((tail->flags & ADD_NEXT) == 0)
  175.            pagesperspec++;
  176.         tail->pageno = num;
  177.         tail->next = newspec();
  178.         tail = tail->next;
  179.         num = -1;
  180.         break;
  181.      default:
  182.         specusage();
  183.      }
  184.      other = 1;
  185.       }
  186.    }
  187.    if (num >= modulo)
  188.       specusage();
  189.    else if (num >= 0)
  190.       tail->pageno = num;
  191.    return (head);
  192. }
  193.  
  194. double singledimen(str)
  195.      char *str;
  196. {
  197.    double num = parsedimen(&str);
  198.    if (*str) usage();
  199.    return (num);
  200. }
  201.  
  202.  
  203. main(argc, argv)
  204.      int argc;
  205.      char *argv[];
  206. {
  207.    int thispg, maxpage;
  208.    int pageindex = 0;
  209.    struct pagespec *specs = NULL;
  210.    int nobinding = 0;
  211.  
  212.    infile = stdin;
  213.    outfile = stdout;
  214.    verbose = 1;
  215.    for (prog = *argv++; --argc; argv++) {
  216.       if (argv[0][0] == '-') {
  217.      switch (argv[0][1]) {
  218.      case 'q':
  219.         verbose = 0;
  220.         break;
  221.      case 'b':
  222.         nobinding = 1;
  223.         break;
  224.      case 'w':
  225.         width = singledimen(*argv+2);
  226.         break;
  227.      case 'h':
  228.         height = singledimen(*argv+2);
  229.         break;
  230.      default:
  231.         if (specs == NULL)
  232.            specs = parsespecs(*argv);
  233.         else
  234.            usage();
  235.      }
  236.       } else if (specs == NULL)
  237.      specs = parsespecs(*argv);
  238.       else if (infile == stdin) {
  239.      if ((infile = fopen(*argv, "r")) == NULL) {
  240.         fprintf(stderr, "%s: can't open input file %s\n", prog, *argv);
  241.         fflush(stderr);
  242.         exit(1);
  243.      }
  244.       } else if (outfile == stdout) {
  245.      if ((outfile = fopen(*argv, "w")) == NULL) {
  246.         fprintf(stderr, "%s: can't open output file %s\n", prog, *argv);
  247.         fflush(stderr);
  248.         exit(1);
  249.      }
  250.       } else usage();
  251.    }
  252.    if (specs == NULL)
  253.       usage();
  254.    if ((infile=seekable(infile))==NULL) {
  255.       fprintf(stderr, "%s: can't seek input\n", prog);
  256.       fflush(stderr);
  257.       exit(1);
  258.    }
  259.    scanpages();
  260.  
  261.    maxpage = ((pages+modulo-1)/modulo)*modulo;
  262.  
  263.    /* rearrange pages: doesn't cope properly with:
  264.     * initmatrix, initgraphics, defaultmatrix, grestoreall, initclip */
  265.    writeheader((maxpage/modulo)*pagesperspec);
  266.    writestring("%%BeginProcSet: pstops 1 0\n");
  267.    writestring("[/showpage/erasepage/copypage]{dup where{pop dup load\n");
  268.    writestring(" type/operatortype eq{1 array cvx dup 0 3 index cvx put\n");
  269.    writestring(" bind def}{pop}ifelse}{pop}ifelse}forall\n");
  270.    writestring("[/letter/legal/executivepage/a4/a4small/b5/com10envelope\n");
  271.    writestring(" /monarchenvelope/c5envelope/dlenvelope/lettersmall/note\n");
  272.    writestring(" /folio/quarto/a5]{dup where{exch{}put}{pop}ifelse}forall\n");
  273.    writestring("/lcvx{dup load dup type dup/operatortype eq{pop exch pop}\n");
  274.    writestring(" {/arraytype eq{dup xcheck{exch pop aload pop}\n");
  275.    writestring(" {pop cvx}ifelse}{pop cvx}ifelse}ifelse}bind def\n");
  276.    writestring("/pstopsmatrix matrix currentmatrix def\n");
  277.    writestring("/defaultmatrix{pstopsmatrix exch copy}bind def\n");
  278.    writestring("/initmatrix{matrix defaultmatrix setmatrix}bind def\n");
  279.    writestring("/pathtoproc{[{currentpoint}stopped{$error/newerror false\n");
  280.    writestring(" put{newpath}}{/newpath cvx 3 1 roll/moveto cvx 4 array\n");
  281.    writestring(" astore cvx}ifelse]{[/newpath cvx{/moveto cvx}{/lineto cvx}\n");
  282.    writestring(" {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop}\n");
  283.    writestring(" stopped{$error/errorname get/invalidaccess eq{cleartomark\n");
  284.    writestring(" $error/newerror false put cvx exec}{stop}ifelse}if}def\n");
  285.    if (width > 0.0 && height > 0.0) {
  286.       char buffer[BUFSIZ];
  287.       writestring("/initclip[/pathtoproc lcvx/matrix lcvx/currentmatrix lcvx");
  288.       writestring("/initmatrix lcvx/initclip lcvx /newpath lcvx\n");
  289.       writestring(" 0 0 /moveto lcvx\n");
  290.       sprintf(buffer,
  291.           " %lf 0/rlineto lcvx 0 %lf/rlineto lcvx -%lf 0/rlineto lcvx\n",
  292.           width, height, width);
  293.       writestring(buffer);
  294.       writestring(" /clip lcvx /newpath lcvx /setmatrix lcvx /exec lcvx]\n");
  295.       writestring(" cvx def\n");
  296.    }
  297.    writestring("/initgraphics{initmatrix newpath initclip 1 setlinewidth\n");
  298.    writestring(" 0 setlinecap 0 setlinejoin []0 setdash 0 setgray\n");
  299.    writestring(" 0 setmiterlimit}bind def\n");
  300.    if (nobinding) /* desperation measures */
  301.       writestring("/bind{}def\n");
  302.    writestring("%%EndProcSet\n");
  303.    writeprolog();
  304.    for (thispg = 0; thispg < maxpage; thispg += modulo) {
  305.       int ppp, add_last = 0;
  306.       struct pagespec *ps;
  307.       for (ppp = 0, ps = specs; ps != NULL; ppp++, ps = ps->next) {
  308.      int actualpg;
  309.      int add_next = ((ps->flags & ADD_NEXT) != 0);
  310.      if (ps->reversed)
  311.         actualpg = maxpage-thispg-modulo+ps->pageno;
  312.      else
  313.         actualpg = thispg+ps->pageno;
  314.      if (actualpg < pages)
  315.         seekpage(actualpg);
  316.      if (!add_last) {
  317.         writepageheader("pstops", ++pageindex);
  318.      }
  319.      writestring("gsave\n");
  320.      if (ps->flags & GSAVE) {
  321.         char buffer[BUFSIZ];
  322.         if (ps->flags & OFFSET) {
  323.            sprintf(buffer, "%lf %lf translate\n", ps->xoff, ps->yoff);
  324.            writestring(buffer);
  325.         }
  326.         if (ps->flags & ROTATE) {
  327.            sprintf(buffer, "%d rotate\n", ps->rotate);
  328.            writestring(buffer);
  329.         }
  330.         if (ps->flags & SCALE) {
  331.            sprintf(buffer, "%lf dup scale\n", ps->scale);
  332.            writestring(buffer);
  333.         }
  334.         writestring("/pstopsmatrix matrix currentmatrix def\n");
  335.      }
  336.      if (width > 0.0 && height > 0.0) {
  337.         writestring("initclip\n");
  338.      }
  339.      writestring("/pstopssaved save def\n");
  340.      if (add_next) {
  341.         writestring("/showpage{}def/copypage{}def/erasepage{}def\n");
  342.      }
  343.      if (actualpg < pages)
  344.         writepagebody();
  345.      else
  346.         writestring("showpage\n");
  347.      writestring("pstopssaved restore grestore\n");
  348.      add_last = add_next;
  349.       }
  350.    }
  351.    writetrailer();
  352.  
  353.    exit(0);
  354. }
  355.