ftp.nice.ch/pub/next/unix/graphics/psutils.5Nov92.N.bs.tar.gz#/psutils/pstops.c

This is pstops.c in view mode; [Download] [Up]

/* pstops.c
 * AJCD 27/1/91
 * rearrange pages in conforming PS file for printing in signatures
 *
 * Usage:
 *       pstops [-q] [-b] [-w<dim>] [-h<dim>] <pagespecs> [infile [outfile]]
 */

#include "psutil.h"

void usage()
{
   fprintf(stderr, "Usage: %s [-q] [-b] [-w<dim>] [-h<dim] <pagespecs> [infile [outfile]]\n",
	   prog);
   fflush(stderr);
   exit(1);
}

void specusage()
{
   fprintf(stderr, "%s: page specification error:\n", prog);
   fprintf(stderr, "  <pagespecs> = [modulo:]<spec>\n");
   fprintf(stderr, "  <spec>      = [-]pageno[@scale][L|R|U][(xoff,yoff)][,spec|+spec]\n");
   fprintf(stderr, "                modulo>=1, 0<=pageno<modulo\n");
   fflush(stderr);
   exit(1);
}

static int modulo = 1;
static int pagesperspec = 1;
static double width = -1.0;
static double height = -1.0;

/* pagespec flags */
#define ADD_NEXT (0x01)
#define ROTATE   (0x02)
#define SCALE    (0x04)
#define OFFSET   (0x08)
#define GSAVE    (ROTATE|SCALE|OFFSET)

struct pagespec {
   int reversed, pageno, flags, rotate;
   double xoff, yoff, scale;
   struct pagespec *next;
};

struct pagespec *newspec()
{
   struct pagespec *temp = (struct pagespec *)malloc(sizeof(struct pagespec));
   temp->reversed = temp->pageno = temp->flags = temp->rotate = 0;
   temp->scale = 1.0;
   temp->xoff = temp->yoff = 0.0;
   temp->next = NULL;
   return (temp);
}

int parseint(sp)
     char **sp;
{
   char *s;
   int n = 0;

   for (s = *sp; isdigit(*s); s++)
      n = n*10 + (*s-'0');
   if (*sp == s) specusage();
   *sp = s;
   return (n);
}

double parsedouble(sp)
     char **sp;
{
   int n = 0, neg = 1;
   char *s = *sp;
   int d = 0, frac = 1;

   if (*s == '-') {
      neg = -1;
      *sp = ++s;
   }
   for (;isdigit(*s); s++)
      n = n*10 + (*s-'0');
   if (*s == '.') {
      *sp = ++s;
      for (; isdigit(*s); s++) {
	 d = d*10 + (*s-'0');
	 frac *= 10;
      }
   }
   if (*sp == s) specusage();
   *sp = s;
   return (neg*((double)n+(double)d/frac));
}

double parsedimen(sp)
     char **sp;
{
   double num = parsedouble(sp);
   char *s = *sp;

   if (strncmp(s, "pt", 2) == 0) {
      s += 2;
   } else if (strncmp(s, "in", 2) == 0) {
      num *= 72.0;
      s += 2;
   } else if (strncmp(s, "cm", 2) == 0) {
      num *= 28.346456692913385211;
      s += 2;
   } else if (*s == 'w') {
      if (width < 0.0) {
	 fprintf(stderr, "%s: width not initialised\n", prog);
	 fflush(stderr);
	 exit(1);
      }
      num *= width;
      s++;
   } else if (*s == 'h') {
      if (height < 0.0) {
	 fprintf(stderr, "%s: height not initialised\n", prog);
	 fflush(stderr);
	 exit(1);
      }
      num *= height;
      s++;
   }
   *sp = s;
   return (num);
}

struct pagespec *parsespecs(str)
     char *str;
{
   char *t;
   struct pagespec *head, *tail;
   int other = 0;
   int num = -1;

   head = tail = newspec();
   while (*str) {
      if (isdigit(*str)) {
	 num = parseint(&str);
      } else {
	 switch (*str++) {
	 case ':':
	    if (other || head != tail || num < 1) specusage();
	    modulo = num;
	    num = -1;
	    break;
	 case '-':
	    tail->reversed = !tail->reversed;
	    break;
	 case '@':
	    if (num < 0) specusage();
	    tail->scale *= parsedouble(&str);
	    tail->flags |= SCALE;
	    break;
	 case 'l': case 'L':
	    tail->rotate += 90;
	    tail->flags |= ROTATE;
	    break;
	 case 'r': case 'R':
	    tail->rotate -= 90;
	    tail->flags |= ROTATE;
	    break;
	 case 'u': case 'U':
	    tail->rotate += 180;
	    tail->flags |= ROTATE;
	    break;
	 case '(':
	    tail->xoff += parsedimen(&str);
	    if (*str++ != ',') specusage();
	    tail->yoff += parsedimen(&str);
	    if (*str++ != ')') specusage();
	    tail->flags |= OFFSET;
	    break;
	 case '+':
	    tail->flags |= ADD_NEXT;
	 case ',':
	    if (num < 0 || num >= modulo) specusage();
	    if ((tail->flags & ADD_NEXT) == 0)
	       pagesperspec++;
	    tail->pageno = num;
	    tail->next = newspec();
	    tail = tail->next;
	    num = -1;
	    break;
	 default:
	    specusage();
	 }
	 other = 1;
      }
   }
   if (num >= modulo)
      specusage();
   else if (num >= 0)
      tail->pageno = num;
   return (head);
}

double singledimen(str)
     char *str;
{
   double num = parsedimen(&str);
   if (*str) usage();
   return (num);
}


main(argc, argv)
     int argc;
     char *argv[];
{
   int thispg, maxpage;
   int pageindex = 0;
   struct pagespec *specs = NULL;
   int nobinding = 0;

   infile = stdin;
   outfile = stdout;
   verbose = 1;
   for (prog = *argv++; --argc; argv++) {
      if (argv[0][0] == '-') {
	 switch (argv[0][1]) {
	 case 'q':
	    verbose = 0;
	    break;
	 case 'b':
	    nobinding = 1;
	    break;
	 case 'w':
	    width = singledimen(*argv+2);
	    break;
	 case 'h':
	    height = singledimen(*argv+2);
	    break;
	 default:
	    if (specs == NULL)
	       specs = parsespecs(*argv);
	    else
	       usage();
	 }
      } else if (specs == NULL)
	 specs = parsespecs(*argv);
      else if (infile == stdin) {
	 if ((infile = fopen(*argv, "r")) == NULL) {
	    fprintf(stderr, "%s: can't open input file %s\n", prog, *argv);
	    fflush(stderr);
	    exit(1);
	 }
      } else if (outfile == stdout) {
	 if ((outfile = fopen(*argv, "w")) == NULL) {
	    fprintf(stderr, "%s: can't open output file %s\n", prog, *argv);
	    fflush(stderr);
	    exit(1);
	 }
      } else usage();
   }
   if (specs == NULL)
      usage();
   if ((infile=seekable(infile))==NULL) {
      fprintf(stderr, "%s: can't seek input\n", prog);
      fflush(stderr);
      exit(1);
   }
   scanpages();

   maxpage = ((pages+modulo-1)/modulo)*modulo;

   /* rearrange pages: doesn't cope properly with:
    * initmatrix, initgraphics, defaultmatrix, grestoreall, initclip */
   writeheader((maxpage/modulo)*pagesperspec);
   writestring("%%BeginProcSet: pstops 1 0\n");
   writestring("[/showpage/erasepage/copypage]{dup where{pop dup load\n");
   writestring(" type/operatortype eq{1 array cvx dup 0 3 index cvx put\n");
   writestring(" bind def}{pop}ifelse}{pop}ifelse}forall\n");
   writestring("[/letter/legal/executivepage/a4/a4small/b5/com10envelope\n");
   writestring(" /monarchenvelope/c5envelope/dlenvelope/lettersmall/note\n");
   writestring(" /folio/quarto/a5]{dup where{dup wcheck{exch{}put}\n");
   writestring(" {pop{}def}ifelse}{pop}ifelse}forall\n");
   writestring("/lcvx{dup load dup type dup/operatortype eq{pop exch pop}\n");
   writestring(" {/arraytype eq{dup xcheck{exch pop aload pop}\n");
   writestring(" {pop cvx}ifelse}{pop cvx}ifelse}ifelse}bind def\n");
   writestring("/pstopsmatrix matrix currentmatrix def\n");
   writestring("/defaultmatrix{pstopsmatrix exch copy}bind def\n");
   writestring("/initmatrix{matrix defaultmatrix setmatrix}bind def\n");
   writestring("/pathtoproc{[{currentpoint}stopped{$error/newerror false\n");
   writestring(" put{newpath}}{/newpath cvx 3 1 roll/moveto cvx 4 array\n");
   writestring(" astore cvx}ifelse]{[/newpath cvx{/moveto cvx}{/lineto cvx}\n");
   writestring(" {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop}\n");
   writestring(" stopped{$error/errorname get/invalidaccess eq{cleartomark\n");
   writestring(" $error/newerror false put cvx exec}{stop}ifelse}if}def\n");
   if (width > 0.0 && height > 0.0) {
      char buffer[BUFSIZ];
      writestring("/initclip[/pathtoproc lcvx/matrix lcvx/currentmatrix lcvx");
      writestring("/initmatrix lcvx/initclip lcvx /newpath lcvx\n");
      writestring(" 0 0 /moveto lcvx\n");
      sprintf(buffer,
	      " %lf 0/rlineto lcvx 0 %lf/rlineto lcvx -%lf 0/rlineto lcvx\n",
	      width, height, width);
      writestring(buffer);
      writestring(" /clip lcvx /newpath lcvx /setmatrix lcvx /exec lcvx]\n");
      writestring(" cvx def\n");
   }
   writestring("/initgraphics{initmatrix newpath initclip 1 setlinewidth\n");
   writestring(" 0 setlinecap 0 setlinejoin []0 setdash 0 setgray\n");
   writestring(" 10 setmiterlimit}bind def\n");
   if (nobinding) /* desperation measures */
      writestring("/bind{}def\n");
   writestring("%%EndProcSet\n");
   writeprolog();
   for (thispg = 0; thispg < maxpage; thispg += modulo) {
      int add_last = 0;
      struct pagespec *ps;
      for (ps = specs; ps != NULL; ps = ps->next) {
	 int actualpg;
	 int add_next = ((ps->flags & ADD_NEXT) != 0);
	 if (ps->reversed)
	    actualpg = maxpage-thispg-modulo+ps->pageno;
	 else
	    actualpg = thispg+ps->pageno;
	 if (actualpg < pages)
	    seekpage(actualpg);
	 if (!add_last) {
	    writepageheader("pstops", ++pageindex);
	 }
	 writestring("/pstopssaved save def\n");
	 if (ps->flags & GSAVE) {
	    char buffer[BUFSIZ];
	    if (ps->flags & OFFSET) {
	       sprintf(buffer, "%lf %lf translate\n", ps->xoff, ps->yoff);
	       writestring(buffer);
	    }
	    if (ps->flags & ROTATE) {
	       sprintf(buffer, "%d rotate\n", ps->rotate);
	       writestring(buffer);
	    }
	    if (ps->flags & SCALE) {
	       sprintf(buffer, "%lf dup scale\n", ps->scale);
	       writestring(buffer);
	    }
	    writestring("/pstopsmatrix matrix currentmatrix def\n");
	 }
	 if (width > 0.0 && height > 0.0) {
	    writestring("initclip\n");
	 }
	 if (add_next) {
	    writestring("/showpage{}def/copypage{}def/erasepage{}def\n");
	 }
	 if (actualpg < pages)
	    writepagebody();
	 else
	    writestring("showpage\n");
	 writestring("pstopssaved restore\n");
	 add_last = add_next;
      }
   }
   writetrailer();

   exit(0);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.