[comp.sources.misc] v08i095: Up: utilities to print conforming PostScript n-up

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (10/29/89)

Posting-number: Volume 8, Issue 95
Submitted-by: jgreely@cis.ohio-state.edu (J Greely)
Archive-name: up

This package allows you to print conforming PS files n-up, with the
scaling, rotation, and page positioning code kept in a readable
configuration file.  It includes a utility to create numbered test
pages, as well as one that rearranges the pages in a PostScript file
into signature order, for producing two-up, double-sided booklets.
The scripts are written in Perl, and require that version 3.0 be
available.  If you don't have Perl, how-to instructions are provided
for converting to another language.  It is known to work on the output
of enscript, pscat, psdit (all from the Adobe TranScript package), the
Adobe documentation supplied with NeXT release 1.0, and absolutely
*no* dvi-to-PS converter (dvips 4.2 seems the most promising, and I'm
working on appropriate hacks).

#! /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 shell archive."
# Contents:  README HowTo Makefile up makeup parr up.rc up.1 makeup.1
#   parr.1 uprc.5
# Wrapped by jgreely@cis.ohio-state.edu on Tue Oct 24 15:16:22 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(3286 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X		    Up, a PostScript print utility
X	    hacked together with a two-by-four by J Greely
X		     (jgreely@cis.ohio-state.edu)
X
X
XThis package allows you to print conforming PS files n-up, with the
Xscaling, rotation, and page positioning code kept in a readable
Xconfiguration file.  It has successfully been used on the output of
Xptroff, enscript, psdit (all from Adobe's TranScript package), and the
XAdobe documentation supplied with NeXT release 1.0, and should work on
Xany file that obeys the rules the way I assume (note: it does not
Xcurrently work with any known dvi-to-PS converter; I'm making some
Xchanges to make it work with dvips 4.2 (available for anonymous ftp at
Xlabrea.stanford.edu), but they're not done yet).  The major feature is
Xthe ability to create your own layouts, with arbitrary scaling,
Xtranslations, and rotations.  The output can be fed back through, for
Xfurther reduction/destruction.
X
X  Warning: if you don't have Larry Wall's Perl language installed,
Xthis utility will be useless to you.  It's not hard (ok, trivial) to
Xconvert it to Nawk or C, and I'll probably get around to it soon, but
Xfor now you need Perl (version 3.0).  Debates on the merits of Perl as
Xa programming language are discouraged by the author.  If Perl is not
Xlocated in /usr/bin, you'll need to change the first line of each
Xexecutable.
X
X  To use, unpack the shar file somewhere, edit the top of Makefile to
Xindicate where things should go, and type "make install". It will
Xinstall several symlinks to the script, as well as a general
Xconfiguration file, which can be overridden by the user.
X
X  Currently, it installs links to print 2, 4, 6, and 16 pages per
Xsheet, and the supplied configuration file has sample layouts for
Xdoing (among others) 8-up, 4-up in greeting-card positions, 10-up in a
Xshrinking spiral, and more.  4up and 16up simply scale the page by .5
Xand .25, respectively (white lie; read my excuse in the config file).
X2up and 6up are rotated, and the page positioning is given below:
X
X		    +-----+-----+   +---+---+---+
X                    |     |     |   | 1 | 2 | 3 |
X                    |  1  |  2  |   +---+---+---+
X                    |     |     |   | 4 | 5 | 6 |
X                    +-----+-----+   +---+---+---+
X
X
X  Note to NeXT users: both Preview and Yap can be used to preview
Xoutput under release 1.0.  Previous versions wouldn't work quite
Xright.
X
X  Note to people in general: after I finished writing this, someone
Xtold me of at least one other n-up utility.  The one I've seen works
Xby what might be called elegant PostScript hacking, but I think mine
Xsolves a different problem.
X
X  Bugs, suggestions, offers of money and sacrifices, and anything
Xinteresting done with this package will be cheerfully accepted.
XDespite rumors to the contrary, I am *not* a black hole for e-mail.
X
X
XAdditional utilities supplied:
X
Xparr	- Page ARRanger.  For arbitrary reordering of pages in a
X	  conforming PS file.  Switches are provided to automatically
X	  do signature-order printing for two-up, left-to-right
X	  layouts ("up -n pup").  Pages can be printed more than once
X	  or not at all, and blank pages may be inserted anywhere.
X
Xmakeup	- generates numbered test pages, for debugging new layouts
X
X--
XJ Greely (jgreely@cis.ohio-state.edu; osu-cis!jgreely), 89/10/23
END_OF_FILE
if test 3286 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'HowTo' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'HowTo'\"
else
echo shar: Extracting \"'HowTo'\" \(5776 characters\)
sed "s/^X//" >'HowTo' <<'END_OF_FILE'
XQuick summary of what this package does, and how to duplicate its
Xeffects if you don't like my code.
X
XA conforming PostScript file, for my purposes, is anything that meets
Xall of the following requirements:
X
X1) first line must begin with the string '%!PS-Adobe'.
X2) Each page must begin with a '%%Page:' line, and the graphics state
X   must be the default at that point (no translation, scaling, or
X   rotation of the coordinate space can carry over between pages).
X   The pages must be numbered starting at 1, which is a bit pedantic
X   of me.  It's part of the spec, but it is by no means necessary for
X   the code to work.  It's a one-line check, and I'm thinking of just
X   scrapping it.
X3) There must be a '%%Trailer' line.
X
X
XAs for what I *do* with all this, it's simple:
X
X1) When I see the '%!PS-Adobe' line, I insert the following lines
X   (ignoring the old '%!PS' line):
X	%!PS-Adobe-2.0
X	%%Pages: (atend)
X   Page counts in the header are first-comes, first-served, so putting
X   mine at the very top will override anything that was in the
X   original file (and since the whole idea is to change the number of
X   pages, this is 'a good thing').  Since I do everything in one pass,
X   I have no idea how many pages there will be, so I defer it until
X   the end.
X2) When I reach the end of the header comments (signified by the first
X   non-%% line or an explicit %%EndComments line), I insert the
X   user-defined prolog definitions into their own dictionary.  To
X   simplify nesting, I use the current PID as part of the dictionary
X   name.  I save the old value of showpage here, and redefine it to
X   print nothing.  It looks like this (modulo interpretation of
X   variables marked by <>):
X	%%BeginProcSet: up_prolog 1 <pid>
X	/UpDict<pid> $plines 3 add dict def
X	UpDict<pid> begin
X	<user prolog>
X	/UpShowpage {showpage} bind def
X	/UpState {} def
X	end
X	/showpage {} def
X	%%EndProcSet: up_prolog 1 <pid>
X3) For every '%%Page:' line, I first delete it, and then, if it is the
X   first page on a sheet, I save the current VM state, and insert the
X   user-specified scaling, rotation, and translation commands.  It
X   looks like this (modulo the interpolation of the variables marked
X   by <>):
X	%%Page: ? <sheet number>
X	UpDict<pid> begin
X	save /UpState exch def
X	<even/odd>
X	<scale, translate, rotate>
X	<page positioning>
X	end
X   For pages that don't start a sheet, I just insert:
X	UpDict<pid> begin
X	<page positioning>
X	end
X5) At the end of every sheet, I restore the VM state, and perform a
X   real showpage, like so:
X	UpDict<pid> begin UpState restore UpShowpage end
X6) When I see the '%%Trailer' line, I replace it with:
X	UpDict<pid> begin UpState restore UpShowpage end
X	%%Trailer
X   You might suspect that this causes an error, or the printing of a
X   blank page, and if everything I said above were true, you'd be
X   right.  The catch is that #5 is a lie.  I detect the end of a sheet
X   by finding myself at the beginning of a new one, so the last sheet
X   never gets printed, unless it's done just before the trailer.
X7) The last bit is simple.  After the very last line of the input is
X   printed, the actual sheet count is added.  This has to be this way,
X   since the *last* in a series of trailer comments is the one heeded.
X   It looks like this:
X	%%Pages: <sheet count>
X
X
XIf this isn't entirely clear, here's a before/after.
X
X----------
XConforming PS file, which prints 4 numbered pages (output of "makeup 4"):
X
X%!PS-Adobe-1.0
X%%Creator: makeup
X%%Title: Page Layout Test
X%%CreationDate: Tue Oct 24 02:33:36 EDT 1989
X%%Pages: (atend)
X%%DocumentFonts: Times-Roman
X%%BoundingBox: 0 0 612 792
X%%EndComments
X/inch {72 mul} def
X/Nfont /Times-Roman findfont 5 inch scalefont def
X/drawpage {
X	2 setlinecap 3 setlinewidth 0 setgray
X	Nfont setfont
X	dup stringwidth
X	11 inch exch sub 2 div
X	exch 8.5 inch exch sub 2 div
X	exch moveto show
X	0.25 inch dup moveto
X	8 inch 0 rlineto
X	0 10.5 inch rlineto
X	-8 inch 0 rlineto
X	0 -10.5 inch rlineto
X	closepath stroke
X	showpage
X} def
X%%EndProlog
X%%Page: ? 1
X(1) drawpage
X%%Page: ? 2
X(2) drawpage
X%%Page: ? 3
X(3) drawpage
X%%Page: ? 4
X(4) drawpage
X%%Trailer
X%%Pages: 4
X
X----------
XPrevious file, filtered to print two pages per sheet ("up -n 2up"):
X
X%!PS-Adobe-2.0
X%%Pages: (atend)
X%%Creator: makeup
X%%Title: Page Layout Test
X%%CreationDate: Tue Oct 24 02:33:36 EDT 1989
X%%Pages: (atend)
X%%DocumentFonts: Times-Roman
X%%BoundingBox: 0 0 612 792
X%%EndComments
X%%BeginProcSet: up_prolog 1 7482
X/UpDict7482 23 3 add dict def
XUpDict7482 begin
X/inch {72 mul} def
X/moveU {0 11 inch translate} def
X/moveR {8.5 inch 0 translate} def
X/moveD {0 -11 inch translate} def
X/moveL {-8.5 inch 0 translate} def
X/rotR {-90 rotate} def
X/rotL {90 rotate} def
X/doSpiral {moveU moveR rotR 0.67 dup scale} def
X/moveHU { 0 5.5 inch translate} def
X/doRevSpiral {moveHU rotL 0.67 dup scale} def
X/UpShowpage {showpage} bind def
X/UpState {} def
Xend
X/showpage {} def
X%%EndProcSet: up_prolog 1 7482
X/inch {72 mul} def
X/Nfont /Times-Roman findfont 5 inch scalefont def
X/drawpage {
X	2 setlinecap 3 setlinewidth 0 setgray
X	Nfont setfont
X	dup stringwidth
X	11 inch exch sub 2 div
X	exch 8.5 inch exch sub 2 div
X	exch moveto show
X	0.25 inch dup moveto
X	8 inch 0 rlineto
X	0 10.5 inch rlineto
X	-8 inch 0 rlineto
X	0 -10.5 inch rlineto
X	closepath stroke
X	showpage
X} def
X%%EndProlog
X%%Page: ? 1
XUpDict7482 begin
Xsave /UpState exch def
X7.75 inch 0 translate rotL 11 17 div dup scale
Xend
X(1) drawpage
XUpDict7482 begin
XmoveR
Xend
X(2) drawpage
XUpDict7482 begin UpState restore UpShowpage end
X%%Page: ? 2
XUpDict7482 begin
Xsave /UpState exch def
X7.75 inch 0 translate rotL 11 17 div dup scale
Xend
X(3) drawpage
XUpDict7482 begin
XmoveR
Xend
X(4) drawpage
XUpDict7482 begin UpState restore UpShowpage end
X%%Trailer
X%%Pages: 2
X
X--
XJ Greely (jgreely@cis.ohio-state.edu; osu-cis!jgreely)
END_OF_FILE
if test 5776 -ne `wc -c <'HowTo'`; then
    echo shar: \"'HowTo'\" unpacked with wrong size!
fi
# end of 'HowTo'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(1059 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile to install 'up'
X#
XLIBDIR=/usr/local/lib
XBINDIR=/usr/local/bin
XMANDIR=/usr/man
XSYMLINK=ln -s
X
XPROG=up
XUTIL=makeup parr
XLIB=up.rc
XLINKS=2up 4up 6up 16up
XMAN1=up.1 makeup.1 parr.1
XMAN5=uprc.5
X
XFILES=README HowTo Makefile $(PROG) $(UTIL) $(LIB) $(MAN1) $(MAN5)
X
Xdefault:
X	@echo Edit Makefile, changing the values of LIBDIR, BINDIR,
X	@echo MANDIR, and SYMLINK, then type \"make install\"
X
Xinstall: $(PROG) $(UTIL) $(LIB) $(MAN1) $(MAN5)
X	cp $(PROG) $(UTIL) $(BINDIR)
X	cp $(LIB) $(LIBDIR)
X	for i in $(LINKS); do $(SYMLINK) $(BINDIR)/$(PROG) $(BINDIR)/$$i; done
X	@-mkdir $(MANDIR)
X	@-mkdir $(MANDIR)/man1
X	@-mkdir $(MANDIR)/man5
X	cp $(MAN1) $(MANDIR)/man1
X	cp $(MAN5) $(MANDIR)/man5
X
Xclean:
X	rm -f core up.shar* *~
X
Xuninstall:
X	-for i in $(PROG) $(UTIL) $(LINKS); do rm $(BINDIR)/$$i; done
X	-rm $(LIBDIR)/$(LIB)
X	-for i in $(MAN1); do rm $(MANDIR)/man1/$$i; done
X	-for i in $(MAN5); do rm $(MANDIR)/man5/$$i; done
X
Xup.shar: $(FILES)
X	shar $(FILES) >up.shar
X	perl -i.old -pe 's/jgreely@[-.\w]+[-\w]/jgreely@cis.ohio-state.edu/g;'\
X	up.shar
X	rm up.shar.old
END_OF_FILE
if test 1059 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'up' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'up'\"
else
echo shar: Extracting \"'up'\" \(4810 characters\)
sed "s/^X//" >'up' <<'END_OF_FILE'
X#!/usr/local/bin/perl
X# up:
X# PostScript n-up print utility.  This script takes conforming PS
X# files, and prints them n-up, where n is controlled by a symbolic
X# name (taken from argv[0] or the command line), and the page
X# positioning and scaling are looked up in a configuration file.
X#
X# usage: up [-n name] [-f config] [file ...]
X#
X# jgreely@cis.ohio-state.edu, 89/10/23
X#
X
X# set the name from $0 (argv[0]), after stripping a path
X#
X@foo = split(/\//,$0);
X$name=pop(@foo);
X
X$HOME=$ENV{"HOME"};
X
X# set a default prolog in case the config file doesn't have one
X# make sure that plines is 2 larger than the number of definitions in
X# the prolog (used to get dictionary size).
X#
X$plines=10;
X$prolog = <<EOF;
X/inch {72 mul} def
X/moveU {0 11 inch translate} def
X/moveR {8.5 inch 0 translate} def
X/moveD {0 -11 inch translate} def
X/moveL {-8.5 inch 0 translate} def
X/rotR {-90 rotate} def
X/rotL {90 rotate} def
XEOF
X
X# search for a configuration file.  The *last* one found is used
X#
X$config = "./up.rc";
X@search_path = ("/usr/lib/up.rc","/usr/local/lib/up.rc","$HOME/.uprc",
X                "./up.rc"); 
Xforeach $file (@search_path) {
X	$config = $file if (-f $file && -r $file);
X}
X
X# check for options on command line.
X#
Xwhile ($_ = $ARGV[0],/^-/) {
X	shift;
X	last if /^-\-$/;
X	/^-[Ff]/ && ($config = shift,next);
X	/^-[Nn]/ && ($name = shift,next);
X	die "usage: up [-f config] [-n name] [file ...]\n";
X}
X
X# read relevant section of configuration file.	For complete format
X# description, see the provided up.rc file or uprc(5).
X#  Basically, read the config file until we find a line containing a
X# name field equal to the current name.	 Once we do, read all name-
X# value pairs up until a line containing just a '.', placing them all
X# into an associative array.
X#
Xopen(config) ||
X  die "can't find file '$config', stopped";
X$in_rec = 0;
Xwhile(<config>) {
X	chop;
X	next if /^\s*#|^\s*$/;	# skip comment and blank lines
X	if (/^prolog\s*=/) {
X		do read_prolog();
X		next;
X	}
X	next unless ($in_rec || /$name/);
X	($field,$value) = split(/\s*=\s*/);
X	if (($field eq "name") && ($value eq $name)) {
X		$in_rec++;
X		next;
X	}
X	last if /^\.$/;
X	$var{$field} = $value;
X}
Xclose(config);
Xdie "no such record '$name' in file '$config', stopped" unless $in_rec;
X$modulus = $var{"modulus"};
Xdie "invalid modulus == $modulus, stopped" unless $modulus;
X
X$_ = <>;
Xif (/^%!PS-Adobe/) {
X	print <<EOF;
X%!PS-Adobe-2.0
X%%Pages: (atend)
XEOF
X}else{
X	die "Not conforming PostScript (no %!PS-Adobe), stopped";
X}
X
X# read comment section (up to first non-%% line, or %%EndComments)
X#
Xwhile (<>) {
X	if (!/^%%/) {
X		do print_prologue();
X		print;
X		last;
X	}
X	if (/^%%EndComments/) {
X		print;
X		do print_prologue();
X		last;
X	}
X	print;
X}
X
Xwhile (<>) {
X	#
X	# to use slightly busted NeXT previewer
X	#
X	next if /^%%Pages:/;
X	if (/^%%Page:/) {
X		do enter_page();
X		next;
X	}
X	if (/^%%Trailer/) {
X		do print_trailer();
X		next;
X	}
X	print;
X}
X# print actual page count.  This must be the last trailer comment
X# printed.
X#
Xprint "%%Pages: $sheet\n";
Xexit(0);
X
X# the prolog consists of simple command definitions you want to make
X# available to the configuration routines.  None of them do anything
X# complicated, but why make life more difficult for the user?
X#
Xsub print_prologue {
X	print <<EOF;
X%%BeginProcSet: up_prolog 1 $$
X/UpDict$$ $plines 3 add dict def
XUpDict$$ begin
X$prolog
X/UpShowpage {showpage} bind def
X/UpState {} def
Xend
X/showpage {} def
X%%EndProcSet: up_prolog 1 $$
XEOF
X}
X
X# basically, at the beginning of a page, pull the number from the page
X# header, take it modulo $modulus, and print things based on that #
X# number.  If it's 1, end the previous sheet (if there is one),
X# increment the sheet number, and print a sheet header.	 For all
X# pages, print the appropriate page motion command.
X#
Xsub enter_page {
X	$page++;
X	($foo,$bar,$oldpage) = split;
X	die "Help! page number mismatch, stopped" if ($oldpage != $page);
X	$temp = $page % $modulus;
X	if ($temp == 1) {
X		if ($sheet++) {
X			print 
X			  "UpDict$$ begin UpState restore UpShowpage end\n";
X		}
X		print <<EOF;
X%%Page: ? $sheet
XUpDict$$ begin
Xsave /UpState exch def
XEOF
X		print $sheet % 2 ? $var{'odd'} : $var{'even'},"\n";
X		print $var{"scale"},"\n";
X	}else{
X		print "UpDict$$ begin\n";
X	}
X	$temp = $modulus unless $temp;
X	print $var{$temp},"\n";
X	print "end\n";
X}
X
X# print the trailer, which for us consists of a showpage (inserted
X# before the trailer comment, to make it part of the last page).
X#
Xsub print_trailer {
X	print "UpDict$$ begin UpState restore UpShowpage end\n" if $page;
X	print "%%Trailer\n";
X}
X
X# read the prolog from the configuration file.	All lines up to the
X# the first one starting with '.' will be placed in $prolog
X#
Xsub read_prolog {
X	$prolog='';
X	#plines=0;
X	while (<config>) {
X		last if /^\./;
X		$prolog .= $_;
X		$plines++;
X	}
X	chop($prolog);
X	$plines+=3;
X}
END_OF_FILE
if test 4810 -ne `wc -c <'up'`; then
    echo shar: \"'up'\" unpacked with wrong size!
fi
chmod +x 'up'
# end of 'up'
fi
if test -f 'makeup' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makeup'\"
else
echo shar: Extracting \"'makeup'\" \(1092 characters\)
sed "s/^X//" >'makeup' <<'END_OF_FILE'
X#!/usr/bin/perl
X# test page printing for up.  print arg pages, each with a box around
X# the edges (.25 inches in), and the page number in large type.
X#  This is useful for debugging page layouts, as well as just wasting
X# paper.
X#
X# usage: makeup count
X#
X# jgreely@cis.ohio-state.edu, 89/10/23
X#
X$count = $ARGV[0];
Xdie "usage: makeup count\n" unless $count > 0;
X
X$date = `date`;
Xchop($date);
X
Xprint <<EOF;
X%!PS-Adobe-1.0
X%%Creator: makeup
X%%Title: Page Layout Test
X%%CreationDate: $date
X%%Pages: (atend)
X%%DocumentFonts: Times-Roman
X%%BoundingBox: 0 0 612 792
X%%EndComments
X/inch {72 mul} def
X/Nfont /Times-Roman findfont 5 inch scalefont def
X/drawpage {
X	2 setlinecap 3 setlinewidth 0 setgray
X	Nfont setfont
X	dup stringwidth
X	11 inch exch sub 2 div
X	exch 8.5 inch exch sub 2 div
X	exch moveto show
X	0.25 inch dup moveto
X	8 inch 0 rlineto
X	0 10.5 inch rlineto
X	-8 inch 0 rlineto
X	0 -10.5 inch rlineto
X	closepath stroke
X	showpage
X} def
X%%EndProlog
XEOF
X
Xfor ($page=1;$page <= $count;$page++) {
X	print "%%Page: ? $page\n($page) drawpage\n";
X}
X
Xprint <<EOF;
X%%Trailer
X%%Pages: $count
XEOF
Xexit(0);
END_OF_FILE
if test 1092 -ne `wc -c <'makeup'`; then
    echo shar: \"'makeup'\" unpacked with wrong size!
fi
chmod +x 'makeup'
# end of 'makeup'
fi
if test -f 'parr' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'parr'\"
else
echo shar: Extracting \"'parr'\" \(2661 characters\)
sed "s/^X//" >'parr' <<'END_OF_FILE'
X#!/usr/bin/perl
X#parr:
X# rearrange conforming PS code to print the pages in an arbitrary
X# order.  The -[sS] options (for signature order) assume two-up, left
X# to right.  The -o option takes a list of ranges, like this:
X#	1-5    1-10,11-20    11-,1-10
X# usage: parr [-o list] [-s] [-S n] [file]
X#
X# jgreely@cis.ohio-state.edu, 89/10/23
X
X$order='';
X$signFlag='';
X$signCount=0;
X$DEBUG=0;
X$rangePrint=0;
X$TMPDIR='/tmp';
X
Xwhile ($_ = $ARGV[0],/^-/) {
X	shift;
X	last if /^-\-$/;
X	/^-o/ && ($order = shift,next);
X	/^-S/ && ($signCount = shift,$signFlag++,next);
X	/^-s/ && ($signFlag++,next);
X	/^-d/ && ($DEBUG++,next);
X	/^-r/ && ($rangePrint++,next);
X	die "usage: parr [-d] [-r] [-o list] [-s] [-S n] [file]\n";
X}
Xif ($signFlag && $order) {
X	die "parr: -s and -o cannot be used together\n";
X}
X
X$file = "$TMPDIR/p$$.header";
X@files = ($file);
X$sheet=0;
Xopen(file,">$file") ||
X  die "$file: $!, stopped";
Xwhile (<>) {
X	#
X	# hack to use NeXT Preview: strip old '%%Pages:' lines
X	#
X	next if /^%%Pages:/;
X	if (/^%%Page:/) {
X		close(file);
X		$sheet++;
X		$file = "$TMPDIR/p$$.$sheet";
X		push(@files,$file);
X		open(file,">$file") ||
X		  die "$file: $!, stopped";
X	}
X	if (/^%%Trailer/) {
X		close(file);
X		$file = "$TMPDIR/p$$.trailer";
X		push(@files,$file);
X		open(file,">$file") ||
X		  die "$file: $!, stopped";
X	}
X	print file $_;
X}
Xclose(file);
X
X@order = ();
Xif ($order) {
X	foreach $range (split(/,/,$order)) {
X		($start,$sep,$end) = split(/(-)/,$range);
X		$start = 1 unless $start;
X		$end = $sheet unless $end;
X		if ($sep) {
X			push(@order,$start..$end);
X		}else{
X			push(@order,$start);
X		}
X	}
X}elsif ($signFlag) {
X	if (! $signCount) {
X		$signCount = $sheet;
X		$signCount += (4 - $sheet % 4) if ($sheet % 4);
X	}else{
X		$signCount *=4;
X	}
X	for($base=0;$base<$sheet;$base+=$signCount) {
X		@tmp = ($signCount/2+$base);
X		push(@tmp,$tmp[0]+1,$tmp[0]+2,$tmp[0]-1);
X		while ($tmp[3] > $base) {
X			push(@order,@tmp);
X			@tmp = ($tmp[0]-2,$tmp[1]+2,$tmp[2]+2,$tmp[3]-2);
X		}
X	}
X}else{
X	@order = (1..$sheet);
X}
X
X@tmp=@order;
X@order=();
Xforeach $page (@tmp) {
X	push(@order,$page > $sheet ? "B" : $page);
X}
X
Xif ($rangePrint) {
X	print join(',',@order),"\n";
X	unlink @files unless $DEBUG;
X	exit(0);
X}
X
Xopen(file,"$TMPDIR/p$$.header");
X$_ = <file>;
Xprint $_,"%%Pages: (atend)\n";
Xprint while <file>;
Xclose(file);
X
Xforeach $page (@order) {
X	$count++;
X	print "%%Page: ? $count\n%%OldPage: $page\n";
X	if ($page eq "B") {
X		print "showpage\n";
X	}else{
X		open(file,"$TMPDIR/p$$.$page");
X		while (<file>) {
X			print unless /^%%Page:/;
X		}
X		close(file);
X	}
X}
Xopen(file,"$TMPDIR/p$$.trailer");
Xprint while <file>;
Xclose(file);
Xprint "%%Pages: $count\n";
X
Xunlink @files unless $DEBUG;
Xexit(0);
END_OF_FILE
if test 2661 -ne `wc -c <'parr'`; then
    echo shar: \"'parr'\" unpacked with wrong size!
fi
chmod +x 'parr'
# end of 'parr'
fi
if test -f 'up.rc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'up.rc'\"
else
echo shar: Extracting \"'up.rc'\" \(3086 characters\)
sed "s/^X//" >'up.rc' <<'END_OF_FILE'
X# jgreely@cis.ohio-state.edu, 89/10/23
X#
X
X# this is the normal prolog, and defines everything used below
X#
Xprolog=
X/inch {72 mul} def
X/moveU {0 11 inch translate} def
X/moveR {8.5 inch 0 translate} def
X/moveD {0 -11 inch translate} def
X/moveL {-8.5 inch 0 translate} def
X/rotR {-90 rotate} def
X/rotL {90 rotate} def
X/doSpiral {moveU moveR rotR 0.67 dup scale} def
X/moveHU { 0 5.5 inch translate} def
X/doRevSpiral {moveHU rotL 0.67 dup scale} def
X.
X
X# up is a synonym for twoup, since my code doesn't work correctly for
X# the case n==1.  Until I robustify it, this will stay.
X#
Xname=up
Xmodulus=2
Xscale=7.75 inch 0 translate rotL 11 17 div dup scale
X1=
X2=moveR
X.
X
Xname=2up
Xmodulus=2
Xscale=7.75 inch 0 translate rotL 11 17 div dup scale
X1=
X2=moveR
X.
X
X# two-up with even pages rotated, for double-siding
X#
Xname=pup
Xmodulus=2
Xeven=moveU moveR rotR rotR
Xodd=
Xscale=7.75 inch 0 translate rotL 11 17 div dup scale
X1=
X2=moveR
X.
X
X# note that 4up is scaled a bit smaller than you might think.  If I
X# just scaled by .5, I'd lose my top and bottom edges (printer
X# limitations)
X#
Xname=4up
Xmodulus=4
Xscale=0.2125 inch 0.275 inch translate 0.475 dup scale
X1=moveU
X2=moveR
X3=moveL moveD
X4=moveR
X.
X
X# this does a greeting-card format, designed to be folded into
X# fourths.  If you're not sure how it's supposed to look, run:
X#    makeup 4 | up -n card | lpr
X#
Xname=card
Xmodulus=4
Xscale=0.2125 inch 0.275 inch translate 0.475 dup scale
X1=moveU moveU moveR rotR rotR
X2=moveU moveU moveR rotR rotR
X3=moveR
X4=moveU moveU moveR rotR rotR
X.
X
X# this is about the limit for a 300 dpi device, unless it's reasonably
X# new and you have good eyes.  I like it at 400 dpi.
X#
Xname=6up
Xmodulus=6
Xscale=0.25 inch 0.75 inch translate rotL 4 11 div dup scale
X1=moveD
X2=moveR
X3=moveR
X4=moveD moveL moveL
X5=moveR
X6=moveR
X.
X
X# this is a bit too far for casual reading.  It's entering magnifying
X# glass territory, which is bad, unless you need to carry lots of RFCs
X# around.
X#
Xname=8up
Xmodulus=8
Xscale=0.7 inch 0 translate rotL 11 34 div dup scale
X1=moveD
X2=moveR
X3=moveR
X4=moveR
X5=moveD moveL moveL moveL
X6=moveR
X7=moveR
X8=moveR
X.
X
X# Steve Romig's contribution to evil PostScript hacking.  To see what
X# it does, run:
X#    makeup 10 | up -n spiral | lpr
X#
Xname=spiral
Xmodulus=10
Xscale=7.75 inch 0 translate rotL 11 17 div dup scale
X1=
X2=doSpiral
X3=doSpiral
X4=doSpiral
X5=doSpiral
X6=doSpiral
X7=doSpiral
X8=doSpiral
X9=doSpiral
X10=doSpiral
X.
X
X# More from Steve, this time in the other direction
X#
Xname=revspiral
Xmodulus=10
Xscale=7.75 inch 0 translate rotL 11 17 div dup scale
X1=moveR
X2=doRevSpiral
X3=doRevSpiral
X4=doRevSpiral
X5=doRevSpiral
X6=doRevSpiral
X7=doRevSpiral
X8=doRevSpiral
X9=doRevSpiral
X10=doRevSpiral
X.
X
X# this is not legible on anything under 400 dpi, and even then you'll
X# probably want a magnifying glass.  You *can* read it with the naked
X# eye, but not for long.
X#
Xname=16up
Xmodulus=16
Xscale=0.25 0.25 scale
X1=moveU moveU moveU
X2=moveR
X3=moveR
X4=moveR
X5=moveD moveL moveL moveL
X6=moveR
X7=moveR
X8=moveR
X9=moveD moveL moveL moveL
X10=moveR
X11=moveR
X12=moveR
X13=moveD moveL moveL moveL
X14=moveR
X15=moveR
X16=moveR
X.
END_OF_FILE
if test 3086 -ne `wc -c <'up.rc'`; then
    echo shar: \"'up.rc'\" unpacked with wrong size!
fi
# end of 'up.rc'
fi
if test -f 'up.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'up.1'\"
else
echo shar: Extracting \"'up.1'\" \(2731 characters\)
sed "s/^X//" >'up.1' <<'END_OF_FILE'
X.TH UP 1 "23 October 1989"
X.SH NAME
Xup \- convert conforming PostScript files to print n-up
X.br
Xmakeup \- create numbered test pages for up
X.SH SYNOPSIS
X.B up
X[
X.B \-f
Xconfig_file ] [
X.B \-n
Xname ] [ file ... ]
X.PP
X.B makeup
Xcount
X.SH DESCRIPTION
X.I Up
Xreads a conforming PostScript file, and performs translation,
Xrotation, and scaling operations to print several pages on one sheet
Xof paper.  It uses a human-readable configuration file to determine
Xhow to arrange pages, and selects named layouts based on the name the
Xprogram was called by (see also the
X.I \-f
Xoption).  The output is also conforming, which means that it can be
Xfed back through for further reduction.
X.PP
XThe configuration file is slightly magical, but easy to use for simple
Xlayouts.  Quite complicated effects are possible by embedding
Xarbitrary PostScript commands.  See
X.IR spiral ,
Xin the supplied configuration file.  The format is completely
Xdescribed in uprc(5).
X.PP
X.I Makeup
Xis a simple utility that generates
X.I count
Xpages of conforming PostScript to stdout, with each page containing a
X10.5x8 inch box, and a large page number.  Its main excuse for
Xexistence is debugging new layouts, although the enterprising could
Xset up calendar formats.
X.SH OPTIONS
X.TP
X.B \-f
X.I config_file
XUse an alternate configuration file.  Normally, it uses the last of
Xthe following that is found: /usr/local/lib/up.rc, ~/.uprc ./up.rc.
X.TP
X.B \-n
X.I name
XExplicitly specify what page layout to use, no matter what name the
Xprogram was called by.  This is handy for testing new layouts, and
Xconfigurations that you haven't created links for yet.
X.SH FILES
X.PD 0
X.TP 25
X.B /usr/local/lib/up.rc 
Xglobal configuration
X.TP
X.B ~/.uprc 
Xuser's personal configuration
X.TP
X.B ./up.rc
Xcurrent directory's configuration
X.br
X.ne 5
X.PD
X.SH "SEE ALSO"
XPostScript Language Reference Manual, perl(1), ptroff(1), enscript(1),
Xpsdvi(1), dvips(1), uprc(5)
X.SH AUTHOR
XJ Greely (jgreely@cis.ohio-state.edu), Ohio State University, Department
Xof Computer and Information Science, etc.  Laws warranted where voided
Xby Prohibition.
X.SH STATUS
XHighly experimental, and dangerous in the wrong hands.  Not to be used
Xwhile under the influence of whimsy.
X.SH BUGS
XDoesn't seem to work with psdvi output, although dvips (3.4) works.
X.PP
XThe configuration file parsing is less than robust.
X.PP
XSome would say that the use of
X.I Perl
Xis a bug.
X.PP
XThe way I test for conformance with Adobe's document structuring
Xconventions is iffy.  I don't apologize for it, but I don't like it,
Xeither.  Eventually, I'll break down and do proper checking, probably
Xwhen I convert it all to C.
X.PP
X.IR Makeup 's
Xpage numbering doesn't fit within the margins after page 999.  I have
Xno intention of fixing this.
END_OF_FILE
if test 2731 -ne `wc -c <'up.1'`; then
    echo shar: \"'up.1'\" unpacked with wrong size!
fi
# end of 'up.1'
fi
if test -f 'makeup.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makeup.1'\"
else
echo shar: Extracting \"'makeup.1'\" \(14 characters\)
sed "s/^X//" >'makeup.1' <<'END_OF_FILE'
X.so man1/up.1
END_OF_FILE
if test 14 -ne `wc -c <'makeup.1'`; then
    echo shar: \"'makeup.1'\" unpacked with wrong size!
fi
# end of 'makeup.1'
fi
if test -f 'parr.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'parr.1'\"
else
echo shar: Extracting \"'parr.1'\" \(1245 characters\)
sed "s/^X//" >'parr.1' <<'END_OF_FILE'
X.TH PARR 1 "23 October 1989"
X.SH NAME
Xparr \- rearrange pages in a PostScript file, for signatures
X.SH SYNOPSIS
X.B parr
X[
X.B \-r
X] [
X.B \-s
X] [
X.B \-S
X.I sheets
X] [
X.B \-o
X.I pagelist
X] [file]
X.SH DESCRIPTION
X.I Parr
Xreads a conforming PostScript file, and rearranges the pages in
Xinteresting ways, of which the primary one is signature order (for
Xdouble-sided, two-up printing).  Pages can be printed more than once
Xor not at all, and blank pages may be inserted anywhere.
X.SH OPTIONS
X.TP
X.B \-r
XJust print the page order to stdout.
X.TP
X.B \-s
XPrint in signature order.  Default is to make one large signature,
Xunless the 
X.B \-S
Xoption is used.  The output is meant to be passed through "up -n pup".
X.TP
X.B \-S
X.I sheets
XImplies the
X.B \-s
Xflag.  Used to indicate how many sheets should be in each signature.
XNote that this is the number of
X.I double-sided
Xsheets.
X.TP
X.B \-o
X.I pagelist
XArbitrary order.  Pages are specified as a comma-separated list of
Xpage ranges, like this: 21-,11-19,20,-10.  A 'B' may be used to
Xindicate the printing of a blank page.
X.SH "SEE ALSO"
XPostScript Language Reference Manual, up(1)
X.SH AUTHOR
XJ Greely (jgreely@cis.ohio-state.edu), Ohio State University, Department
Xof Computer and Information Science, etc.
END_OF_FILE
if test 1245 -ne `wc -c <'parr.1'`; then
    echo shar: \"'parr.1'\" unpacked with wrong size!
fi
# end of 'parr.1'
fi
if test -f 'uprc.5' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uprc.5'\"
else
echo shar: Extracting \"'uprc.5'\" \(2484 characters\)
sed "s/^X//" >'uprc.5' <<'END_OF_FILE'
X.TH UPRC 5 "24 August 1989"
X.SH NAME
Xuprc \- layout configuration file for "up"
X.SH DESCRIPTION
XThe
X.I uprc
Xfile contains all of the information necessary to describe a page
Xlayout for the
X.I up
Xutility.  The format is simple, but capable of some impressively
Xtwisted output.  A sample configuration is given below, followed by a
Xcomplete explanation.  Records in a file begin with a line containing
Xeither "name=something" or "prolog=", and end with a line containing
Xjust a period.
X.IP
X prolog=
X /inch {72 mul} def
X /moveU {0 11 inch translate} def
X /moveR {8.5 inch 0 translate} def
X /moveD {0 -11 inch translate} def
X /moveL {-8.5 inch 0 translate} def
X /rotR {-90 rotate} def
X /rotL {90 rotate} def
X .
X
X name=4up
X modulus=4
X scale=0.2125 inch 0.275 inch translate 0.475 dup scale
X 1=moveU
X 2=moveR
X 3=moveL moveD
X 4=moveR
X .
X.PP
XThe
X.I prolog
Xrecord contains an arbitrary number of lines of PostScript code to be
Xplaced right before the "%%EndProlog" comment in the header.  These
Xcommands must not effect the graphics state, and should only be used
Xto define functions for use at page breaks.  The default header (shown
Xabove) defines functions to move the page origin (in terms of pages),
Xand rotate the co-ordinate space 90 degrees left and right.  More than
Xone header can be present in a file; the
X.I last
Xone found before the desired layout record will be used.
X.PP
XLayout records contain five types of fields.
X.IR name ,
X.IR modulus ,
X.IR even/odd ,
X.IR <number> ,
Xand
X.IR scale .
XThe 
X.I name
Xfield may contain any number of alphanumeric characters, and
Xis what determines the logical record name.  The
X.I modulus
Xfield must contain a decimal number indicating the number of pages to
Xbe placed on a sheet.  There should be fields numbered from 1 through
X.IR modulus ,
Xcontaining the PostScript commands to move the origin to the correct
Xplace for that page (relative to the location of the previously
Xprinted page).  The
X.I scale
Xfield contains PostScript commands that set up the scaling at the
Xbeginning of each sheet.  Despite the name, rotations and translations
Xalso belong here.  The
X.I even/odd
Xfields are used to make even and odd sheets print differently.
XThey're not often useful, but they're handy for preparing double-sided
Xoutput.
X.PP
XBlank lines and lines beginning with a "#" character are ignored.
X.SH FILES
X/usr/local/lib/up.rc, ~/.uprc, ./up.rc
X.SH "SEE ALSO"
Xup(1), PostScript Language Reference Manual
X.SH AUTHOR
XJ Greely (jgreely@cis.ohio-state.edu)
END_OF_FILE
if test 2484 -ne `wc -c <'uprc.5'`; then
    echo shar: \"'uprc.5'\" unpacked with wrong size!
fi
# end of 'uprc.5'
fi
echo shar: End of shell archive.
exit 0