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