Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Booklet Style: Source for psbook etc

2 views
Skip to first unread message

Mark Hickman

unread,
May 21, 1991, 6:03:55 PM5/21/91
to
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: m...@math.canterbury.ac.nz

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

----------------------------------------------------------------------
From: aj...@lfcs.edinburgh.ac.uk (Angus Duggan)
Newsgroups: alt.sources
Subject: [REPOST] PostScript utilities
Keywords: signature order
Message-ID: <86...@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 aj...@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: aj...@uk.ac.ed.lfcs
The King's Buildings, Mayfield Road, | VOICE: (UK) 031 650 5126
Edinburgh, EH9 3JZ, Scotland. | OR: ajcd%lfcs.e...@nsfnet-relay.ac.uk

James Darrell McCauley

unread,
May 22, 1991, 12:37:43 AM5/22/91
to
It seems to me that the pagination problem should have
been addressed in Lamport's book.sty. Does anyone know
why it wasn't? Is there a way that the quire.tex macros
can be worked into it?
--
James Darrell McCauley, Grad Res Asst, Spatial Analysis Lab
Dept of Ag Engr, Texas A&M Univ, College Station, TX 77843-2117, USA
(jdm...@diamond.tamu.edu, jdm...@tamagen.bitnet)

Don Hosek

unread,
May 22, 1991, 3:15:31 AM5/22/91
to
In article <16...@helios.TAMU.EDU>, jdm...@tamsun.tamu.edu (James Darrell McCauley) writes:
> It seems to me that the pagination problem should have
> been addressed in Lamport's book.sty. Does anyone know
> why it wasn't? Is there a way that the quire.tex macros
> can be worked into it?

If you mean the imposition problem, it's because TeX really can't
handle that. Consider the 64page document to be printed 2-up
duplex and folded in half to form a booklet. Sheet one has pages
1 and 64 plus 2 and 63 on it. For TeX to know what goes where, it
has to know how many pages there are and hold the *whole* thing
in memory. Not really practical. Of course real-world imposition
involves printing large sheets which are folded in half several
times and trimmed to form signatures. Most paperbacks today are
printed in 16-page signatures (octavo) and the printed sheets
will have pages that are rotated ninety degrees. e.g.

V(9) V(8) V(5) V(12)
A(16) A(1) A(4) A(13)

where the parenthesised number is the page number and the angle
of the letter shows where the top of the page would be. This, of
course, requires special DVI-processing abilities.

-dh

--
Don Hosek | To retrieve files from ymir via the mailserver,
dho...@ymir.claremont.edu | send a message to mail...@ymir.claremont.edu
Quixote Digital Typography | with a line saying send [DIRECTORY]FILENAME
714-625-0147 | where DIRECTORY is the FTP directory (sans
---------------------------+ "anonymous") and FILENAME is the filename, e.g.
"send [tex]00readme.txt". There is a list of files in each directory under the
name 00files.txt. Binary files are not available by this technique.

Angus Duggan

unread,
May 22, 1991, 4:56:08 AM5/22/91
to
In article <1991May22....@csc.canterbury.ac.nz>, m...@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 grun...@edu.colorado.foobar.

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

a.

Marcel van der Goot

unread,
May 22, 1991, 3:37:27 PM5/22/91
to
jdm...@tamsun.tamu.edu (James Darrell McCauley) wrote

> It seems to me that the pagination problem should have
> been addressed in Lamport's book.sty. Does anyone know
> why it wasn't? Is there a way that the quire.tex macros
> can be worked into it?

I'm not really sure which pagination problem you mean. Quire.tex
does its job through modification of \shipout. The page number is
already printed on the page when \shipout is called, so the normal
page numbers will come out correctly. The only problem with page
numbers is when the file contains \write commands. In LaTeX this
gives you trouble in particular when you have \pagerefs or make
a table of contents. The solution is as follows:
- First run LaTeX on your document without saying \quire (or \makequire)
(you have to do this anyway to get the number of pages). Make
sure that all the references are right. (LaTeX warns you if labels
have changed --- if so, rerun LaTeX as usual.)
- Now, on the run where you say \quire (or \makequire), you should also
say \nofiles in the preamble (nothing else changes). This will
prevent LaTeX from changing the .aux and .toc files, so that you
get all the correct page numbers. (It also prevents some junk from
being written to your terminal when you use \quire.)
The reason that the use of \nofiles is not mentioned in quire.doc is
that I'm not a LaTeX user and didn't know about it at the time.

dho...@euler.claremont.edu (Don Hosek) wrote in response


> If you mean the imposition problem, it's because TeX really can't
> handle that. Consider the 64page document to be printed 2-up
> duplex and folded in half to form a booklet. Sheet one has pages
> 1 and 64 plus 2 and 63 on it.

Quire.tex is intended to handle simple cases of imposition, namely
the case where each page is folded only once. For real book production
this is indeed insufficient, but for most ``average'' users it is
exactly what is needed to easily produce home-made booklets. In most
cases you don't want to fold standard letter size or A4 paper more
than once, and most laserprinters cannot handle larger paper.
For instance, if you say \quire{64}, TeX will produce 32 sheets; sheet 1
contains pages 1 and 64, sheet 2 pages 2 and 63, etc. If you print sheets
double-sided (by reinserting the printed sheets in the laserprinter, or
using a photocopier), you'll get 16 sheets that you can fold into a
booklet. (In this particular case I would suggest using \quire{32} to
get two 8-sheet sets --- that folds easier.)

> For TeX to know what goes where, it has to know how many pages there
> are and hold the *whole* thing in memory. Not really practical.

The first problem is easily solved by first running TeX normally.
After all, almost no one can produce a 64-page booklet in one run.
The second problem is indeed a problem. Quire.tex tries to solve it
by exchanging memory for computation: you can print only part of the
sheets, and then rerun TeX (several times if you have very little
memory) to generate the remaining sheets. (I must say that on a sun
I have never actually had any problems --- apparently there is quite
some memory available.)

I am well aware that the problem can also be solved through manipulation
of the dvi file, or even using PostScript. Doing everything in TeX
has the advantage that you don't have to install other programs or
buy a special printer.

(quire.tex and quire.doc are available from ymir.claremont.edu [134.173.4.23],
direcory [tex.inputs.midnight].)


Marcel van der Goot
.----------------------------------------------------------------
| Blauw de viooltjes, mar...@vlsi.cs.caltech.edu
| Rood zijn de rozen;
| Een rijm kan gezet
| Met plaksel en dozen.
|

0 new messages