[comp.text.tex] Booklet Style: Source for psbook etc

msh@math.canterbury.ac.nz (Mark Hickman) (05/22/91)

It appears that there is interest in Angus Duggan's postscript utilities.
They were originally posted in the alt.sources newsgroup. Since I (and I guess
many other readers of this group) don't read that newsgroup, I thought
that it might be worthwhile to repost them here. 

P.S. dvidvi was described to me as a dvi driver. I misinterpreted this to
mean a driver like dvips etc. In fact it converts a dvi file into another
dvi file with pages etc rearranged. It is perhaps a better choice for people
using cm fonts.

-- 
Mark Hickman

email: msh@math.canterbury.ac.nz

smail: Department of Mathematics
       University of Canterbury
       Christchurch, NEW ZEALAND

----------------------------------------------------------------------
From: ajcd@lfcs.edinburgh.ac.uk (Angus Duggan)
Newsgroups: alt.sources
Subject: [REPOST] PostScript utilities
Keywords: signature order
Message-ID: <8673@skye.cs.ed.ac.uk>
Date: 10 Apr 91 10:40:29 GMT

[This is a repost of the (patched) source, because some people didn't get them
first time. Note the return address lfcs.edinburgh.ac.uk; it appears that
cs.edinburgh.ac.uk is getting confused with Czechoslovakia from some sites.
The address dcs.edinburgh.ac.uk might also work.]

People seem to have been asking for programs to perform page manipulation for
PostScript recently; here's my set of utilities for selecting and rearranging
pages from PostScript documents.

[Also, please note that they use a grotty trick to make the input file
seekable, which might not be portable to other Unixes or OS.]

a.

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  Makefile README epsffit.c psbook.1 psbook.c psnup
#   psselect.1 psselect.c pstops.1 pstops.c psutil.c psutil.h
# Wrapped by ajcd@bute on Wed Apr 10 11:33:10 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(643 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X# Makefile for PS utilities
X
XCFLAGS=-O
X
X# epsffit fits an epsf file to a given bounding box
X# psbook rearranges pages into signatures
X# psselect selects page ranges
X# pstops performs general page rearrangement and merging
X
Xall: psbook psselect pstops epsffit
X
Xepsffit: epsffit.c
X	$(CC) $(CFLAGS) -o epsffit epsffit.c
X
Xpsbook: psbook.o psutil.o
X	$(CC) -o psbook psutil.o psbook.o
X
Xpsselect: psselect.o psutil.o
X	$(CC) -o psselect psutil.o psselect.o
X
Xpstops: pstops.o psutil.o
X	$(CC) -o pstops psutil.o pstops.o
X
Xpsbook.c: psutil.h
X
Xpstops.c: psutil.h
X
Xpsutil.c: psutil.h
X
Xpsselect.c: psutil.h
X
Xclean:
X	rm -f *.o psbook psselect pstops epsffit
END_OF_Makefile
if test 643 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(1737 characters\)
sed "s/^X//" >README <<'END_OF_README'
XPostScript Utilities	        Angus Duggan		6 April 1991
X
XThis shar file contains some utilities for manipulating PostScript documents.
XPage selection and rearrangement are supported, including arrangement into
Xsignatures for booklet printing, and page merging for 2up/4up/8up/9up printing.
X
XFILES
X
XThe files contained are:
X
X-rw-r--r--  1 ajcd     cs_pg         643 Apr  6 10:45 Makefile
X-rw-r--r--  1 ajcd     cs_pg        1737 Apr  6 11:39 README
X-rw-r--r--  1 ajcd     cs_pg        3673 Jan 29 17:28 epsffit.c
X-rw-r--r--  1 ajcd     cs_pg        1066 Feb 12 13:18 psbook.1
X-rw-r--r--  1 ajcd     cs_pg        1990 Feb  7 18:54 psbook.c
X-rwxr-xr-x  1 ajcd     cs_pg        2121 Apr  6 12:00 psnup
X-rw-r--r--  1 ajcd     cs_pg        1509 Feb 12 13:18 psselect.1
X-rw-r--r--  1 ajcd     cs_pg        4621 Feb 12 12:34 psselect.c
X-rw-r--r--  1 ajcd     cs_pg        3227 Feb 20 10:16 pstops.1
X-rw-r--r--  1 ajcd     cs_pg        9272 Feb 20 14:06 pstops.c
X-rw-r--r--  1 ajcd     cs_pg        5201 Feb 12 12:38 psutil.c
X-rw-r--r--  1 ajcd     cs_pg         663 Feb  7 18:54 psutil.h
X
XPROGRAMS
X
Xpsbook          rearranges pages into signatures
Xpsselect        selects pages and page ranges
Xpstops          performs general page rearrangement and selection
Xpsnup           uses pstops to merge multiple pages per sheet
Xepsffit         fits an EPSF file to a given bounding box
X
Xpsselect in modeled after Chris Torek's dviselect program, and psbook is
Xmodeled after Tom Rokicki's dvidvi program. psbook is modeled on my own
Xdvibook program, which borrows heavily from Chris Torek's dviselect.
X
XBUGS
X
XThe utilities don't check for PS-Adobe-?.? conformance; they assume documents
Xconform.
X
XBug fixes and suggestions to ajcd@lfcs.edinburgh.ac.uk
END_OF_README
if test 1737 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f epsffit.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"epsffit.c\"
else
echo shar: Extracting \"epsffit.c\" \(3673 characters\)
sed "s/^X//" >epsffit.c <<'END_OF_epsffit.c'
X/* epsffit.c
X * AJCD 6 Dec 90
X * fit epsf file into constrained size
X * Usage:
X *       epsffit [-c] [-r] [-a] [-s] llx lly urx ury
X *               -c centres the image in the bounding box given
X *               -r rotates the image by 90 degrees anti-clockwise
X *               -a alters the aspect ratio to fit the bounding box
X *               -s adds a showpage at the end of the image
X */
X
X#include <stdio.h>
X#include <ctype.h>
X
X#define min(x,y) ((x) > (y) ? (y) : (x))
X#define max(x,y) ((x) > (y) ? (x) : (y))
X
Xstatic char *prog;
X
Xusage()
X{
X   fprintf(stderr, "Usage: %s [-c] [-r] [-a] [-s] llx lly urx ury\n", prog);
X   exit(1);
X}
X
Xmain(argc, argv)
X     int argc;
X     char **argv;
X{
X   int fit[4], i;
X   int bbfound = 0;              /* %%BoundingBox: found */
X   int urx, ury, llx, lly;
X   int furx, fury, fllx, flly, fwidth, fheight;
X   int showpage = 0, centre = 0, rotate = 0, aspect = 0;
X   char buf[BUFSIZ];
X
X   prog = *argv++; argc--;
X
X   while (argc > 0 && argv[0][0] == '-') {
X      switch (argv[0][1]) {
X      case 'c': centre = 1; break;
X      case 's': showpage = 1; break;
X      case 'r': rotate = 1; break;
X      case 'a': aspect = 1; break;
X      default:  usage();
X      }
X      argc--;
X      argv++;
X   }
X
X   if (argc != 4) usage();
X   fllx = atoi(argv[0]);
X   flly = atoi(argv[1]);
X   furx = atoi(argv[2]);
X   fury = atoi(argv[3]);
X   if (rotate) {
X      fwidth = fury - flly;
X      fheight = furx - fllx;
X   } else {
X      fwidth = furx - fllx;
X      fheight = fury - flly;
X   }
X
X   while (fgets(buf, BUFSIZ, stdin)) {
X      if (buf[0] == '%' && (buf[1] == '%' || buf[1] == '!')) {
X	 /* still in comment section */
X	 if (!strncmp(buf, "%%BoundingBox:", 14)) {
X	    if (sscanf(buf, "%%%%BoundingBox:%d %d %d %d\n",
X		       &llx, &lly, &urx, &ury) == 4)
X	       bbfound = 1;
X	 } else if (!strncmp(buf, "%%EndComments", 13)) {
X	    strcpy(buf, "\n"); /* don't repeat %%EndComments */
X	    break;
X	 } else fputs(buf,stdout);
X      } else break;
X   }
X   if (bbfound) { /* put BB, followed by scale&translate */
X      double width = urx-llx, height = ury-lly;
X      double xscale = fwidth/width, yscale = fheight/height;
X      double xoffset = fllx, yoffset = flly;
X      if (!aspect) {       /* preserve aspect ratio ? */
X	 xscale = yscale = min(xscale,yscale);
X      }
X      width *= xscale;     /* actual width and height after scaling */
X      height *= yscale;
X      if (centre) {
X	 if (rotate) {
X	    xoffset += (fheight - height)/2;
X	    yoffset += (fwidth - width)/2;
X	 } else {
X	    xoffset += (fwidth - width)/2;
X	    yoffset += (fheight - height)/2;
X	 }
X      }
X      printf("%%%%BoundingBox: %d %d %d %d\n", (int)xoffset, (int)yoffset,
X	     (int)(xoffset+(rotate ? height : width)),
X	     (int)(yoffset+(rotate ? width : height)));
X      if (rotate) {  /* compensate for original image shift */
X	 xoffset += height + lly * yscale;  /* displacement for rotation */
X	 yoffset -= llx * xscale;
X      } else {
X	 xoffset -= llx * xscale;
X	 yoffset -= lly * yscale;
X      }
X      puts("%%EndComments");
X      if (showpage)
X	 puts("save /showpage{}def /copypage{}def /erasepage{}def");
X      else
X	 puts("%%BeginProcSet: epsffit 1 0");
X      puts("gsave");
X      printf("%.3lf %.3lf translate\n", xoffset, yoffset);
X      if (rotate)
X	 puts("90 rotate");
X      printf("%.3lf %.3lf scale\n", xscale, yscale);
X      if (!showpage)
X	 puts("%%EndProcSet");
X   }
X   do {
X      fputs(buf,stdout);
X   } while (fgets(buf, BUFSIZ, stdin));
X   if (bbfound) {
X      puts("grestore");
X      if (showpage)
X	 puts("restore showpage"); /* just in case */
X   } else {
X      fprintf(stderr, "%s: no %%%%BoundingBox:\n", prog);
X      exit(1);
X   }
X   exit(0);
X}
END_OF_epsffit.c
if test 3673 -ne `wc -c <epsffit.c`; then
    echo shar: \"epsffit.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f psbook.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"psbook.1\"
else
echo shar: Extracting \"psbook.1\" \(1066 characters\)
sed "s/^X//" >psbook.1 <<'END_OF_psbook.1'
X.TH PSBOOK 1
X.SH NAME
Xpsbook \- rearrange pages in PostScript file into signatures
X.SH SYNOPSIS
X.B psbook
X[
X.B \-q
X] [
X.B \-s\fIsignature\fR
X] [
X.I infile
X[
X.I outfile
X] ]
X.SH DESCRIPTION
X.I Psbook
Xrearranges pages from a PostScript document into ``signatures'' for
Xprinting books or booklets, creating a new PostScript file. The
Xinput PostScript file should follow the Adobe Document Structuring
XConventions.
X.PP
XThe
X.I \-s
Xoption selects the size of signature which will be used. The signature size is
Xthe number of sides which will be folded and bound together; the number given
Xshould be a multiple of four. The default is to use one signature for the
Xwhole file. Extra blank sides will be added if the file does not contain a
Xmultiple of four pages.
X.PP
XPsbook normally prints the page numbers of the pages rearranged; the
X.I \-q
Xoption suppresses this.
X.SH AUTHOR
XAngus Duggan
X.SH "SEE ALSO"
Xpsselect(1), pstops(1)
X.SH TRADEMARKS
X.B PostScript
Xis a trademark of Adobe Systems Incorporated.
X.SH BUGS
X.I Psbook
Xcannot cope with documents longer than 5000 pages.
END_OF_psbook.1
if test 1066 -ne `wc -c <psbook.1`; then
    echo shar: \"psbook.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f psbook.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"psbook.c\"
else
echo shar: Extracting \"psbook.c\" \(1990 characters\)
sed "s/^X//" >psbook.c <<'END_OF_psbook.c'
X/* psbook.c
X * AJCD 27/1/91
X * rearrange pages in conforming PS file for printing in signatures
X *
X * Usage:
X *       psbook [-q] [-s<signature>] [infile [outfile]]
X */
X
X#include "psutil.h"
X
Xvoid usage()
X{
X   fprintf(stderr, "Usage: %s [-q] [-s<signature>] [infile [outfile]]\n",
X	   prog);
X   fprintf(stderr, "       <signature> must be positive and divisible by 4\n");
X   fflush(stderr);
X   exit(1);
X}
X
X
Xmain(argc, argv)
X     int argc;
X     char *argv[];
X{
X   int signature = 0;
X   int currentpg, maxpage;
X
X   infile = stdin;
X   outfile = stdout;
X   verbose = 1;
X   for (prog = *argv++; --argc; argv++) {
X      if (argv[0][0] == '-') {
X	 switch (argv[0][1]) {
X	 case 's':
X	    signature = atoi(*argv+2);
X	    if (signature < 1 || signature % 4) usage();
X	    break;
X	 case 'q':
X	    verbose = 0;
X	    break;
X	 default:
X	    usage();
X	 }
X      } else if (infile == stdin) {
X	 if ((infile = fopen(*argv, "r")) == NULL) {
X	    fprintf(stderr, "%s: can't open input file %s\n", prog, *argv);
X	    fflush(stderr);
X	    exit(1);
X	 }
X      } else if (outfile == stdout) {
X	 if ((outfile = fopen(*argv, "w")) == NULL) {
X	    fprintf(stderr, "%s: can't open output file %s\n", prog, *argv);
X	    fflush(stderr);
X	    exit(1);
X	 }
X      } else usage();
X   }
X   if ((infile=seekable(infile))==NULL) {
X      fprintf(stderr, "%s: can't seek input\n", prog);
X      fflush(stderr);
X      exit(1);
X   }
X   scanpages();
X
X   maxpage = pages+(4-pages%4)%4;
X
X   if (!signature)
X      signature = maxpage;
X
X   /* rearrange pages */
X   writeheader(maxpage);
X   writeprolog();
X   for (currentpg = 0; currentpg < maxpage; currentpg++) {
X      int actualpg = currentpg - currentpg%signature;
X      switch(currentpg%4) {
X      case 0:
X      case 3:
X	 actualpg += signature-1-(currentpg%signature)/2;
X	 break;
X      case 1:
X      case 2:
X	 actualpg += (currentpg%signature)/2;
X	 break;
X      }
X      if (actualpg < pages)
X	 writepage(actualpg);
X      else
X	 writeemptypage();
X   }
X   writetrailer();
X
X   exit(0);
X}
END_OF_psbook.c
if test 1990 -ne `wc -c <psbook.c`; then
    echo shar: \"psbook.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f psnup -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"psnup\"
else
echo shar: Extracting \"psnup\" \(2121 characters\)
sed "s/^X//" >psnup <<'END_OF_psnup'
X#!/bin/sh
X# psnup: put multiple pages onto one physical sheet of paper.
X# usage:
X#       psnup [-w<dim>] [-h<dim>] [-l] [-2|-4|-8|-9] [file...]
X#               -w<dim> sets the paper width
X#               -h<dim> sets the paper height
X#               -l      is used if the pages are in landscape orientation
X
Xio= landscape=0 nup=1 width=-w21cm height=-h29.7cm
X
Xwhile test $# != 0
Xdo      case "$1" in
X        -w*)    width=$1 ;;
X        -h*)    height=$1 ;;
X        -l)     landscape=1 ;;
X        -2)     nup=2 ;;
X        -4)     nup=4 ;;
X        -8)     nup=8 ;;
X        -9)     nup=9 ;;
X        *)      io="$io $1"
X        esac
X        shift
Xdone
X
Xscale= offset=
Xcase "$nup" in
X2)      scale=@0.707
X        if [ $landscape = 0 ]
X        then offset="(1w,0) (1w,0.5h)"
X        else offset="(0,0.5h) (0,0)"
X        fi
X        landscape=`expr 1 - $landscape` ;;
X4)      scale=@0.5
X        if [ $landscape = 0 ]
X        then offset="(0,0.5h) (0.5w,0.5h) (0,0) (0.5w,0)"
X        else offset="(0.5w,0) (0.5w,0.5h) (1w,0) (1w,0.5h)"
X        fi ;;
X8)      scale=@0.3536
X        if [ $landscape = 0 ]
X        then offset="(0.5w,0) (0.5w,0.25h) (0.5w,0.5h) (0.5w,0.75h)\
X                     (1w,0) (1w,0.25h) (1w,0.5h) (1w,0.75h)"
X        else offset="(0,0.75h) (0.5w,0.75h) (0,0.5h) (0.5w,0.5h)\
X                     (0,0.25h) (0.5w,0.25h) (0,0.25h) (0.5w,0.25h)"
X        fi
X        landscape=`expr 1 - $landscape` ;;
X9)      scale=@0.3333
X        if [ $landscape = 0 ]
X        then offset="(0,0.666h) (0.333w,0.666h) (0.666w,0.666h)\
X                     (0,0.333h) (0.333w,0.333h) (0.666w,0.333h)\
X                     (0,0) (0.333w,0) (0.666w,0)"
X        else offset="(0.333w,0) (0.333w,0.333h) (0.333w,0.666h)\
X                     (0.666w,0) (0.666w,0.333h) (0.666w,0.666h)\
X                     (1w,0) (1w,0.333h) (1w,0.666h)"
X        fi ;;
Xesac
X
Xif [ $landscape = 0 ]
Xthen rotate=
Xelse rotate=L
Xfi
X
Xoptions= sep= page=0
X
Xset -- ${offset:-""}
Xwhile [ $page -lt $nup ]
Xdo      options="$options${options:++}$page$rotate$scale$1"
X        page=`expr $page + 1`
X        shift
Xdone
X
Xpstops $width $height "$nup:$options" $io
END_OF_psnup
if test 2121 -ne `wc -c <psnup`; then
    echo shar: \"psnup\" unpacked with wrong size!
fi
chmod +x psnup
# end of overwriting check
fi
if test -f psselect.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"psselect.1\"
else
echo shar: Extracting \"psselect.1\" \(1509 characters\)
sed "s/^X//" >psselect.1 <<'END_OF_psselect.1'
X.TH PSSELECT 1
X.SH NAME
Xpsselect \- select pages from a PostScript file
X.SH SYNOPSIS
X.B psselect
X[
X.B \-q
X] [
X.B \-e
X] [
X.B \-o
X] [
X.B \-r
X] [
X.B \-p\fIpages\fR
X] [
X.I infile
X[
X.I outfile
X] ]
X.SH DESCRIPTION
X.I Psselect
Xselects pages from a PostScript document, creating a new PostScript file. The
Xinput PostScript file should follow the Adobe Document Structuring
XConventions.
X.PP
XThe 
X.I \-e
Xoption selects all of the even pages; it may be used in conjunction with the
Xother page selection options.
X.PP
XThe 
X.I \-o
Xoption selects all of the odd pages; it may be used in conjunction with the
Xother page selection options.
X.PP
XThe 
X.I \-p\fIpages\fR
Xoption specifies the pages which are to be selected.
X.I Pages
Xis a comma separated list of page ranges, each of which may be a page number,
Xor a page range of the form \fIfirst\fR-\fIlast\fR. If \fIfirst\fR is omitted,
Xthe
Xfirst page is assumed, and if \fIlast\fR is omitted, the last page is assumed.
X.PP
XThe 
X.I \-r
Xoption causes
X.I psselect
Xto output the selected pages in reverse order.
X.PP
XPsselect normally prints the page numbers of the pages rearranged; the
X.I \-q
Xoption suppresses this.
X.SH NOTES
X.I Psselect
Xselects pages in the order that they appear in the file, starting from one. The
Xactual page number in the document may be different.
X.SH AUTHOR
XAngus Duggan
X.SH "SEE ALSO"
Xpsbook(1), pstops(1)
X.SH TRADEMARKS
X.B PostScript
Xis a trademark of Adobe Systems Incorporated.
X.SH BUGS
X.I Psselect
Xcannot cope with documents longer than 5000 pages.
END_OF_psselect.1
if test 1509 -ne `wc -c <psselect.1`; then
    echo shar: \"psselect.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f psselect.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"psselect.c\"
else
echo shar: Extracting \"psselect.c\" \(4621 characters\)
sed "s/^X//" >psselect.c <<'END_OF_psselect.c'
X/* psselect.c
X * AJCD 27/1/91
X * rearrange pages in conforming PS file for printing in signatures
X *
X * Usage:
X *       psselect [-q] [-e] [-o] [-r] [-p<pages>] [infile [outfile]]
X */
X
X#include "psutil.h"
X
Xvoid usage()
X{
X   fprintf(stderr,
X	   "Usage: %s [-q] [-e] [-o] [-r] [-p<pages>] [infile [outfile]]\n",
X	   prog);
X   fflush(stderr);
X   exit(1);
X}
X
Xstruct pgrange {
X   int first, last;
X   struct pgrange *next;
X};
X
Xtypedef struct pgrange range;
X
Xrange * makerange(beg, end, next)
X     int beg, end;
X     range *next;
X{
X   range *new;
X   if ((new = (range *)malloc(sizeof(range))) == NULL) {
X      fprintf(stderr, "%s: out of memory\n", prog);
X      fflush(stderr);
X      exit(1);
X   }
X   new->first = beg;
X   new->last = end;
X   new->next = next;
X   return (new);
X}
X
Xrange * mergerange(beg, end, curr)
X     int beg, end;
X     range *curr;
X{
X   if (curr) {
X      range *this, *prev;
X      for (this=prev=curr; this; prev=this, this=this->next) {
X	 int lo = (beg < curr->first) ? -1 : (beg > curr->last) ? 1 : 0;
X	 int hi = (end < curr->first) ? -1 : (end > curr->last) ? 1 : 0;
X	 if (hi < 0)
X	    return (makerange(beg, end, curr));
X	 else if (lo <= 0) { /* beginning of range */
X	    if (lo < 0)
X	       this->first = beg;
X	    if (hi > 0) {
X	       while (this->next && this->next->first <= end) {
X		  range *eaten = this->next;
X		  this->next = eaten->next;
X		  if (eaten->last > end)
X		     end = eaten->last;
X		  free(eaten);
X	       }
X	       this->last = end;
X	    }  /* else range included; no change */
X	    return (curr);
X	 }
X      }
X      prev->next = makerange(beg, end, NULL);
X      return (curr);
X   } else return (makerange(beg, end, NULL));
X}
X
X
Xrange * addrange(str, rp)
X     char *str;
X     range *rp;
X{
X   int first=0;
X   if (isdigit(*str)) {
X      first = atoi(str);
X      while (isdigit(*str)) str++;
X   }
X   switch (*str) {
X   case '\0':
X      if (first)
X	 return (mergerange(first, first, rp));
X      break;
X   case ',':
X      if (first)
X	 return (addrange(str+1, mergerange(first, first, rp)));
X      break;
X   case '-':
X   case ':':
X      str++;
X      if (isdigit(*str)) {
X	 int last = atoi(str);
X	 while (isdigit(*str)) str++;
X	 if (!first)
X	    first = 1;
X	 if (last >= first) 
X	    switch (*str) {
X	    case '\0':
X	       return (mergerange(first, last, rp));
X	    case ',':
X	       return (addrange(str+1, mergerange(first, last, rp)));
X	    }
X      } else if (*str == '\0')
X	 return (mergerange(first, MAXPAGES, rp));
X   }
X   fprintf(stderr, "%s: invalid page range\n", prog);
X   fflush(stderr);
X   exit(1);
X}
X
X
Xint selectpage(page, even, odd, rp)
X     int page, even, odd;
X     range *rp;
X{
X   if (page&1) {
X      if (odd) return (1);
X   } else {
X      if (even) return (1);
X   }
X   while (rp) {
X      if (page >= rp->first) {
X	 if (page <= rp->last)
X	    return (1);
X      } else return (0);
X      rp = rp->next;
X   }
X   return (0);
X}
X
X
Xmain(argc, argv)
X     int argc;
X     char *argv[];
X{
X   int currentpg, maxpage = 0;
X   int even = 0, odd = 0, all = 1, reverse = 0;
X   range *pagerange = NULL;
X
X   infile = stdin;
X   outfile = stdout;
X   verbose = 1;
X   for (prog = *argv++; --argc; argv++) {
X      if (argv[0][0] == '-') {
X	 switch (argv[0][1]) {
X	 case 'e':
X	    even = 1; all = 0;
X	    break;
X	 case 'o':
X	    odd = 1; all = 0; 
X	    break;
X	 case 'r':
X	    reverse = 1;
X	    break;
X	 case 'p':
X	    pagerange = addrange(*argv+2, pagerange); all = 0;
X	    break;
X	 case 'q':
X	    verbose = 0;
X	    break;
X	 default:
X	    usage();
X	 }
X      } else if (infile == stdin) {
X	 if ((infile = fopen(*argv, "r")) == NULL) {
X	    fprintf(stderr, "%s: can't open input file %s\n", prog, *argv);
X	    fflush(stderr);
X	    exit(1);
X	 }
X      } else if (outfile == stdout) {
X	 if ((outfile = fopen(*argv, "w")) == NULL) {
X	    fprintf(stderr, "%s: can't open output file %s\n", prog, *argv);
X	    fflush(stderr);
X	    exit(1);
X	 }
X      } else usage();
X   }
X   if ((infile=seekable(infile))==NULL) {
X      fprintf(stderr, "%s: can't seek input\n", prog);
X      fflush(stderr);
X      exit(1);
X   }
X   scanpages();
X
X   for (currentpg = 1; currentpg <= pages; currentpg++)
X      if (selectpage(currentpg, even || all, odd || all, pagerange))
X	 maxpage++;
X
X   /* select pages */
X   writeheader(maxpage);
X   writeprolog();
X   if (reverse) {
X      for (currentpg = pages; currentpg > 0; currentpg--)
X	 if (selectpage(currentpg, even || all, odd || all, pagerange))
X	    writepage(currentpg-1);
X   } else {
X      for (currentpg = 1; currentpg <= pages; currentpg++)
X	 if (selectpage(currentpg, even || all, odd || all, pagerange))
X	    writepage(currentpg-1);
X   }
X   writetrailer();
X
X   exit(0);
X}
END_OF_psselect.c
if test 4621 -ne `wc -c <psselect.c`; then
    echo shar: \"psselect.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f pstops.1 -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"pstops.1\"
else
echo shar: Extracting \"pstops.1\" \(3227 characters\)
sed "s/^X//" >pstops.1 <<'END_OF_pstops.1'
X.TH PSTOPS 1
X.SH NAME
Xpstops \- select pages from a PostScript file
X.SH SYNOPSIS
X.B pstops
X[
X.B \-q
X]
X[
X.B \-b
X]
X[
X.B \-w\fIwidth\fR
X]
X[
X.B \-h\fIheight\fR
X]
X.I pagespecs
X[
X.I infile
X[
X.I outfile
X] ]
X.SH DESCRIPTION
X.I Pstops
Xrearranges pages from a PostScript document, creating a new PostScript file.
XThe input PostScript file should follow the Adobe Document Structuring
XConventions.
X.I Pstops
Xcan be used to perform a large number of arbitrary re-arrangements of
XDocuments, including arranging for printing 2-up, 4-up, booklets, reversing,
Xselecting front or back sides of documents, scaling, etc.
X.PP
X.I pagespecs
Xfollow the syntax:
X.RS
X.TP 12
X.I pagespecs
X.I = [modulo:]specs
X.TP
X.I specs
X.I = spec[+specs][,specs]
X.TP
X.I spec
X.I = [-]pageno[@scale][L][R][U][(xoff,yoff)]
X.RE
X.sp
X.I modulo
Xis the number of pages in each block. The value of
X.I modulo
Xshould be greater than 0; the default value is 1.
X.I specs
Xare the page specifications for the pages in each block. The value of the
X.I pageno
Xin each
X.I spec
Xshould be between 0 (for the first page in the block) and \fImodulo\fR-1
X(for the last page in each block) inclusive.
XThe optional dimensions
X.I xoff
Xand
X.I yoff
Xshift the page by the specified (positive) amount.
X.I xoff
Xand
X.I yoff
Xare in PostScript's points, but may be followed by the units
X.B "cm"
Xor
X.B "in"
Xto convert to centimetres or inches, or the flag
X.B "w"
Xor
X.B "h"
Xto specify as a multiple of the width or height.
XThe optional parameters \fIL\fR, \fIR\fR, and \fIU\fR rotate the page left,
Xright, or upside-down.
XThe optional
X.I scale
Xparameter scales the page by the fraction specified.
XIf the optional minus sign is specified, the page is relative to the end of
Xthe document, instead of the start.
X
XIf page \fIspec\fRs are separated by
X.B \+
Xthe pages will be merged into one page; if they are separated by
X.B \,
Xthey will be on separate pages.
XIf there is only one page specification, with
X.I pageno
Xzero, the \fIpageno\fR may be omitted.
X.PP
XThe
X.I \-w
Xoption gives the width which is used by the
X.B "w"
Xdimension specifier, and the
X.I \-h
Xoption gives the height which is used by the
X.B "h"
Xdimension specifier. These dimensions are also used (after scaling) to set the
Xclipping path for each page.
X.PP
XThe
X.I \-b
Xoption prevents any
X.B bind
Xoperators in the PostScript prolog from binding. This may be needed in cases
Xwhere complex multi-page re-arrangements are being done.
X.PP
XPstops normally prints the page numbers of the pages re-arranged; the
X.I \-q
Xoption suppresses this.
X.SH EXAMPLES
XThis section contains some sample re-arrangements. To put two pages on one
Xsheet (of A4 paper), the pagespec to use is:
X.sp
X.ce
X2:0L@0.7(21cm,0)+1L@0.7(21cm,14.85cm)
X.sp
XTo select all of the odd pages in reverse order, use:
X.sp
X.ce
X2:-0
X.sp
XTo re-arrange pages for printing 2-up booklets, use
X.sp
X.ce
X4:-3L@0.7(21cm,0)+0L@0.7(21cm,14.85cm)
X.sp
Xfor the front sides, and
X.sp
X.ce
X4:1L@0.7(21cm,0)+-2L@0.7(21cm,14.85cm)
X.sp
Xfor the reverse sides (or join them with a comma for duplex printing).
X.SH AUTHOR
XAngus Duggan
X.SH "SEE ALSO"
Xpsbook(1), psselect(1)
X.SH TRADEMARKS
X.B PostScript
Xis a trademark of Adobe Systems Incorporated.
X.SH BUGS
X.I Pstops
Xcannot cope with documents longer than 5000 pages.
END_OF_pstops.1
if test 3227 -ne `wc -c <pstops.1`; then
    echo shar: \"pstops.1\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f pstops.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"pstops.c\"
else
echo shar: Extracting \"pstops.c\" \(9273 characters\)
sed "s/^X//" >pstops.c <<'END_OF_pstops.c'
X/* pstops.c
X * AJCD 27/1/91
X * rearrange pages in conforming PS file for printing in signatures
X *
X * Usage:
X *       pstops [-q] [-b] [-w<dim>] [-h<dim>] <pagespecs> [infile [outfile]]
X */
X
X#include "psutil.h"
X
Xvoid usage()
X{
X   fprintf(stderr, "Usage: %s [-q] [-b] [-w<dim>] [-h<dim] <pagespecs> [infile [outfile]]\n",
X	   prog);
X   fflush(stderr);
X   exit(1);
X}
X
Xvoid specusage()
X{
X   fprintf(stderr, "%s: page specification error:\n", prog);
X   fprintf(stderr, "  <pagespecs> = [modulo:]<spec>\n");
X   fprintf(stderr, "  <spec>      = [-]pageno[@scale][L|R|U][(xoff,yoff)][,spec|+spec]\n");
X   fprintf(stderr, "                modulo>=1, 0<=pageno<modulo\n");
X   fflush(stderr);
X   exit(1);
X}
X
Xstatic int modulo = 1;
Xstatic int pagesperspec = 1;
Xstatic double width = -1.0;
Xstatic double height = -1.0;
X
X/* pagespec flags */
X#define ADD_NEXT (0x01)
X#define ROTATE   (0x02)
X#define SCALE    (0x04)
X#define OFFSET   (0x08)
X#define GSAVE    (ROTATE|SCALE|OFFSET)
X
Xstruct pagespec {
X   int reversed, pageno, flags, rotate;
X   double xoff, yoff, scale;
X   struct pagespec *next;
X};
X
Xstruct pagespec *newspec()
X{
X   struct pagespec *temp = (struct pagespec *)malloc(sizeof(struct pagespec));
X   temp->reversed = temp->pageno = temp->flags = temp->rotate = 0;
X   temp->scale = 1.0;
X   temp->xoff = temp->yoff = 0.0;
X   temp->next = NULL;
X   return (temp);
X}
X
Xint parseint(sp)
X     char **sp;
X{
X   char *s;
X   int n = 0;
X
X   for (s = *sp; isdigit(*s); s++)
X      n = n*10 + (*s-'0');
X   if (*sp == s) specusage();
X   *sp = s;
X   return (n);
X}
X
Xdouble parsedouble(sp)
X     char **sp;
X{
X   int n = parseint(sp);
X   char *s = *sp;
X   int d = 0, frac = 1;
X
X   if (*s == '.') {
X      *sp = ++s;
X      for (; isdigit(*s); s++) {
X	 d = d*10 + (*s-'0');
X	 frac *= 10;
X      }
X      if (*sp == s) specusage();
X   }
X   *sp = s;
X   return ((double)n+(double)d/frac);
X}
X
Xdouble parsedimen(sp)
X     char **sp;
X{
X   double num = parsedouble(sp);
X   char *s = *sp;
X
X   if (strncmp(s, "pt", 2) == 0) {
X      s += 2;
X   } else if (strncmp(s, "in", 2) == 0) {
X      num *= 72.0;
X      s += 2;
X   } else if (strncmp(s, "cm", 2) == 0) {
X      num *= 28.346456692913385211;
X      s += 2;
X   } else if (*s == 'w') {
X      if (width < 0.0) {
X	 fprintf(stderr, "%s: width not initialised\n", prog);
X	 fflush(stderr);
X	 exit(1);
X      }
X      num *= width;
X      s++;
X   } else if (*s == 'h') {
X      if (height < 0.0) {
X	 fprintf(stderr, "%s: height not initialised\n", prog);
X	 fflush(stderr);
X	 exit(1);
X      }
X      num *= height;
X      s++;
X   }
X   *sp = s;
X   return (num);
X}
X
Xstruct pagespec *parsespecs(str)
X     char *str;
X{
X   char *t;
X   struct pagespec *head, *tail;
X   int other = 0;
X   int num = -1;
X
X   head = tail = newspec();
X   while (*str) {
X      if (isdigit(*str)) {
X	 num = parseint(&str);
X      } else {
X	 switch (*str++) {
X	 case ':':
X	    if (other || head != tail || num < 1) specusage();
X	    modulo = num;
X	    num = -1;
X	    break;
X	 case '-':
X	    tail->reversed = !tail->reversed;
X	    break;
X	 case '@':
X	    if (num < 0) specusage();
X	    tail->scale *= parsedouble(&str);
X	    tail->flags |= SCALE;
X	    break;
X	 case 'l': case 'L':
X	    tail->rotate += 90;
X	    tail->flags |= ROTATE;
X	    break;
X	 case 'r': case 'R':
X	    tail->rotate -= 90;
X	    tail->flags |= ROTATE;
X	    break;
X	 case 'u': case 'U':
X	    tail->rotate += 180;
X	    tail->flags |= ROTATE;
X	    break;
X	 case '(':
X	    tail->xoff += parsedimen(&str);
X	    if (*str++ != ',') specusage();
X	    tail->yoff += parsedimen(&str);
X	    if (*str++ != ')') specusage();
X	    tail->flags |= OFFSET;
X	    break;
X	 case '+':
X	    tail->flags |= ADD_NEXT;
X	 case ',':
X	    if (num < 0 || num >= modulo) specusage();
X	    if ((tail->flags & ADD_NEXT) == 0)
X	       pagesperspec++;
X	    tail->pageno = num;
X	    tail->next = newspec();
X	    tail = tail->next;
X	    num = -1;
X	    break;
X	 default:
X	    specusage();
X	 }
X	 other = 1;
X      }
X   }
X   if (num >= modulo)
X      specusage();
X   else if (num >= 0)
X      tail->pageno = num;
X   return (head);
X}
X
Xdouble singledimen(str)
X     char *str;
X{
X   double num = parsedimen(&str);
X   if (*str) usage();
X   return (num);
X}
X
X
Xmain(argc, argv)
X     int argc;
X     char *argv[];
X{
X   int thispg, maxpage;
X   int pageindex = 0;
X   struct pagespec *specs = NULL;
X   int nobinding = 0;
X
X   infile = stdin;
X   outfile = stdout;
X   verbose = 1;
X   for (prog = *argv++; --argc; argv++) {
X      if (argv[0][0] == '-') {
X	 switch (argv[0][1]) {
X	 case 'q':
X	    verbose = 0;
X	    break;
X	 case 'b':
X	    nobinding = 1;
X	    break;
X	 case 'w':
X	    width = singledimen(*argv+2);
X	    break;
X	 case 'h':
X	    height = singledimen(*argv+2);
X	    break;
X	 default:
X	    if (specs == NULL)
X	       specs = parsespecs(*argv);
X	    else
X	       usage();
X	 }
X      } else if (specs == NULL)
X	 specs = parsespecs(*argv);
X      else if (infile == stdin) {
X	 if ((infile = fopen(*argv, "r")) == NULL) {
X	    fprintf(stderr, "%s: can't open input file %s\n", prog, *argv);
X	    fflush(stderr);
X	    exit(1);
X	 }
X      } else if (outfile == stdout) {
X	 if ((outfile = fopen(*argv, "w")) == NULL) {
X	    fprintf(stderr, "%s: can't open output file %s\n", prog, *argv);
X	    fflush(stderr);
X	    exit(1);
X	 }
X      } else usage();
X   }
X   if (specs == NULL)
X      usage();
X   if ((infile=seekable(infile))==NULL) {
X      fprintf(stderr, "%s: can't seek input\n", prog);
X      fflush(stderr);
X      exit(1);
X   }
X   scanpages();
X
X   maxpage = ((pages+modulo-1)/modulo)*modulo;
X
X   /* rearrange pages: doesn't cope properly with:
X    * initmatrix, initgraphics, defaultmatrix, grestoreall, initclip */
X   writeheader((maxpage/modulo)*pagesperspec);
X   writestring("%%BeginProcSet: pstops 1 0\n");
X   writestring("[/showpage/erasepage/copypage]{dup where{pop dup load\n");
X   writestring(" type/operatortype eq{1 array cvx dup 0 3 index cvx put\n");
X   writestring(" bind def}{pop}ifelse}{pop}ifelse}forall\n");
X   writestring("[/letter/legal/executivepage/a4/a4small/b5/com10envelope\n");
X   writestring(" /monarchenvelope/c5envelope/dlenvelope/lettersmall/note\n");
X   writestring(" /folio/quarto/a5]{dup where{exch{}put}{pop}ifelse}forall\n");
X   writestring("/lcvx{dup load dup type dup/operatortype eq{pop exch pop}\n");
X   writestring(" {/arraytype eq{dup xcheck{exch pop aload pop}\n");
X   writestring(" {pop cvx}ifelse}{pop cvx}ifelse}ifelse}bind def\n");
X   writestring("/pstopsmatrix matrix currentmatrix def\n");
X   writestring("/defaultmatrix{pstopsmatrix exch copy}bind def\n");
X   writestring("/initmatrix{matrix defaultmatrix setmatrix}bind def\n");
X   writestring("/pathtoproc{[{currentpoint}stopped{$error/newerror false\n");
X   writestring(" put{newpath}}{/newpath cvx 3 1 roll/moveto cvx 4 array\n");
X   writestring(" astore cvx}ifelse]{[/newpath cvx{/moveto cvx}{/lineto cvx}\n");
X   writestring(" {/curveto cvx}{/closepath cvx}pathforall]cvx exch pop}\n");
X   writestring(" stopped{$error/errorname get/invalidaccess eq{cleartomark\n");
X   writestring(" $error/newerror false put cvx exec}{stop}ifelse}if}def\n");
X   if (width > 0.0 && height > 0.0) {
X      char buffer[BUFSIZ];
X      writestring("/initclip[/pathtoproc lcvx/matrix lcvx/currentmatrix lcvx");
X      writestring("/initmatrix lcvx/initclip lcvx /newpath lcvx\n");
X      writestring(" 0 0 /moveto lcvx\n");
X      sprintf(buffer,
X	      " %lf 0/rlineto lcvx 0 %lf/rlineto lcvx -%lf 0/rlineto lcvx\n",
X	      width, height, width);
X      writestring(buffer);
X      writestring(" /clip lcvx /newpath lcvx /setmatrix lcvx /exec lcvx]\n");
X      writestring(" cvx def\n");
X   }
X   writestring("/initgraphics{initmatrix newpath initclip 1 setlinewidth\n");
X   writestring(" 0 setlinecap 0 setlinejoin []0 setdash 0 setgray\n");
X   writestring(" 10 setmiterlimit}bind def\n");
X   if (nobinding) /* desperation measures */
X      writestring("/bind{}def\n");
X   writestring("%%EndProcSet\n");
X   writeprolog();
X   for (thispg = 0; thispg < maxpage; thispg += modulo) {
X      int ppp, add_last = 0;
X      struct pagespec *ps;
X      for (ppp = 0, ps = specs; ps != NULL; ppp++, ps = ps->next) {
X	 int actualpg;
X	 int add_next = ((ps->flags & ADD_NEXT) != 0);
X	 if (ps->reversed)
X	    actualpg = maxpage-thispg-modulo+ps->pageno;
X	 else
X	    actualpg = thispg+ps->pageno;
X	 if (actualpg < pages)
X	    seekpage(actualpg);
X	 if (!add_last) {
X	    writepageheader("pstops", ++pageindex);
X	 }
X	 writestring("gsave\n");
X	 if (ps->flags & GSAVE) {
X	    char buffer[BUFSIZ];
X	    if (ps->flags & OFFSET) {
X	       sprintf(buffer, "%lf %lf translate\n", ps->xoff, ps->yoff);
X	       writestring(buffer);
X	    }
X	    if (ps->flags & ROTATE) {
X	       sprintf(buffer, "%d rotate\n", ps->rotate);
X	       writestring(buffer);
X	    }
X	    if (ps->flags & SCALE) {
X	       sprintf(buffer, "%lf dup scale\n", ps->scale);
X	       writestring(buffer);
X	    }
X	    writestring("/pstopsmatrix matrix currentmatrix def\n");
X	 }
X	 if (width > 0.0 && height > 0.0) {
X	    writestring("initclip\n");
X	 }
X	 writestring("/pstopssaved save def\n");
X	 if (add_next) {
X	    writestring("/showpage{}def/copypage{}def/erasepage{}def\n");
X	 }
X	 if (actualpg < pages)
X	    writepagebody();
X	 else
X	    writestring("showpage\n");
X	 writestring("pstopssaved restore grestore\n");
X	 add_last = add_next;
X      }
X   }
X   writetrailer();
X
X   exit(0);
X}
END_OF_pstops.c
if test 9273 -ne `wc -c <pstops.c`; then
    echo shar: \"pstops.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f psutil.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"psutil.c\"
else
echo shar: Extracting \"psutil.c\" \(5201 characters\)
sed "s/^X//" >psutil.c <<'END_OF_psutil.c'
X/* psutil.c
X * AJCD 29/1/91
X * utilities for PS programs
X */
X
X#define LOCAL
X#include "psutil.h"
X
X#include <fcntl.h>
X#include <string.h>
X
Xstatic char buffer[BUFSIZ];
Xstatic long bytes = 0;
Xstatic long pagescmt = 0;
Xstatic long headerlen = 0;
Xstatic int outputpage = 0;
Xstatic char pagelabel[BUFSIZ];
Xstatic int pageno;
Xstatic long pagelength;
X
X/* make a file seekable; trick stolen from Chris Torek's libdvi */
X
XFILE *seekable(fp)
X     FILE *fp;
X{
X   int fd, tf, n, w;
X   char *tmpdir, *p;
X
X   fd = fileno(fp);
X   if (lseek(fd, 0L, 1) >= 0 && !isatty(fd))
X      return (fp);
X
X   if ((tmpdir = getenv("TMPDIR")) == NULL)
X      tmpdir = TMPDIR;
X   (void) sprintf(buffer, "%s/#%d", tmpdir, getpid());
X   if ((tf = open(buffer, O_RDWR | O_CREAT | O_EXCL, 0666)) == -1)
X      return (NULL);
X   (void) unlink(buffer);
X
X   while ((n = read(fd, p = buffer, BUFSIZ)) > 0) {
X      do {
X	 if ((w = write(tf, p, n)) < 0) {
X	    (void) close(tf);
X	    (void) fclose(fp);
X	    return (NULL);
X	 }
X	 p += w;
X      } while ((n -= w) > 0);
X   }
X   if (n < 0) {
X      (void) close(tf);
X      (void) fclose(fp);
X      return (NULL);
X   }
X
X   /* discard the input file, and rewind and open the temporary */
X   (void) fclose(fp);
X   (void) lseek(tf, 0L, 0);
X   if ((fp = fdopen(tf, "r")) == NULL) {
X      (void) close(tf);
X   }
X   return (fp);
X}
X
X
Xint fcopy(len)
X     long len;
X{
X   while (len) {
X      int n = (len > BUFSIZ) ? BUFSIZ : len;
X      if (!(fread(buffer, sizeof(char), n, infile) &&
X	    fwrite(buffer, sizeof(char), n, outfile)))
X	 return (0);
X      len -= n;
X      bytes += n;
X   }
X   return (1);
X}
X
X/* build array of pointers to start/end of pages */
X
Xscanpages()
X{
X   register char *comment = buffer+2;
X   register int nesting = 0;
X
X   pages = 0;
X   fseek(infile, 0L, 0);
X   while (fgets(buffer, BUFSIZ, infile) != NULL)
X      if (*buffer == '%') {
X	 if (buffer[1] == '%') {
X	    if (strncmp(comment, "Page:", 5) == 0)
X	       pageptr[pages++] = ftell(infile)-strlen(buffer);
X	    else if (headerlen == 0 && strncmp(comment, "Pages:", 6) == 0)
X	       pagescmt = ftell(infile)-strlen(buffer);
X	    else if (headerlen == 0 &&
X		     strncmp(comment, "EndComments", 11) == 0)
X	       headerlen = ftell(infile);
X	    else if (strncmp(comment, "BeginDocument", 13) == 0)
X	       nesting++;
X	    else if (strncmp(comment, "EndDocument", 11) == 0)
X	       nesting--;
X	    else if (strncmp(comment, "BeginBinary", 11) == 0)
X	       nesting++;
X	    else if (strncmp(comment, "EndBinary", 9) == 0)
X	       nesting--;
X	    else if (nesting == 0 && strncmp(comment, "Trailer", 7) == 0) {
X	       fseek(infile, (long)(-strlen(buffer)), 1);
X	       break;
X	    }
X	 } else if (headerlen == 0 && buffer[1] != '!')
X	    headerlen = ftell(infile)-strlen(buffer);
X      }
X   pageptr[pages] = ftell(infile);
X}
X
Xseekpage(p)
X     int p;
X{
X   fseek(infile, pageptr[p], 0);
X   if (fgets(buffer, BUFSIZ, infile) != NULL &&
X       sscanf(buffer, "%%%%Page: %s %d\n", pagelabel, &pageno) == 2) {
X      pagelength = pageptr[p+1]-pageptr[p]-strlen(buffer);
X   } else {
X      fprintf(stderr, "%s: I/O error seeking page %d\n", prog, p);
X      fflush(stderr);
X      exit(1);
X   }
X}
X
Xwritestring(s)
X     char *s;
X{
X   fputs(s, outfile);
X   bytes += strlen(s);
X}
X
Xwritepageheader(label, page)
X     char *label;
X     int page;
X{
X   if (verbose) {
X      sprintf(buffer, "[%d] ", page);
X      message(buffer);
X   }
X   sprintf(buffer, "%%%%Page: %s %d\n", label, ++outputpage);
X   writestring(buffer);
X}
X
Xwritepagebody()
X{
X   if (!fcopy(pagelength)) {
X      fprintf(stderr, "%s: I/O error writing page %d\n", prog, outputpage);
X      fflush(stderr);
X      exit(1);
X   }
X}
X
Xwritepage(p)
X     int p;
X{
X   seekpage(p);
X   writepageheader(pagelabel, p+1);
X   writepagebody();
X}
X
X/* write header: should alter %%Pages: comment */
Xwriteheader(p)
X     int p;
X{
X   long len = headerlen;
X   fseek(infile, 0L, 0);
X   if (pagescmt && pagescmt < len) {
X      if (!fcopy(pagescmt) || fgets(buffer, BUFSIZ, infile) == NULL) {
X	 fprintf(stderr, "%s: I/O error in header\n", prog);
X	 fflush(stderr);
X	 exit(1);
X      }
X      len -= pagescmt+strlen(buffer);
X      sprintf(buffer, "%%%%Pages: %d 0\n", p);
X      writestring(buffer);
X   }
X   if (!fcopy(len)) {
X      fprintf(stderr, "%s: I/O error in header\n", prog);
X      fflush(stderr);
X      exit(1);
X   }
X}
X
X
Xwriteprolog()
X{
X   if (!fcopy(pageptr[0]-headerlen)) {
X      fprintf(stderr, "%s: I/O error in prologue\n", prog);
X      fflush(stderr);
X      exit(1);
X   }
X}
X
X/* write trailer */
Xwritetrailer()
X{
X   fseek(infile, pageptr[pages], 0);
X   while (fgets(buffer, BUFSIZ, infile) != NULL) {
X      writestring(buffer);
X   }
X   if (verbose) {
X      sprintf(buffer, "Wrote %d pages, %ld bytes\n", outputpage, bytes);
X      message(buffer);
X   }
X}
X
X/* write message to stderr */
Xmessage(s)
X     char *s;
X{
X   static int pos = 0;
X   char *nl = strchr(s, '\n');
X   int len = nl ? (nl-s) : strlen(s);
X
X   if (pos+len > 79 && (pos > 79 || len < 80)) {
X      fputc('\n', stderr);
X      pos = 0;
X   }
X   fputs(s, stderr);
X   fflush(stderr);
X   pos += len;
X}
X
X
Xint writeemptypage()
X{
X   if (verbose)
X      message("[*] ");
X   sprintf(buffer, "%%%%Page: * %d\nshowpage\n", ++outputpage);
X   writestring(buffer);
X}
X
END_OF_psutil.c
if test 5201 -ne `wc -c <psutil.c`; then
    echo shar: \"psutil.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f psutil.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"psutil.h\"
else
echo shar: Extracting \"psutil.h\" \(663 characters\)
sed "s/^X//" >psutil.h <<'END_OF_psutil.h'
X/* psutil.h
X * AJCD 29/1/91
X * utilities for PS programs
X */
X
X#include <stdio.h>
X
X#ifndef LOCAL
X#define LOCAL extern
X#endif
X
X#define TMPDIR "/tmp"
X#define MAXPAGES 5000 /* max pages in document */
X
XLOCAL char *prog;
XLOCAL long pageptr[MAXPAGES];
XLOCAL int pages;
XLOCAL int verbose;
XLOCAL FILE *infile;
XLOCAL FILE *outfile;
X
XLOCAL FILE *seekable();
XLOCAL int fcopy();
XLOCAL writepage();
XLOCAL seekpage();
XLOCAL writepageheader();
XLOCAL writepagebody();
XLOCAL writeheader();
XLOCAL writeprolog();
XLOCAL writetrailer();
XLOCAL writeemptypage();
XLOCAL scanpages();
XLOCAL writestring();
XLOCAL message();
X
Xextern long lseek();
Xextern long ftell();
Xextern char *getenv();
END_OF_psutil.h
if test 663 -ne `wc -c <psutil.h`; then
    echo shar: \"psutil.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 1 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
Angus Duggan, Department of Computer Science,	| I'm pink, therefore I'm Spam.
University of Edinburgh, JCMB,			| JANET:  ajcd@uk.ac.ed.lfcs
The King's Buildings, Mayfield Road,		| VOICE:  (UK) 031 650 5126
Edinburgh, EH9 3JZ, Scotland.	| OR:  ajcd%lfcs.ed.ac.uk@nsfnet-relay.ac.uk

ajcd@cs.ed.ac.uk (Angus Duggan) (05/22/91)

In article <1991May22.100359.796@csc.canterbury.ac.nz>, msh@math.canterbury.ac.nz (Mark Hickman) writes:
> It appears that there is interest in Angus Duggan's postscript utilities.
> They were originally posted in the alt.sources newsgroup. Since I (and I guess
> many other readers of this group) don't read that newsgroup, I thought
> that it might be worthwhile to repost them here. 
> 
> P.S. dvidvi was described to me as a dvi driver. I misinterpreted this to
> mean a driver like dvips etc. In fact it converts a dvi file into another
> dvi file with pages etc rearranged. It is perhaps a better choice for people
> using cm fonts.

I have just posted dvibook, my DVI file signature rearrangement program, to
alt.sources. It requires Chris Torek's DVI library, available with the SeeTeX
distribution from grunwald@edu.colorado.foobar. 

Dvibook rearranges pages in the DVI file into signatures of the size specified.

a.
-- 
Angus Duggan, Department of Computer Science,	| I'm pink, therefore I'm Spam.
University of Edinburgh, JCMB,			| JANET:  ajcd@uk.ac.ed.lfcs
The King's Buildings, Mayfield Road,		| VOICE:  (UK) 031 650 5126
Edinburgh, EH9 3JZ, Scotland.	| OR:  ajcd%lfcs.ed.ac.uk@nsfnet-relay.ac.uk