summaryrefslogtreecommitdiff
path: root/dviware/psprint/unix
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/psprint/unix
Initial commit
Diffstat (limited to 'dviware/psprint/unix')
-rw-r--r--dviware/psprint/unix/00readme.txt125
-rw-r--r--dviware/psprint/unix/bad.ps19
-rw-r--r--dviware/psprint/unix/box.ps12
-rw-r--r--dviware/psprint/unix/build9
-rw-r--r--dviware/psprint/unix/ctrld1
-rw-r--r--dviware/psprint/unix/dvireader.h143
-rw-r--r--dviware/psprint/unix/dvireader.p1495
-rw-r--r--dviware/psprint/unix/files.h17
-rw-r--r--dviware/psprint/unix/fontlist.ps97
-rw-r--r--dviware/psprint/unix/fontreader.h9
-rw-r--r--dviware/psprint/unix/fontreader.p926
-rw-r--r--dviware/psprint/unix/fontsample.tex241
-rw-r--r--dviware/psprint/unix/globals.h14
-rw-r--r--dviware/psprint/unix/greybox.ps31
-rw-r--r--dviware/psprint/unix/info.ps107
-rw-r--r--dviware/psprint/unix/lino_fonts.ps68
-rw-r--r--dviware/psprint/unix/lino_header.ps273
-rw-r--r--dviware/psprint/unix/lino_pages.ps16
-rw-r--r--dviware/psprint/unix/lino_trailer.ps1
-rw-r--r--dviware/psprint/unix/lw_fonts.ps43
-rw-r--r--dviware/psprint/unix/lw_header.ps136
-rw-r--r--dviware/psprint/unix/lw_trailer.ps1
-rw-r--r--dviware/psprint/unix/nasty.tex349
-rw-r--r--dviware/psprint/unix/options.h44
-rw-r--r--dviware/psprint/unix/options.p469
-rw-r--r--dviware/psprint/unix/piechart.ps68
-rw-r--r--dviware/psprint/unix/ps.ps20
-rw-r--r--dviware/psprint/unix/ps40_fonts.ps39
-rw-r--r--dviware/psprint/unix/ps40_header.ps67
-rw-r--r--dviware/psprint/unix/psdvi.p859
-rw-r--r--dviware/psprint/unix/psfonts.tex69
-rw-r--r--dviware/psprint/unix/psprint403
-rw-r--r--dviware/psprint/unix/psprint.man358
-rw-r--r--dviware/psprint/unix/pstext.tex73
-rw-r--r--dviware/psprint/unix/pswriter.h58
-rw-r--r--dviware/psprint/unix/pswriter.p340
-rw-r--r--dviware/psprint/unix/random.ps39
-rw-r--r--dviware/psprint/unix/setmargins.ps7
-rw-r--r--dviware/psprint/unix/test.tex13
-rw-r--r--dviware/psprint/unix/tex.ps236
-rw-r--r--dviware/psprint/unix/text.ps83
-rw-r--r--dviware/psprint/unix/two.ps119
-rw-r--r--dviware/psprint/unix/userguide.tex563
-rw-r--r--dviware/psprint/unix/wide.ps117
44 files changed, 8177 insertions, 0 deletions
diff --git a/dviware/psprint/unix/00readme.txt b/dviware/psprint/unix/00readme.txt
new file mode 100644
index 0000000000..f94dcb9723
--- /dev/null
+++ b/dviware/psprint/unix/00readme.txt
@@ -0,0 +1,125 @@
+PSPRINT 3.0 for UNIX, October 1989
+==================================
+Andrew Trevorrow
+
+PSPRINT is a public-domain PostScript driver that can print a DVI file,
+raw PostScript program, or text file on a variety of PostScript printers.
+Currently supported printers are the Apple LaserWriter, DEC's PrintServer 40
+and the Linotronic 300.
+
+This version of PSPRINT was developed on a Pyramid running OS/x.
+It should be reasonably easy to port the program to any other UNIX system
+with a Pascal compiler.
+
+Installation
+------------
+
+1. Use Build to create the psdvi program.
+ You may need to change the Pascal source files to suit your compiler.
+2. Make sure all the files in this directory are world readable or executable.
+3. Copy psprint into something like /usr/bin, edit it and make any changes to
+ suit your site (see in particular the values flagged by SYSDEP).
+
+The important files in this directory
+-------------------------------------
+
+Executable files:
+psprint script that users run
+psdvi program run by psprint to turn DVI file into PostScript
+Build compiles and links psdvi
+
+Documentation and help files:
+userguide.tex LaTeX source for the PSPRINT User Guide
+piechart.ps used in userguide.tex to produce Figure 1
+greybox.ps used in userguide.tex to produce Figure 2
+random.ps used in userguide.tex to produce Figure 3
+psfonts.tex illustrates use of PostScript fonts in a TeX document
+pstext.tex used in psfonts.tex; defines \PStext and \CMtext
+psprint.man source file for on-line help
+
+Pascal source files:
+psdvi.p the main module for psdvi
+globals.h global data and routines
+files.h random file i/o routines
+options.h/p command line interface routines
+dvireader.h/p DVI file access routines
+fontreader.h/p PK and TFM file access routines
+pswriter.h/p PostScript generating routines
+
+Test files:
+nasty.tex TeX source for nasty.dvi, a torture test for psdvi
+bad.ps used by nasty.tex; contains deliberate PostScript error
+box.ps used by nasty.tex; draws a box
+empty.ps used by nasty.tex; empty file
+test.tex TeX source for test.dvi; tests origin position
+
+These files are used by psprint:
+ps.ps prologue for a PostScript job
+tex.ps prologue for a DVI job
+text.ps prologue for a text job
+two.ps prologue for a two-page-per-sheet text job
+wide.ps prologue for a two-wide-page-per-sheet text job
+ctrld contains ^D (sent at end of each lw/lino job)
+lw_header.ps defines @bannerpage and error handler
+lw_trailer.ps calls @bannerpage
+lw_fonts.ps converts TFM names to LaserWriter font names
+lino_header.ps defines @bannerpage, @footerpage, error handler, etc.
+lino_trailer.ps calls @footerpage
+lino_fonts.ps converts TFM names to Linotronic font names
+ps40_header.ps defines error handler
+ps40_fonts.ps converts TFM names to PrintServer font names
+
+Other useful files:
+fontsample.tex TeX source for producing font samples
+fontlist.ps prints a list of the available fonts in your printer
+info.ps to discover various printer details
+lino_pages.ps tests various page setups available in Linotronic
+setmargins.ps permanently adjusts margin settings in LaserWriter
+
+Revision history
+----------------
+
+Version 1.0 was released in January 1988 and was based on an Apollo DOMAIN
+Pascal version (which in turn was based on a VAX/VMS Modula-2 version).
+
+Version 3.0 was released in October 1988 and corresponds to
+VAX/VMS version 3.0 of PSPRINT. Here are the changes to version 1.0:
+
+Changes to psprint:
+ - Many new options have been added:
+ -device lw/lino/ps40 specifies the type of PostScript printer
+ -two will print a text file with two 60-line by 80-col "pages" per A4 sheet
+ -wide will print a text file with two 60-line by 132-col "pages" per A4 sheet
+ -o file saves the PostScript code in given file rather than printing it
+ -q queue overrides the default queue
+ -n string includes given string on the flag page
+ -i integer allows you to print every ith page in the current page range
+ -conserve/-noconserve control the conservation of VM
+ -reverse/-noreverse control the order in which pages are printed
+ -flag/-noflag control whether or not a flag page is produced
+ -manual instructs a LaserWriter to wait for paper to be fed manually
+ -cutmarks/-nocutmarks control whether or not cut marks appear on Lino output
+ -size a3l/a4p/a4l/a5p/a5l/b5p/b5l specifies which Lino page setup to use
+ -lowres switches Linotronic DVI output to "low" resolution (635dpi)
+ -ho dimension shifts DVI output horizontally by given amount
+ -vo dimension shifts DVI output vertically by given amount
+ - A single .tmp file is now created and queued for printing
+ (or renamed if "-o file" is used).
+ - A PSPRINT User Guide has been written.
+
+Changes to psdvi:
+ - The version number is now displayed if -s is used.
+ - psdvi can now handle PostScript fonts.
+ The -P (psprefix) option defines the unique font name prefix used to
+ recognize a PostScript font and the -T (tfmdir) option defines the
+ location of the TFM files for these fonts.
+ - The -ho and -vo options allow horizontal and vertical margin shifting.
+ - The -f (fontdir) option value must end with '/' (as must -t) and is now
+ automatically prepended to the -d (dummyfont) option value.
+ - The limitation requiring a fixed-length fontsize substring in PK file names
+ has been removed.
+ - The search for the end of a DVI file now allows for trailing NUL-bytes
+ (after the terminating 223-bytes) to cope with DVI files that have been
+ transferred to and from a VMS machine.
+ - The copying of header and special files in PSWriter has been speeded up.
+ - The generation of bitmap hex data in FontReader has been speeded up.
diff --git a/dviware/psprint/unix/bad.ps b/dviware/psprint/unix/bad.ps
new file mode 100644
index 0000000000..e419ef5eb6
--- /dev/null
+++ b/dviware/psprint/unix/bad.ps
@@ -0,0 +1,19 @@
+% this file contains deliberate PS error(s) to test error handling
+
+/Courier findfont 20 scalefont setfont
+72 72 moveto
+(hello) show
+
+% put a few objects on stack before error
+
+999999
+mark
+/abc
+(abc)
+[ 0.99 (ABC) /xyz ]
+{ 1 }
+true
+
+xxx % undefined
+
+showpage
diff --git a/dviware/psprint/unix/box.ps b/dviware/psprint/unix/box.ps
new file mode 100644
index 0000000000..b9dfb348ae
--- /dev/null
+++ b/dviware/psprint/unix/box.ps
@@ -0,0 +1,12 @@
+72 72 scale % units are now inches instead of big points
+
+newpath
+ 0 0 moveto % bottom left corner at origin
+ 0 1 rlineto
+ 1 0 rlineto
+ 0 -1 rlineto
+ closepath
+ .1 setlinewidth
+stroke
+
+showpage % redefined to do nothing if this file included in TeX \special
diff --git a/dviware/psprint/unix/build b/dviware/psprint/unix/build
new file mode 100644
index 0000000000..a25ff3e61c
--- /dev/null
+++ b/dviware/psprint/unix/build
@@ -0,0 +1,9 @@
+# Compile (with optimization) and link PSDVI.
+#
+echo options.p ; pascal -OPG -f -c options.p
+echo dvireader.p ; pascal -OPG -f -c dvireader.p
+echo fontreader.p ; pascal -OPG -f -c fontreader.p
+echo pswriter.p ; pascal -OPG -f -c pswriter.p
+echo psdvi.p ; pascal -OPG -f -c psdvi.p
+echo linking psdvi...
+pascal *.o -o psdvi
diff --git a/dviware/psprint/unix/ctrld b/dviware/psprint/unix/ctrld
new file mode 100644
index 0000000000..ce9a8a9d59
--- /dev/null
+++ b/dviware/psprint/unix/ctrld
@@ -0,0 +1 @@
+
diff --git a/dviware/psprint/unix/dvireader.h b/dviware/psprint/unix/dvireader.h
new file mode 100644
index 0000000000..0a0db2c07a
--- /dev/null
+++ b/dviware/psprint/unix/dvireader.h
@@ -0,0 +1,143 @@
+(* DVIReader *)
+
+CONST
+ ruletablesize = 300; (* maximum number of rules in a ruletable *)
+ ruletablesizem = ruletablesize - 1;
+ chartablesize = 3000; (* maximum number of chars in a chartable *)
+ chartablesizem = chartablesize - 1;
+ maxfontspec = maxstring; (* max length of a font file specification *)
+ maxspeciallen = maxstring; (* max length of \special string *)
+ maxTeXchar = 255; (* ignore character codes > 255 *)
+
+TYPE
+ (* Information about the rules and characters appearing on a page is stored
+ in dynamic one-way lists to avoid imposing any limit on their numbers.
+ To reduce pointer overheads, the nodes in these lists contain large
+ tables (the values of ruletablesize and chartablesize have been chosen
+ so that the vast majority of DVI pages will only require one-node lists).
+ When interpreting a DVI page, DVIReader adds a new rule or character node
+ to the TAIL of the relevant list so that when the main program
+ accesses such lists (starting at the head), rules and characters will be
+ processed in somewhat the same sequence as seen in the DVI file; i.e.,
+ top-to-bottom and left-to-right across the page.
+ Since a character list is part of the information stored for a font,
+ the precise sequence in which DVI characters are seen is not remembered.
+ Font information is also linked together in a one-way list, but the
+ ordering is more or less random (see, however, the SortFonts routine).
+ *)
+ ruleinfoptr = ^ruleinfo;
+ ruleinfo = (* a node in a list of ruletables *)
+ RECORD
+ rulecount : INTEGER; (* number of rules in ruletable *)
+ ruletable : ARRAY [0..ruletablesizem] OF
+ RECORD
+ hp, vp : INTEGER; (* pixel coords of rule's ref point *)
+ wd, ht : INTEGER; (* dimensions of rule in pixels *)
+ END;
+ nextrule : ruleinfoptr; (* next node in rule list *)
+ END;
+
+ charinfoptr = ^charinfo;
+ charinfo = (* a node in list of chartables *)
+ RECORD
+ charcount : INTEGER; (* number of chars in chartable *)
+ chartable : ARRAY [0..chartablesizem] OF
+ RECORD
+ hp, vp : INTEGER; (* pixel coords of char's ref point *)
+ code : 0..maxTeXchar; (* char's code and pixeltable index *)
+ END;
+ nextchar : charinfoptr; (* next node in char list *)
+ END;
+
+ (* DVIReader uses wd, ht, xo and yo to calculate minhp, minvp, maxhp and
+ maxvp. dwidth and pwidth are used to advance horizontally.
+ The mapadr and loaded fields are not used by DVIReader; they are used
+ by FontReader and the main program to load character bitmaps.
+ *)
+ pixeltableptr = ^pixeltable;
+ pixeltable = ARRAY [0..maxTeXchar] OF
+ RECORD
+ wd, ht : INTEGER; (* glyph width and height in pixels; they
+ define the size of the smallest box
+ containing all the black pixels *)
+ xo, yo : INTEGER; (* x and y offsets from top left corner
+ of glyph to character's reference point *)
+ dwidth : INTEGER; (* advance width in DVI units computed from
+ fix width stored in font file *)
+ pwidth : INTEGER; (* advance width in pixels computed from
+ fix width stored in font file *)
+ mapadr : INTEGER; (* byte offset of bitmap info in font file *)
+ loaded : BOOLEAN; (* has bitmap been downloaded? *)
+ END;
+
+ fontinfoptr = ^fontinfo;
+ fontinfo = (* a node in list of fonts *)
+ RECORD
+ psfont : BOOLEAN; (* is this a PostScript font? *)
+ fontused : BOOLEAN; (* is font used on current page? *)
+ fontnum : INTEGER; (* DVI font number: -2^31 .. 2^30 - 1 *)
+ scaledsize : INTEGER; (* scaled font size in DVI units *)
+ designsize : INTEGER; (* design size in DVI units *)
+ fontarea : string; (* explicit font directory *)
+ fontarealen : INTEGER; (* length of fontarea *)
+ fontname : string; (* font name; e.g., "cmr10" *)
+ fontnamelen : INTEGER; (* length of font name *)
+ fontspec : string; (* complete font file pathname *)
+ fontspeclen : INTEGER; (* length of fontspec *)
+ fontexists : BOOLEAN; (* can fontspec be opened? *)
+ fontid : string; (* unique font identifier *)
+ totalchars : INTEGER; (* number of chars from font on page *)
+ charlist : charinfoptr; (* head of char information list *)
+ chartail : charinfoptr; (* tail of char information list *)
+ pixelptr : pixeltableptr; (* allocated once: 1st time font used *)
+ nextfont : fontinfoptr; (* next node in font list *)
+ END;
+
+ (* For the parameter in MoveToTeXPage: *)
+ TeXcounters = ARRAY [0..9] OF INTEGER;
+ TeXpageinfo =
+ RECORD
+ value : TeXcounters; (* \count0..\count9 values *)
+ present : ARRAY [0..9] OF BOOLEAN; (* is counter relevant? *)
+ lastvalue : 0..9; (* last relevant counter *)
+ END;
+
+ (* DVIReader also builds a list of \special info: *)
+ specialinfoptr = ^specialinfo;
+ specialinfo = RECORD
+ special : string;
+ hp, vp : INTEGER;
+ nextspecial : specialinfoptr;
+ END;
+
+
+VAR
+ (* Most of these should be treated as read-only parameters: *)
+ DVImag : INTEGER; (* magnification stored in DVI file *)
+ totalpages : INTEGER; (* number of pages in DVI file *)
+ totalfonts : INTEGER; (* number of fonts in DVI file *)
+ currDVIpage : INTEGER; (* updated by MoveTo... calls *)
+ currTeXpage : TeXcounters; (* ditto *)
+ speciallist : specialinfoptr; (* head of \special information list *)
+ totalrules : INTEGER; (* number of rules on current page *)
+ rulelist : ruleinfoptr; (* head of rule information list *)
+ ruletail : ruleinfoptr; (* tail of rule information list *)
+ fontlist : fontinfoptr; (* head of font information list *)
+ currfont : fontinfoptr; (* InterpretPage's current font info *)
+ pageempty : BOOLEAN; (* is page empty of rules and chars? *)
+ minhp : INTEGER; (* minimum horizontal pixel coordinate *)
+ minvp : INTEGER; (* minimum vertical pixel coordinate *)
+ maxhp : INTEGER; (* maximum horizontal pixel coordinate *)
+ maxvp : INTEGER; (* maximum vertical pixel coordinate *)
+
+PROCEDURE InitDVIReader; EXTERNAL;
+PROCEDURE OpenDVIFile (name : string); EXTERNAL;
+PROCEDURE SetConversionFactor (resolution, magnification : INTEGER); EXTERNAL;
+FUNCTION PixelRound (DVIunits : INTEGER) : INTEGER; EXTERNAL;
+PROCEDURE MoveToDVIPage (n : INTEGER); EXTERNAL;
+PROCEDURE MoveToNextPage (ascending : BOOLEAN); EXTERNAL;
+FUNCTION MoveToTeXPage (VAR newTeXpage : TeXpageinfo) : BOOLEAN; EXTERNAL;
+FUNCTION CurrMatchesNew (VAR newTeXpage : TeXpageinfo) : BOOLEAN; EXTERNAL;
+PROCEDURE InterpretPage; EXTERNAL;
+PROCEDURE SortFonts (VAR unusedlist : fontinfoptr); EXTERNAL;
+PROCEDURE CloseDVIFile; EXTERNAL;
diff --git a/dviware/psprint/unix/dvireader.p b/dviware/psprint/unix/dvireader.p
new file mode 100644
index 0000000000..152a8d6844
--- /dev/null
+++ b/dviware/psprint/unix/dvireader.p
@@ -0,0 +1,1495 @@
+(* Routines and data structures for use in a TeX82 DVI translator.
+ Much of the code in DVIReader is based on DVITYPE 2.7 by Donald Knuth.
+ DVITYPE is a program for verifying a DVI file and also serves as a model
+ for other DVI-reading programs. See the TeXWARE manual by Knuth for a
+ complete description of DVITYPE and the format of DVI files.
+ For efficiency reasons we assume the given DVI file is formatted correctly;
+ it is the job of DVITYPE to diagnose bad DVI files.
+*)
+
+#include 'globals.h';
+#include 'files.h';
+#include 'dvireader.h';
+#include 'fontreader.h';
+#include 'fontreader.h'; (* only PixelTableRoutine *)
+#include 'options.h'; (* hoffset and voffset *)
+
+(*******************************************************************************
+ DECLARATIONS FOR ACCESSING BYTES IN A DVI FILE
+
+ A DVI file is a stream of 8-bit bytes. Once opened, we can access any byte
+ by setting DVIoffset to the required position and then calling GetDVIByte.
+*)
+
+VAR
+ DVIfile : integer; (* DVI file descriptor *)
+ DVIoffset : INTEGER; (* current byte offset in DVIfile *)
+ currDVIbuff : INTEGER; (* starting byte offset in buffer *)
+ DVIbuff : buffer; (* input buffer *)
+ postpostid : INTEGER; (* offset of postpost's id byte *)
+
+(*******************************************************************************
+ DECLARATIONS FOR GETTING TO A DVI PAGE
+
+ The user can select a particular page by specifying a DVI page
+ number (from 1 to totalpages), or a TeX page number (based on the
+ values of \count0,\count1,...,\count9), or simply requesting the next page
+ in the DVI file (which depends on whether we are ascending or not).
+ We will often need to follow the DVI backpointers to locate the bop byte
+ of a selected page.
+*)
+
+VAR
+ curreop, (* position of eop byte of current page *)
+ currbop, (* position of bop byte of current page *)
+ lastbop : INTEGER; (* position of last bop byte *)
+ prevbop : INTEGER; (* position of bop byte of previous page;
+ note that prevbop of first page = -1 *)
+
+(*******************************************************************************
+ DECLARATIONS FOR INTERPRETING A DVI PAGE
+
+ The commands between the bop and eop bytes for a particular page need to be
+ translated (based on the method used by DVITYPE) before we can determine the
+ the position and shape of all rules on that page, as well as the position
+ of all characters and which fonts they belong to.
+*)
+
+CONST
+ (* Use symbolic names for the opcodes of DVI commands: *)
+ setchar0 = 0; (* setchar1..setchar127 = 1..127 *)
+ set1 = 128; (* set2,set3,set4 = 129,130,131 *)
+ setrule = 132;
+ put1 = 133; (* put2,put3,put4 = 134,135,136 *)
+ putrule = 137;
+ nop = 138;
+ bop = 139;
+ eop = 140;
+ push = 141;
+ pop = 142;
+ right1 = 143; w0 = 147; x0 = 152; down1 = 157; y0 = 161; z0 = 166;
+ right2 = 144; w1 = 148; x1 = 153; down2 = 158; y1 = 162; z1 = 167;
+ right3 = 145; w2 = 149; x2 = 154; down3 = 159; y2 = 163; z2 = 168;
+ right4 = 146; w3 = 150; x3 = 155; down4 = 160; y3 = 164; z3 = 169;
+ w4 = 151; x4 = 156; y4 = 165; z4 = 170;
+ fntnum0 = 171; (* fntnum1..fntnum63 = 172..234 *)
+ fnt1 = 235; (* fnt2,fnt3,fnt4 = 236,237,238 *)
+ xxx1 = 239; (* xxx2,xxx3,xxx4 = 240,241,242 *)
+ fntdef1 = 243; (* fntdef2,fntdef3,fntdef4 = 244,245,246 *)
+ pre = 247;
+ post = 248;
+ postpost = 249;
+ (* undefined commands = 250..255 *)
+
+ maxstacksize = 100; (* maximum stack size for state values *)
+ maxstacksizem = maxstacksize - 1;
+ maxdrift = 2; (* prevent hh & vv from drifting too far *)
+ maxint = 2147483647; (* 2^31 - 1 *)
+
+VAR
+ DVIcommand : 0..255; (* holds next DVI command *)
+ maxstack, (* max pushes over pops in DVI file *)
+ num, (* DVI numerator *)
+ den : INTEGER; (* DVI denominator *)
+ conv : REAL; (* converts DVI units to pixels *)
+ h, v, (* current pos on page in DVI units *)
+ w, x, (* horizontal increments in DVI units *)
+ y, z, (* vertical increments in DVI units *)
+ hh, vv : INTEGER; (* h and v in pixels (approx) *)
+ hhh, vvv : INTEGER; (* h and v rounded to nearest pixel *)
+ hstack, vstack, (* push down stacks for state values *)
+ wstack, xstack,
+ ystack, zstack,
+ hhstack, vvstack : ARRAY [0..maxstacksizem] OF INTEGER;
+ stackpos : 0..maxstacksize; (* stacks empty when stackpos = 0,
+ i.e., top of stacks = stackpos - 1 *)
+ fontspace : INTEGER; (* used in DoRight and DoDown *)
+ thisrule : ruleinfoptr; (* temporary pointer to node in rulelist *)
+ thischar : charinfoptr; (* temporary pointer to node in charlist *)
+ thisspecial : specialinfoptr; (* temporary ptr to node in speciallist *)
+
+
+(******************************************************************************)
+
+(* Here are the functions used to get byte/s from DVIfile.
+ They are essentially the same as those used in DVITYPE.
+*)
+
+FUNCTION GetDVIByte : INTEGER;
+
+(* Returns the value (unsigned) of the byte at DVIoffset and
+ advances DVIoffset for the next GetDVIByte.
+ Buffering is used to reduce the number of IOS calls.
+*)
+
+VAR buffstart, result : INTEGER;
+
+BEGIN
+buffstart := (DVIoffset DIV bufflen) * bufflen; (* 0, bufflen, 2*bufflen... *)
+IF buffstart <> currDVIbuff THEN BEGIN
+ currDVIbuff := buffstart;
+ result := lseek(DVIfile, buffstart, 0);
+ { DEBUG
+ IF result <> buffstart THEN BEGIN
+ writeln('Lseek failed in GetDVIByte!'); exit(1);
+ END;
+ GUBED }
+ result := read(DVIfile, DVIbuff, bufflen);
+ { DEBUG
+ IF result = -1 THEN BEGIN
+ writeln('Read failed in GetDVIByte!'); exit(1);
+ END;
+ GUBED }
+END;
+GetDVIByte := ORD(DVIbuff[DVIoffset - buffstart]);
+DVIoffset := DVIoffset + 1;
+END; (* GetDVIByte *)
+
+(******************************************************************************)
+
+FUNCTION SignedDVIByte : INTEGER; (* the next byte, signed *)
+
+VAR b : INTEGER;
+
+BEGIN
+b := GetDVIByte;
+IF b < 128 THEN
+ SignedDVIByte := b
+ELSE
+ SignedDVIByte := b - 256;
+END; (* SignedDVIByte *)
+
+(******************************************************************************)
+
+FUNCTION GetTwoDVIBytes : INTEGER; (* the next 2 bytes, unsigned *)
+
+VAR a, b : INTEGER;
+
+BEGIN
+a := GetDVIByte;
+b := GetDVIByte;
+GetTwoDVIBytes := a * 256 + b;
+END; (* GetTwoDVIBytes *)
+
+(******************************************************************************)
+
+FUNCTION SignedDVIPair : INTEGER; (* the next 2 bytes, signed *)
+
+VAR a, b : INTEGER;
+
+BEGIN
+a := GetDVIByte;
+b := GetDVIByte;
+IF a < 128 THEN
+ SignedDVIPair := a * 256 + b
+ELSE
+ SignedDVIPair := (a - 256) * 256 + b;
+END; (* SignedDVIPair *)
+
+(******************************************************************************)
+
+FUNCTION GetThreeDVIBytes : INTEGER; (* the next 3 bytes, unsigned *)
+
+VAR a, b, c : INTEGER;
+
+BEGIN
+a := GetDVIByte;
+b := GetDVIByte;
+c := GetDVIByte;
+GetThreeDVIBytes := (a * 256 + b) * 256 + c;
+END; (* GetThreeDVIBytes *)
+
+(******************************************************************************)
+
+FUNCTION SignedDVITrio : INTEGER; (* the next 3 bytes, signed *)
+
+VAR a, b, c : INTEGER;
+
+BEGIN
+a := GetDVIByte;
+b := GetDVIByte;
+c := GetDVIByte;
+IF a < 128 THEN
+ SignedDVITrio := (a * 256 + b) * 256 + c
+ELSE
+ SignedDVITrio := ((a - 256) * 256 + b) * 256 + c;
+END; (* SignedDVITrio *)
+
+(******************************************************************************)
+
+FUNCTION SignedDVIQuad : INTEGER; (* the next 4 bytes, signed *)
+
+TYPE int_or_bytes = RECORD
+ CASE b : BOOLEAN OF
+ TRUE : (int : INTEGER);
+ FALSE : (byt : PACKED ARRAY [0..3] OF CHAR);
+ END;
+
+VAR w : int_or_bytes;
+
+BEGIN
+WITH w DO BEGIN
+ w.byt[0] := CHR(GetDVIByte);
+ w.byt[1] := CHR(GetDVIByte);
+ w.byt[2] := CHR(GetDVIByte);
+ w.byt[3] := CHR(GetDVIByte);
+END;
+SignedDVIQuad := w.int;
+(* Pyramid Pascal returns incorrect answer if a >= 128!!!
+IF a < 128 THEN
+ SignedDVIQuad := ((a * 256 + b) * 256 + c) * 256 + d
+ELSE
+ SignedDVIQuad := (((a - 256) * 256 + b) * 256 + c) * 256 + d;
+*)
+END; (* SignedDVIQuad *)
+
+(******************************************************************************)
+
+PROCEDURE ProcessPostamble;
+
+(* Having successfully opened the DVI file, we find the postamble
+ and initialize these global variables:
+ lastbop, num, den, DVImag, maxstack, totalpages.
+ The font definitions are read by ProcessFontDefs.
+*)
+
+VAR postamblepos, postamble, pagehtplusdp, pagewidth : INTEGER;
+
+BEGIN
+DVIoffset := postpostid - 4;
+postamblepos := SignedDVIQuad; (* get post_post's postamble ptr *)
+DVIoffset := postamblepos;
+postamble := GetDVIByte;
+lastbop := SignedDVIQuad;
+num := SignedDVIQuad;
+den := SignedDVIQuad;
+DVImag := SignedDVIQuad;
+pagehtplusdp := SignedDVIQuad;
+pagewidth := SignedDVIQuad;
+maxstack := SignedDVIPair;
+totalpages := SignedDVIPair;
+IF maxstack > maxstacksize THEN BEGIN
+ writeln; writeln('Stack capacity exceeded!'); exit(1);
+ (* now we don't need to test for stack overflow in DoPush *)
+END;
+{ DEBUG
+ writeln('postamble opcode = ', postamble:1);
+ writeln('postion of last bop = ', lastbop:1);
+ writeln('num = ', num:1);
+ writeln('den = ', den:1);
+ writeln('DVI mag = ', DVImag:1);
+ writeln('ht+dp of tallest page = ', pagehtplusdp:1);
+ writeln('width of widest page = ', pagewidth:1);
+ writeln('max stack depth = ', maxstack:1);
+ writeln('total # of pages = ', totalpages:1);
+GUBED }
+END; (* ProcessPostamble *)
+
+(******************************************************************************)
+
+PROCEDURE ProcessFontDefs;
+
+(* Read the fntdef commands in the postamble (fntdef commands in the DVI
+ pages will be skipped) and store the information in the font list.
+ (Note that complete fontspecs are NOT built here because DVIReader does not
+ want to know about the format or naming conventions of font files.)
+ Since ProcessPostamble ended by reading the totalpages parameter, the
+ next GetDVIByte should return nop or first fntdef.
+*)
+
+VAR f, c, s, d, a, l : INTEGER; (* hold fntdef parameters *)
+ i : INTEGER; ch : CHAR; (* for getting farea and fname *)
+ farea, fname : string; (* a and l bytes long respectively *)
+
+BEGIN
+totalfonts := 0; (* number of nodes in font list *)
+fontlist := NIL;
+REPEAT
+ DVIcommand := GetDVIByte;
+ IF (DVIcommand >= fntdef1) AND (DVIcommand <= fntdef1+3) THEN BEGIN
+ CASE DVIcommand - fntdef1 OF
+ 0 : f := GetDVIByte;
+ 1 : f := GetTwoDVIBytes;
+ 2 : f := GetThreeDVIBytes;
+ 3 : f := SignedDVIQuad
+ END;
+ c := SignedDVIQuad; (* checksum; ignore it *)
+ s := SignedDVIQuad; (* scaled size *)
+ d := SignedDVIQuad; (* design size *)
+ a := GetDVIByte; (* length of font area *)
+ l := GetDVIByte; (* length of font name *)
+ farea := ''; (* initialize with blanks *)
+ FOR i := 0 TO a-1 DO BEGIN (* read and store font area *)
+ ch := CHR(GetDVIByte);
+ IF i < maxfontspec THEN farea[i] := ch;
+ END;
+ fname := '';
+ FOR i := 0 TO l-1 DO BEGIN (* read and store font name *)
+ ch := CHR(GetDVIByte);
+ IF i < maxfontspec THEN fname[i] := ch;
+ END;
+ NEW(currfont);
+ WITH currfont^ DO BEGIN
+ fontused := FALSE;
+ fontnum := f;
+ scaledsize := s;
+ designsize := d;
+ fontarea := farea; fontarealen := a;
+ fontname := fname; fontnamelen := l;
+ fontspec := '';
+ fontspeclen := 0; (* fontspec is built in FontReader *)
+ fontexists := FALSE; (* becomes TRUE if fontspec can be opened *)
+ totalchars := 0;
+ charlist := NIL; (* first node allocated in DoFont *)
+ chartail := NIL; (* nodes are added to tail of char list *)
+ pixelptr := NIL; (* allocated once per font; see DoFont *)
+ nextfont := fontlist;
+ END;
+ fontlist := currfont; (* add new font to head of list *)
+ totalfonts := totalfonts + 1;
+ END
+ ELSE IF DVIcommand = nop THEN
+ (* nop commands can occur between DVI commands *)
+ ELSE IF DVIcommand = postpost THEN
+ (* we have reached end of postamble *)
+ ELSE BEGIN
+ writeln; writeln('Unexpected DVI command in postamble = ', DVIcommand:1);
+ exit(1);
+ END;
+UNTIL DVIcommand = postpost;
+END; (* ProcessFontDefs *)
+
+(******************************************************************************)
+
+PROCEDURE OpenDVIFile (name : string);
+
+(* If the given file can be opened and is a valid TeX82 DVI file then
+ the following global variables are initialized:
+
+ DVImag := magnification value stored in DVI file (TeX's \mag)
+ totalpages := total number of pages in DVI file
+ currDVIpage := 0 (and remains so until a page is selected)
+ currTeXpage := ten 0s (ditto)
+ totalfonts := total number of fonts in DVI file (= nodes in font list)
+ fontlist^. (nodes are added to head of list)
+ fontused := FALSE
+ fontnum := internal DVI font number
+ scaledsize := scaled size of font (in DVI units)
+ designsize := design size of font (in DVI units)
+ fontarea := a string of min(fontarealen,maxfontspec) characters
+ fontname := a string of min(fontnamelen,maxfontspec) characters
+ fontspec := a null string (fontspeclen := 0)
+ fontexists := FALSE
+ totalchars := 0
+ charlist := NIL
+ chartail := NIL
+ pixelptr := NIL
+ nextfont := next node in font list (if not NIL)
+*)
+
+LABEL 666, 777, 888;
+
+VAR length, i : integer;
+
+BEGIN
+currDVIbuff := -1; (* impossible value for first GetDVIByte *)
+length := 0;
+WHILE length < maxstring DO BEGIN
+ IF name[length] = ' ' THEN goto 888;
+ length := length + 1;
+END;
+888:
+IF length < maxstring THEN name[length] := CHR(0); (* terminate with NULL *)
+DVIfile := open(name, O_RDONLY, 0);
+IF length < maxstring THEN name[length] := ' '; (* restore space *)
+IF DVIfile >= 0 THEN BEGIN
+ (* get offset of last DVI byte *)
+ DVIoffset := lseek(DVIfile, 0, 2);
+ IF DVIoffset = -1 THEN BEGIN
+ writeln('Failed to find end of file!'); exit(1);
+ END;
+ IF DVIoffset = 0 THEN BEGIN
+ writeln('File is empty!'); exit(1);
+ END;
+ { DEBUG
+ writeln('total bytes = ', DVIoffset:1);
+ GUBED }
+ DVIoffset := DVIoffset - 1;
+ WHILE TRUE DO BEGIN (* skip any NULs *)
+ IF GetDVIByte <> 0 THEN goto 777;
+ IF DVIoffset = 1 THEN goto 777; (* start of file! *)
+ DVIoffset := DVIoffset - 2; (* GetDVIByte increments *)
+ END;
+ 777:
+ DVIoffset := DVIoffset - 1;
+ WHILE TRUE DO BEGIN (* skip 223s *)
+ IF GetDVIByte <> 223 THEN goto 666;
+ IF DVIoffset = 1 THEN goto 666; (* start of file! *)
+ DVIoffset := DVIoffset - 2; (* GetDVIByte increments *)
+ END;
+ 666:
+ DVIoffset := DVIoffset - 1;
+ postpostid := DVIoffset; (* remember offset of id byte *)
+ IF GetDVIByte <> 2 THEN BEGIN
+ writeln(name:length,' is not a valid DVI file!'); exit(1);
+ END
+ ELSE BEGIN
+ ProcessPostamble; (* get DVImag, totalpages, etc *)
+ ProcessFontDefs; (* build and initialize font list *)
+ currDVIpage := 0; (* we haven't processed a page yet *)
+ FOR i := 0 TO 9 DO currTeXpage[i] := 0;
+ END;
+END
+ELSE BEGIN
+ writeln('Couldn''t open file: ', name:length); exit(1);
+END;
+END; (* OpenDVIFile *)
+
+(******************************************************************************)
+
+PROCEDURE SkipFntdef (which : INTEGER);
+
+(* Read past a fntdef command without interpreting it. *)
+
+VAR dummy, a, l, i : INTEGER;
+
+BEGIN
+CASE which OF (* which = DVIcommand - fntdef1 *)
+ 0 : dummy := GetDVIByte;
+ 1 : dummy := GetTwoDVIBytes;
+ 2 : dummy := GetThreeDVIBytes;
+ 3 : dummy := SignedDVIQuad
+END;
+dummy := SignedDVIQuad;
+dummy := SignedDVIQuad;
+dummy := SignedDVIQuad;
+a := GetDVIByte; (* length of directory *)
+l := GetDVIByte; (* length of font name *)
+FOR i := 1 TO l+a DO
+ dummy := GetDVIByte;
+END; (* SkipFntdef *)
+
+(******************************************************************************)
+
+PROCEDURE ReadFirstBop;
+
+(* Read first bop by skipping past preamble; update currbop and currDVIpage. *)
+
+VAR k, i, dummy : INTEGER;
+
+BEGIN
+DVIoffset := 14; (* position of preamble's k parameter *)
+k := GetDVIByte; (* length of x parameter *)
+FOR i := 1 TO k DO
+ dummy := GetDVIByte; (* skip preamble comment *)
+REPEAT (* skip any nops and fntdefs *)
+ DVIcommand := GetDVIByte;
+ IF (DVIcommand = nop) OR (DVIcommand = bop) THEN
+ (* do nothing *)
+ ELSE IF (DVIcommand >= fntdef1) AND (DVIcommand <= fntdef1+3) THEN
+ SkipFntdef(DVIcommand - fntdef1)
+ ELSE BEGIN
+ writeln;
+ writeln('Unexpected DVI command before first bop = ', DVIcommand:1);
+ exit(1);
+ END;
+UNTIL DVIcommand = bop;
+currbop := DVIoffset - 1; (* position in DVI file of first bop *)
+currDVIpage := 1;
+END; (* ReadFirstBop *)
+
+(******************************************************************************)
+
+PROCEDURE ReadNextBop;
+
+(* We are currently positioned after an eop byte which we know is not the
+ last. This routine positions us after the next bop byte and updates
+ currbop and currDVIpage.
+*)
+
+BEGIN
+REPEAT (* skip any nops and fntdefs *)
+ DVIcommand := GetDVIByte;
+ IF (DVIcommand = nop) OR (DVIcommand = bop) THEN
+ (* do nothing *)
+ ELSE IF (DVIcommand >= fntdef1) AND (DVIcommand <= fntdef1+3) THEN
+ SkipFntdef(DVIcommand - fntdef1)
+ ELSE BEGIN
+ writeln;
+ writeln('Unexpected DVI command between eop and bop = ', DVIcommand:1);
+ exit(1);
+ END;
+UNTIL DVIcommand = bop;
+currbop := DVIoffset - 1; (* position in DVI file of this bop *)
+currDVIpage := currDVIpage + 1;
+END; (* ReadNextBop *)
+
+(******************************************************************************)
+
+PROCEDURE ReadBopParameters;
+
+(* We should now be positioned after the bop of desired page, so read
+ the 10 TeX counters and update currTeXpage and prevbop.
+ At the end of this routine we will be at the byte after currbop's parameters
+ and ready to InterpretPage.
+*)
+
+VAR i : INTEGER;
+
+BEGIN
+FOR i := 0 TO 9 DO
+ currTeXpage[i] := SignedDVIQuad;
+prevbop := SignedDVIQuad; (* position of previous bop in DVI file *)
+END; (* ReadBopParameters *)
+
+(******************************************************************************)
+
+PROCEDURE MoveToNextPage (ascending : BOOLEAN);
+
+(* MoveToNextPage will select the next page, depending on the current page
+ and the specified direction. If the value of currDVIpage is 0 (set in
+ OpenDVIFile), then MoveToNextPage will select the first page if ascending is
+ TRUE and the last page if ascending is FALSE. If currDVIpage is > 0 then
+ MoveToNextPage will select currDVIpage+1 if ascending (unless currDVIpage =
+ totalpages, in which case it does nothing), or currDVIpage-1 if descending
+ (unless currDVIpage = 0).
+
+ Before calling InterpretPage, PSDVI must position DVIReader to the
+ desired page by calling one of the MoveTo... routines.
+ The global variables updated if a page is located by any MoveTo... call are:
+ currDVIpage := the current DVI page (1..totalpages)
+ currTeXpage := the ten TeX counter values stored with this page
+ Note that currDVIpage is initially 0 until one of these routines succeeds.
+*)
+
+LABEL 999;
+
+BEGIN
+IF (currDVIpage = 1) AND (NOT ascending) THEN
+ goto 999
+ELSE IF (currDVIpage = totalpages) AND ascending THEN
+ goto 999
+ELSE IF currDVIpage = 0 THEN
+ (* we haven't processed a page yet *)
+ IF ascending THEN (* get first page *)
+ ReadFirstBop
+ ELSE BEGIN (* get last page *)
+ currbop := lastbop;
+ DVIoffset := currbop + 1;
+ currDVIpage := totalpages;
+ END
+ELSE
+ IF ascending THEN
+ (* currently positioned after eop of currDVIpage, so get next bop *)
+ ReadNextBop
+ ELSE BEGIN
+ (* move to bop pointed to by currbop's backpointer *)
+ currbop := prevbop;
+ DVIoffset := currbop + 1; (* move to byte after previous bop *)
+ currDVIpage := currDVIpage - 1;
+ END;
+ReadBopParameters; (* update currTeXpage and prevbop *)
+999:
+END; (* MoveToNextPage *)
+
+(******************************************************************************)
+
+PROCEDURE MoveToDVIPage (n : INTEGER);
+
+(* Move to nth DVI page; n should be in 1..totalpages. *)
+
+LABEL 888, 999;
+
+BEGIN
+IF (n < 1) OR (n > totalpages) THEN (* do nothing *)
+ goto 999
+ELSE IF n = 1 THEN
+ (* Note that this test must come before next test so that we avoid any
+ problems when currDVIpage initially = 0. *)
+ ReadFirstBop
+(* We have removed the ELSIF code because it assumes InterpretPage is called
+ after every MoveTo... routine (which PSDVI does NOT call when locating the
+ first and final pages of a given subrange).
+ELSE IF n = currDVIpage + 1 THEN
+ ReadNextBop
+*)
+ELSE BEGIN
+ IF n < currDVIpage THEN BEGIN
+ currbop := prevbop; (* start searching backwards from previous page *)
+ currDVIpage := currDVIpage - 1;
+ END
+ ELSE IF n > currDVIpage THEN BEGIN
+ currbop := lastbop; (* start searching backwards from last page *)
+ currDVIpage := totalpages;
+ END;
+ (* if n = currDVIpage we'll just move back to currbop *)
+ (* n is now <= currDVIpage so search by following backpointers *)
+ WHILE TRUE DO
+ IF n = currDVIpage THEN BEGIN
+ DVIoffset := currbop + 1; (* move to byte after currbop *)
+ goto 888;
+ END
+ ELSE BEGIN
+ DVIoffset := currbop + 41; (* move to location of backpointer *)
+ currbop := SignedDVIQuad; (* get location of previous page *)
+ currDVIpage := currDVIpage - 1;
+ END;
+ 888:
+END;
+ReadBopParameters; (* update currTeXpage and prevbop *)
+999:
+END; (* MoveToDVIPage *)
+
+(******************************************************************************)
+
+FUNCTION CurrMatchesNew (VAR newTeXpage : TeXpageinfo) : BOOLEAN;
+
+(* Return TRUE iff currTeXpage matches newTeXpage. *)
+
+VAR i : 0..9;
+
+BEGIN
+CurrMatchesNew := TRUE;
+WITH newTeXpage DO
+ FOR i := 0 TO lastvalue DO
+ IF present[i] THEN
+ IF value[i] <> currTeXpage[i] THEN
+ CurrMatchesNew := FALSE;
+END; (* CurrMatchesNew *)
+
+(******************************************************************************)
+
+FUNCTION MoveToTeXPage (VAR newTeXpage : TeXpageinfo) : BOOLEAN;
+
+(* MoveToTeXPage will search for the lowest DVI page matching the given TeX page
+ specification. (TeX stores the values of \count0,\count1,...,\count9 with
+ every DVI page. Plain TeX uses \count0 to control page numbering.)
+ newTeXpage is a VAR parameter only for efficiency; it won't be changed.
+ The value array stores the requested counter values, the present array
+ indicates which counters are relevant and lastvalue indicates
+ the position (0..9) of the last relevant counter.
+
+ PSDVI converts a more friendly representation
+ of a TeX page request into the TeXpageinfo format. For example,
+ [2..5] would be converted to: and [] would be converted to:
+ value = [2,?,5,?,?,?,?,?,?,?] value = [?,?,?,?,?,?,?,?,?,?]
+ present = [T,F,T,?,?,?,?,?,?,?] present = [F,?,?,?,?,?,?,?,?,?]
+ lastvalue = 2 lastvalue = 0
+ MoveToTeXPage returns TRUE iff the requested TeX page is located.
+*)
+
+LABEL 999;
+
+VAR savecurrbop, savecurrDVIpage : INTEGER;
+ nextbop : INTEGER;
+ i : INTEGER;
+ atleastone : BOOLEAN;
+
+BEGIN
+(* save away current page and DVI position *)
+savecurrDVIpage := currDVIpage;
+IF currDVIpage <> 0 THEN (* only if we've processed a page *)
+ savecurrbop := currbop;
+ (* note that curreop is saved in last InterpretPage *)
+(* search backwards through all DVI pages for lowest matching page *)
+atleastone := FALSE;
+nextbop := lastbop;
+FOR i := totalpages DOWNTO 1 DO BEGIN
+ DVIoffset := nextbop + 1;
+ ReadBopParameters; (* update currTeXpage and prevbop *)
+ IF CurrMatchesNew(newTeXpage) THEN BEGIN
+ currbop := nextbop;
+ currDVIpage := i;
+ atleastone := TRUE;
+ END;
+ nextbop := prevbop;
+END;
+IF NOT atleastone THEN BEGIN (* no match, so restore currDVIpage *)
+ currDVIpage := savecurrDVIpage;
+ IF currDVIpage <> 0 THEN BEGIN (* restore page and positioning info *)
+ currbop := savecurrbop;
+ DVIoffset := currbop + 1;
+ ReadBopParameters; (* restore currTeXpage and prevbop *)
+ DVIoffset := curreop + 1;
+ (* we should now be after the eop byte of the original page *)
+ END;
+ MoveToTeXPage := FALSE;
+ goto 999;
+END
+ELSE (* we found lowest matching page *)
+ DVIoffset := currbop + 1;
+ReadBopParameters; (* update currTeXpage and prevbop *)
+MoveToTeXPage := TRUE;
+999:
+END; (* MoveToTeXPage *)
+
+(******************************************************************************)
+
+PROCEDURE SetConversionFactor (resolution, magnification : INTEGER);
+
+(* This routine must be called before the first InterpretPage call.
+ DVIReader needs to know the resolution and magnification values
+ before it attempts to convert DVI units into pixel values.
+*)
+
+BEGIN
+conv := num/254000.0 * resolution/den * magnification/1000.0;
+END; (* SetConversionFactor *)
+
+(******************************************************************************)
+
+PROCEDURE InitStateValues;
+
+(* Initialize state values and stack. *)
+
+BEGIN
+hh := hoffset; (* 0 if no horizontal shift specified *)
+vv := voffset; (* 0 if no vertical shift specified *)
+IF hoffset >= 0 THEN
+ h := TRUNC(hoffset / conv + 0.5)
+ELSE
+ h := - TRUNC(ABS(hoffset) / conv + 0.5);
+IF voffset >= 0 THEN
+ v := TRUNC(voffset / conv + 0.5)
+ELSE
+ v := - TRUNC(ABS(voffset) / conv + 0.5);
+w := 0; x := 0;
+y := 0; z := 0;
+stackpos := 0;
+fontspace := 0; (* for DoRight and DoDown before a DoFont call *)
+END; (* InitStateValues *)
+
+(******************************************************************************)
+
+PROCEDURE InitPage;
+
+(* Initialize page so that there are no fonts, chars, rules, specials. *)
+
+BEGIN
+(* page edges will change if there is at least one char or rule on page *)
+minhp := maxint;
+minvp := maxint;
+maxhp := -maxint;
+maxvp := -maxint;
+currfont := fontlist;
+WHILE currfont <> NIL DO
+ WITH currfont^ DO BEGIN
+ IF fontused THEN BEGIN (* only reset those fonts used in last page *)
+ fontused := FALSE;
+ totalchars := 0;
+ (* deallocate char list completely; DoFont will allocate first node *)
+ WHILE charlist <> NIL DO BEGIN
+ thischar := charlist;
+ charlist := thischar^.nextchar;
+ DISPOSE(thischar);
+ END;
+ chartail := NIL;
+ (* pixel table remains allocated *)
+ END;
+ currfont := nextfont;
+ END;
+currfont := NIL; (* current font is undefined at start of page *)
+totalrules := 0;
+(* deallocate rule information except for one node (for DoSet/PutRule) *)
+WHILE rulelist <> ruletail DO BEGIN
+ thisrule := rulelist;
+ rulelist := thisrule^.nextrule;
+ DISPOSE(thisrule);
+END;
+rulelist^.rulecount := 0; (* no rules in this node *)
+rulelist^.nextrule := NIL;
+(* deallocate \special information *)
+WHILE speciallist <> NIL DO BEGIN
+ thisspecial := speciallist;
+ speciallist := speciallist^.nextspecial;
+ DISPOSE(thisspecial);
+END;
+END; (* InitPage *)
+
+(******************************************************************************)
+
+FUNCTION PixelRound (DVIunits : INTEGER) : INTEGER;
+
+(* Return the nearest number of pixels in the given DVI dimension. *)
+
+BEGIN
+IF DVIunits > 0 THEN
+ PixelRound := TRUNC(conv * DVIunits + 0.5)
+ELSE
+ PixelRound := - TRUNC(conv * ABS(DVIunits) + 0.5);
+END; (* PixelRound *)
+
+(******************************************************************************)
+
+PROCEDURE DoSetChar (ch : INTEGER);
+
+(* Add char info to current chartable, update our horizontal
+ position on the page and check the page edges.
+*)
+
+LABEL 999;
+
+BEGIN
+WITH currfont^ DO BEGIN
+ IF ch > maxTeXchar THEN BEGIN
+ writeln('Unknown character from ', fontspec:fontspeclen);
+ goto 999; (* ignore ch *)
+ END;
+ WITH chartail^ DO
+ IF charcount = chartablesize THEN BEGIN
+ (* allocate a new chartable *)
+ NEW(nextchar); (* add new node to end of char list *)
+ nextchar^.charcount := 0; (* reset charcount *)
+ nextchar^.nextchar := NIL;
+ chartail := nextchar;
+ END;
+ WITH chartail^ DO BEGIN (* may be new chartable *)
+ WITH chartable[charcount] DO BEGIN
+ hp := hh;
+ vp := vv;
+ code := ch;
+ END;
+ WITH pixelptr^[ch] DO BEGIN
+ (* do page edges increase? *)
+ IF vv - yo < minvp THEN minvp := vv - yo;
+ IF hh - xo < minhp THEN minhp := hh - xo;
+ IF vv + (ht - yo - 1) > maxvp THEN maxvp := vv + (ht - yo - 1);
+ IF hh + (wd - xo - 1) > maxhp THEN maxhp := hh + (wd - xo - 1);
+ (* add pixel width calculated in PixelTableRoutine *)
+ hh := hh + pwidth;
+ (* use hhh and maxdrift to prevent hh drifting too far from h *)
+ hhh := PixelRound(h + dwidth);
+ IF ABS(hhh - hh) > maxdrift THEN
+ IF hhh > hh THEN
+ hh := hhh - maxdrift
+ ELSE
+ hh := hhh + maxdrift;
+ (* add DVI width calculated in PixelTableRoutine *)
+ h := h + dwidth;
+ END;
+ totalchars := totalchars + 1;
+ charcount := charcount + 1;
+ END;
+END;
+999:
+END; (* DoSetChar *)
+
+(******************************************************************************)
+
+PROCEDURE DoPutChar (ch : INTEGER);
+
+(* Exactly the same as DoSetChar, but we DON'T update the horizontal
+ position on the page. (We still have to check page edges.)
+*)
+
+LABEL 999;
+
+BEGIN
+WITH currfont^ DO BEGIN
+ IF ch > maxTeXchar THEN BEGIN
+ writeln('Unknown character from ', fontspec:fontspeclen);
+ goto 999; (* ignore ch *)
+ END;
+ WITH chartail^ DO
+ IF charcount = chartablesize THEN BEGIN
+ (* allocate a new chartable *)
+ NEW(nextchar); (* add new node to end of char list *)
+ nextchar^.charcount := 0; (* reset charcount *)
+ nextchar^.nextchar := NIL;
+ chartail := nextchar;
+ END;
+ WITH chartail^ DO BEGIN (* may be new chartable *)
+ WITH chartable[charcount] DO BEGIN
+ hp := hh;
+ vp := vv;
+ code := ch;
+ END;
+ WITH pixelptr^[ch] DO BEGIN
+ (* do page edges increase? *)
+ IF vv - yo < minvp THEN minvp := vv - yo;
+ IF hh - xo < minhp THEN minhp := hh - xo;
+ IF vv + (ht - yo - 1) > maxvp THEN maxvp := vv + (ht - yo - 1);
+ IF hh + (wd - xo - 1) > maxhp THEN maxhp := hh + (wd - xo - 1);
+ END;
+ totalchars := totalchars + 1;
+ charcount := charcount + 1;
+ END;
+END;
+999:
+END; (* DoPutChar *)
+
+(******************************************************************************)
+
+PROCEDURE DoPush;
+
+(* Push state values onto stack.
+ No need to test for stack overflow since we compare maxstack and
+ maxstacksize in ProcessPostamble.
+*)
+
+BEGIN
+hstack[stackpos] := h; vstack[stackpos] := v;
+wstack[stackpos] := w; xstack[stackpos] := x;
+ystack[stackpos] := y; zstack[stackpos] := z;
+hhstack[stackpos] := hh; vvstack[stackpos] := vv;
+stackpos := stackpos + 1;
+END; (* DoPush *)
+
+(******************************************************************************)
+
+PROCEDURE DoPop;
+
+(* Pop state values from top of stack. *)
+
+BEGIN
+{ DEBUG
+ IF stackpos = 0 THEN BEGIN
+ writeln; writeln('Stack empty!'); exit(1);
+ END;
+GUBED }
+stackpos := stackpos - 1;
+h := hstack[stackpos]; v := vstack[stackpos];
+w := wstack[stackpos]; x := xstack[stackpos];
+y := ystack[stackpos]; z := zstack[stackpos];
+hh := hhstack[stackpos]; vv := vvstack[stackpos];
+END; (* DoPop *)
+
+(******************************************************************************)
+
+PROCEDURE DoRight (amount : INTEGER);
+
+(* Move the reference point horizontally by given amount (usually +ve).
+ When the amount is small, like a kern, hh changes
+ by rounding the amount; but when the amount is large, hh changes by rounding
+ the true position h so that accumulated rounding errors disappear.
+*)
+
+BEGIN
+IF (amount < fontspace) AND (amount > -4 * fontspace) THEN BEGIN
+ hh := hh + PixelRound(amount);
+ (* use hhh and maxdrift to prevent hh drifting too far from h *)
+ hhh := PixelRound(h + amount);
+ IF ABS(hhh - hh) > maxdrift THEN
+ IF hhh > hh THEN
+ hh := hhh - maxdrift
+ ELSE
+ hh := hhh + maxdrift;
+END
+ELSE
+ hh := PixelRound(h + amount);
+h := h + amount;
+END; (* DoRight *)
+
+(******************************************************************************)
+
+PROCEDURE DoDown (amount : INTEGER);
+
+(* Move the reference point vertically by given amount (usually +ve).
+ Rounding is done similarly to DoRight but with the threshold between
+ small and large amounts increased by a factor of 5.
+*)
+
+BEGIN
+IF ABS(amount) < 5 * fontspace THEN BEGIN
+ vv := vv + PixelRound(amount);
+ (* use vvv and maxdrift to prevent vv drifting too far from v *)
+ vvv := PixelRound(v + amount);
+ IF ABS(vvv - vv) > maxdrift THEN
+ IF vvv > vv THEN
+ vv := vvv - maxdrift
+ ELSE
+ vv := vvv + maxdrift;
+END
+ELSE
+ vv := PixelRound(v + amount);
+v := v + amount;
+END; (* DoDown *)
+
+(******************************************************************************)
+
+FUNCTION RulePixels (DVIunits : INTEGER) : INTEGER;
+
+(* Return the number of pixels in the given height or width of a rule
+ using the method recommended in DVITYPE.
+*)
+
+VAR n : INTEGER;
+
+BEGIN
+n := TRUNC(conv * DVIunits);
+IF n < conv * DVIunits THEN RulePixels := n + 1 ELSE RulePixels := n;
+END; (* RulePixels *)
+
+(******************************************************************************)
+
+PROCEDURE DoSetRule (height, width : INTEGER);
+
+(* Add rule information to current ruletable, update page edges, h and hh
+ (but only if width and height are > 0).
+*)
+
+BEGIN
+IF (height > 0) AND (width > 0) THEN BEGIN
+ WITH ruletail^ DO
+ IF rulecount = ruletablesize THEN BEGIN
+ (* allocate a new ruletable *)
+ NEW(nextrule); (* add new node to end of rule list *)
+ nextrule^.rulecount := 0; (* reset rulecount *)
+ nextrule^.nextrule := NIL;
+ ruletail := nextrule;
+ END;
+ WITH ruletail^ DO BEGIN (* may be new ruletable *)
+ WITH ruletable[rulecount] DO BEGIN
+ hp := hh;
+ vp := vv;
+ wd := RulePixels(width);
+ ht := RulePixels(height);
+ (* do page edges increase? *)
+ IF vv - (ht - 1) < minvp THEN minvp := vv - (ht - 1);
+ IF hh + (wd - 1) > maxhp THEN maxhp := hh + (wd - 1);
+ (* ref pt of rule is bottom left black pixel *)
+ IF vv > maxvp THEN maxvp := vv;
+ IF hh < minhp THEN minhp := hh;
+ hh := hh + wd;
+ (* use hhh and maxdrift to prevent hh drifting too far from h *)
+ hhh := PixelRound(h + width);
+ IF ABS(hhh - hh) > maxdrift THEN
+ IF hhh > hh THEN
+ hh := hhh - maxdrift
+ ELSE
+ hh := hhh + maxdrift;
+ h := h + width;
+ END;
+ totalrules := totalrules + 1;
+ rulecount := rulecount + 1;
+ END;
+END;
+END; (* DoSetRule *)
+
+(******************************************************************************)
+
+PROCEDURE DoPutRule (height, width : INTEGER);
+
+(* Exactly the same as DoSetRule, but we DON'T update the horizontal
+ position on the page. (We still have to check page edges.)
+*)
+
+BEGIN
+IF (height > 0) AND (width > 0) THEN BEGIN
+ WITH ruletail^ DO
+ IF rulecount = ruletablesize THEN BEGIN
+ (* allocate a new ruletable *)
+ NEW(nextrule); (* add new node to end of rule list *)
+ nextrule^.rulecount := 0; (* reset rulecount *)
+ nextrule^.nextrule := NIL;
+ ruletail := nextrule;
+ END;
+ WITH ruletail^ DO BEGIN (* may be new ruletable *)
+ WITH ruletable[rulecount] DO BEGIN
+ hp := hh;
+ vp := vv;
+ wd := RulePixels(width);
+ ht := RulePixels(height);
+ (* do page edges increase? *)
+ IF vv - (ht - 1) < minvp THEN minvp := vv - (ht - 1);
+ IF hh + (wd - 1) > maxhp THEN maxhp := hh + (wd - 1);
+ (* ref pt of rule is bottom left black pixel *)
+ IF vv > maxvp THEN maxvp := vv;
+ IF hh < minhp THEN minhp := hh;
+ END;
+ totalrules := totalrules + 1;
+ rulecount := rulecount + 1;
+ END;
+END;
+END; (* DoPutRule *)
+
+(******************************************************************************)
+
+PROCEDURE DoFont (externf : INTEGER);
+
+(* Search font list for externf, setting currfont and fontspace.
+ If this is the first time we've seen this font (on current page) then
+ we need to allocate the first chartable.
+ If this is the first time we've seen this font used at all then we
+ allocate a pixeltable and call routine to fill it in.
+*)
+
+LABEL 888;
+
+BEGIN
+currfont := fontlist;
+WHILE currfont <> NIL DO
+ IF currfont^.fontnum <> externf THEN
+ currfont := currfont^.nextfont
+ ELSE
+ goto 888;
+888:
+{ DEBUG
+ IF currfont = NIL THEN BEGIN
+ writeln; writeln('Failed to find font #', externf:1); exit(1);
+ END;
+GUBED }
+WITH currfont^ DO BEGIN
+ IF fontused THEN
+ (* do nothing since we've already used this font on this page *)
+ ELSE BEGIN
+ fontused := TRUE;
+ NEW(charlist); (* allocate first chartable *)
+ WITH charlist^ DO BEGIN
+ charcount := 0; (* for DoSet/PutChar *)
+ nextchar := NIL; (* this node is also last *)
+ END;
+ chartail := charlist;
+ IF pixelptr = NIL THEN BEGIN (* first time we've seen this font *)
+ NEW(pixelptr);
+ PixelTableRoutine;
+ END;
+ END;
+ fontspace := scaledsize DIV 6;
+ (* See DVITYPE; a 3-unit thin space.
+ Note that a thin space is 1/6 of a quad, where a quad is
+ 1 em in the current font and usually equals the design size.
+ *)
+END;
+END; (* DoFont *)
+
+(******************************************************************************)
+
+PROCEDURE DoSpecial (hpos, vpos, totalbytes : INTEGER); (* in *)
+
+(* DVIReader has seen a \special command while interpreting the current page.
+ It will pass the current page position and number of bytes in the command.
+ We save the info away in speciallist for later use by the main program.
+*)
+
+VAR i, flush : INTEGER; temp : specialinfoptr;
+
+BEGIN
+NEW(temp);
+WITH temp^ DO BEGIN
+ special := ''; (* SYSDEP: fill with spaces *)
+ FOR i := 0 TO totalbytes-1 DO
+ IF i < maxspeciallen THEN special[i] := CHR(GetDVIByte);
+ (* we must read all the \special bytes *)
+ IF totalbytes > maxspeciallen THEN BEGIN
+ warncount := warncount + 1;
+ writeln;
+ writeln('\special command truncated:');
+ writeln(special:maxspeciallen);
+ FOR i := 1 TO totalbytes - maxspeciallen DO flush := GetDVIByte;
+ END;
+ hp := hpos;
+ vp := vpos;
+ nextspecial := speciallist;
+END;
+speciallist := temp; (* add new info to head of list *)
+END; (* DoSpecial *)
+
+(******************************************************************************)
+
+PROCEDURE InterpretPage;
+
+(* When this routine is called we are positioned after the bytes of a bop
+ command (i.e., at currbop + 45). At the end of this routine we will be
+ positioned after the eop byte for the current page. In between we carry
+ out the important task of translating the DVI description of this page
+ and filling in the following global data structures:
+
+ totalrules := number of rules on page
+ rulelist^. (nodes are added to tail of rule list)
+ rulecount := number of rules in this ruletable
+ ruletable[0..rulecount-1].
+ hp, vp := reference point of a rule
+ wd, ht := pixel dimensions of a rule (both > 0)
+ nextrule := next node in rule list (if not NIL)
+ ruletail := pointer to last node in rule list
+
+ speciallist^. (nodes are added to head of this list)
+ hp, vp := reference point on page
+ special := \special bytes
+ nextspecial := next node in list (if not NIL)
+
+ fontlist^.
+ (the following fontinfo is relevant only if fontused is TRUE)
+ totalchars := number of chars on page from this font
+ charlist^. (nodes are added to tail of char list)
+ charcount := number of chars in this chartable
+ chartable[0..charcount-1].
+ hp, vp := reference point of a character
+ code := TeX character code (and index into pixel table)
+ nextchar := next node in char list (if not NIL)
+ chartail := pointer to last node in char list
+ pixelptr^[0..maxTeXchar].
+ (filled in by FontReader's PixelTableRoutine)
+ wd, ht := glyph width and height in pixels
+ xo, yo := offsets from the character's reference point
+ dwidth := advance width in DVI units
+ pwidth := advance width in pixels
+ mapadr := offset in fontspec of the glyph's bitmap info
+ bitmap := NIL
+ nextfont := next node in font list (if not NIL)
+
+ pageempty := TRUE iff the page has no rules and no characters
+ minhp, minvp, maxhp, maxvp
+ := the edges of the page (undefined if pageempty is TRUE)
+ They define the smallest rectangle containing all black
+ pixels on the page;(minhp,minvp) is the top left corner.
+
+ Reference points for rules and characters are stored as a pair of
+ horizontal and vertical pixel coordinates. The point (0,0) is assumed
+ to be the pixel 1 inch in from the top and left edges of an imaginary sheet
+ of paper. Horizontal coordinates increase to the right and vertical
+ coordinates increase down the paper.
+ The number of pixels per inch is defined by the resolution parameter
+ given to SetConversionFactor.
+*)
+
+VAR param, ht, wd : INTEGER;
+
+BEGIN
+InitStateValues;
+InitPage;
+REPEAT
+ DVIcommand := GetDVIByte;
+ (* For efficiency reasons the most frequent commands should be tested 1st.
+ The following order is the result of frequency testing on typical
+ DVI files. Note that the most frequent commands in the DVI file
+ generated by TeX 1.3 for the Dec. 1983 LaTeX manual were:
+ <set1, w0, right3, push/pop, x0, w3, y0, fntnum25, right2, fntnum31,
+ down3, x2, right4, w2, x3, down4, z0, fntnum8, setrule, y3, etc.
+ *)
+ IF DVIcommand < set1 THEN DoSetChar(DVIcommand) (* 0..127 *)
+ ELSE IF DVIcommand = w0 THEN DoRight(w)
+ ELSE IF DVIcommand = right3 THEN DoRight(SignedDVITrio)
+ ELSE IF DVIcommand = push THEN DoPush
+ ELSE IF DVIcommand = pop THEN DoPop
+ ELSE IF DVIcommand = x0 THEN DoRight(x)
+ ELSE IF DVIcommand = w3 THEN BEGIN w := SignedDVITrio; DoRight(w) END
+ ELSE IF DVIcommand = y0 THEN DoDown(y)
+
+ ELSE IF (DVIcommand > z4) AND (DVIcommand < fnt1) (* fntnum0..fntnum63 *)
+ THEN DoFont(DVIcommand - fntnum0)
+
+ (* catch all the remaining movement commands *)
+ ELSE IF (DVIcommand > pop) AND (DVIcommand < fntnum0) THEN BEGIN
+ IF DVIcommand = right2 THEN DoRight(SignedDVIPair)
+ ELSE IF DVIcommand = right4 THEN DoRight(SignedDVIQuad)
+ ELSE IF DVIcommand = x2 THEN BEGIN x := SignedDVIPair; DoRight(x) END
+ ELSE IF DVIcommand = x3 THEN BEGIN x := SignedDVITrio; DoRight(x) END
+ ELSE IF DVIcommand = down3 THEN DoDown(SignedDVITrio)
+ ELSE IF DVIcommand = down4 THEN DoDown(SignedDVIQuad)
+ ELSE IF DVIcommand = w2 THEN BEGIN w := SignedDVIPair; DoRight(w) END
+ ELSE IF DVIcommand = z0 THEN DoDown(z)
+ ELSE IF DVIcommand = y3 THEN BEGIN y := SignedDVITrio; DoDown(y) END
+ ELSE IF DVIcommand = z3 THEN BEGIN z := SignedDVITrio; DoDown(z) END
+ ELSE IF DVIcommand = down2 THEN DoDown(SignedDVIPair)
+ (* the next DVI commands are used very rarely (by TeX 1.3 at least) *)
+ ELSE IF DVIcommand = w1 THEN BEGIN w := SignedDVIByte; DoRight(w) END
+ ELSE IF DVIcommand = w4 THEN BEGIN w := SignedDVIQuad; DoRight(w) END
+ ELSE IF DVIcommand = x1 THEN BEGIN x := SignedDVIByte; DoRight(x) END
+ ELSE IF DVIcommand = x4 THEN BEGIN x := SignedDVIQuad; DoRight(x) END
+ ELSE IF DVIcommand = y1 THEN BEGIN y := SignedDVIByte; DoDown(y) END
+ ELSE IF DVIcommand = y2 THEN BEGIN y := SignedDVIPair; DoDown(y) END
+ ELSE IF DVIcommand = y4 THEN BEGIN y := SignedDVIQuad; DoDown(y) END
+ ELSE IF DVIcommand = z1 THEN BEGIN z := SignedDVIByte; DoDown(z) END
+ ELSE IF DVIcommand = z2 THEN BEGIN z := SignedDVIPair; DoDown(z) END
+ ELSE IF DVIcommand = z4 THEN BEGIN z := SignedDVIQuad; DoDown(z) END
+ ELSE IF DVIcommand = right1 THEN DoRight(SignedDVIByte)
+ ELSE IF DVIcommand = down1 THEN DoDown(SignedDVIByte)
+ ELSE BEGIN
+ writeln; writeln('Bug in InterpretPage!'); exit(1);
+ END;
+ END
+ ELSE IF DVIcommand = setrule THEN BEGIN
+ ht := SignedDVIQuad; wd := SignedDVIQuad; DoSetRule(ht,wd);
+ END
+ ELSE IF DVIcommand = putrule THEN BEGIN
+ ht := SignedDVIQuad; wd := SignedDVIQuad; DoPutRule(ht,wd);
+ END
+ ELSE IF (DVIcommand >= put1) AND (DVIcommand <= put1+3) THEN
+ CASE DVIcommand - put1 OF
+ 0 : DoPutChar(GetDVIByte);
+ 1 : DoPutChar(GetTwoDVIBytes);
+ 2 : DoPutChar(GetThreeDVIBytes);
+ 3 : DoPutChar(SignedDVIQuad)
+ END
+
+ ELSE IF (DVIcommand >= set1) AND (DVIcommand <= set1+3) THEN
+ CASE DVIcommand - set1 OF
+ 0 : DoSetChar(GetDVIByte);
+ 1 : DoSetChar(GetTwoDVIBytes);
+ 2 : DoSetChar(GetThreeDVIBytes);
+ 3 : DoSetChar(SignedDVIQuad)
+ END
+
+ ELSE IF (DVIcommand >= fnt1) AND (DVIcommand <= fnt1+3) THEN
+ CASE DVIcommand - fnt1 OF
+ 0 : DoFont(GetDVIByte);
+ 1 : DoFont(GetTwoDVIBytes);
+ 2 : DoFont(GetThreeDVIBytes);
+ 3 : DoFont(SignedDVIQuad)
+ END
+
+ ELSE IF (DVIcommand >= xxx1) AND (DVIcommand <= xxx1+3) THEN BEGIN
+ CASE DVIcommand - xxx1 OF
+ 0 : param := GetDVIByte;
+ 1 : param := GetTwoDVIBytes;
+ 2 : param := GetThreeDVIBytes;
+ 3 : param := SignedDVIQuad
+ END;
+ (* pass current pixel position and number of bytes *)
+ DoSpecial(hh, vv, param);
+ END
+
+ (* skip fntdef command since we've got this info from postamble *)
+ ELSE IF (DVIcommand >= fntdef1) AND (DVIcommand <= fntdef1+3)
+ THEN SkipFntdef(DVIcommand - fntdef1)
+
+ ELSE IF DVIcommand = nop THEN (* do nothing *)
+ ELSE IF DVIcommand = eop THEN (* do nothing *)
+ ELSE BEGIN
+ writeln;
+ writeln('Unexpected DVI command while interpreting page = ', DVIcommand:1);
+ exit(1);
+ END;
+UNTIL DVIcommand = eop;
+(* save position of eop byte for use in MoveToTeXPage *)
+curreop := DVIoffset - 1;
+IF stackpos <> 0 THEN BEGIN
+ writeln; writeln('Stack not empty at eop!'); exit(1);
+END;
+pageempty := (minhp = maxint) AND (minvp = maxint) AND
+ (maxhp = -maxint) AND (maxvp = -maxint); (* InitPage values *)
+END; (* InterpretPage *)
+
+(******************************************************************************)
+
+PROCEDURE SortFonts (VAR unusedlist : fontinfoptr); (* out *)
+
+(* Sort fontlist in order of ascending totalchars.
+ Fonts with least characters can then be accessed first.
+ Since the number of fonts used on a typical page is quite small, a simple
+ sorting algorithm should be good enough. Note that unused fonts are moved
+ to the end of the list and unusedlist points to the first such node.
+ PSDVI need only process fonts up to (but excluding) unusedlist
+ and does not have to worry about checking the fontused flag.
+ If unusedlist is NIL then either 1) all fonts are used on the current page
+ or 2) fontlist is also NIL (totalfonts = 0).
+*)
+
+VAR newfontlist, prevfont, largest, prevlargest : fontinfoptr;
+ mostchars : INTEGER;
+
+BEGIN
+newfontlist := NIL;
+(* go thru fontlist once and move all unused fonts to head of newfontlist *)
+prevfont := NIL;
+currfont := fontlist;
+WHILE currfont <> NIL DO
+ WITH currfont^ DO
+ IF fontused THEN BEGIN
+ prevfont := currfont; (* remember previous node *)
+ currfont := nextfont;
+ END
+ ELSE
+ (* move node from fontlist to head of newfontlist
+ and don't change prevfont
+ *)
+ IF prevfont = NIL THEN BEGIN
+ fontlist := nextfont; (* remove first node in fontlist *)
+ nextfont := newfontlist;
+ newfontlist := currfont;
+ currfont := fontlist;
+ END
+ ELSE BEGIN
+ prevfont^.nextfont := nextfont;
+ nextfont := newfontlist;
+ newfontlist := currfont;
+ currfont := prevfont^.nextfont;
+ END;
+(* unusedlist will be last unused font moved to newfontlist. It will be NIL
+ if either fontlist is NIL or all fonts are used.
+*)
+unusedlist := newfontlist;
+(* Now go thru fontlist repeatedly moving node with max totalchars to
+ head of newfontlist until fontlist is exhausted.
+*)
+WHILE fontlist <> NIL DO BEGIN
+ prevfont := NIL;
+ currfont := fontlist;
+ prevlargest := NIL;
+ largest := fontlist;
+ mostchars := 0;
+ WHILE currfont <> NIL DO (* search for largest totalchars *)
+ WITH currfont^ DO BEGIN
+ IF totalchars > mostchars THEN BEGIN
+ prevlargest := prevfont;
+ largest := currfont;
+ mostchars := totalchars;
+ END;
+ prevfont := currfont;
+ currfont := nextfont;
+ END;
+ (* move largest node from fontlist to head of newfontlist *)
+ WITH largest^ DO BEGIN
+ IF prevlargest = NIL THEN
+ fontlist := nextfont (* remove first node in fontlist *)
+ ELSE
+ prevlargest^.nextfont := nextfont;
+ nextfont := newfontlist;
+ newfontlist := largest;
+ END;
+END;
+fontlist := newfontlist; (* used fonts now sorted and unused fonts at end *)
+END; (* SortFonts *)
+
+(******************************************************************************)
+
+PROCEDURE CloseDVIFile;
+
+(* Close the currently open DVI file and deallocate dynamic data structures. *)
+
+VAR result : integer;
+
+BEGIN
+result := close(DVIfile);
+WHILE fontlist <> NIL DO BEGIN
+ currfont := fontlist;
+ WITH currfont^ DO BEGIN
+ WHILE charlist <> NIL DO BEGIN
+ thischar := charlist;
+ charlist := thischar^.nextchar;
+ DISPOSE(thischar); (* deallocate char list *)
+ END;
+ IF pixelptr <> NIL THEN
+ DISPOSE(pixelptr); (* deallocate pixel table *)
+ fontlist := nextfont;
+ END;
+ DISPOSE(currfont); (* deallocate font information *)
+END;
+(* Deallocate rule information except for one node
+ (in case PSDVI ever opens another DVI file).
+*)
+WHILE rulelist <> ruletail DO BEGIN
+ thisrule := rulelist;
+ rulelist := thisrule^.nextrule;
+ DISPOSE(thisrule);
+END;
+WHILE speciallist <> NIL DO BEGIN
+ thisspecial := speciallist;
+ speciallist := speciallist^.nextspecial;
+ DISPOSE(thisspecial);
+END;
+END; (* CloseDVIFile *)
+
+(******************************************************************************)
+
+PROCEDURE InitDVIReader;
+
+BEGIN
+totalrules := 0;
+NEW(rulelist); (* for first InitPage *)
+ruletail := rulelist; (* ditto *)
+speciallist := NIL; (* ditto *)
+fontlist := NIL; (* safer for CloseDVIFile *)
+END; (* InitDVIReader *)
diff --git a/dviware/psprint/unix/files.h b/dviware/psprint/unix/files.h
new file mode 100644
index 0000000000..98a09bd8c9
--- /dev/null
+++ b/dviware/psprint/unix/files.h
@@ -0,0 +1,17 @@
+(* Random file access; used in DVIReader and FontReader *)
+
+CONST
+ bufflen = 1024; (* size of buffer for holding DVI/PK bytes *)
+ bufflenm = bufflen - 1;
+
+ O_RDONLY = 0; (* SYSDEP: read-only flag for open;
+ value came from /usr/include/sys/fcntl.h
+ *)
+
+TYPE
+ buffer = ARRAY [0..bufflenm] OF CHAR;
+
+FUNCTION open (VAR path : string; flags, mode : integer) : integer; EXTERNAL;
+FUNCTION lseek (f, offset, whence : integer) : integer; EXTERNAL;
+FUNCTION read (f : integer; VAR b : buffer; n : integer) : integer; EXTERNAL;
+FUNCTION close (f : integer) : integer; EXTERNAL;
diff --git a/dviware/psprint/unix/fontlist.ps b/dviware/psprint/unix/fontlist.ps
new file mode 100644
index 0000000000..4bcd9d57b1
--- /dev/null
+++ b/dviware/psprint/unix/fontlist.ps
@@ -0,0 +1,97 @@
+% Produces an alphabetical list of fonts available in printer.
+
+/MaxNrOfFonts 50 def % Maximum numbers of fonts...
+/Xpos 136 def
+/Ypos 690 def
+/num 0 def % local counter
+/incr {
+ /num num 1 add def
+} def
+
+/s40 { 40 string } def % Proper length of the fontname
+
+/showline { % Show and newlines
+ show
+ newline
+} def
+
+/newline { % Spacing between lines
+ /Ypos Ypos 12 sub def
+ Xpos Ypos moveto
+} def
+
+/CountFonts { % Count the fonts and put the names into array
+ FontDirectory
+ {
+ pop
+ s40
+ cvs
+ incr
+ }
+ forall
+ /FontArray num array def
+ FontArray astore
+ pop
+} def
+
+/ListFonts { % Sort the fonts and show them on paper
+ Bubbelsort
+ FontArray
+ {
+ showline
+ }
+ forall
+} def
+
+/Bubbelsort { % Here is the sorting routine
+ 1 1 num 1 sub
+ {
+ /localcount exch def
+ num 1 sub -1 localcount
+ {
+ /innercount exch def
+ /firststring FontArray innercount 1 sub get def
+ /secondstring FontArray innercount get def
+ firststring secondstring gt
+ {
+ FontArray innercount 1 sub secondstring put
+ FontArray innercount firststring put
+ } if
+ } for
+ } for
+} def
+
+/prettyline
+{ /YPOSition exch def
+ newpath
+ Xpos Ypos YPOSition add moveto
+ Xpos 100 add Ypos YPOSition add lineto
+ stroke
+} def
+
+/Times-Roman findfont 12 scalefont setfont
+14 prettyline
+
+Xpos Ypos 18 add moveto
+CountFonts
+(Number of fonts: ) show
+num s40 cvs show
+
+30 prettyline
+Xpos Ypos moveto
+ListFonts
+newline
+
+/Times-Bold findfont 12 scalefont setfont
+(Total memory: ) show
+vmstatus s40 cvs show newline
+(Memory used: ) show
+s40 cvs show newline
+pop
+(Free memory: ) show
+vmstatus exch sub s40 cvs show newline newline
+pop
+/Times-Roman findfont 12 scalefont setfont
+(From ulfis@nada.kth.se, 88-10-05) show
+
+showpage
diff --git a/dviware/psprint/unix/fontreader.h b/dviware/psprint/unix/fontreader.h
new file mode 100644
index 0000000000..f120304167
--- /dev/null
+++ b/dviware/psprint/unix/fontreader.h
@@ -0,0 +1,9 @@
+(* FontReader *)
+
+PROCEDURE InitFontReader; EXTERNAL;
+PROCEDURE PixelTableRoutine; EXTERNAL;
+PROCEDURE LoadBitmap (fontptr : fontinfoptr; code : INTEGER); EXTERNAL;
+PROCEDURE BuildFontSpec (fontptr : fontinfoptr;
+ VAR firstn, lastn : INTEGER); EXTERNAL;
+FUNCTION OpenFontFile (VAR name : string) : BOOLEAN; EXTERNAL;
+PROCEDURE CloseFontFile; EXTERNAL;
diff --git a/dviware/psprint/unix/fontreader.p b/dviware/psprint/unix/fontreader.p
new file mode 100644
index 0000000000..c52c214a1e
--- /dev/null
+++ b/dviware/psprint/unix/fontreader.p
@@ -0,0 +1,926 @@
+(* FontReader implements the routines for reading character metric and
+ bitmap information from PK files, or from TFM files for PostScript fonts.
+*)
+
+#include 'globals.h';
+#include 'files.h';
+#include 'options.h';
+#include 'dvireader.h';
+#include 'fontreader.h';
+#include 'pswriter.h'; (* for PSfile and NewBitmapFont *)
+
+TYPE
+ BITSET = SET OF 0..31;
+
+ (* SYSDEP: The following variant record is needed because
+ Pyramid Pascal does not provide type coercion.
+ Note that we couldn't overlay INTEGER and BITSET because
+ of the crazy storage scheme used to represent a set of 0..31
+ where the bit order within a word is 7..0 15..8 23..16 31..24!
+ *)
+
+ bytes_or_bits = RECORD
+ CASE b : BOOLEAN OF
+ TRUE : (ch : PACKED ARRAY [0..3] OF CHAR);
+ FALSE : (bits : BITSET);
+ END;
+
+VAR
+ PTfile : integer; (* PK/TFM file descriptor *)
+ PToffset : INTEGER; (* current byte offset in PTfile *)
+ currPTbuff : INTEGER; (* starting byte offset in buffer *)
+ PTbuffer : buffer; (* input buffer *)
+ psprefixlen, (* length of psprefix string *)
+ fontdirlen : INTEGER; (* length of fontdir string *)
+ hexdigs : ARRAY [0..15] OF CHAR; (* 0..9ABCDEF for LoadBitmap *)
+ gpower : ARRAY [0..32] OF BITSET; (* 0,1,11,111,1111,... *)
+ turnon : BOOLEAN; (* is current run black? *)
+ dynf, (* dynamic packing variable *)
+ repeatcount, (* times to repeat the next row *)
+ bitweight : INTEGER; (* for bits or nybbles from inputbyte *)
+ inputbyte : bytes_or_bits; (* the current input byte *)
+ lf, lh, bc, ec, nw, nh : INTEGER; (* TFM file data *)
+ TFMinfo : ARRAY [0..255] OF
+ RECORD
+ wdindex, htindex, dpindex : INTEGER;
+ END;
+ charmetrics : ARRAY [0..255] OF
+ RECORD
+ width, height, depth : ARRAY [0..3] OF INTEGER;
+ END;
+
+(******************************************************************************)
+
+PROCEDURE BuildTFMSpec (fontptr : fontinfoptr);
+
+(* Build a complete TFM file specification in fontptr^.fontspec.
+ This will only be done once per font; fontspeclen will no longer be 0.
+ fontptr^.fontexists becomes TRUE if the file can be opened.
+*)
+
+LABEL 999;
+
+VAR f, result, i, nxt : INTEGER;
+
+BEGIN
+WITH fontptr^ DO BEGIN
+ i := 0;
+ IF fontarealen > 0 THEN BEGIN
+ nxt := fontarealen;
+ REPEAT
+ fontspec[i] := fontarea[i]; (* start fontspec with fontarea *)
+ i := i + 1;
+ UNTIL (i = nxt) OR (i > maxfontspec);
+ END
+ ELSE BEGIN
+ nxt := Len(tfmdir); (* assume > 0 *)
+ REPEAT
+ fontspec[i] := tfmdir[i]; (* start fontspec with tfmdir *)
+ i := i + 1;
+ UNTIL (i = nxt) OR (i > maxfontspec);
+ END;
+ IF nxt >= maxfontspec THEN BEGIN
+ fontspeclen := maxfontspec;
+ goto 999; (* fontspec truncated *)
+ END;
+ (* nxt is current length of fontspec; append fontname.tfm *)
+ i := 0;
+ WHILE (i < fontnamelen) AND (nxt < maxfontspec) DO BEGIN
+ fontspec[nxt] := fontname[i]; (* append fontname *)
+ i := i + 1;
+ nxt := nxt + 1;
+ END;
+ IF nxt + 4 <= maxfontspec THEN BEGIN (* append .tfm *)
+ fontspec[nxt] := '.'; nxt := nxt + 1;
+ fontspec[nxt] := 't'; nxt := nxt + 1;
+ fontspec[nxt] := 'f'; nxt := nxt + 1;
+ fontspec[nxt] := 'm'; nxt := nxt + 1;
+ END
+ ELSE BEGIN
+ fontspeclen := maxfontspec;
+ goto 999; (* fontspec truncated *)
+ END;
+ fontspeclen := nxt;
+ IF fontspeclen < maxstring THEN fontspec[fontspeclen] := CHR(0);
+ f := open(fontspec,O_RDONLY,0); (* try to open file *)
+ IF fontspeclen < maxstring THEN fontspec[fontspeclen] := ' ';
+ IF f >= 0 THEN BEGIN
+ result := close(f);
+ fontexists := TRUE; (* fontspec exists *)
+ END;
+END;
+999:
+END; (* BuildTFMSpec *)
+
+(******************************************************************************)
+
+FUNCTION CompleteFontSpec (fontptr : fontinfoptr;
+ nxt : INTEGER;
+ fontsizelen : INTEGER;
+ VAR firstn : INTEGER) : BOOLEAN;
+
+(* Return TRUE if we can append "fontname.n...npk" to fontspec.
+ Such a scheme is used in the latest TeX distributions.
+*)
+
+LABEL 999;
+
+VAR i : INTEGER;
+
+BEGIN
+WITH fontptr^ DO BEGIN
+ i := 0;
+ WHILE (i < fontnamelen) AND (nxt < maxfontspec) DO BEGIN
+ fontspec[nxt] := fontname[i]; (* append fontname *)
+ i := i + 1;
+ nxt := nxt + 1;
+ END;
+ firstn := nxt + 1; (* position of 1st n *)
+ IF nxt + fontsizelen + 2 < maxfontspec THEN BEGIN
+ fontspec[nxt] := '.';
+ nxt := nxt + fontsizelen + 1; (* skip n...n *)
+ fontspec[nxt] := 'p'; (* append pk *)
+ nxt := nxt + 1;
+ fontspec[nxt] := 'k';
+ nxt := nxt + 1;
+ END
+ ELSE BEGIN
+ fontspeclen := maxfontspec;
+ CompleteFontSpec := FALSE;
+ goto 999; (* fontspec truncated *)
+ END;
+ fontspeclen := nxt;
+ IF nxt < maxfontspec THEN fontspec[nxt] := ' '; (* terminate string *)
+ CompleteFontSpec := TRUE;
+END;
+999:
+END; (* CompleteFontSpec *)
+
+(******************************************************************************)
+
+PROCEDURE BuildFontSpec (fontptr : fontinfoptr; VAR firstn, lastn : INTEGER);
+
+(* Build a complete file specification in fontptr^.fontspec.
+ This will only be done once per font; fontspeclen will no longer be 0.
+ fontptr^.fontexists becomes TRUE if the file can be opened.
+*)
+
+LABEL 888, 999;
+
+VAR f, result, i, j, nxt, fontsize, tempsize, tempsizelen : INTEGER;
+
+BEGIN
+WITH fontptr^ DO BEGIN
+ (* first check for a PostScript font; following code will set psfont to TRUE
+ if psprefixlen = 0 --- ALL fonts will be considered PostScript fonts
+ *)
+ psfont := TRUE;
+ i := 0;
+ WHILE TRUE DO BEGIN
+ IF i = psprefixlen THEN goto 888;
+ IF Cap(fontname[i]) <> Cap(psprefix[i]) THEN BEGIN
+ psfont := FALSE;
+ goto 888;
+ END;
+ i := i + 1;
+ END;
+ 888:
+ IF psfont THEN BEGIN
+ BuildTFMSpec(fontptr); (* build TFM file spec *)
+ goto 999;
+ END;
+ i := 0;
+ nxt := fontdirlen;
+ REPEAT
+ fontspec[i] := fontdir[i]; (* start fontspec with fontdir *)
+ i := i + 1;
+ UNTIL (i = nxt) OR (i > maxfontspec);
+ IF nxt >= maxfontspec THEN BEGIN
+ fontspeclen := maxfontspec;
+ goto 999; (* fontspec truncated *)
+ END;
+ fontsize := TRUNC( mag * (scaledsize / designsize)
+ * (resolution / 1000.0) + 0.5 );
+ IF fontsize = 0 THEN
+ fontsize := fontsize + 1; (* allow for subtracting 1 *)
+ tempsize := fontsize;
+ i := 1;
+ WHILE TRUE DO BEGIN
+ (* Complete rest of fontspec starting at nxt
+ and return the position of first digit for fontsize.
+ We have to try fontsize +/- 1 before giving up because
+ rounding problems can occur in the above fontsize calculation.
+ *)
+ j := tempsize;
+ tempsizelen := 0;
+ WHILE j > 0 DO BEGIN
+ tempsizelen := tempsizelen + 1;
+ j := j DIV 10;
+ END;
+ IF NOT CompleteFontSpec(fontptr, nxt, tempsizelen, firstn) THEN
+ goto 999; (* fontspec truncated *)
+ lastn := firstn + tempsizelen - 1;
+ (* put tempsize into fontspec[firstn..lastn] *)
+ FOR j := lastn DOWNTO firstn DO BEGIN
+ fontspec[j] := CHR(ORD('0') + (tempsize MOD 10));
+ tempsize := tempsize DIV 10;
+ END;
+ IF i > 3 THEN (* original fontsize has been restored *)
+ goto 999; (* could not open fontspec *)
+ IF fontspeclen < maxstring THEN fontspec[fontspeclen] := CHR(0);
+ f := open(fontspec,O_RDONLY,0); (* try to open file *)
+ IF fontspeclen < maxstring THEN fontspec[fontspeclen] := ' ';
+ IF f >= 0 THEN BEGIN
+ result := close(f);
+ fontexists := TRUE; (* fontspec exists *)
+ goto 999;
+ END
+ ELSE IF i = 1 THEN
+ tempsize := fontsize - 1 (* try fontsize-1 *)
+ ELSE IF i = 2 THEN
+ tempsize := fontsize + 1 (* try fontsize+1 *)
+ ELSE
+ tempsize := fontsize; (* restore original fontsize *)
+ i := i + 1;
+ END;
+END;
+999:
+END; (* BuildFontSpec *)
+
+(******************************************************************************)
+
+FUNCTION OpenFontFile (VAR name : string) : BOOLEAN;
+
+(* Return TRUE if given file can be opened.
+ Only one font file will be open at any given time.
+*)
+
+LABEL 888;
+
+VAR length : integer;
+
+BEGIN
+currPTbuff := -1; (* impossible value for first GetPTByte *)
+length := 0;
+WHILE length < maxstring DO BEGIN
+ IF name[length] = ' ' THEN goto 888;
+ length := length + 1;
+END;
+888:
+IF length < maxstring THEN name[length] := CHR(0); (* terminate with NULL *)
+PTfile := open(name, O_RDONLY, 0);
+IF length < maxstring THEN name[length] := ' '; (* restore space *)
+OpenFontFile := PTfile >= 0;
+END; (* OpenFontFile *)
+
+(******************************************************************************)
+
+PROCEDURE CloseFontFile;
+
+(* Close the currently open font file. *)
+
+VAR result : integer;
+
+BEGIN
+result := close(PTfile);
+END; (* CloseFontFile *)
+
+(******************************************************************************)
+
+FUNCTION GetPTByte : INTEGER;
+
+(* Returns the value (unsigned) of the byte at PToffset and
+ advances PToffset for the next GetPTByte.
+*)
+
+VAR buffstart, result : INTEGER;
+
+BEGIN
+buffstart := (PToffset DIV bufflen) * bufflen; (* 0, bufflen, 2*bufflen... *)
+IF buffstart <> currPTbuff THEN BEGIN
+ currPTbuff := buffstart;
+ result := lseek(PTfile, buffstart, 0);
+ { DEBUG
+ IF result <> buffstart THEN BEGIN
+ writeln('Lseek failed in GetPTByte!'); exit(1);
+ END;
+ GUBED }
+ result := read(PTfile, PTbuffer, bufflen);
+ { DEBUG
+ IF result = -1 THEN BEGIN
+ writeln('Read failed in GetPTByte!'); exit(1);
+ END;
+ GUBED }
+END;
+GetPTByte := ORD(PTbuffer[PToffset - buffstart]);
+PToffset := PToffset + 1;
+END; (* GetPTByte *)
+
+(******************************************************************************)
+
+FUNCTION SignedPTByte : INTEGER; (* the next byte, signed *)
+
+VAR b : INTEGER;
+
+BEGIN
+b := GetPTByte;
+IF b < 128 THEN
+ SignedPTByte := b
+ELSE
+ SignedPTByte := b - 256;
+END; (* SignedPTByte *)
+
+(******************************************************************************)
+
+FUNCTION GetTwoPTBytes : INTEGER; (* the next 2 bytes, unsigned *)
+
+VAR a, b : INTEGER;
+
+BEGIN
+a := GetPTByte;
+b := GetPTByte;
+GetTwoPTBytes := a * 256 + b;
+END; (* GetTwoPTBytes *)
+
+(******************************************************************************)
+
+FUNCTION SignedPTPair : INTEGER; (* the next 2 bytes, signed *)
+
+VAR a, b : INTEGER;
+
+BEGIN
+a := GetPTByte;
+b := GetPTByte;
+IF a < 128 THEN
+ SignedPTPair := a * 256 + b
+ELSE
+ SignedPTPair := (a - 256) * 256 + b;
+END; (* SignedPTPair *)
+
+(******************************************************************************)
+
+FUNCTION GetThreePTBytes : INTEGER; (* the next 3 bytes, unsigned *)
+
+VAR a, b, c : INTEGER;
+
+BEGIN
+a := GetPTByte;
+b := GetPTByte;
+c := GetPTByte;
+GetThreePTBytes := (a * 256 + b) * 256 + c;
+END; (* GetThreePTBytes *)
+
+(******************************************************************************)
+
+FUNCTION SignedPTQuad : INTEGER; (* the next 4 bytes, signed *)
+
+
+TYPE int_or_bytes = RECORD
+ CASE b : BOOLEAN OF
+ TRUE : (int : INTEGER);
+ FALSE : (byt : PACKED ARRAY [0..3] OF CHAR);
+ END;
+
+VAR w : int_or_bytes;
+
+BEGIN
+WITH w DO BEGIN
+ w.byt[0] := CHR(GetPTByte);
+ w.byt[1] := CHR(GetPTByte);
+ w.byt[2] := CHR(GetPTByte);
+ w.byt[3] := CHR(GetPTByte);
+END;
+SignedPTQuad := w.int;
+END; (* SignedPTQuad *)
+
+(******************************************************************************)
+
+FUNCTION GetNyb : INTEGER;
+
+(* Return next nybble in PK file. *)
+
+BEGIN
+IF bitweight = 0 THEN BEGIN
+ (* SYSDEP: Pyramid Pascal stores bits 7..0 in the LEFT
+ byte of a 4-byte BITSET word. *)
+ inputbyte.ch[0] := CHR(GetPTByte);
+ bitweight := 16; (* for next call of GetNyb *)
+ GetNyb := ORD(inputbyte.ch[0]) DIV 16; (* high nybble *)
+END
+ELSE BEGIN
+ bitweight := 0; (* for next call of GetNyb *)
+ GetNyb := ORD(inputbyte.ch[0]) MOD 16; (* low nybble *)
+END;
+END; (* GetNyb *)
+
+(******************************************************************************)
+
+FUNCTION PackedNum : INTEGER;
+
+(* Return next run count using algorithm given in section 23 of PKtype.
+ A possible side-effect is to set the global repeatcount value used
+ to duplicate the current row.
+*)
+
+VAR i, j : INTEGER;
+
+BEGIN
+i := GetNyb;
+IF i = 0 THEN BEGIN
+ REPEAT j := GetNyb; i := i + 1 UNTIL j <> 0;
+ WHILE i > 0 DO BEGIN j := j * 16 + GetNyb; i := i - 1 END;
+ PackedNum := j - 15 + (13 - dynf) * 16 + dynf;
+END
+ELSE IF i <= dynf THEN
+ PackedNum := i
+ELSE IF i < 14 THEN
+ PackedNum := (i - dynf - 1) * 16 + GetNyb + dynf + 1
+ELSE BEGIN
+ IF i = 14 THEN
+ repeatcount := PackedNum (* recursive *)
+ ELSE
+ repeatcount := 1; (* nybble = 15 *)
+ PackedNum := PackedNum; (* recursive *)
+END;
+END; (* PackedNum *)
+
+(******************************************************************************)
+
+PROCEDURE LoadBitmap (fontptr : fontinfoptr; code : INTEGER);
+
+(* Output PostScript character definition using bitmap info at mapadr
+ in currently open PK file.
+*)
+
+CONST maxhexline = 72; (* keep even and < 80 *)
+
+VAR
+ hexline : PACKED ARRAY [1..maxhexline] OF CHAR;
+ hexcount, (* current hexline length *)
+ i, j, flagbyte, bitpos, bytesperrow,
+ rowsleft, hbit, count, rp : INTEGER;
+ byte : bytes_or_bits; (* we'll only consider bits 0..7 *)
+ row : ARRAY [0..400] OF CHAR; (* maximum glyph width = 3200 bits *)
+
+BEGIN
+WITH fontptr^.pixelptr^[code] DO BEGIN
+bytesperrow := (wd + 7) DIV 8; (* bytes in one row *)
+PToffset := mapadr; (* mapadr = flagbyte offset in PK file *)
+flagbyte := GetPTByte; (* assume < 240 *)
+dynf := flagbyte DIV 16;
+turnon := (flagbyte MOD 16) >= 8; (* is 1st pixel black? *)
+flagbyte := flagbyte MOD 8; (* value of bottom 3 bits *)
+IF flagbyte < 4 THEN (* skip short char preamble *)
+ PToffset := PToffset + 10
+ELSE IF flagbyte < 7 THEN (* skip extended short char preamble *)
+ PToffset := PToffset + 16
+ELSE (* skip long char preamble *)
+ PToffset := PToffset + 36;
+hexline[1] := '['; (* start of hex string *)
+hexline[2] := '<';
+hexcount := 2; (* chars in current hexline *)
+bitweight := 0; (* to get 1st inputbyte *)
+IF dynf = 14 THEN BEGIN
+ (* raster info is a string of bits in the next (wd * ht + 7) DIV 8 bytes *)
+ FOR i := 1 TO ht DO BEGIN
+ byte.bits := []; (* set all bits to 0 *)
+ bitpos := 7; (* leftmost bit *)
+ FOR j := 1 TO wd DO BEGIN
+ IF bitweight = 0 THEN BEGIN
+ inputbyte.ch[0] := CHR(GetPTByte);
+ bitweight := 8;
+ END;
+ bitweight := bitweight - 1; (* 7..0 *)
+ IF bitweight IN inputbyte.bits THEN
+ byte.bits := byte.bits + [bitpos]; (* include bitpos *)
+ IF bitpos > 0 THEN
+ bitpos := bitpos - 1 (* next bit *)
+ ELSE BEGIN
+ (* SYSDEP: Pyramid Pascal stores bits 7..0 in the LEFT
+ byte of a 4-byte BITSET word. *)
+ hexcount := hexcount + 1;
+ hexline[hexcount] := hexdigs[ ORD(byte.ch[0]) DIV 16 ];
+ hexcount := hexcount + 1;
+ hexline[hexcount] := hexdigs[ ORD(byte.ch[0]) MOD 16 ];
+ IF hexcount = maxhexline THEN BEGIN
+ writeln(PSfile,hexline:hexcount);
+ hexcount := 0;
+ END;
+ byte.bits := [];
+ bitpos := 7;
+ END;
+ END;
+ IF bitpos < 7 THEN BEGIN
+ hexcount := hexcount + 1;
+ hexline[hexcount] := hexdigs[ ORD(byte.ch[0]) DIV 16 ];
+ hexcount := hexcount + 1;
+ hexline[hexcount] := hexdigs[ ORD(byte.ch[0]) MOD 16 ];
+ IF hexcount = maxhexline THEN BEGIN
+ writeln(PSfile,hexline:hexcount);
+ hexcount := 0;
+ END;
+ END;
+ END
+END
+ELSE BEGIN
+ (* raster info is encoded as run and repeat counts *)
+ rowsleft := ht;
+ hbit := wd;
+ repeatcount := 0;
+ rp := 1;
+ bitpos := 8;
+ byte.bits := [];
+ WHILE rowsleft > 0 DO BEGIN
+ count := PackedNum;
+ WHILE count > 0 DO BEGIN
+ IF (count < bitpos) AND (count < hbit) THEN BEGIN
+ IF turnon THEN
+ byte.bits := byte.bits + gpower[bitpos]
+ - gpower[bitpos - count];
+ hbit := hbit - count;
+ bitpos := bitpos - count;
+ count := 0;
+ END
+ ELSE IF (count >= hbit) AND (hbit <= bitpos) THEN BEGIN
+ IF turnon THEN
+ byte.bits := byte.bits + gpower[bitpos]
+ - gpower[bitpos - hbit];
+ (* SYSDEP: Pyramid Pascal stores bits 7..0 in the LEFT
+ byte of a 4-byte BITSET word. *)
+ row[rp] := byte.ch[0];
+ (* end of current row, so send it repeatcount+1 times *)
+ FOR i := 0 TO repeatcount DO
+ FOR j := 1 TO bytesperrow DO BEGIN
+ hexcount := hexcount + 1;
+ hexline[hexcount] := hexdigs[ ORD(row[j]) DIV 16 ];
+ hexcount := hexcount + 1;
+ hexline[hexcount] := hexdigs[ ORD(row[j]) MOD 16 ];
+ IF hexcount = maxhexline THEN BEGIN
+ writeln(PSfile,hexline:hexcount);
+ hexcount := 0;
+ END;
+ END;
+ rowsleft := rowsleft - (repeatcount + 1);
+ repeatcount := 0;
+ rp := 1;
+ byte.bits := [];
+ bitpos := 8;
+ count := count - hbit;
+ hbit := wd;
+ END
+ ELSE BEGIN
+ IF turnon THEN byte.bits := byte.bits + gpower[bitpos];
+ row[rp] := byte.ch[0];
+ rp := rp + 1;
+ byte.bits := [];
+ count := count - bitpos;
+ hbit := hbit - bitpos;
+ bitpos := 8;
+ END;
+ END;
+ turnon := NOT turnon;
+ END;
+END;
+IF hexcount > 0 THEN write(PSfile,hexline:hexcount);
+writeln(PSfile, '>');
+writeln(PSfile, bytesperrow * 8:1, ' ', ht:1, ' ', xo:1, ' ', yo:1, ' ',
+ pwidth:1, '] ', code:1, ' dc');
+END; (* WITH *)
+END; (* LoadBitmap *)
+
+(******************************************************************************)
+
+FUNCTION FixToDVI (b0, b1, b2, b3 : INTEGER) : INTEGER;
+
+(* Convert the given fix width (made up of 4 bytes) into DVI units
+ using the method recommended in DVITYPE.
+*)
+
+VAR alpha, beta, temp, s : INTEGER;
+
+BEGIN
+WITH currfont^ DO BEGIN
+ s := scaledsize;
+ alpha := 16 * s;
+ beta := 16;
+ WHILE s >= 8#40000000 DO BEGIN (* 2^23 *)
+ s := s DIV 2;
+ beta := beta DIV 2;
+ END;
+ temp := (((((b3 * s) DIV 8#400) + (b2 * s)) DIV 8#400) + (b1 * s)) DIV beta;
+ IF b0 > 0 THEN
+ IF b0 = 255 THEN
+ FixToDVI := temp - alpha
+ ELSE BEGIN
+ writeln; writeln('Bad TFM width! 1st byte = ', b0:1); exit(1);
+ END
+ ELSE
+ FixToDVI := temp;
+END;
+END; (* FixToDVI *)
+
+(******************************************************************************)
+
+PROCEDURE PKFillPixelTable;
+
+(* Fill the pixeltable for currfont^ using the font directory info
+ in the currently open PK file.
+*)
+
+LABEL 888;
+
+CONST
+ pkid = 89;
+ pkpost = 245;
+ pknoop = 246;
+ pkpre = 247;
+
+VAR
+ i, j, flagbyte, flagpos,
+ chcode, (* assumed to be <= 255 *)
+ packetlen, endofpacket,
+ b0, b1, b2, b3 : INTEGER; (* 4 bytes in TFM width *)
+
+BEGIN
+WITH currfont^ DO BEGIN
+ PToffset := 0; (* move to first byte *)
+ IF GetPTByte <> pkpre THEN BEGIN
+ writeln; writeln('Bad pre command in ', fontspec:fontspeclen); exit(1);
+ END;
+ IF GetPTByte <> pkid THEN BEGIN
+ writeln; writeln('Bad id byte in ', fontspec:fontspeclen); exit(1);
+ END;
+ j := GetPTByte; (* length of comment *)
+ PToffset := PToffset + j + 16; (* skip rest of preamble *)
+ FOR i := 0 TO maxTeXchar DO
+ WITH pixelptr^[i] DO BEGIN
+ mapadr := 0; (* all chars absent initially *)
+ loaded := FALSE; (* bitmap not yet downloaded *)
+ END;
+ WHILE TRUE DO BEGIN
+ flagpos := PToffset; (* remember position of flagbyte *)
+ flagbyte := GetPTByte;
+ IF flagbyte < 240 THEN BEGIN (* read character definition *)
+ flagbyte := flagbyte MOD 8; (* value of bottom 3 bits *)
+ IF flagbyte < 4 THEN BEGIN (* short char preamble *)
+ packetlen := flagbyte * 256 + GetPTByte;
+ chcode := GetPTByte;
+ endofpacket := packetlen + PToffset;
+ WITH pixelptr^[chcode] DO BEGIN
+ b1 := GetPTByte;
+ b2 := GetPTByte;
+ b3 := GetPTByte;
+ dwidth := FixToDVI(0,b1,b2,b3); (* b0 = 0 *)
+ pwidth := GetPTByte;
+ wd := GetPTByte;
+ ht := GetPTByte;
+ xo := SignedPTByte;
+ yo := SignedPTByte;
+ END;
+ END
+ ELSE IF flagbyte < 7 THEN BEGIN (* extended short char preamble *)
+ packetlen := (flagbyte - 4) * 65536 + GetTwoPTBytes;
+ chcode := GetPTByte;
+ endofpacket := packetlen + PToffset;
+ WITH pixelptr^[chcode] DO BEGIN
+ b1 := GetPTByte;
+ b2 := GetPTByte;
+ b3 := GetPTByte;
+ dwidth := FixToDVI(0,b1,b2,b3); (* b0 = 0 *)
+ pwidth := GetTwoPTBytes;
+ wd := GetTwoPTBytes;
+ ht := GetTwoPTBytes;
+ xo := SignedPTPair;
+ yo := SignedPTPair;
+ END;
+ END
+ ELSE BEGIN (* long char preamble *)
+ packetlen := SignedPTQuad;
+ chcode := SignedPTQuad;
+ endofpacket := packetlen + PToffset;
+ WITH pixelptr^[chcode] DO BEGIN
+ b0 := GetPTByte;
+ b1 := GetPTByte;
+ b2 := GetPTByte;
+ b3 := GetPTByte;
+ dwidth := FixToDVI(b0,b1,b2,b3);
+ pwidth := SignedPTQuad DIV 65536; (* dx in pixels *)
+ PToffset := PToffset + 4; (* skip dy *)
+ wd := SignedPTQuad;
+ ht := SignedPTQuad;
+ xo := SignedPTQuad;
+ yo := SignedPTQuad;
+ END;
+ END;
+ WITH pixelptr^[chcode] DO
+ IF (wd = 0) OR (ht = 0) THEN
+ mapadr := 0 (* no bitmap *)
+ ELSE
+ mapadr := flagpos; (* position of flagbyte *)
+ PToffset := endofpacket; (* skip raster info *)
+ END
+ ELSE
+ CASE flagbyte OF
+ 240, 241, 242, 243 :
+ BEGIN
+ i := 0;
+ FOR j := 240 TO flagbyte DO i := 256 * i + GetPTByte;
+ PToffset := PToffset + i; (* skip special parameter *)
+ END;
+ 244 : PToffset := PToffset + 4; (* skip numspecial param *)
+ pknoop : ; (* do nothing *)
+ pkpost : goto 888; (* no more char defs *)
+ OTHERWISE
+ writeln; writeln('Bad flag byte in ', fontspec:fontspeclen);
+ exit(1);
+ END;
+ END; (* of LOOP; flagbyte = pkpost *)
+ 888:
+END;
+END; (* PKFillPixelTable *)
+
+(******************************************************************************)
+
+PROCEDURE ReadTFMIntegers;
+
+(* Read the first 6 16-bit integers in the TFM file. See TFtoPL section 8. *)
+
+BEGIN
+PToffset := 0; (* start reading at 1st byte in TFM file *)
+lf := GetTwoPTBytes;
+lh := GetTwoPTBytes;
+bc := GetTwoPTBytes;
+ec := GetTwoPTBytes;
+nw := GetTwoPTBytes;
+nh := GetTwoPTBytes;
+END; (* ReadTFMIntegers *)
+
+(******************************************************************************)
+
+PROCEDURE ReadTFMCharInfo;
+
+(* Read the TFMinfo array. See TFtoPL section 11. *)
+
+VAR c, i : INTEGER;
+
+BEGIN
+PToffset := 24 + (lh * 4); (* offset of TFMinfo array *)
+FOR c := bc TO ec DO
+ WITH TFMinfo[c] DO BEGIN
+ wdindex := GetPTByte * 4; (* offset from start of width array *)
+ i := GetPTByte; (* 2nd byte contains htindex and dpindex *)
+ htindex := (i DIV 16) * 4; (* offset from start of height array *)
+ dpindex := (i MOD 16) * 4; (* offset from start of depth array *)
+ PToffset := PToffset + 2; (* skip itindex and remainder bytes *)
+ END;
+END; (* ReadTFMCharInfo *)
+
+(******************************************************************************)
+
+PROCEDURE ReadTFMCharMetrics;
+
+(* Read the charmetrics array using the indices in TFMinfo. *)
+
+VAR wdbase, htbase, dpbase, b, c : INTEGER;
+
+BEGIN
+wdbase := 24 + lh * 4 + (ec - bc + 1) * 4; (* offset of width array *)
+htbase := wdbase + nw * 4; (* offset of height array *)
+dpbase := htbase + nh * 4; (* offset of depth array *)
+FOR c := bc TO ec DO
+ WITH TFMinfo[c] DO
+ WITH charmetrics[c] DO BEGIN
+ PToffset := wdbase + wdindex;
+ FOR b := 0 TO 3 DO width[b] := GetPTByte;
+ PToffset := htbase + htindex;
+ FOR b := 0 TO 3 DO height[b] := GetPTByte;
+ PToffset := dpbase + dpindex;
+ FOR b := 0 TO 3 DO depth[b] := GetPTByte;
+ END;
+END; (* ReadTFMCharMetrics *)
+
+(******************************************************************************)
+
+PROCEDURE TFMFillPixelTable;
+
+(* Fill the pixeltable for currfont^ (a PostScript font)
+ using information in the currently open TFM file.
+*)
+
+VAR c, dheight, pheight, ddepth, pdepth : INTEGER;
+
+BEGIN
+ReadTFMIntegers; (* read lf..nh *)
+ReadTFMCharInfo; (* fill TFMinfo array *)
+ReadTFMCharMetrics; (* fill charmetrics array *)
+WITH currfont^ DO BEGIN
+ FOR c := 0 TO bc - 1 DO
+ pixelptr^[c].mapadr := 0; (* chars < bc don't exist *)
+ FOR c := ec + 1 TO 255 DO
+ pixelptr^[c].mapadr := 0; (* chars > ec don't exist *)
+ FOR c := bc TO ec DO
+ WITH pixelptr^[c] DO
+ WITH charmetrics[c] DO BEGIN
+ dwidth := FixToDVI(width[0],width[1],width[2],width[3]);
+ dheight := FixToDVI(height[0],height[1],height[2],height[3]);
+ ddepth := FixToDVI(depth[0],depth[1],depth[2],depth[3]);
+ (* convert DVI units to pixels *)
+ pwidth := PixelRound(dwidth);
+ pheight := PixelRound(dheight);
+ pdepth := PixelRound(ddepth);
+ (* Since we don't have access to bitmap info for a PostScript font
+ we will have to use the TFM width/height/depth info to
+ approximate wd, ht, xo, yo.
+ *)
+ wd := pwidth;
+ wd := wd - (wd DIV 8); (* better approximation *)
+ ht := pheight + pdepth;
+ xo := 0;
+ yo := pheight - 1;
+ IF (wd = 0) OR (ht = 0) THEN
+ mapadr := 0 (* char all-white or not in font *)
+ ELSE
+ mapadr := 1; (* anything but 0 *)
+ loaded := FALSE; (* no bitmap available *)
+ END;
+END;
+END; (* TFMFillPixelTable *)
+
+(******************************************************************************)
+
+PROCEDURE PixelTableRoutine;
+
+(* DVIReader has just allocated a new pixeltable for currfont^ and
+ calls this routine from InterpretPage only ONCE per font
+ (the first time the font is used).
+ We get the pixeltable information from the font file given by fontspec.
+ We also set fontid to a unique identifier of the form "fontname.fontsize".
+ If fontspec does not exist then dummyfont is used and fontid is undefined.
+ We don't output any PostScript for non-existent fonts.
+*)
+
+VAR i, fontsizelen, firstn, lastn : INTEGER;
+
+BEGIN
+(* Initialize currfont^.fontspec and return start and end of fontsize
+ (unless psfont flag is set to TRUE).
+ currfont^.fontexists may also become TRUE.
+*)
+BuildFontSpec(currfont,firstn,lastn);
+WITH currfont^ DO BEGIN
+ IF OpenFontFile(fontspec) THEN BEGIN
+ (* only need fontid for a bitmapped font *)
+ IF NOT psfont THEN BEGIN
+ fontid := fontname;
+ fontsizelen := lastn - firstn + 1;
+ IF fontnamelen + fontsizelen < maxfontspec THEN BEGIN
+ (* append ".fontsize" to fontid *)
+ fontid[fontnamelen] := '.';
+ FOR i := 1 TO fontsizelen DO
+ fontid[fontnamelen + i] := fontspec[firstn + i - 1];
+ END
+ ELSE BEGIN
+ (* in the unlikely event that there is no room to append ".fontsize"
+ we simply leave fontid = fontname and hope it's unique *)
+ writeln;
+ writeln('Warning! fontname too long: ', fontname:fontnamelen);
+ END;
+ IF NOT conserveVM THEN NewBitmapFont(fontid);
+ END;
+ END
+ ELSE IF OpenFontFile(dummyfont) THEN BEGIN
+ (* fontid is left undefined; it will not be used *)
+ warncount := warncount + 1;
+ writeln;
+ writeln('Couldn''t open font file: ', fontspec:fontspeclen);
+ (* use dummy font info instead *)
+ END
+ ELSE BEGIN
+ writeln;
+ writeln('Couldn''t open dummy font: ', dummyfont:Len(dummyfont));
+ exit(1);
+ END;
+ IF psfont AND fontexists THEN
+ TFMFillPixelTable
+ ELSE
+ PKFillPixelTable;
+ CloseFontFile;
+END;
+END; (* PixelTableRoutine *)
+
+(******************************************************************************)
+
+PROCEDURE InitFontReader;
+
+(* This routine initializes some global variables. *)
+
+VAR i : INTEGER;
+
+BEGIN
+hexdigs := '0123456789ABCDEF'; (* for LoadBitmap *)
+gpower[0] := [];
+FOR i := 1 TO 8 DO
+ gpower[i] := gpower[i-1] + [i-1]; (* for LoadBitmap *)
+psprefixlen := Len(psprefix);
+fontdirlen := Len(fontdir);
+END; (* InitFontReader *)
diff --git a/dviware/psprint/unix/fontsample.tex b/dviware/psprint/unix/fontsample.tex
new file mode 100644
index 0000000000..f531af4cf3
--- /dev/null
+++ b/dviware/psprint/unix/fontsample.tex
@@ -0,0 +1,241 @@
+% This file produces font samples.
+% See the end for how to select fonts for evaluation.
+
+\nopagenumbers
+\parindent=0pt
+\hsize=6.3in
+\vsize=9.7in
+
+\def\init{\font\testfont=\fontname
+ \leftline{\tt\fontname}
+ \bigskip\bigskip
+ \testfont}
+
+\newcount\m \newcount\n \newcount\p \newdimen\dim
+\def\oct#1{\hbox{\rm\'{}\kern-.2em\it#1\/\kern.05em}} % octal constant
+\def\hex#1{\hbox{\rm\H{}\tt#1}} % hexadecimal constant
+\def\setdigs#1"#2{\gdef\h{#2}% \h=hex prefix; \0\1=corresponding octal
+ \m=\n \divide\m by 64 \xdef\0{\the\m}%
+ \multiply\m by-64 \advance\m by\n \divide\m by 8 \xdef\1{\the\m}}
+\def\testrow{\setbox0=\hbox{\penalty 1\def\\{\char"\h}%
+ \\0\\1\\2\\3\\4\\5\\6\\7\\8\\9\\A\\B\\C\\D\\E\\F%
+ \global\p=\lastpenalty}} % \p=1 if none of the characters exist
+\def\oddline{\cr
+ \noalign{\nointerlineskip}
+ \multispan{19}\hrulefill&
+ \setbox0=\hbox{\lower 2.3pt\hbox{\hex{\h x}}}\smash{\box0}\cr
+ \noalign{\nointerlineskip}}
+\newif\ifskipping
+
+\def\halfevenline{\loop\skippingfalse
+ \ifnum\n<128 \m=\n \divide\m 16 \chardef\next=\m
+ \expandafter\setdigs\meaning\next \testrow
+ \ifnum\p=1
+ \skippingfalse % if \skippingtrue then empty rows are removed
+ \fi\fi
+ \ifskipping \global\advance\n 16 \repeat
+ \ifnum\n=128 \let\next=\endchart\else\let\next=\halfmorechart\fi
+ \next}
+\def\halfmorechart{\cr\noalign{\hrule\penalty5000}
+ \chartline \oddline \m=\1 \advance\m 1 \xdef\1{\the\m}
+ \chartline \halfevenline}
+
+\def\evenline{\loop\skippingfalse
+ \ifnum\n<256 \m=\n \divide\m 16 \chardef\next=\m
+ \expandafter\setdigs\meaning\next \testrow
+ \ifnum\p=1
+ \skippingfalse % if \skippingtrue then empty rows are removed
+ \fi\fi
+ \ifskipping \global\advance\n 16 \repeat
+ \ifnum\n=256 \let\next=\endchart\else\let\next=\morechart\fi
+ \next}
+
+\def\morechart{\cr\noalign{\hrule\penalty5000}
+ \chartline \oddline \m=\1 \advance\m 1 \xdef\1{\the\m}
+ \chartline \evenline}
+\def\chartline{&\oct{\0\1x}&&\:&&\:&&\:&&\:&&\:&&\:&&\:&&\:&&}
+\def\chartstrut{\lower4.5pt\vbox to14pt{}}
+
+\def\halftable{$$\global\n=0
+ \halign to\hsize\bgroup
+ \chartstrut##\tabskip0pt plus10pt&
+ &\hfil##\hfil&\vrule##\cr
+ \lower6.5pt\null
+ &&&\oct0&&\oct1&&\oct2&&\oct3&&\oct4&&\oct5&&\oct6&&\oct7&\halfevenline}
+
+\def\table{$$\global\n=0
+ \halign to\hsize\bgroup
+ \chartstrut##\tabskip0pt plus10pt&
+ &\hfil##\hfil&\vrule##\cr
+ \lower6.5pt\null
+ &&&\oct0&&\oct1&&\oct2&&\oct3&&\oct4&&\oct5&&\oct6&&\oct7&\evenline}
+
+\def\endchart{\cr\noalign{\hrule}
+ \raise11.5pt\null&&&\hex 8&&\hex 9&&\hex A&&\hex B&
+ &\hex C&&\hex D&&\hex E&&\hex F&\cr\egroup$$\par\vfil\eject}
+
+\def\:{\setbox0=\hbox{\char\n}%
+ \ifdim\ht0>7.5pt\reposition
+ \else\ifdim\dp0>2.5pt\reposition\fi\fi
+ \box0\global\advance\n 1 }
+\def\reposition{\setbox0=\vbox{\kern2pt\box0}\dim=\dp0
+ \advance\dim 2pt \dp0=\dim}
+\def\centerlargechars{
+ \def\reposition{\setbox0=\hbox{$\vcenter{\kern2pt\box0\kern2pt}$}}}
+
+\def\text#1{{\baselineskip=#1\rightskip=0pt plus5em
+Our task is to create a paragraph illustrating what a typical piece of text
+looks like in a particular \TeX\ font. It should be stressed that not all
+\TeX\ fonts can be used for typesetting text. We need to show most of the
+characters in this font---for instance, something like ``the quick brown fox
+jumps over a lazy dog'' would use all the lower-case letters.
+How about ``THE QUICK BROWN FOX JUMPS OVER 9876543210 LAZY DOGS'' to make
+sure we show all the upper-case letters and digits? Such a paragraph would
+hardly be typical! Then there's ligatures (try and fit in words like fluffy,
+waffle, firefly, difficult) and examples of kerning (boxer, AWAY, vowel).
+But how do we put all this stuff into a paragraph that makes sense!?\par
+}\bigskip\bigskip}
+
+
+% Computer Modern fonts currently have 128 characters, so we use \halftable.
+% Parameter to \text is the \baselineskip and should be 2pt more than font size.
+% It is not possible to produce a DVI file with all the fonts listed below
+% because TeX has a limitation of about 100 fonts.
+
+\def\fontname{circle10} \init\halftable % no \text
+\def\fontname{circlew10} \init\halftable % no \text
+\def\fontname{cmb10} \init\text{12pt}\halftable
+\def\fontname{cmbsy10} \init\halftable % no \text
+\def\fontname{cmbx10} \init\text{12pt}\halftable
+\def\fontname{cmbx12} \init\text{14pt}\halftable
+\def\fontname{cmbx5} \init\text{7pt}\halftable
+\def\fontname{cmbx6} \init\text{8pt}\halftable
+\def\fontname{cmbx7} \init\text{9pt}\halftable
+\def\fontname{cmbx8} \init\text{10pt}\halftable
+\def\fontname{cmbx9} \init\text{11pt}\halftable
+\def\fontname{cmbxsl10} \init\text{12pt}\halftable
+\def\fontname{cmbxti10} \init\text{12pt}\halftable
+\def\fontname{cmcsc10} \init\text{12pt}\halftable
+\def\fontname{cmdunh10} \init\text{12pt}\halftable
+\def\fontname{cmex10} \init\halftable % no \text
+\def\fontname{cmff10} \init\text{12pt}\halftable
+\def\fontname{cmfi10} \init\text{12pt}\halftable
+\def\fontname{cmfib8} \init\text{10pt}\halftable
+%% TOO BIG!!! \def\fontname{cminch} \init\halftable % no \text
+%\def\fontname{cmitt10} \init\text{12pt}\halftable
+%\def\fontname{cmmi10} \init\halftable % no \text
+%\def\fontname{cmmi12} \init\halftable % no \text
+%\def\fontname{cmmi5} \init\halftable % no \text
+%\def\fontname{cmmi6} \init\halftable % no \text
+%\def\fontname{cmmi7} \init\halftable % no \text
+%\def\fontname{cmmi8} \init\halftable % no \text
+%\def\fontname{cmmi9} \init\halftable % no \text
+%\def\fontname{cmmib10} \init\halftable % no \text
+%\def\fontname{cmr10} \init\text{12pt}\halftable
+%\def\fontname{cmr12} \init\text{14pt}\halftable
+%\def\fontname{cmr17} \init\text{19pt}\halftable
+%\def\fontname{cmr5} \init\text{7pt}\halftable
+%\def\fontname{cmr6} \init\text{8pt}\halftable
+%\def\fontname{cmr7} \init\text{9pt}\halftable
+%\def\fontname{cmr8} \init\text{10pt}\halftable
+%\def\fontname{cmr9} \init\text{11pt}\halftable
+%\def\fontname{cmsl10} \init\text{12pt}\halftable
+%\def\fontname{cmsl12} \init\text{14pt}\halftable
+%\def\fontname{cmsl8} \init\text{10pt}\halftable
+%\def\fontname{cmsl9} \init\text{11pt}\halftable
+%\def\fontname{cmsltt10} \init\text{12pt}\halftable
+%\def\fontname{cmss10} \init\text{12pt}\halftable
+%\def\fontname{cmss12} \init\text{14pt}\halftable
+%\def\fontname{cmss17} \init\text{19pt}\halftable
+%\def\fontname{cmss8} \init\text{10pt}\halftable
+%\def\fontname{cmss9} \init\text{11pt}\halftable
+%\def\fontname{cmssbx10} \init\text{12pt}\halftable
+%\def\fontname{cmssdc10} \init\text{12pt}\halftable
+%\def\fontname{cmssi10} \init\text{12pt}\halftable
+%\def\fontname{cmssi12} \init\text{14pt}\halftable
+%\def\fontname{cmssi17} \init\text{19pt}\halftable
+%\def\fontname{cmssi8} \init\text{10pt}\halftable
+%\def\fontname{cmssi9} \init\text{11pt}\halftable
+%\def\fontname{cmssq8} \init\text{10pt}\halftable
+%\def\fontname{cmssqi8} \init\text{10pt}\halftable
+%\def\fontname{cmsy10} \init\halftable % no \text
+%\def\fontname{cmsy5} \init\halftable % no \text
+%\def\fontname{cmsy6} \init\halftable % no \text
+%\def\fontname{cmsy7} \init\halftable % no \text
+%\def\fontname{cmsy8} \init\halftable % no \text
+%\def\fontname{cmsy9} \init\halftable % no \text
+%\def\fontname{cmtcsc10} \init\text{12pt}\halftable
+%\def\fontname{cmtex10} \init\text{12pt}\halftable
+%\def\fontname{cmtex8} \init\text{10pt}\halftable
+%\def\fontname{cmtex9} \init\text{11pt}\halftable
+%\def\fontname{cmti10} \init\text{12pt}\halftable
+%\def\fontname{cmti12} \init\text{14pt}\halftable
+%\def\fontname{cmti7} \init\text{9pt}\halftable
+%\def\fontname{cmti8} \init\text{10pt}\halftable
+%\def\fontname{cmti9} \init\text{11pt}\halftable
+%\def\fontname{cmtt10} \init\text{12pt}\halftable
+%\def\fontname{cmtt12} \init\text{14pt}\halftable
+%\def\fontname{cmtt8} \init\text{10pt}\halftable
+%\def\fontname{cmtt9} \init\text{11pt}\halftable
+%\def\fontname{cmu10} \init\text{12pt}\halftable
+%\def\fontname{cmvtt10} \init\text{12pt}\halftable
+%\def\fontname{crest} \init\halftable % no \text
+%\def\fontname{lasy10} \init\halftable % no \text
+%\def\fontname{lasy5} \init\halftable % no \text
+%\def\fontname{lasy6} \init\halftable % no \text
+%\def\fontname{lasy7} \init\halftable % no \text
+%\def\fontname{lasy8} \init\halftable % no \text
+%\def\fontname{lasy9} \init\halftable % no \text
+%\def\fontname{lasyb10} \init\halftable % no \text
+%\def\fontname{line10} \init\halftable % no \text
+%\def\fontname{linew10} \init\halftable % no \text
+%\def\fontname{logo10} \init\halftable % no \text
+%\def\fontname{logo8} \init\halftable % no \text
+%\def\fontname{logo9} \init\halftable % no \text
+%\def\fontname{logobf10} \init\halftable % no \text
+%\def\fontname{logosl10} \init\halftable % no \text
+
+% PostScript fonts can have up to 256 characters.
+% These fonts are resident in all PostScript printers:
+
+%\def\fontname{ps-times-r at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-times-b at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-times-bi at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-times-i at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-times-s at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-courier at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-courier-b at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-courier-bo at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-courier-o at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-helv at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-helv-b at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-helv-bo at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-helv-o at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-symbol at 10pt} \init\table % no \text
+
+% These fonts are in LaserWriter Plus and later models:
+
+%\def\fontname{ps-avantg-b at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-avantg-bo at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-avantg-d at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-avantg-do at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-bookman-d at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-bookman-di at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-bookman-l at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-bookman-li at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-helv-n at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-helv-nb at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-helv-nbo at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-helv-no at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-ncs-b at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-ncs-bo at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-ncs-i at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-ncs-r at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-pal-b at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-pal-bi at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-pal-i at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-pal-r at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-zapfch-mi at 10pt} \init\text{12pt}\table
+%\def\fontname{ps-zapfdb at 10pt} \init\table % no \text
+
+\end
diff --git a/dviware/psprint/unix/globals.h b/dviware/psprint/unix/globals.h
new file mode 100644
index 0000000000..b2e49f4b7c
--- /dev/null
+++ b/dviware/psprint/unix/globals.h
@@ -0,0 +1,14 @@
+(* Global data and routines *)
+
+CONST
+ maxstring = 80;
+ maxstringm = maxstring - 1;
+
+TYPE
+ string = ARRAY [0..maxstringm] OF CHAR;
+
+VAR
+ warncount : INTEGER; (* used to determine exit status *)
+
+PROCEDURE exit (status : integer); EXTERNAL;
+(* SYSDEP: 0 = success, 1 = error, 2 = warning *)
diff --git a/dviware/psprint/unix/greybox.ps b/dviware/psprint/unix/greybox.ps
new file mode 100644
index 0000000000..220564810a
--- /dev/null
+++ b/dviware/psprint/unix/greybox.ps
@@ -0,0 +1,31 @@
+% This file is inserted into the PSPRINT User Guide using \special.
+% It draws a shaded rectangle.
+
+72 72 scale % units are now inches instead of big points
+
+% uncomment the next line if you want to "psprint greybox.ps"
+% 2 2 translate
+
+newpath % prepare to draw a rectangle
+ -.25 0.1 moveto % top left corner is a little left and above origin
+ 0 -.7 rlineto % down .7
+ 4.5 0 rlineto % right 4.5
+ 0 .7 rlineto % up .7
+closepath % complete rectangle
+gsave % save current path
+
+0.9 setgray % light grey
+
+statusdict /product known
+{ statusdict /product get
+ 0 11 getinterval
+ (LaserWriter) eq
+ {.99 setgray} if % if LaserWriter use very light shading (0=black, 1=white)
+} if
+
+fill % paint interior of rectangle
+grestore % restore current path
+.01 setlinewidth % thickness of borders
+stroke % paint borders
+
+showpage
diff --git a/dviware/psprint/unix/info.ps b/dviware/psprint/unix/info.ps
new file mode 100644
index 0000000000..c1fbaf1f98
--- /dev/null
+++ b/dviware/psprint/unix/info.ps
@@ -0,0 +1,107 @@
+% Print page showing various status values.
+
+/oldusertime usertime def
+
+initgraphics
+newpath clippath stroke % show maximum image area
+
+72 0 translate % move origin to the right
+/vpos 720 def % initial vertical pos
+0 vpos moveto % start near top left corner
+
+/newline
+{ /vpos vpos 12 sub def % decrease vertical pos
+ 0 vpos moveto % move to start of new line
+} def
+
+/Courier findfont 10 scalefont setfont
+
+statusdict begin
+ margins % int int (top and left margins)
+ 9 sccbatch % baud options (for 9-pin serial channel)
+ 25 sccbatch % baud options (for 25-pin serial channel)
+ revision % int
+ product dup % string
+ (Linotype) eq
+ { userdiskpercent % percent
+ diskstatus % free total
+ resolution % int
+ true % we are running on a Linotronic
+ }
+ { false % we are running on some other device
+ } ifelse
+end
+
+% true or false currently on top of stack
+
+{ (RESOLUTION = ) show ( ) cvs show newline
+ (DISK STATUS = ) show ( ) cvs show
+ ( ) show ( ) cvs show newline
+ (USER DISK % = ) show ( ) cvs show newline
+} if
+
+(PRODUCT = ) show show newline
+(REVISION = ) show ( ) cvs show newline
+(VERSION = ) show version show newline
+
+newline
+(CHANNEL 25 = ) show ( ) cvs show
+( ) show ( ) cvs show newline
+(CHANNEL 9 = ) show ( ) cvs show
+( ) show ( ) cvs show newline
+
+newline
+(LEFT MARGIN = ) show ( ) cvs show newline
+(TOP MARGIN = ) show ( ) cvs show newline
+
+version cvr 25.0 gt % PS version >= 25.0 ?
+{
+ newline
+ currentpacking % bool
+ (CURRENT PACKING = ) show
+ ( ) cvs show newline
+
+ newline
+ currentcacheparams % mark lower upper
+ (CURRENT CACHE PARAMS) show newline
+ counttomark
+ { ( ) cvs show newline }
+ repeat
+ pop % remove mark
+} if
+
+newline
+(DEFAULTMATRIX = ) show
+matrix defaultmatrix % [ ? ? ? ? ? ? ]
+dup 0 get ( ) cvs show ( ) show
+dup 1 get ( ) cvs show ( ) show
+dup 2 get ( ) cvs show ( ) show
+dup 3 get ( ) cvs show ( ) show
+dup 4 get ( ) cvs show ( ) show
+dup 5 get ( ) cvs show ( ) show
+newline
+pop
+
+newline
+(CACHE STATUS) show newline
+cachestatus % bsize bmax msize mmax csize cmax blimit
+(blimit = ) show ( ) cvs show newline
+(cmax = ) show ( ) cvs show newline
+(csize = ) show ( ) cvs show newline
+(mmax = ) show ( ) cvs show newline
+(msize = ) show ( ) cvs show newline
+(bmax = ) show ( ) cvs show newline
+(bsize = ) show ( ) cvs show newline
+
+newline
+(VM STATUS) show newline
+vmstatus % savelevel vmused vmmax
+(vm max = ) show ( ) cvs show newline
+(vm used = ) show ( ) cvs show newline
+(save level = ) show ( ) cvs show newline
+
+newline
+(JOB TIME (secs) = ) show
+usertime oldusertime sub 1000 div ( ) cvs show newline
+
+showpage
diff --git a/dviware/psprint/unix/lino_fonts.ps b/dviware/psprint/unix/lino_fonts.ps
new file mode 100644
index 0000000000..e0c18a2fcc
--- /dev/null
+++ b/dviware/psprint/unix/lino_fonts.ps
@@ -0,0 +1,68 @@
+% This file converts TFM font names into the actual Linotronic font names:
+
+ % These fonts are resident in all PostScript printers:
+/ps-courier-b /Courier-Bold def
+/ps-courier-bo /Courier-BoldOblique def
+/ps-courier-o /Courier-Oblique def
+/ps-courier /Courier def
+/ps-helv-b /Helvetica-Bold def
+/ps-helv-bo /Helvetica-BoldOblique def
+/ps-helv-o /Helvetica-Oblique def
+/ps-helv /Helvetica def
+/ps-symbol /Symbol def
+/ps-times-b /Times-Bold def
+/ps-times-bi /Times-BoldItalic def
+/ps-times-i /Times-Italic def
+/ps-times-r /Times-Roman def
+
+ % This font will be constructed from Times-Roman:
+/ps-times-s /Times-Slanted def
+
+ % These fonts MIGHT be available in Linotronic:
+/ps-avantg-b /AvantGarde-Book def
+/ps-avantg-bo /AvantGarde-BookOblique def
+/ps-avantg-d /AvantGarde-Demi def
+/ps-avantg-do /AvantGarde-DemiOblique def
+/ps-bookman-d /Bookman-Demi def
+/ps-bookman-di /Bookman-DemiItalic def
+/ps-bookman-l /Bookman-Light def
+/ps-bookman-li /Bookman-LightItalic def
+/ps-helv-n /Helvetica-Narrow def
+/ps-helv-nb /Helvetica-Narrow-Bold def
+/ps-helv-nbo /Helvetica-Narrow-BoldOblique def
+/ps-helv-no /Helvetica-Narrow-Oblique def
+/ps-ncs-b /NewCenturySchlbk-Bold def
+/ps-ncs-bo /NewCenturySchlbk-BoldItalic def
+/ps-ncs-i /NewCenturySchlbk-Italic def
+/ps-ncs-r /NewCenturySchlbk-Roman def
+/ps-pal-b /Palatino-Bold def
+/ps-pal-bi /Palatino-BoldItalic def
+/ps-pal-i /Palatino-Italic def
+/ps-pal-r /Palatino-Roman def
+/ps-zapfch-mi /ZapfChancery-MediumItalic def
+/ps-zapfdb /ZapfDingbats def
+
+ % These fonts don't have TFM files for them as yet:
+% /??? /Garamond-Bold def
+% /??? /Garamond-BoldItalic def
+% /??? /Garamond-Light def
+% /??? /Garamond-LightItalic def
+% /??? /Goudy-Bold def
+% /??? /Goudy-BoldItalic def
+% /??? /Goudy-Italic def
+% /??? /Goudy def
+% /??? /Helvetica-Light def
+% /??? /Helvetica-LightOblique def
+% /??? /NewBaskerville-Bold def
+% /??? /NewBaskerville-BoldItalic def
+% /??? /NewBaskerville-Italic def
+% /??? /NewBaskerville-Roman def
+% /??? /Optima-Bold def
+% /??? /Optima-BoldOblique def
+% /??? /Optima-Oblique def
+% /??? /Optima def
+% /??? /Sonata def
+% /??? /Souvenir-Demi def
+% /??? /Souvenir-DemiItalic def
+% /??? /Souvenir-Light def
+% /??? /Souvenir-LightItalic def
diff --git a/dviware/psprint/unix/lino_header.ps b/dviware/psprint/unix/lino_header.ps
new file mode 100644
index 0000000000..44aaeef320
--- /dev/null
+++ b/dviware/psprint/unix/lino_header.ps
@@ -0,0 +1,273 @@
+% This file is sent at the start of each Linotronic job.
+% It defines @bannerpage, @footerpage and a PostScript error handler.
+% It also defines page sizes and orientations, margin, and cutmark procedure.
+
+statusdict begin /waittimeout 300 def end % wait 5 minutes
+
+/@bannerpage % called below
+{ initgraphics
+ statusdict begin
+ 842 72 0 1 setpageparams % width height margin orientation
+ end
+ 25 0 translate % move origin to the right
+ /vpos 55 def % initial vertical pos
+ 0 vpos moveto % start near top left corner
+ /newline
+ { /vpos vpos 15 sub def % decrease vertical pos by 15pt
+ 0 vpos moveto % move to start of new line
+ } def
+ /newline2
+ { /vpos vpos 10 sub def % decrease vertical pos by 10pt
+ 0 vpos moveto % move to start of new line
+ } def
+ /Courier findfont % Courier typewriter font
+ 9 scalefont setfont % at 9pt
+ (****************************************************************************\
+**********************************************************) show newline2
+ /Courier findfont % Courier typewriter font
+ 15 scalefont setfont % at 15pt
+ @USER show newline % user name and file spec
+ /Courier findfont % Courier typewriter font
+ 9 scalefont setfont % at 9pt
+ @DATE show newline2
+ @NOTE show newline2
+ (----------------------------------------------------------------------------\
+----------------------------------------------------------) show
+ /#copies 1 def % print only 1 copy of banner page
+ systemdict /showpage get exec
+} def
+
+/@footerpage % called at end of job or after error
+{ initgraphics
+ statusdict begin
+ 842 72 0 1 setpageparams % width height margin orientation
+ end
+ 25 0 translate % move origin to the right
+ /vpos 55 def % initial vertical pos
+ 0 vpos moveto % start near top left corner
+ /newline
+ { /vpos vpos 15 sub def % decrease vertical pos by 15pt
+ 0 vpos moveto % move to start of new line
+ } def
+ /newline2
+ { /vpos vpos 10 sub def % decrease vertical pos by 10pt
+ 0 vpos moveto % move to start of new line
+ } def
+ /Courier findfont % Courier typewriter font
+ 9 scalefont setfont % at 9pt
+ (----------------------------------------------------------------------------\
+----------------------------------------------------------) show newline2
+ /Courier findfont % Courier typewriter font
+ 15 scalefont setfont % at 15pt
+ @USER show newline % user name and file spec
+ /Courier findfont % Courier typewriter font
+ 9 scalefont setfont % at 9pt
+ @DATE show newline2
+ (PAGE COUNT: ) show
+ statusdict begin
+ pagecount % current pagecount
+ end
+ @oldpagecount % pagecount saved in banner.ps
+ sub ( ) cvs
+ show newline2 % show pages printed
+ (****************************************************************************\
+**********************************************************) show
+ /#copies 1 def % print only 1 copy of footer page
+ systemdict /showpage get exec
+} def
+
+% Redefine the error handler in errordict to show a suitable error message.
+
+/@errpage 64 dict def
+@errpage begin
+/prnt
+{ dup type/stringtype ne{=string cvs}if dup length 6 mul/tx exch def/ty 10 def
+ currentpoint/toy exch def/tox exch def 1 setgray newpath
+ tox toy 2 sub moveto 0 ty rlineto tx 0 rlineto 0 ty neg rlineto
+ closepath fill tox toy moveto 0 setgray show
+} bind def
+/nl {currentpoint exch pop lmargin exch moveto 0 -11 rmoveto} def
+/== {/cp 0 def typeprint nl} def
+/typeprint
+{ dup type dup currentdict exch known
+ {exec}{unknowntype}ifelse
+} readonly def
+/lmargin 72 def
+/rmargin 72 def
+/tprint
+{ dup length cp add rmargin gt{nl/cp 0 def}if
+ dup length cp add/cp exch def prnt
+} readonly def
+/cvsprint {=string cvs tprint( )tprint} readonly def
+/unknowntype {exch pop cvlit(??)tprint cvsprint} readonly def
+/integertype {cvsprint} readonly def
+/realtype {cvsprint} readonly def
+/booleantype {cvsprint} readonly def
+/operatortype {(//)tprint cvsprint} readonly def
+/marktype {pop(-mark- )tprint} readonly def
+/dicttype {pop(-dictionary- )tprint} readonly def
+/nulltype {pop(-null- )tprint} readonly def
+/filetype {pop(-filestream- )tprint} readonly def
+/savetype {pop(-savelevel- )tprint} readonly def
+/fonttype {pop(-fontid- )tprint} readonly def
+/nametype {dup xcheck not{(/)tprint}if cvsprint} readonly def
+/stringtype
+{ dup rcheck{(\()tprint tprint(\))tprint}{pop(-string- )tprint}ifelse
+} readonly def
+/arraytype
+{ dup rcheck{dup xcheck
+ {({)tprint{typeprint}forall(})tprint}
+ {([)tprint{typeprint}forall(])tprint}ifelse}{pop(-array- )tprint}ifelse
+} readonly def
+/packedarraytype
+{ dup rcheck{dup xcheck
+ {({)tprint{typeprint}forall(})tprint}
+ {([)tprint{typeprint}forall(])tprint}ifelse}{pop(-packedarray- )tprint}ifelse
+} readonly def
+/courier /Courier findfont 10 scalefont def
+/@oldhandleerror errordict /handleerror get def % save current error handler
+end
+% of @errpage
+
+errordict /handleerror % redefine error handler
+{ systemdict begin $error begin @errpage begin
+ newerror
+ { /newerror false store
+ vmstatus pop pop 0 ne { grestoreall } if
+ initgraphics
+ newpath clippath pathbbox % push LLx LLy URx URy
+ lmargin exch 360 sub moveto % subtract 5" from URy
+ pop pop pop % remove URx LLy LLx
+ courier setfont
+ (POSTSCRIPT ERROR: ) prnt errorname prnt nl
+ (OFFENDING COMMAND: ) prnt /command load prnt nl
+ $error /ostack known
+ { (OPERAND STACK:) prnt nl
+ $error /ostack get aload length {==} repeat
+ } if
+ /#copies 1 store % print only one error page
+ systemdict /showpage get exec
+ userdict begin @footerpage end % then print footer page
+ /newerror true store
+ /@oldhandleerror load end end end exec }
+ { end end end }
+ ifelse
+} dup 0 systemdict put dup 4 @errpage put bind readonly put
+
+@bannerpage % print the banner page
+
+/@oldpagecount % used in @footerpage
+ statusdict begin pagecount end
+def
+
+% margin is offset (in pts) from paper edge.
+% psprint must make sure that one of the following page setups is called.
+% The built-in page setups are available in version 42.5 but not 38.0.
+
+/A3Lsetup
+{ /margin 0 def % margin + width must be <= 842 = 11.7in
+ statusdict begin
+ margin setpagemargin
+ end
+ a3 % built-in procedure in userdict
+} def
+
+/A4Psetup
+{ /margin 0 def % margin + width must be <= 842 = 11.7in
+ statusdict begin
+ margin setpagemargin
+ end
+ A4 % built-in procedure in userdict
+} def
+
+/A4Lsetup
+{ /margin 25 def
+ statusdict begin
+ margin setpagemargin
+ end
+ a4 % built-in procedure in userdict
+} def
+
+/A5Psetup
+{ /margin 25 def
+ statusdict begin
+ margin setpagemargin
+ end
+ A5 % built-in procedure in userdict
+} def
+
+/A5Lsetup
+{ /margin 25 def
+ statusdict begin
+ margin setpagemargin
+ end
+ a5 % built-in procedure in userdict
+} def
+
+/B5Psetup
+{ /margin 25 def
+ statusdict begin
+ margin setpagemargin
+ end
+ B5 % built-in procedure in userdict
+} def
+
+/B5Lsetup
+{ /margin 25 def
+ statusdict begin
+ margin setpagemargin
+ end
+ b5 % built-in procedure in userdict
+} def
+
+/cornercuts
+{ % draw short lines at corners of page image area
+ initgraphics
+ newpath clippath pathbbox % push LLx LLy URx URy
+ /URy exch def
+ /URx exch def
+ % don't use LLx LLy because they don't allow for margin setting
+ pop pop
+ newpath % remove clipping path
+ % line length = 10pt
+ URx URy moveto -10 0 rlineto
+ URx URy moveto 0 -10 rlineto
+ 0 0 moveto 10 0 rlineto
+ 0 0 moveto 0 10 rlineto
+ 0 URy moveto 10 0 rlineto
+ 0 URy moveto 0 -10 rlineto
+ URx 0 moveto -10 0 rlineto
+ URx 0 moveto 0 10 rlineto
+ 0.2 setlinewidth
+ stroke
+} def
+
+% psprint will override this default if user asks for -nocut:
+
+/@cutmarks { cornercuts } def
+
+% Redefine userdict showpage to first call @cutmarks, then showpage
+% from systemdict, then a thin blank page to separate job pages:
+
+/showpage
+{ @cutmarks % draw any cut marks
+ systemdict /showpage get exec % show current page
+ statusdict begin pageparams end % get width height margin orientation
+ /oldorientation exch def
+ /oldmargin exch def
+ /oldheight exch def
+ /oldwidth exch def % save current page setups
+ /old#copies #copies def % save current #copies
+ /#copies 1 def % only print 1 gap page
+ statusdict begin
+ 842 18 0 1 setpageparams % 18pt = .25" gap
+ end
+ systemdict /showpage get exec % show gap page
+ /@oldpagecount @oldpagecount 1 add def % increment @oldpagecount
+ oldwidth
+ oldheight
+ oldmargin
+ oldorientation
+ statusdict begin setpageparams end % restore saved page setup
+ /#copies old#copies def % restore saved #copies
+} def
diff --git a/dviware/psprint/unix/lino_pages.ps b/dviware/psprint/unix/lino_pages.ps
new file mode 100644
index 0000000000..3813b51408
--- /dev/null
+++ b/dviware/psprint/unix/lino_pages.ps
@@ -0,0 +1,16 @@
+% Tests Lino page setups defined in lino_header.ps.
+
+/Helvetica findfont 30 scalefont setfont
+
+/borders
+{ % draw border lines around page image area
+ newpath clippath 0.1 setlinewidth stroke
+} def
+
+A3Lsetup borders 216 216 moveto (A3L) show showpage
+A4Psetup borders 216 216 moveto (A4P) show showpage
+A4Lsetup borders 216 216 moveto (A4L) show showpage
+A5Psetup borders 216 216 moveto (A5P) show showpage
+A5Lsetup borders 216 216 moveto (A5L) show showpage
+B5Psetup borders 216 216 moveto (B5P) show showpage
+B5Lsetup borders 216 216 moveto (B5L) show showpage
diff --git a/dviware/psprint/unix/lino_trailer.ps b/dviware/psprint/unix/lino_trailer.ps
new file mode 100644
index 0000000000..26534f7984
--- /dev/null
+++ b/dviware/psprint/unix/lino_trailer.ps
@@ -0,0 +1 @@
+@footerpage % print footer page at end of Linotronic job
diff --git a/dviware/psprint/unix/lw_fonts.ps b/dviware/psprint/unix/lw_fonts.ps
new file mode 100644
index 0000000000..56589c8cd0
--- /dev/null
+++ b/dviware/psprint/unix/lw_fonts.ps
@@ -0,0 +1,43 @@
+% This file converts TFM font names into the actual LaserWriter font names:
+
+ % These fonts are resident in all PostScript printers:
+/ps-courier-b /Courier-Bold def
+/ps-courier-bo /Courier-BoldOblique def
+/ps-courier-o /Courier-Oblique def
+/ps-courier /Courier def
+/ps-helv-b /Helvetica-Bold def
+/ps-helv-bo /Helvetica-BoldOblique def
+/ps-helv-o /Helvetica-Oblique def
+/ps-helv /Helvetica def
+/ps-symbol /Symbol def
+/ps-times-b /Times-Bold def
+/ps-times-bi /Times-BoldItalic def
+/ps-times-i /Times-Italic def
+/ps-times-r /Times-Roman def
+
+ % This font will be constructed from Times-Roman:
+/ps-times-s /Times-Slanted def
+
+ % These fonts are resident in a LaserWriter Plus:
+/ps-avantg-b /AvantGarde-Book def
+/ps-avantg-bo /AvantGarde-BookOblique def
+/ps-avantg-d /AvantGarde-Demi def
+/ps-avantg-do /AvantGarde-DemiOblique def
+/ps-bookman-d /Bookman-Demi def
+/ps-bookman-di /Bookman-DemiItalic def
+/ps-bookman-l /Bookman-Light def
+/ps-bookman-li /Bookman-LightItalic def
+/ps-helv-n /Helvetica-Narrow def
+/ps-helv-nb /Helvetica-Narrow-Bold def
+/ps-helv-nbo /Helvetica-Narrow-BoldOblique def
+/ps-helv-no /Helvetica-Narrow-Oblique def
+/ps-ncs-b /NewCenturySchlbk-Bold def
+/ps-ncs-bo /NewCenturySchlbk-BoldItalic def
+/ps-ncs-i /NewCenturySchlbk-Italic def
+/ps-ncs-r /NewCenturySchlbk-Roman def
+/ps-pal-b /Palatino-Bold def
+/ps-pal-bi /Palatino-BoldItalic def
+/ps-pal-i /Palatino-Italic def
+/ps-pal-r /Palatino-Roman def
+/ps-zapfch-mi /ZapfChancery-MediumItalic def
+/ps-zapfdb /ZapfDingbats def
diff --git a/dviware/psprint/unix/lw_header.ps b/dviware/psprint/unix/lw_header.ps
new file mode 100644
index 0000000000..bd6bbac0d1
--- /dev/null
+++ b/dviware/psprint/unix/lw_header.ps
@@ -0,0 +1,136 @@
+% psprint uses this file to build an appropriate header file for each job.
+% It defines @bannerpage and redefines the PostScript error handler.
+
+statusdict begin /waittimeout 300 def end % wait 5 minutes
+
+/@oldpagecount statusdict begin pagecount end def
+
+/@bannerpage % called at end of job or upon error
+{ initgraphics
+ 36 0 translate % move origin to the right
+ /vpos 800 def % initial vertical pos
+ 0 vpos moveto % start near top left corner
+ /newline
+ { /vpos vpos 20 sub def % decrease vertical pos by 20pt
+ 0 vpos moveto % move to start of new line
+ } def
+ /Courier findfont % Courier typewriter font
+ 12 scalefont setfont % at 12pt
+ (*********************** psprint 3.0 **********************) show newline
+ @USER show newline
+ @NODE show newline
+ @FILE show newline
+ @FORMAT show newline
+ @QUEUED show newline
+ (PAGES : ) show
+ statusdict begin
+ pagecount % current pagecount
+ end
+ @oldpagecount % pagecount saved at start of job
+ sub ( ) cvs
+ show newline % show pages printed
+ @NOTE show newline
+% @status % uncomment to get status info
+ /#copies 1 def % only 1 copy of banner page
+ systemdict /showpage get exec
+} def
+
+% Uncomment the following (and above call) to get status info on banner page:
+%
+% /@oldusertime usertime def % save current usertime
+% /@status % show cache and VM status values
+% { newline
+% (CACHE STATUS) show newline
+% cachestatus % bsize bmax msize mmax csize cmax blimit
+% (blimit = ) show ( ) cvs show newline
+% (cmax = ) show ( ) cvs show newline
+% (csize = ) show ( ) cvs show newline
+% (mmax = ) show ( ) cvs show newline
+% (msize = ) show ( ) cvs show newline
+% (bmax = ) show ( ) cvs show newline
+% (bsize = ) show ( ) cvs show newline
+% newline
+% (VM STATUS) show newline
+% vmstatus % savelevel vmused vmmax
+% (vm max = ) show ( ) cvs show newline
+% (vm used = ) show ( ) cvs show newline
+% (save level = ) show ( ) cvs show newline
+% newline
+% (JOB TIME (secs) = ) show usertime @oldusertime sub 1000 div
+% ( ) cvs show
+% } def
+
+% Redefine the error handler in errordict to show a suitable error message.
+
+/@errpage 64 dict def
+@errpage begin
+/prnt
+{ dup type/stringtype ne{=string cvs}if dup length 6 mul/tx exch def/ty 10 def
+ currentpoint/toy exch def/tox exch def 1 setgray newpath
+ tox toy 2 sub moveto 0 ty rlineto tx 0 rlineto 0 ty neg rlineto
+ closepath fill tox toy moveto 0 setgray show
+} bind def
+/nl {currentpoint exch pop lmargin exch moveto 0 -11 rmoveto} def
+/== {/cp 0 def typeprint nl} def
+/typeprint
+{ dup type dup currentdict exch known
+ {exec}{unknowntype}ifelse
+} readonly def
+/lmargin 72 def
+/rmargin 72 def
+/tprint
+{ dup length cp add rmargin gt{nl/cp 0 def}if
+ dup length cp add/cp exch def prnt
+} readonly def
+/cvsprint {=string cvs tprint( )tprint} readonly def
+/unknowntype {exch pop cvlit(??)tprint cvsprint} readonly def
+/integertype {cvsprint} readonly def
+/realtype {cvsprint} readonly def
+/booleantype {cvsprint} readonly def
+/operatortype {(//)tprint cvsprint} readonly def
+/marktype {pop(-mark- )tprint} readonly def
+/dicttype {pop(-dictionary- )tprint} readonly def
+/nulltype {pop(-null- )tprint} readonly def
+/filetype {pop(-filestream- )tprint} readonly def
+/savetype {pop(-savelevel- )tprint} readonly def
+/fonttype {pop(-fontid- )tprint} readonly def
+/nametype {dup xcheck not{(/)tprint}if cvsprint} readonly def
+/stringtype
+{ dup rcheck{(\()tprint tprint(\))tprint}{pop(-string- )tprint}ifelse
+} readonly def
+/arraytype
+{ dup rcheck{dup xcheck
+ {({)tprint{typeprint}forall(})tprint}
+ {([)tprint{typeprint}forall(])tprint}ifelse}{pop(-array- )tprint}ifelse
+} readonly def
+/packedarraytype
+{ dup rcheck{dup xcheck
+ {({)tprint{typeprint}forall(})tprint}
+ {([)tprint{typeprint}forall(])tprint}ifelse}{pop(-packedarray- )tprint}ifelse
+} readonly def
+/courier /Courier findfont 10 scalefont def
+/@oldhandleerror errordict /handleerror get def % save current error handler
+end
+% of @errpage
+
+errordict /handleerror % redefine error handler
+{ systemdict begin $error begin @errpage begin
+ newerror
+ { /newerror false store
+ vmstatus pop pop 0 ne { grestoreall } if
+ initgraphics courier setfont
+ lmargin 792 moveto
+ (POSTSCRIPT ERROR: ) prnt errorname prnt nl
+ (OFFENDING COMMAND: ) prnt /command load prnt nl
+ $error /ostack known
+ { (OPERAND STACK:) prnt nl
+ $error /ostack get aload length {==} repeat
+ } if
+ /#copies 1 store % print only one error page
+ systemdict /showpage get exec
+ userdict begin @bannerpage end % print banner page
+ /newerror true store
+ /@oldhandleerror load end end end exec }
+ { end end end }
+ ifelse
+} dup 0 systemdict put dup 4 @errpage put bind readonly put
diff --git a/dviware/psprint/unix/lw_trailer.ps b/dviware/psprint/unix/lw_trailer.ps
new file mode 100644
index 0000000000..6ab5dcd5e2
--- /dev/null
+++ b/dviware/psprint/unix/lw_trailer.ps
@@ -0,0 +1 @@
+@bannerpage
diff --git a/dviware/psprint/unix/nasty.tex b/dviware/psprint/unix/nasty.tex
new file mode 100644
index 0000000000..784e60f4aa
--- /dev/null
+++ b/dviware/psprint/unix/nasty.tex
@@ -0,0 +1,349 @@
+% TeX source file for testing PSDVI and PSPRINT with a very nasty DVI file
+% (using the same philosophy as Donald Knuth's torture test for TeX).
+% First 11 pages are nasty but should all be printable.
+% Remaining pages contain one or more deliberate errors!!!
+
+\nopagenumbers
+\topskip 0pt
+\parindent 0pt
+\parskip 0pt
+
+% DVI page 1
+\message{Empty page.}
+\null
+\vfil\eject
+
+% DVI page 2
+\message{Page with special file empty.ps.}
+\null
+\special{empty.ps}
+\vfil\eject
+
+% DVI page 3
+\message{Page with special file box.ps.}
+\null
+\vskip 2in
+\special{box.ps}
+\vskip 2in
+\special{box.ps 1.5 .5 scale} % test optional PostScript text
+\vskip 2in
+\special{box.ps } % should just add blank line
+\vfil\eject
+
+% DVI page 4
+\message{Page with special file box.ps in horizontal mode.}
+\null
+\vskip 1in
+\line{a\hfil \special{box.ps} \hfil b}
+\vfil\eject
+
+% DVI page 5
+\message{Page with 1 black pixel at (0,0).}
+\hrule height 1sp width 1sp depth 0sp
+\vfil\eject
+
+% DVI page 6
+\message{A4 paper filled with 1mm grid.}
+{% change page size and location temporarily
+\hoffset=-1in
+\voffset=-1in
+\hsize=209.9mm
+\vsize=296.9mm
+\newcount\temp
+\hbox to \hsize
+{\temp=209
+\loop\ifnum\temp>0
+ \vrule height \vsize width 1sp
+ \hfil
+ \advance\temp by -1
+\repeat
+\vrule height \vsize width 1sp
+}
+\vskip -\vsize
+\temp=296
+\loop\ifnum\temp>0
+ \hrule height 1sp width \hsize
+ \vfil
+ \advance\temp by -1
+\repeat
+\hrule height 1sp width \hsize
+\eject
+}% reset page size and location
+
+% DVI page 7
+\message{Multiple TeX page counters.}
+\footline={\hss\tenrm\folio\hss} % turn on page numbers
+\pageno=0
+\count1=1 \count2=2 \count3=3 \count4=4 \count9=9
+\noindent
+This is \TeX\ page [0.1.2.3.4.....9].
+\vfil\eject
+\count1=0 \count2=0 \count3=0 \count4=0 \count9=0 % reset TeX counters
+
+% DVI page 8
+\message{Negative TeX page.}
+\pageno=-99
+This is \TeX\ page [-99].
+\vfil\eject
+\pageno=0 % restart TeX page numbers
+\nopagenumbers % turn off page numbers again
+
+% DVI page 9
+\message{Standard paragraphs in Computer Modern and PostScript fonts.}
+
+\font\sf=cmss10
+\font\timesr=ps-times-r at 10pt
+\font\helv=ps-helv at 10pt
+
+\rm
+Our task is to create a paragraph illustrating what a typical piece of text
+looks like in a particular \TeX\ font. It should be stressed that not all
+\TeX\ fonts can be used for typesetting text. We need to show most of the
+characters in this font---for instance, something like ``the quick brown fox
+jumps over a lazy dog'' would use all the lower-case letters. Hmmm \dots\
+how about ``THE QUICK BROWN FOX JUMPS OVER 9876543210 LAZY DOGS'' to make
+sure we show all the upper-case letters and digits? Such a paragraph would
+hardly be typical! Then there's ligatures (try and fit in words like
+fluffy, waffle, firefly, difficult) and examples of kerning (boxer, cooked,
+vowel). Not to mention the various accents and other special letters:
+prot\'eg\'e, r\^ole, na\"\i ve, \AE sop's \OE vres en fran\c cais.
+But how do we put all this stuff into a paragraph that makes sense!?
+
+\bigskip
+\timesr
+Our task is to create a paragraph illustrating what a typical piece of text
+looks like in a particular \TeX\ font. It should be stressed that not all
+\TeX\ fonts can be used for typesetting text. We need to show most of the
+characters in this font---for instance, something like ``the quick brown fox
+jumps over a lazy dog'' would use all the lower-case letters. Hmmm \dots\
+how about ``THE QUICK BROWN FOX JUMPS OVER 9876543210 LAZY DOGS'' to make
+sure we show all the upper-case letters and digits? Such a paragraph would
+hardly be typical! Then there's ligatures (try and fit in words like
+fluffy, waffle, firefly, difficult) and examples of kerning (boxer, cooked,
+vowel). Not to mention the various accents and other special letters:
+prot\'eg\'e, r\^ole, na\"\i ve, \AE sop's \OE vres en fran\c cais.
+But how do we put all this stuff into a paragraph that makes sense!?
+
+\bigskip
+\sf
+Our task is to create a paragraph illustrating what a typical piece of text
+looks like in a particular \TeX\ font. It should be stressed that not all
+\TeX\ fonts can be used for typesetting text. We need to show most of the
+characters in this font---for instance, something like ``the quick brown fox
+jumps over a lazy dog'' would use all the lower-case letters. Hmmm \dots\
+how about ``THE QUICK BROWN FOX JUMPS OVER 9876543210 LAZY DOGS'' to make
+sure we show all the upper-case letters and digits? Such a paragraph would
+hardly be typical! Then there's ligatures (try and fit in words like
+fluffy, waffle, firefly, difficult) and examples of kerning (boxer, cooked,
+vowel). Not to mention the various accents and other special letters:
+prot\'eg\'e, r\^ole, na\"\i ve, \AE sop's \OE vres en fran\c cais.
+But how do we put all this stuff into a paragraph that makes sense!?
+
+\bigskip
+\helv
+Our task is to create a paragraph illustrating what a typical piece of text
+looks like in a particular \TeX\ font. It should be stressed that not all
+\TeX\ fonts can be used for typesetting text. We need to show most of the
+characters in this font---for instance, something like ``the quick brown fox
+jumps over a lazy dog'' would use all the lower-case letters. Hmmm \dots\
+how about ``THE QUICK BROWN FOX JUMPS OVER 9876543210 LAZY DOGS'' to make
+sure we show all the upper-case letters and digits? Such a paragraph would
+hardly be typical! Then there's ligatures (try and fit in words like
+fluffy, waffle, firefly, difficult) and examples of kerning (boxer, cooked,
+vowel). Not to mention the various accents and other special letters:
+prot\'eg\'e, r\^ole, na\"\i ve, \AE sop's \OE vres en fran\c cais.
+But how do we put all this stuff into a paragraph that makes sense!?
+
+\bigskip
+\rm The cat sat on the mat. \timesr The cat sat on the mat.
+\sf The cat sat on the mat. \helv The cat sat on the mat.
+
+\rm
+\vfil\eject
+
+% DVI page 10
+\message{Verbatim tt strings.}
+\input ../dv/verbatim
+\begintt
+--------------------------------------------------------------------------------
+- -
+--------------------------------------------------------------------------------
+\endtt
+\vfil\eject
+
+% DVI page 11
+\message{Page with all-white character.}
+\font\cmtex=cmtex10
+\leftline{\cmtex a\char32 b}
+\vfil\eject
+
+% REMAINING PAGES HAVE DELIBERATE ERRORS!!!
+
+% DVI page 12
+\pageno=100
+\message{Page with non-existent fonts.}
+\font\FA=cmr5 scaled 500
+\font\FB=cmr5 scaled 3000
+\font\FC=cmr10 scaled 200
+\font\FD=cmr10 scaled 5000
+\font\FE=cmsl10 scaled 1
+\font\FF=cmsl10 scaled 10000
+\leftline{\FA CMR5 at mag 500 does not exist.}
+\leftline{\FB CMR5 at mag 3000 does not exist.}
+\leftline{\FC CMR10 at mag 200 does not exist.}
+\leftline{\FD CMR10 at mag 5000 does not exist.}
+\leftline{\FE CMSL10 at mag 1 does not exist.}
+\leftline{\FF CMSL10 at mag 10000 does not exist.}
+\vfil\eject
+
+% DVI page 13
+\message{Page beyond top and left edges of A4 paper.}
+{% change page size and location
+\voffset -3in
+\hoffset -9in
+\leftline{Page off paper.}
+\vfil\eject
+}% restore page size and location
+
+% DVI page 14
+\message{Page beyond bottom and right edges of A4 paper.}
+{% change page size and location
+\voffset 3in
+\hoffset 9in
+\null\vfil
+\rightline{Page off paper.}
+\eject
+}% restore page size and location
+
+% DVI page 15
+\message{Page beyond all edges of A4 paper.}
+{% change page size and location
+\voffset -3in
+\hoffset -3in
+\vsize 15in
+\hsize 15in
+\line{Page off paper.\hfil Page off paper.}
+\vfil
+\line{Page off paper.\hfil Page off paper.}
+\eject
+}% restore page size and location
+
+% DVI page 16
+\message{Page with illegal special files.}
+\null
+\special{}
+\special{This is not a file name.}
+\special{%
+12345678901234567890123456789012345678901234567890%
+1234567890123456789012345678901}
+% one character too many (see string in globals.h)
+\vfil\eject
+
+% DVI page 17
+\message{Page with bad special file.}
+\null
+\special{bad.ps} % bad.ps has deliberate PostScript error
+\vfil\eject
+
+% DVI page 18
+% PostScript printers can get 1 pixel rounding errors which show up in TeX
+% math extension symbols made up of rules and cmex characters.
+% tex.ps tries to minimize such problems by using setmatrix to
+% define a device-specific coordinate system, and making slight adjustments
+% to the height, width and positioning of rules.
+
+\message{Page with possible rounding problems.}
+
+\hrule width 2in height 1mm
+\bigskip
+
+\def\prob{$$\shift
+\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+\sqrt{1+x}}}}}}}
+\quad
+\{\underbrace{\overbrace{\mathstrut a,\ldots,a}
+ ^{k\;{\tenit a's}},
+\overbrace{\mathstrut b,\ldots,b}
+ ^{l\;{\tenit b's}}}_{k+l\rm\;elements}\}.
+\quad
+\left\{\vbox to 27pt{}\left\{\vbox to 24pt{}\left\{
+\vbox to 21pt{}\Biggl\{\biggl\{\Bigl\{
+\bigl\{{\bf t}\bigr\}\Bigr\}\biggr\}
+\Biggr\}\right\}\right\}\right\}
+$$}
+
+\def\shift{}
+\prob
+\bigskip
+
+\def\shift{\hskip 10pt}
+\prob
+\bigskip\bigskip
+
+\def\shift{\hskip 20pt}
+\prob
+\bigskip\bigskip\bigskip
+
+\def\shift{\hskip 30pt}
+\prob
+
+\vfil\eject
+
+% DVI page 19
+\message{Page will exceed VM in LaserWriter 2.0.}
+\font\huge=cminch
+\font\bigrm=cmr10 scaled\magstep5
+\font\bigbf=cmbx10 scaled\magstep5
+\font\bigit=cmti10 scaled\magstep5
+\font\bigsl=cmsl10 scaled\magstep5
+\font\bigtt=cmtt10 scaled\magstep5
+\hrule
+\vfil
+\centerline{\huge ABCDE}
+\vfil
+\centerline{\bigrm This is the largest ROMAN}
+\centerline{\bigbf This is the largest BOLD}
+\centerline{\bigit This is the largest ITALIC}
+\centerline{\bigsl This is the largest SLANTED}
+\centerline{\bigtt This is the largest TYPEWRITER}
+\vfil
+\rm
+abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789\hfil\break
+Some ligatures: fluffy, difficult, deftly. Some kerning: book, box, AVATAR.
+Here is a paragraph using the PLAIN output format.
+Let us hope we see some improvement. If not, think again.
+The cat sat on the mat.
+\bigskip
+\bf
+abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789\hfil\break
+Some ligatures: fluffy, difficult, deftly. Some kerning: book, box, AVATAR.
+Here is a paragraph using the PLAIN output format.
+Let us hope we see some improvement. If not, think again.
+The cat sat on the mat.
+\bigskip
+\it
+abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789\hfil\break
+Some ligatures: fluffy, difficult, deftly. Some kerning: book, box, AVATAR.
+Here is a paragraph using the PLAIN output format.
+Let us hope we see some improvement. If not, think again.
+The cat sat on the mat.
+\bigskip
+\sl
+abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789\hfil\break
+Some ligatures: fluffy, difficult, deftly. Some kerning: book, box, AVATAR.
+Here is a paragraph using the PLAIN output format.
+Let us hope we see some improvement. If not, think again.
+The cat sat on the mat.
+\bigskip
+\tt
+{\obeylines
+abcdefghijklmnopqrstuvwxyz
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+0123456789
+
+}
+\rm
+\vfil
+\hrule
+\eject
+
+\bye
diff --git a/dviware/psprint/unix/options.h b/dviware/psprint/unix/options.h
new file mode 100644
index 0000000000..8750573ca3
--- /dev/null
+++ b/dviware/psprint/unix/options.h
@@ -0,0 +1,44 @@
+(* Options *)
+
+TYPE
+ validunits = (ic,cm,mm,pc,pt,bp,px);
+
+VAR
+ resolution, (* pixels per inch *)
+ mag, (* override DVI mag; 0 = use DVI mag *)
+ hoffset, (* horizontal margin shift in pixels *)
+ voffset, (* vertical margin shift in pixels *)
+ paperwd, (* paper width in pixels *)
+ paperht (* paper height in pixels *)
+ : INTEGER;
+ tfmdir, (* location of PostScript TFMs *)
+ psprefix, (* prefix for all PostScript fonts *)
+ fontdir, (* location of PK files *)
+ dummyfont, (* dummy PK file *)
+ DVIname (* DVI file name *)
+ : string;
+
+ (* The above options are also available with DVItoVDU.
+ The following options are only available with PSDVI.
+ *)
+
+ units (* defines how dimensions will be displayed *)
+ : validunits;
+ stats, (* show some statistics? *)
+ reverse, (* output pages in reverse order? *)
+ conserveVM, (* conserve virtual memory? *)
+ subrange (* user has selected a subrange of pages? *)
+ : BOOLEAN;
+ firstDVIpage, (* first DVI page selected (0 if TeX page) *)
+ finalDVIpage, (* final DVI page selected (0 if TeX page) *)
+ increment (* further restricts page selection *)
+ : INTEGER;
+ firstTeXpage, (* first TeX page selected *)
+ finalTeXpage, (* final TeX page selected *)
+ header, (* header file prefixed to output *)
+ PSname (* explicit file name for PostScript output *)
+ : string;
+
+PROCEDURE InitOptions; EXTERNAL;
+FUNCTION Cap (ch : CHAR) : CHAR; EXTERNAL;
+FUNCTION Len (str : string) : INTEGER; EXTERNAL;
diff --git a/dviware/psprint/unix/options.p b/dviware/psprint/unix/options.p
new file mode 100644
index 0000000000..05a6adb908
--- /dev/null
+++ b/dviware/psprint/unix/options.p
@@ -0,0 +1,469 @@
+(* This module initializes the DVI file parameter and command line options.
+ Highly SYSDEP!
+*)
+
+#include 'globals.h';
+#include 'options.h';
+
+VAR
+ option : CHAR; (* current command option *)
+ value : string; (* current option's value *)
+ vlength : INTEGER; (* current value's length *)
+ argnum : INTEGER; (* 0..argc-1; used in argv calls *)
+
+FUNCTION sscanf (VAR s, format : string; VAR r : real) : integer;
+EXTERNAL;
+
+(******************************************************************************)
+
+FUNCTION Cap (ch : CHAR) : CHAR;
+
+(* If ch is in 'a'..'z' then return capitalized letter else return ch. *)
+
+BEGIN
+IF (ch < 'a') OR (ch > 'z') THEN Cap := ch ELSE Cap := CHR(ORD(ch) - 32);
+END; (* Cap *)
+
+(******************************************************************************)
+
+FUNCTION Len (str : string) : INTEGER;
+
+(* Return length of given string, assumed to be padded with blanks. *)
+
+LABEL 888;
+
+VAR i : INTEGER;
+
+BEGIN
+i := maxstring;
+WHILE i > 0 DO BEGIN
+ IF str[i-1] <> ' ' THEN goto 888;
+ i := i - 1;
+END;
+888:
+Len := i;
+END; (* Len *)
+
+(******************************************************************************)
+
+FUNCTION ExplicitExt (fname : string; len : INTEGER) : BOOLEAN;
+
+(* SYSDEP: Check for an extension of the form ".*" where * is any string
+ not containing "/". len is length of fname.
+ If "." found then TRUE is returned, otherwise FALSE.
+*)
+
+LABEL 999;
+
+BEGIN
+WHILE len > 0 DO BEGIN (* search backwards looking for . *)
+ len := len - 1;
+ IF fname[len] = '/' THEN BEGIN (* handle file names like ../myfiles/foo *)
+ ExplicitExt := FALSE;
+ goto 999;
+ END
+ ELSE IF fname[len] = '.' THEN BEGIN
+ ExplicitExt := TRUE;
+ goto 999;
+ END;
+END;
+ExplicitExt := FALSE;
+999:
+END; (* ExplicitExt *)
+
+(******************************************************************************)
+
+PROCEDURE GetValue;
+
+(* Get parameter following current option and store in value. *)
+
+VAR i : integer;
+
+BEGIN
+IF vlength > 2 THEN BEGIN (* allow things like -m1000 *)
+ FOR i := 0 TO vlength - 1 DO
+ value[i] := value[i+2]; (* shift value left 2 places *)
+ vlength := vlength - 2;
+END
+ELSE BEGIN
+ (* option should be followed by value *)
+ value := ' ';
+ IF argnum < argc THEN argv(argnum,value);
+ vlength := Len(value); (* 0 if no more args *)
+ argnum := argnum + 1;
+ IF vlength <= 0 THEN BEGIN
+ writeln('Missing value after -',option);
+ exit(1);
+ END;
+END;
+END; (* GetValue *)
+
+(******************************************************************************)
+
+PROCEDURE GetCardinal (VAR n : INTEGER);
+
+(* If current value represents a positive integer then return via n. *)
+
+VAR result : integer; r : real; fmt : string;
+
+BEGIN
+fmt := '%f';
+result := sscanf(value,fmt,r);
+n := trunc(r);
+IF (ABS(result) <> 1) OR (n <= 0) THEN BEGIN
+ writeln('Bad -',option,' value: ',value:vlength);
+ writeln('Specify a positive integer.');
+ exit(1);
+END;
+END; (* GetCardinal *)
+
+(******************************************************************************)
+
+PROCEDURE GetPosDimen (VAR r : REAL; VAR un : validunits);
+
+(* A valid +ve dimension consists of a positive integer or real number followed
+ by a two-letter unit: cm, mm, in, pc, pt, bp or px (or in uppercase).
+ If current value represents a valid +ve dimension, we return number part
+ in r and validunits part in un.
+*)
+
+VAR i, result : INTEGER; ch1, ch2 : CHAR; fmt : string;
+
+BEGIN
+(* extract un *)
+IF vlength > 1 THEN i := vlength-1 ELSE i := 1;
+IF (Cap(value[i-1]) = 'I') AND (Cap(value[i]) = 'N') THEN
+ un := ic
+ELSE IF (Cap(value[i-1]) = 'C') AND (Cap(value[i]) = 'M') THEN
+ un := cm
+ELSE IF (Cap(value[i-1]) = 'M') AND (Cap(value[i]) = 'M') THEN
+ un := mm
+ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'C') THEN
+ un := pc
+ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'T') THEN
+ un := pt
+ELSE IF (Cap(value[i-1]) = 'B') AND (Cap(value[i]) = 'P') THEN
+ un := bp
+ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'X') THEN
+ un := px
+ELSE BEGIN
+ writeln('Bad units in -',option,' value: ',value:vlength);
+ writeln('Last two letters should be cm, mm, in, pc, pt, bp or px.');
+ exit(1);
+END;
+ch1 := value[i-1]; (* remember letters in units *)
+ch2 := value[i];
+value[i] := ' '; (* remove units *)
+value[i-1] := ' ';
+fmt := '%f';
+result := sscanf(value,fmt,r);
+IF (ABS(result) <> 1) OR (r <= 0.0) THEN BEGIN
+ value[i-1] := ch1; (* restore units *)
+ value[i] := ch2;
+ writeln('Bad -',option,' value: ',value:vlength);
+ writeln('Specify a positive dimension.');
+ exit(1);
+END;
+END; (* GetPosDimen *)
+
+(******************************************************************************)
+
+PROCEDURE GetDimen (VAR r : REAL; VAR un : validunits);
+
+(* A valid dimension consists of an integer or real number followed
+ by a two-letter unit: cm, mm, in, pc, pt, bp or px (or in uppercase).
+ If current value represents a valid dimension, we return number part
+ in r and validunits part in un.
+*)
+
+VAR i, result : INTEGER; ch1, ch2 : CHAR; fmt : string;
+
+BEGIN
+(* extract un *)
+IF vlength > 1 THEN i := vlength-1 ELSE i := 1;
+IF (Cap(value[i-1]) = 'I') AND (Cap(value[i]) = 'N') THEN
+ un := ic
+ELSE IF (Cap(value[i-1]) = 'C') AND (Cap(value[i]) = 'M') THEN
+ un := cm
+ELSE IF (Cap(value[i-1]) = 'M') AND (Cap(value[i]) = 'M') THEN
+ un := mm
+ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'C') THEN
+ un := pc
+ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'T') THEN
+ un := pt
+ELSE IF (Cap(value[i-1]) = 'B') AND (Cap(value[i]) = 'P') THEN
+ un := bp
+ELSE IF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'X') THEN
+ un := px
+ELSE BEGIN
+ writeln('Bad units in -',option,' value: ',value:vlength);
+ writeln('Last two letters should be cm, mm, in, pc, pt, bp or px.');
+ exit(1);
+END;
+ch1 := value[i-1]; (* remember letters in units *)
+ch2 := value[i];
+value[i] := ' '; (* remove units *)
+value[i-1] := ' ';
+fmt := '%f';
+result := sscanf(value,fmt,r);
+IF (ABS(result) <> 1) THEN BEGIN
+ value[i-1] := ch1; (* restore units *)
+ value[i] := ch2;
+ writeln('Bad -',option,' value: ',value:vlength);
+ writeln('Specify a dimension.');
+ exit(1);
+END;
+END; (* GetDimen *)
+
+(******************************************************************************)
+
+PROCEDURE GetUnits;
+
+(* Make sure current value is valid and set units if so. *)
+
+VAR ch1, ch2 : CHAR;
+
+BEGIN
+ch1 := Cap(value[0]);
+ch2 := Cap(value[1]);
+IF (ch1 = 'I') AND (ch2 = 'N') THEN
+ units := ic
+ELSE IF (ch1 = 'C') AND (ch2 = 'M') THEN
+ units := cm
+ELSE IF (ch1 = 'M') AND (ch2 = 'M') THEN
+ units := mm
+ELSE IF (ch1 = 'P') AND (ch2 = 'C') THEN
+ units := pc
+ELSE IF (ch1 = 'P') AND (ch2 = 'T') THEN
+ units := pt
+ELSE IF (ch1 = 'B') AND (ch2 = 'P') THEN
+ units := bp
+ELSE IF (ch1 = 'P') AND (ch2 = 'X') THEN
+ units := px
+ELSE BEGIN
+ writeln('Bad -',option,' value: ',value:vlength);
+ writeln('Specify cm, mm, in, pc, pt, bp or px.');
+ exit(1);
+END;
+END; (* GetUnits *)
+
+(******************************************************************************)
+
+PROCEDURE GetPages;
+
+(* Parse -p value. If valid then subrange will become TRUE.
+ -p can have any value of the form "first:final" where first and/or
+ final can be a DVI page (positive integer), or TeX page ([i0. ... .i9]),
+ or empty. If first empty then firstDVIpage = 1; if final empty then
+ finalDVIpage = maxint. If ":final" is omitted then
+ finalDVIpage = firstDVIpage.
+ If first/final is a TeX page specification (i.e., starts with '[')
+ then first/finalDVIpage is set to 0 and first/finalTeXpage contains the
+ given string (and parsing is done by the main module).
+*)
+
+LABEL 888;
+
+VAR i, j, result : INTEGER; r : real; fmt : string;
+
+BEGIN
+subrange := TRUE;
+firstTeXpage := ' ';
+finalTeXpage := ' ';
+i := 0;
+(* extract first page *)
+WHILE i < vlength DO BEGIN
+ IF value[i] = ':' THEN goto 888;
+ firstTeXpage[i] := value[i];
+ i := i + 1;
+END;
+888:
+IF value[0] = ':' THEN (* first page not given *)
+ firstDVIpage := 1
+ELSE IF firstTeXpage[0] = '[' THEN (* TeX page given *)
+ firstDVIpage := 0
+ELSE BEGIN (* DVI page given *)
+ fmt := '%f';
+ result := sscanf(firstTeXpage,fmt,r);
+ firstDVIpage := trunc(r);
+ IF (ABS(result) <> 1) OR (firstDVIpage <= 0) THEN BEGIN
+ writeln('Bad first page in -',option,' value: ',value:vlength);
+ writeln('Specify a positive integer.');
+ exit(1);
+ END;
+END;
+IF i = vlength THEN BEGIN (* no colon; n or [t] *)
+ IF firstTeXpage[0] = '[' THEN BEGIN
+ finalTeXpage := firstTeXpage; (* [t] = [t]:[t] *)
+ finalDVIpage := 0;
+ END
+ ELSE
+ finalDVIpage := firstDVIpage; (* n = n:n *)
+END
+ELSE BEGIN (* value[i] = ':' *)
+ i := i + 1;
+ j := 0;
+ WHILE i < vlength DO BEGIN (* extract final page *)
+ finalTeXpage[j] := value[i];
+ i := i + 1;
+ j := j + 1;
+ END;
+ IF j = 0 THEN (* no page after ':' *)
+ finalDVIpage := maxint
+ ELSE IF finalTeXpage[0] = '[' THEN (* TeX page given *)
+ finalDVIpage := 0
+ ELSE BEGIN (* DVI page given *)
+ fmt := '%f';
+ result := sscanf(finalTeXpage,fmt,r);
+ finalDVIpage := trunc(r);
+ IF (ABS(result) <> 1) OR (finalDVIpage <= 0) THEN BEGIN
+ writeln('Bad final page in -',option,' value: ',value:vlength);
+ writeln('Specify a positive integer.');
+ exit(1);
+ END;
+ END;
+END;
+END; (* GetPages *)
+
+(******************************************************************************)
+
+FUNCTION DimenPixels (r : REAL; u : validunits) : INTEGER;
+
+(* Return given dimension in terms of pixels. *)
+
+BEGIN
+CASE u OF
+ ic : DimenPixels := TRUNC(r * resolution + 0.5);
+ cm : DimenPixels := TRUNC((r / 2.54) * resolution + 0.5);
+ mm : DimenPixels := TRUNC((r / 25.4) * resolution + 0.5);
+ bp : DimenPixels := TRUNC((r / 72.0) * resolution + 0.5);
+ pt : DimenPixels := TRUNC((r / 72.27) * resolution + 0.5);
+ pc : DimenPixels := TRUNC((r / 72.27) * 12.0 * resolution + 0.5);
+ px : DimenPixels := TRUNC(r + 0.5)
+END;
+END; (* DimenPixels *)
+
+(******************************************************************************)
+
+PROCEDURE InitOptions;
+
+(* Get DVI file and any options from command line.
+ If an option appears more than once then we return the last value.
+*)
+
+VAR
+ hoffu, voffu, xu, yu : validunits;
+ hoffr, voffr, xr, yr : REAL;
+ landscape : boolean;
+ temp, strlen, i : integer;
+ str : string;
+
+BEGIN
+(* initialize option values with defaults; note that the psprint script can
+ set up different defaults
+*)
+resolution := 300; (* LaserWriter resolution *)
+hoffu := ic;
+voffu := ic;
+hoffr := 0.0; (* no margin shifting *)
+voffr := 0.0;
+xu := ic; (* paper dimensions in inches *)
+yu := ic;
+xr := 8.3; (* A4 paper is 8.3" wide *)
+yr := 11.7; (* A4 paper is 11.7" high *)
+mag := 0; (* use DVI mag *)
+fontdir := '/tex/pk/'; (* location of PK files *)
+dummyfont := 'cmr10.300pk'; (* typical font *)
+tfmdir := '/tex/fonts/'; (* location of PS TFM files *)
+psprefix := 'ps-'; (* prefix in PS font names *)
+DVIname := ' '; (* SYSDEP: empty string *)
+(* above are same as DVItoVDU options *)
+header := '/usr/users/applied/staff/atrevorr/psdvi/tex.ps';
+PSname := 'out.ps'; (* output file (-o) *)
+units := ic; (* inches (-u) *)
+stats := FALSE; (* display stats? (-s) *)
+reverse := FALSE; (* reverse page order? (-b) *)
+conserveVM := FALSE; (* conserve VM? (-c) *)
+landscape := FALSE; (* reverse -x and -y? (-l) *)
+subrange := FALSE; (* -p value given? *)
+firstDVIpage := 0;
+finalDVIpage := 0;
+firstTeXpage := '[]';
+finalTeXpage := '[]';
+argnum := 1; (* 0 is command *)
+WHILE argnum < argc DO BEGIN
+ value := ' ';
+ argv(argnum,value);
+ vlength := Len(value);
+ argnum := argnum + 1;
+ IF value[0] = '-' THEN BEGIN
+ IF vlength > 1 THEN option := value[1] ELSE option := ' ';
+ CASE option OF
+ 'r' : BEGIN GetValue; GetCardinal(resolution); END;
+ 'm' : BEGIN GetValue; GetCardinal(mag); END;
+ 'i' : BEGIN GetValue; GetCardinal(increment); END;
+ 'x' : BEGIN GetValue; GetPosDimen(xr,xu); END;
+ 'y' : BEGIN GetValue; GetPosDimen(yr,yu); END;
+ 'H' : BEGIN GetValue; GetDimen(hoffr,hoffu); END;
+ 'V' : BEGIN GetValue; GetDimen(voffr,voffu); END;
+ 'T' : BEGIN GetValue; tfmdir := value; END;
+ 'P' : BEGIN GetValue; psprefix := value; END;
+ 'd' : BEGIN GetValue; dummyfont := value; END;
+ 'f' : BEGIN GetValue; fontdir := value; END;
+ 'h' : BEGIN GetValue; header := value; END;
+ 'o' : BEGIN GetValue; PSname := value; END;
+ 'u' : BEGIN GetValue; GetUnits; END;
+ 'p' : BEGIN GetValue; GetPages; END;
+ 's' : stats := TRUE;
+ 'b' : reverse := TRUE;
+ 'c' : conserveVM := TRUE;
+ 'l' : landscape := TRUE;
+ (* bad string values will be detected in other modules *)
+ OTHERWISE
+ writeln('Unknown option: -',option);
+ exit(1);
+ END;
+ END
+ ELSE BEGIN
+ (* value doesn't start with '-', so assume it is DVI file *)
+ DVIname := value;
+ IF NOT ExplicitExt(DVIname,vlength) THEN (* append .dvi *)
+ IF vlength + 3 < maxstring THEN BEGIN
+ DVIname[vlength] := '.';
+ DVIname[vlength+1] := 'd';
+ DVIname[vlength+2] := 'v';
+ DVIname[vlength+3] := 'i';
+ END
+ ELSE BEGIN (* user has given a mighty long file name *)
+ writeln('DVI file name too long: ',DVIname:maxstring);
+ exit(1);
+ END;
+ (* bad DVIname will be detected upon open in main module *)
+ END;
+END;
+IF DVIname[0] = ' ' THEN BEGIN (* no file name on command line *)
+ writeln('DVI file not given!');
+ exit(1);
+END;
+(* prepend fontdir to dummyfont *)
+str := fontdir;
+strlen := Len(fontdir);
+FOR i := 1 TO Len(dummyfont) DO BEGIN
+ IF strlen < maxstring THEN BEGIN
+ str[strlen] := dummyfont[i-1];
+ strlen := strlen + 1;
+ END;
+END;
+dummyfont := str;
+(* set h/voffset and paperwd/ht only after resolution has been decided *)
+hoffset := DimenPixels(hoffr,hoffu);
+voffset := DimenPixels(voffr,voffu);
+paperwd := DimenPixels(xr,xu);
+paperht := DimenPixels(yr,yu);
+IF landscape THEN BEGIN (* swap paperwd and paperht *)
+ temp := paperwd;
+ paperwd := paperht;
+ paperht := temp;
+END;
+IF increment = 0 THEN increment := 1; (* do normal page selection *)
+END; (* InitOptions *)
diff --git a/dviware/psprint/unix/piechart.ps b/dviware/psprint/unix/piechart.ps
new file mode 100644
index 0000000000..1d9d6137ea
--- /dev/null
+++ b/dviware/psprint/unix/piechart.ps
@@ -0,0 +1,68 @@
+% This file is inserted into the PSPRINT User Guide using \special.
+% It draws a simple pie chart (based on p.187 of the PostScript Cookbook).
+
+/DrawSlice
+{ % this routine expects 3 parameters on stack:
+ /endangle exch def
+ /startangle exch def
+ /thelabel exch def
+ newpath 0 0 moveto
+ 0 0 radius startangle endangle arc
+ closepath
+ 1.415 setmiterlimit % bevel the lines joining in the centre
+ 0.01 Inch setlinewidth
+ stroke
+ gsave
+ % calculate starting position for label
+ startangle endangle add 2 div rotate
+ radius labelps add 0 translate
+ 0 0 transform
+ grestore
+ itransform
+ /y exch def /x exch def
+ x y moveto
+ x 0 lt { thelabel stringwidth pop neg 0 rmoveto } if % move label left
+ y 0 lt { 0 labelps neg rmoveto } if % move label down
+ thelabel show
+} def
+
+/DrawPieChart
+{ % this routine expects 5 parameters on stack:
+ /radius exch def
+ /ycenter exch def
+ /xcenter exch def
+ /PieArray exch def
+ /labelps exch def
+ xcenter ycenter translate
+ /Helvetica findfont labelps scalefont setfont
+ /curangle 0 def
+ PieArray
+ { /slicearray exch def
+ slicearray aload pop
+ /percent exch def
+ /label exch def
+ /perangle percent 100 div 360 mul def
+ label curangle curangle perangle add DrawSlice
+ /curangle curangle perangle add def
+ } forall % repeat above procedure for each element in PieArray
+} def
+
+/Inch { 72 mul } def % converts inches to points
+
+% ----- MAIN PROGRAM -----
+
+8 % label point size
+[ % PieArray is an array of arrays
+ [ (Blueberry) 12 ]
+ [ (Apple) 30 ]
+ [ (Cherry) 12 ] % include any number of label, percentage pairs
+ [ (Raspberry) 16 ] % but make sure the numbers add up to 100
+ [ (Apricot) 24 ]
+ [ (Other) 6 ]
+]
+3.15 Inch 1.0 Inch % x,y center of pie chart
+ % (3.15in * 2 = 6.3in = text width in User Guide)
+.7 Inch % radius
+DrawPieChart % draw pie chart using above arguments
+
+showpage
diff --git a/dviware/psprint/unix/ps.ps b/dviware/psprint/unix/ps.ps
new file mode 100644
index 0000000000..83021f4df6
--- /dev/null
+++ b/dviware/psprint/unix/ps.ps
@@ -0,0 +1,20 @@
+% Prologue for a PostScript job.
+% It assumes psprint has defined land and dev.
+
+land % only do something if /landscape given
+{ dev (LINO) eq % Linotronic allows different page sizes
+ { initgraphics
+ newpath clippath pathbbox % push LLx LLy URx URy
+ pop % URy
+ 0 translate % move origin right by URx (= page image width)
+ pop % LLy
+ pop % LLx
+ 90 rotate % rotate axes 90deg anticlockwise
+ }
+ { % dev = LW or PS40
+ 8.3 72 mul 0 translate % move origin right by 8.3in (= A4 width)
+ 90 rotate % rotate axes 90deg anticlockwise
+ } ifelse
+} if
+
+% The above transformations can be overridden by initgraphics/initmatrix etc.
diff --git a/dviware/psprint/unix/ps40_fonts.ps b/dviware/psprint/unix/ps40_fonts.ps
new file mode 100644
index 0000000000..a24e0651ff
--- /dev/null
+++ b/dviware/psprint/unix/ps40_fonts.ps
@@ -0,0 +1,39 @@
+% This file converts TFM font names into the actual PrintServer 40 font names:
+
+ % These fonts are resident in all PostScript printers:
+/ps-courier-b /Courier-Bold def
+/ps-courier-bo /Courier-BoldOblique def
+/ps-courier-o /Courier-Oblique def
+/ps-courier /Courier def
+/ps-helv-b /Helvetica-Bold def
+/ps-helv-bo /Helvetica-BoldOblique def
+/ps-helv-o /Helvetica-Oblique def
+/ps-helv /Helvetica def
+/ps-symbol /Symbol def
+/ps-times-b /Times-Bold def
+/ps-times-bi /Times-BoldItalic def
+/ps-times-i /Times-Italic def
+/ps-times-r /Times-Roman def
+
+ % This font will be constructed from Times-Roman:
+/ps-times-s /Times-Slanted def
+
+ % These fonts are also resident in PrintServer 40:
+/ps-avantg-b /AvantGarde-Book def
+/ps-avantg-bo /AvantGarde-BookOblique def
+/ps-avantg-d /AvantGarde-Demi def
+/ps-avantg-do /AvantGarde-DemiOblique def
+/ps-ncs-b /NewCenturySchlbk-Bold def
+/ps-ncs-bo /NewCenturySchlbk-BoldItalic def
+/ps-ncs-i /NewCenturySchlbk-Italic def
+/ps-ncs-r /NewCenturySchlbk-Roman def
+
+ % These fonts don't have TFM files for them as yet:
+% /??? /Souvenir-Demi def
+% /??? /Souvenir-DemiItalic def
+% /??? /Souvenir-Light def
+% /??? /Souvenir-LightItalic def
+% /??? /LubalinGraph-Book def
+% /??? /LubalinGraph-BookOblique def
+% /??? /LubalinGraph-Demi def
+% /??? /LubalinGraph-DemiOblique def
diff --git a/dviware/psprint/unix/ps40_header.ps b/dviware/psprint/unix/ps40_header.ps
new file mode 100644
index 0000000000..524d07137b
--- /dev/null
+++ b/dviware/psprint/unix/ps40_header.ps
@@ -0,0 +1,67 @@
+% For the PrintServer 40 we don't need to produce a banner page.
+% We still redefine the error handler though:
+
+/@errpage 64 dict def
+@errpage begin
+/prnt
+ {dup type/stringtype ne{=string cvs}if dup length 6 mul/tx exch def/ty 10 def
+ currentpoint/toy exch def/tox exch def 1 setgray newpath
+ tox toy 2 sub moveto 0 ty rlineto tx 0 rlineto 0 ty neg rlineto
+ closepath fill tox toy moveto 0 setgray show}bind def
+/nl{currentpoint exch pop lmargin exch moveto 0 -10 rmoveto}def
+/=={/cp 0 def typeprint nl}def
+/typeprint{dup type dup currentdict exch known
+ {exec}{unknowntype}ifelse}readonly def
+/lmargin 72 def/rmargin 72 def
+/tprint{dup length cp add rmargin gt{nl/cp 0 def}if
+ dup length cp add/cp exch def prnt}readonly def
+/cvsprint{=string cvs tprint( )tprint}readonly def
+/unknowntype{exch pop cvlit(??)tprint cvsprint}readonly def
+/integertype{cvsprint}readonly def
+/realtype{cvsprint}readonly def
+/booleantype{cvsprint}readonly def
+/operatortype{(//)tprint cvsprint}readonly def
+/marktype{pop(-mark- )tprint}readonly def
+/dicttype{pop(-dictionary- )tprint}readonly def
+/nulltype{pop(-null- )tprint}readonly def
+/filetype{pop(-filestream- )tprint}readonly def
+/savetype{pop(-savelevel- )tprint}readonly def
+/fonttype{pop(-fontid- )tprint}readonly def
+/nametype{dup xcheck not{(/)tprint}if cvsprint}readonly def
+/stringtype
+ {dup rcheck{(\()tprint tprint(\))tprint}{pop(-string- )tprint}ifelse
+ }readonly def
+/arraytype
+ {dup rcheck{dup xcheck
+ {({)tprint{typeprint}forall(})tprint}
+ {([)tprint{typeprint}forall(])tprint}ifelse}{pop(-array- )tprint}ifelse
+ }readonly def
+/packedarraytype
+ {dup rcheck{dup xcheck
+ {({)tprint{typeprint}forall(})tprint}
+ {([)tprint{typeprint}forall(])tprint}ifelse}{pop(-packedarray- )tprint}ifelse
+ }readonly def
+/courier /Courier findfont 10 scalefont def
+/@oldhandleerror errordict /handleerror get def
+end
+
+errordict /handleerror
+{ systemdict begin $error begin @errpage begin
+ newerror
+ { /newerror false store
+ vmstatus pop pop 0 ne { grestoreall } if
+ initgraphics courier setfont
+ lmargin 792 moveto
+ (POSTSCRIPT ERROR: ) prnt errorname prnt nl
+ (OFFENDING COMMAND: ) prnt /command load prnt nl
+ $error /ostack known
+ { (OPERAND STACK:) prnt nl
+ $error /ostack get aload length {==} repeat
+ } if
+ /#copies 1 store
+ systemdict /showpage get exec
+ /newerror true store
+ /@oldhandleerror load end end end exec }
+ { end end end }
+ ifelse
+} dup 0 systemdict put dup 4 @errpage put bind readonly put
diff --git a/dviware/psprint/unix/psdvi.p b/dviware/psprint/unix/psdvi.p
new file mode 100644
index 0000000000..ad3e365cc7
--- /dev/null
+++ b/dviware/psprint/unix/psdvi.p
@@ -0,0 +1,859 @@
+PROGRAM PSDVI (output);
+
+CONST version = 'This is PSDVI, version 3.0';
+
+(* Author: Andrew Trevorrow
+ Implementation: Pyramid Pascal
+
+ Description:
+ This program is run by the psprint script to read a DVI file
+ and create an equivalent PostScript file.
+
+ Notes:
+ - See AAAREAD.ME for revision history.
+ - Debugging code is bracketed by { DEBUG } ... { GUBED }.
+ This code will be commented out in the final working version.
+ - System-dependent code is indicated by the string "SYSDEP".
+ - Uncertain code is indicated by the string "???".
+ - Unfinished code is indicated by the string "!!!".
+ - Goto 999 is used to emulate a RETURN (from procedure) statement.
+ - Goto <= 888 is used to emulate an EXIT (from loop) statement.
+ - The above notes are also true for all separately compiled modules.
+*)
+
+#include 'globals.h';
+#include 'options.h';
+#include 'dvireader.h';
+#include 'fontreader.h';
+#include 'pswriter.h';
+
+CONST
+ pagesperline = 10; (* number of pages displayed per line *)
+
+VAR
+ papertop,
+ paperleft,
+ paperbottom,
+ paperright, (* these define the edges of the paper *)
+ pagecount : INTEGER; (* count of pages actually output *)
+ unusedfont : fontinfoptr; (* first unused font in sorted fontlist *)
+
+(******************************************************************************)
+
+PROCEDURE Initialize;
+
+BEGIN
+(* top left corner of paper is fixed at (-1",-1") *)
+papertop := -resolution;
+paperleft := -resolution;
+paperbottom := papertop + paperht - 1;
+paperright := paperleft + paperwd - 1;
+warncount := 0;
+pagecount := 0;
+END; (* Initialize *)
+
+(**********************************************************************)
+
+PROCEDURE ShowUnits;
+
+BEGIN
+CASE units OF
+ ic : write('in') ;
+ cm : write('cm') ;
+ mm : write('mm') ;
+ pc : write('pc') ;
+ pt : write('pt') ;
+ bp : write('bp') ;
+ px : write('px') ;
+END;
+END; (* ShowUnits *)
+
+(******************************************************************************)
+
+PROCEDURE ShowDimension (pixels : INTEGER);
+
+(* Show the given pixel dimension in terms of units. *)
+
+LABEL 999;
+
+VAR realdim : REAL; fracpart : INTEGER;
+
+BEGIN
+CASE units OF
+ ic : realdim := pixels / resolution ;
+ cm : realdim := pixels / resolution * 2.54 ;
+ mm : realdim := pixels / resolution * 25.4 ;
+ pc : realdim := pixels / resolution * 72.27 / 12.0 ;
+ pt : realdim := pixels / resolution * 72.27 ;
+ bp : realdim := pixels / resolution * 72.0 ;
+ px : BEGIN write(pixels:1, 'px'); goto 999 END;
+END;
+(* show realdim to an accuracy of 1 decimal place *)
+IF ABS(realdim) < 0.05 THEN
+ write('0.0')
+ELSE BEGIN
+ IF realdim < 0.0 THEN BEGIN
+ write('-');
+ realdim := ABS(realdim);
+ END;
+ realdim := realdim + 0.05; (* round up to 1 decimal place *)
+ write(TRUNC(realdim):1); (* whole part *)
+ write('.');
+ fracpart := TRUNC((realdim - TRUNC(realdim)) * 10.0);
+ (* fracpart is now 0..9 *)
+ write(fracpart:1);
+END;
+ShowUnits;
+999:
+END; (* ShowDimension *)
+
+(******************************************************************************)
+
+PROCEDURE ShowOptions;
+
+(* Show DVI file name and option values. *)
+
+BEGIN
+writeln(version); writeln;
+writeln('DVI file = ', DVIname:Len(DVIname));
+writeln('PostScript file = ', PSname:Len(PSname));
+writeln('Header file = ', header:Len(header));
+writeln('Resolution = ', resolution:1, ' pixels per inch');
+write ('Magnification = ', mag:1);
+IF mag <> DVImag THEN
+ writeln(' (DVI mag of ', DVImag:1, ' was overridden)')
+ELSE
+ writeln(' (DVI mag)');
+writeln('TFM directory = ', tfmdir:Len(tfmdir));
+writeln('PS font prefix = ', psprefix:Len(psprefix));
+writeln('Font directory = ', fontdir:Len(fontdir));
+writeln('Dummy font = ', dummyfont:Len(dummyfont));
+write ('Horizontal offset = '); ShowDimension(hoffset); writeln;
+write ('Vertical offset = '); ShowDimension(voffset); writeln;
+write ('Paper width = '); ShowDimension(paperwd); writeln;
+write ('Paper height = '); ShowDimension(paperht); writeln;
+write ('Units = '); ShowUnits; writeln;
+write ('Reverse = ');
+IF reverse THEN writeln('true') ELSE writeln('false');
+write ('Stats = ');
+IF stats THEN writeln('true') ELSE writeln('false');
+write ('Conserve VM = ');
+IF conserveVM THEN writeln('true') ELSE writeln('false');
+write ('Pages = ');
+IF subrange THEN BEGIN
+ IF firstDVIpage = 0 THEN write(firstTeXpage:Len(firstTeXpage))
+ ELSE write(firstDVIpage:1);
+ write(':');
+ IF finalDVIpage = 0 THEN write(finalTeXpage:Len(finalTeXpage))
+ ELSE write(finalDVIpage:1);
+END
+ELSE
+ write('all pages');
+IF increment > 1 THEN write(', but with an increment of ',increment:1);
+writeln;
+writeln;
+END; (* ShowOptions *)
+
+(******************************************************************************)
+
+FUNCTION GetInteger (VAR str : string; (* in *)
+ strlen : INTEGER; (* in *)
+ VAR pos : INTEGER; (* in/out *)
+ VAR n : INTEGER (* out *)
+ ) : BOOLEAN;
+
+(* Extract an integer from given str starting at given pos.
+ pos is also used to return the position after the integer.
+ If no integer is found then set n to 0 and return FALSE (pos will only
+ change if leading spaces were skipped).
+ If ABS(n) > limit then set n to sign * limit.
+ Valid syntax is +{digit} or -{digit} or digit{digit}.
+ Note that a + or - by itself is valid and sets n to 0.
+*)
+
+LABEL 777, 888;
+
+CONST limit = 2147483647; (* 2^31 - 1 *)
+ threshold = limit DIV 10; (* nearing overflow *)
+
+VAR absval, last : INTEGER;
+ sign : INTEGER;
+ inttoobig : BOOLEAN;
+
+BEGIN
+WHILE pos < strlen DO BEGIN (* skip any spaces *)
+ IF str[pos] <> ' ' THEN goto 888;
+ pos := pos + 1;
+END;
+888:
+absval := 0; sign := 1; last := pos;
+inttoobig := FALSE;
+IF pos < strlen THEN BEGIN
+ IF str[pos] = '-' THEN BEGIN
+ sign := -1;
+ last := last + 1;
+ END
+ ELSE IF str[pos] = '+' THEN
+ last := last + 1;
+ WHILE last < strlen DO BEGIN
+ IF (str[last] < '0') OR (str[last] > '9') THEN goto 777;
+ IF (absval > threshold) OR ((absval = threshold) AND (str[last] > '7'))
+ THEN
+ inttoobig := TRUE
+ ELSE
+ absval := absval * 10 + (ORD(str[last]) - ORD('0'));
+ last := last + 1;
+ END;
+ 777:
+END;
+IF pos = last THEN BEGIN
+ n := 0;
+ GetInteger := FALSE;
+END
+ELSE BEGIN
+ pos := last;
+ IF inttoobig THEN absval := limit;
+ n := sign * absval;
+ GetInteger := TRUE;
+END;
+END; (* GetInteger *)
+
+(******************************************************************************)
+
+FUNCTION ParseTeXPage (VAR pagestring : string;
+ VAR newTeXpage : TeXpageinfo) : BOOLEAN;
+
+(* Return TRUE if TeX page specification in pagestring is valid. If so then
+ newTeXpage will contain the appropriate information for CurrMatchesNew.
+ The syntax of a TeX page specification is [n{.n}] where n is any integer as
+ defined by GetInteger. Up to 10 integers may be given and are separated by
+ periods, even if absent. Trailing periods may be omitted. Spaces before
+ and after integers and periods are skipped. The 10 positions correspond to
+ the \count0, \count1, ... ,\count9 values that TeX stores with every page.
+*)
+
+LABEL 555, 666, 777, 888, 999;
+
+VAR pos, len : INTEGER;
+
+BEGIN
+WITH newTeXpage DO BEGIN
+ pos := 0;
+ IF pagestring[pos] <> '[' THEN BEGIN
+ writeln('[ expected!');
+ ParseTeXPage := FALSE;
+ goto 999;
+ END;
+ lastvalue := 0;
+ len := 0;
+ WHILE len < maxstring DO
+ IF pagestring[len] = ' ' THEN goto 888 ELSE len := len + 1;
+ 888:
+ WHILE TRUE DO BEGIN
+ pos := pos + 1;
+ present[lastvalue] := GetInteger(pagestring, len, pos, value[lastvalue]);
+ (* pos now at len, space, period, non-digit or ']' *)
+ WHILE pos < len DO BEGIN
+ IF pagestring[pos] <> ' ' THEN goto 777;
+ pos := pos + 1; (* skip any spaces *)
+ END;
+ 777:
+ IF pos = len THEN BEGIN (* check this first! *)
+ writeln('] expected!');
+ ParseTeXPage := FALSE;
+ goto 999;
+ END;
+ IF pagestring[pos] = ']' THEN (* end of TeX page specification *)
+ goto 666;
+ IF lastvalue < 9 THEN
+ lastvalue := lastvalue + 1
+ ELSE BEGIN
+ writeln('] expected after 10 integers!');
+ ParseTeXPage := FALSE;
+ goto 999;
+ END;
+ IF pagestring[pos] <> '.' THEN BEGIN
+ writeln('Period, integer or ] expected!');
+ ParseTeXPage := FALSE;
+ goto 999;
+ END;
+ END;
+ 666:
+ WHILE lastvalue > 0 DO BEGIN
+ IF present[lastvalue] THEN goto 555;
+ lastvalue := lastvalue - 1;
+ END;
+ 555:
+END;
+ParseTeXPage := TRUE;
+999:
+END; (* ParseTeXPage *)
+
+(******************************************************************************)
+
+PROCEDURE CheckPageRange;
+
+(* If user requested a page subrange then we make sure it is valid. *)
+
+LABEL 777, 888;
+
+VAR newTeXpage : TeXpageinfo;
+
+BEGIN
+IF NOT subrange THEN BEGIN (* translate all pages *)
+ firstDVIpage := 1;
+ finalDVIpage := totalpages;
+END
+ELSE BEGIN
+ IF firstDVIpage = 0 THEN (* parse and locate firstTeXpage *)
+ IF ParseTeXPage(firstTeXpage,newTeXpage) THEN BEGIN
+ MoveToDVIPage(1);
+ (* go forwards until newTeXpage matches currTeXpage *)
+ WHILE TRUE DO BEGIN
+ IF CurrMatchesNew(newTeXpage) THEN BEGIN
+ firstDVIpage := currDVIpage;
+ goto 888;
+ END
+ ELSE IF currDVIpage = totalpages THEN BEGIN
+ writeln('First TeX page does not exist!');
+ exit(1);
+ END
+ ELSE
+ MoveToDVIPage(currDVIpage + 1);
+ END;
+ 888:
+ END
+ ELSE BEGIN
+ writeln('Error in first TeX page!');
+ exit(1);
+ END;
+ IF finalDVIpage = 0 THEN (* parse and locate finalTeXpage *)
+ IF ParseTeXPage(finalTeXpage,newTeXpage) THEN BEGIN
+ MoveToDVIPage(totalpages);
+ (* go backwards until newTeXpage matches currTeXpage *)
+ WHILE TRUE DO BEGIN
+ IF CurrMatchesNew(newTeXpage) THEN BEGIN
+ finalDVIpage := currDVIpage;
+ goto 777;
+ END
+ ELSE IF currDVIpage = 1 THEN BEGIN
+ writeln('Final TeX page does not exist!');
+ exit(1);
+ END
+ ELSE
+ MoveToDVIPage(currDVIpage - 1);
+ END;
+ 777:
+ END
+ ELSE BEGIN
+ writeln('Error in final TeX page!');
+ exit(1);
+ END;
+ IF firstDVIpage > finalDVIpage THEN BEGIN
+ writeln('First page > final page!');
+ exit(1);
+ END
+ ELSE IF firstDVIpage > totalpages THEN BEGIN
+ writeln('First page > total number of pages!');
+ exit(1);
+ END;
+ (* allow user to give a final page > totalpages *)
+ IF finalDVIpage > totalpages THEN finalDVIpage := totalpages;
+END;
+END; (* CheckPageRange *)
+
+(******************************************************************************)
+
+PROCEDURE ShowTeXPage;
+
+(* Show current TeX page counter(s). *)
+
+LABEL 888;
+
+VAR i, lastnonzero : INTEGER;
+
+BEGIN
+write('[');
+lastnonzero := 9;
+WHILE lastnonzero > 0 DO BEGIN
+ IF currTeXpage[lastnonzero] <> 0 THEN goto 888;
+ lastnonzero := lastnonzero - 1; (* find last counter with non-zero value *)
+END;
+888:
+(* always show \count0 but don't show trailing 0 counters *)
+FOR i := 0 TO lastnonzero DO BEGIN
+ write(currTeXpage[i]:1);
+ IF i <> lastnonzero THEN write('.');
+END;
+write(']');
+END; (* ShowTeXPage *)
+
+(******************************************************************************)
+
+PROCEDURE PageOffPaper;
+
+(* One or more page edges do not fall within the paper edges.
+ We show user just how bad the problem is.
+*)
+
+BEGIN
+warncount := warncount + 1;
+writeln;
+write('Page off paper (paper is ');
+ShowDimension(paperwd); write(' wide by ');
+ShowDimension(paperht); write(' high)');
+writeln;
+IF minhp < paperleft THEN BEGIN
+ write('Beyond left edge by ');
+ ShowDimension(paperleft - minhp);
+ writeln;
+END;
+IF maxhp > paperright THEN BEGIN
+ write('Beyond right edge by ');
+ ShowDimension(maxhp - paperright);
+ writeln;
+END;
+IF minvp < papertop THEN BEGIN
+ write('Above top edge by ');
+ ShowDimension(papertop - minvp);
+ writeln;
+END;
+IF maxvp > paperbottom THEN BEGIN
+ write('Below bottom edge by ');
+ ShowDimension(maxvp - paperbottom);
+ writeln;
+END;
+END; (* PageOffPaper *)
+
+(******************************************************************************)
+
+PROCEDURE OpenFont (thisfontinfo : fontinfoptr);
+
+BEGIN
+WITH thisfontinfo^ DO
+ IF OpenFontFile(fontspec) THEN
+ { DEBUG
+ BEGIN
+ writeln;
+ writeln('Loading characters for ', fontspec:fontspeclen);
+ END
+ GUBED }
+ ELSE BEGIN
+ (* this should never happen since we avoid loading dummy font chars *)
+ writeln;
+ writeln('Bug in OpenFont! Could not open: ', fontspec:fontspeclen);
+ exit(1);
+ END;
+END; (* OpenFont *)
+
+(******************************************************************************)
+
+PROCEDURE LoadFonts;
+
+(* For each bitmapped font that is used (and exists) on the current page,
+ go thru charlist and call LoadBitmap for each character that hasn't yet
+ been downloaded. BeginBitmapFont will only be called if necessary.
+*)
+
+VAR
+ thisfontinfo : fontinfoptr; (* current font info in fontlist *)
+ thischarinfo : charinfoptr; (* current char info in charlist *)
+ thischar : INTEGER; (* current index into current chartable *)
+ fontopen : BOOLEAN; (* is thisfontinfo^.fontspec open? *)
+
+BEGIN
+thisfontinfo := fontlist;
+WHILE thisfontinfo <> unusedfont DO
+(* SortFonts makes sure we only consider used fonts *)
+WITH thisfontinfo^ DO BEGIN
+ (* do nothing if resident PostScript font or bitmapped font doesn't exist *)
+ IF (NOT psfont) AND fontexists THEN BEGIN
+ fontopen := FALSE; (* avoid opening font unnecessarily *)
+ thischarinfo := charlist;
+ WHILE thischarinfo <> NIL DO (* process unloaded chars in chartable *)
+ WITH thischarinfo^ DO BEGIN
+ thischar := 0;
+ WHILE thischar < charcount DO BEGIN
+ WITH chartable[thischar] DO
+ WITH pixelptr^[code] DO
+ IF (NOT loaded) AND (mapadr > 0) THEN BEGIN (* load bitmap *)
+ IF NOT fontopen THEN BEGIN
+ OpenFont(thisfontinfo);
+ BeginBitmapFont(fontid);
+ fontopen := TRUE; (* only open once *)
+ END;
+ LoadBitmap(thisfontinfo,code);
+ loaded := TRUE; (* only load once *)
+ END;
+ thischar := thischar + 1;
+ END;
+ thischarinfo := nextchar;
+ END;
+ IF fontopen THEN CloseFontFile;
+ END;
+ thisfontinfo := nextfont;
+END;
+END; (* LoadFonts *)
+
+(******************************************************************************)
+
+PROCEDURE DoSpecials;
+
+(* Call OutputSpecial for each \special command on the current page.
+ (The speciallist is built during InterpretPage.)
+*)
+
+VAR temp : specialinfoptr;
+
+BEGIN
+temp := speciallist;
+WHILE temp <> NIL DO
+ WITH temp^ DO BEGIN
+ (* The \special bytes are treated as a file name, possibly followed by
+ a space and additional PostScript text.
+ PSWriter will read this file and copy it verbatim to the output file.
+ The optional text is prefixed to the file as a separate line.
+ *)
+ IF NOT OutputSpecial(special,hp,vp) THEN BEGIN
+ warncount := warncount + 1;
+ writeln;
+ writeln('Couldn''t open \special file: ', special:Len(special));
+ END
+ ELSE IF stats THEN BEGIN
+ writeln;
+ write('\special command at (');
+ ShowDimension(hp); write(',');
+ ShowDimension(vp); write('): ');
+ write(special:Len(special)); writeln;
+ END;
+ temp := nextspecial;
+ END;
+END; (* DoSpecials *)
+
+(******************************************************************************)
+
+PROCEDURE DoFonts;
+
+(* For each font that is used (and exists) on the current page,
+ call the appropriate sequence of PSWriter routines depending on
+ the conserveVM flag and whether the font is bitmapped or resident.
+*)
+
+VAR
+ thisfontinfo : fontinfoptr; (* current font info in fontlist *)
+ thischarinfo : charinfoptr; (* current char info in charlist *)
+ thischar : INTEGER; (* current index into current chartable *)
+
+BEGIN
+thisfontinfo := fontlist;
+WHILE thisfontinfo <> unusedfont DO
+(* SortFonts makes sure we only consider used fonts! *)
+WITH thisfontinfo^ DO BEGIN
+ IF fontexists THEN BEGIN (* won't be dummy font info *)
+ IF psfont THEN
+ BeginPostScriptFont(fontname,scaledsize,mag)
+ ELSE BEGIN
+ IF conserveVM THEN SaveVM(fontid);
+ BeginBitmapFont(fontid);
+ END;
+
+ IF conserveVM AND (NOT psfont) THEN BEGIN (* download bitmaps *)
+ OpenFont(thisfontinfo);
+ thischarinfo := charlist;
+ WHILE thischarinfo <> NIL DO (* process unique chars *)
+ WITH thischarinfo^ DO BEGIN
+ thischar := 0;
+ WHILE thischar < charcount DO BEGIN
+ WITH chartable[thischar] DO
+ WITH pixelptr^[code] DO
+ IF (NOT loaded) AND (mapadr > 0) THEN BEGIN
+ LoadBitmap(thisfontinfo,code);
+ loaded := TRUE; (* but only once *)
+ END;
+ thischar := thischar + 1;
+ END;
+ thischarinfo := nextchar;
+ END;
+ CloseFontFile;
+ (* reset loaded flags to FALSE for next page *)
+ FOR thischar := 0 TO maxTeXchar DO
+ pixelptr^[thischar].loaded := FALSE;
+ END;
+
+ IF psfont THEN BEGIN
+ thischarinfo := charlist;
+ WHILE thischarinfo <> NIL DO
+ WITH thischarinfo^ DO BEGIN
+ thischar := 0;
+ WHILE thischar < charcount DO BEGIN
+ WITH chartable[thischar] DO
+ WITH pixelptr^[code] DO
+ IF mapadr > 0 THEN (* char exists *)
+ SetPostScriptChar(CHR(code),
+ hp,vp, (* reference point *)
+ pwidth); (* advance width *)
+ thischar := thischar + 1;
+ END;
+ thischarinfo := nextchar;
+ END;
+ END
+ ELSE BEGIN
+ thischarinfo := charlist;
+ WHILE thischarinfo <> NIL DO
+ WITH thischarinfo^ DO BEGIN
+ thischar := 0;
+ WHILE thischar < charcount DO BEGIN
+ WITH chartable[thischar] DO
+ WITH pixelptr^[code] DO
+ IF mapadr > 0 THEN (* char exists *)
+ SetBitmapChar(CHR(code),
+ hp,vp, (* reference point *)
+ pwidth); (* advance width *)
+ thischar := thischar + 1;
+ END;
+ thischarinfo := nextchar;
+ END;
+ END;
+ EndFont;
+
+ IF conserveVM AND (NOT psfont) THEN RestoreVM;
+ END;
+ thisfontinfo := nextfont;
+END;
+END; (* DoFonts *)
+
+(******************************************************************************)
+
+PROCEDURE DoRules;
+
+(* Call SetRule for each rule on the current page. *)
+
+VAR thisrule : INTEGER; thisruleinfo : ruleinfoptr;
+
+BEGIN
+thisruleinfo := rulelist;
+WHILE thisruleinfo <> NIL DO
+ WITH thisruleinfo^ DO BEGIN
+ thisrule := 0;
+ WHILE thisrule < rulecount DO BEGIN
+ WITH ruletable[thisrule] DO SetRule(wd,ht,hp,vp);
+ thisrule := thisrule + 1;
+ END;
+ thisruleinfo := nextrule;
+ END;
+END; (* DoRules *)
+
+(******************************************************************************)
+
+PROCEDURE DoPage;
+
+(* Interpret the current DVI page and fill in DVIReader's data structures.
+ PSWriter routines are called at appropriate times to output
+ the PostScript description of the current page.
+*)
+
+BEGIN
+pagecount := pagecount + 1;
+write(currDVIpage:1); (* show the current DVI page *)
+write('/'); ShowTeXPage; (* and TeX page *)
+flush(output); (* SYSDEP: show page immediately *)
+IF pagecount MOD pagesperline = 0 THEN writeln ELSE write(' ');
+
+BeginPage(currDVIpage);
+InterpretPage; (* PixelTableRoutine calls NewBitmapFont *)
+IF pageempty THEN BEGIN
+ OutputPage(currDVIpage); (* must be called even if no chars/rules *)
+ DoSpecials;
+END
+ELSE BEGIN
+ (* check that the page edges are within the paper edges *)
+ IF (minhp < paperleft) OR (minvp < papertop) OR
+ (maxhp > paperright) OR (maxvp > paperbottom) THEN
+ PageOffPaper;
+ (* Sort fonts in order of increasing totalchars and
+ return pointer to first unused font (for LoadFonts and DoFonts).
+ *)
+ SortFonts(unusedfont);
+ IF NOT conserveVM THEN LoadFonts;
+ OutputPage(currDVIpage);
+ DoSpecials;
+ DoFonts;
+ DoRules;
+END;
+EndPage(currDVIpage); (* final PostScript for current page *)
+END; (* DoPage *)
+
+(******************************************************************************)
+
+PROCEDURE ShowPtSize (scaledsize : INTEGER);
+
+(* Show given font size (in DVI units) in terms of (possibly magnified) pts. *)
+
+VAR realdim : REAL; fracpart : INTEGER;
+
+BEGIN
+write(' at ');
+realdim := (scaledsize / 16#10000) * (mag / 1000.0);
+(* show realdim to an accuracy of 1 decimal place *)
+IF ABS(realdim) < 0.05 THEN
+ write('0')
+ELSE BEGIN
+ IF realdim < 0.0 THEN BEGIN
+ write('-');
+ realdim := ABS(realdim);
+ END;
+ realdim := realdim + 0.05; (* round up to 1 decimal place *)
+ write(TRUNC(realdim):1); (* whole part *)
+ fracpart := TRUNC((realdim - TRUNC(realdim)) * 10.0); (* 0..9 *)
+ IF fracpart > 0 THEN
+ write('.', fracpart:1);
+END;
+write('pt');
+END; (* ShowPtSize *)
+
+(******************************************************************************)
+
+PROCEDURE ShowPageStats;
+
+(* Show rule/font/character statistics for current page. *)
+
+VAR fontcount : INTEGER; thisfontinfo : fontinfoptr;
+
+BEGIN
+writeln;
+writeln('Total rules on current page = ', totalrules:1);
+writeln('Fonts on current page:');
+fontcount := 0;
+thisfontinfo := fontlist;
+WHILE thisfontinfo <> NIL DO
+ WITH thisfontinfo^ DO BEGIN
+ IF fontused THEN BEGIN
+ write(fontspec:fontspeclen);
+ IF psfont THEN ShowPtSize(scaledsize);
+ IF NOT fontexists THEN write(' DOES NOT EXIST!');
+ fontcount := fontcount + 1;
+ writeln(' total chars = ', totalchars:1);
+ END;
+ thisfontinfo := nextfont;
+ END;
+writeln('Total fonts on current page = ', fontcount:1);
+writeln;
+END; (* ShowPageStats *)
+
+(******************************************************************************)
+
+PROCEDURE ShowFinalStats;
+
+(* Show some overall statistics. *)
+
+VAR fontsused, c, loadcount, loadtotal, bitmapbytes : INTEGER;
+ thisfontinfo : fontinfoptr;
+
+BEGIN
+writeln('Summary');
+writeln('=======');
+writeln;
+writeln('Total pages output = ', pagecount:1);
+writeln('Total pages in DVI file = ', totalpages:1);
+writeln('Total fonts in DVI file = ', totalfonts:1);
+(* go thru fontlist showing info for EVERY font *)
+fontsused := 0;
+loadtotal := 0;
+bitmapbytes := 0;
+thisfontinfo := fontlist;
+WHILE thisfontinfo <> NIL DO
+ WITH thisfontinfo^ DO BEGIN
+ IF fontspeclen > 0 THEN BEGIN
+ write(fontspec:fontspeclen);
+ IF psfont THEN ShowPtSize(scaledsize);
+ IF fontexists THEN BEGIN
+ fontsused := fontsused + 1;
+ IF (NOT conserveVM) AND (NOT psfont) THEN BEGIN
+ loadcount := 0;
+ FOR c := 0 TO maxTeXchar DO
+ WITH pixelptr^[c] DO
+ IF loaded AND (mapadr > 0) THEN BEGIN
+ loadcount := loadcount + 1;
+ bitmapbytes := bitmapbytes + (ht * ((wd + 7) DIV 8));
+ END;
+ write(' loaded chars = ', loadcount:1);
+ loadtotal := loadtotal + loadcount;
+ END;
+ END
+ ELSE
+ write(' DOES NOT EXIST!');
+ END
+ ELSE BEGIN
+ write(fontname:fontnamelen, ' scaled ');
+ write(TRUNC(mag * (scaledsize / designsize) + 0.5):1);
+ write(' not used');
+ END;
+ writeln;
+ thisfontinfo := nextfont;
+ END;
+writeln('Total fonts actually used = ', fontsused:1);
+IF NOT conserveVM THEN BEGIN
+ writeln('Total characters loaded = ', loadtotal:1);
+ writeln('Hex digits in loaded bitmaps = 2 * ', bitmapbytes:1);
+END;
+END; (* ShowFinalStats *)
+
+(******************************************************************************)
+
+PROCEDURE TopLevel;
+
+LABEL 888;
+
+BEGIN
+InitOptions; (* init DVIname and options *)
+InitDVIReader;
+InitFontReader;
+OpenDVIFile(DVIname); (* and read DVImag etc. *)
+IF mag = 0 THEN mag := DVImag; (* use DVImag *)
+SetConversionFactor(resolution,mag); (* for DVIReader *)
+Initialize;
+IF stats THEN ShowOptions;
+CheckPageRange; (* set firstDVIpage, finalDVIpage *)
+IF NOT OpenOutput(PSname) THEN BEGIN
+ writeln('Couldn''t open output file: ', PSname:Len(PSname));
+ exit(1);
+END;
+IF header[0] <> ' ' THEN (* output header file first *)
+ IF NOT OutputHeader(header) THEN BEGIN
+ writeln('Couldn''t open header file: ', header:Len(header));
+ exit(1);
+ END;
+IF increment > 1 THEN (* finalDVIpage may need reducing *)
+ WHILE (finalDVIpage - firstDVIpage) MOD increment > 0 DO
+ finalDVIpage := finalDVIpage - 1;
+IF reverse THEN BEGIN
+ MoveToDVIPage(finalDVIpage); (* start with finalDVIpage *)
+ finalDVIpage := firstDVIpage; (* and end with firstDVIpage *)
+END
+ELSE
+ MoveToDVIPage(firstDVIpage); (* start with firstDVIpage *)
+WHILE TRUE DO BEGIN
+ DoPage; (* do at least one page *)
+ IF stats THEN ShowPageStats;
+ IF currDVIpage = finalDVIpage THEN goto 888;
+ IF reverse THEN
+ MoveToDVIPage(currDVIpage - increment)
+ ELSE
+ MoveToDVIPage(currDVIpage + increment);
+END;
+888:
+IF pagecount MOD pagesperline > 0 THEN writeln;
+IF stats THEN ShowFinalStats;
+CloseDVIFile;
+CloseOutput;
+IF warncount > 0 THEN
+ exit(2)
+ELSE
+ exit(0);
+END; (* TopLevel *)
+
+(******************************************************************************)
+
+BEGIN
+TopLevel;
+END. (* PSDVI *)
diff --git a/dviware/psprint/unix/psfonts.tex b/dviware/psprint/unix/psfonts.tex
new file mode 100644
index 0000000000..11e55aec2a
--- /dev/null
+++ b/dviware/psprint/unix/psfonts.tex
@@ -0,0 +1,69 @@
+% This TeX source file illustrates the use (and abuse) of PostScript fonts.
+
+\input pstext % defines \PStext and \CMtext
+
+\nopagenumbers
+\parindent=0pt
+\parskip=\bigskipamount
+
+The following fonts should be available in all PostScript printers:
+
+\font\courb=ps-courier-b at 10pt
+\font\courbo=ps-courier-bo at 10pt
+\font\couro=ps-courier-o at 10pt
+\font\cour=ps-courier at 10pt
+\font\helvb=ps-helv-b at 10pt
+\font\helvbo=ps-helv-bo at 10pt
+\font\helvo=ps-helv-o at 10pt
+\font\helv=ps-helv at 10pt
+\font\tb=ps-times-b at 10pt
+\font\tbi=ps-times-bi at 10pt
+\font\ti=ps-times-i at 10pt
+\font\ts=ps-times-s at 10pt
+\font\tr=ps-times-r at 10pt
+\font\sy=ps-symbol at 10pt
+
+\bigskip
+\leftline{\courb Courier-Bold}
+\leftline{\courbo Courier-BoldOblique}
+\leftline{\couro Courier-Oblique}
+\leftline{\cour Courier}
+\leftline{\helvb Helvetica-Bold}
+\leftline{\helvbo Helvetica-BoldOblique}
+\leftline{\helvo Helvetica-Oblique}
+\leftline{\helv Helvetica}
+\leftline{\tb Times-Bold}
+\leftline{\tbi Times-BoldItalic}
+\leftline{\ti Times-Italic}
+\leftline{\ts Times-Slanted}
+\leftline{\tr Times-Roman}
+\leftline{\sy Symbol \rm (Symbol)}
+
+A PostScript font can be used at any desired size:
+
+\font\trA=ps-times-r at 12pt
+\font\trB=ps-times-r at 20pt
+\font\trC=ps-times-r at 34.5pt
+
+\bigskip
+\leftline{\tr Times-Roman at 10pt}
+\leftline{\trA Times-Roman at 12pt}
+\leftline{\trB Times-Roman at 20pt}
+\leftline{\trC Times-Roman at 34.5pt}
+
+\def\sometext
+{\'o \`o \^o \"o \~o \=o \.o \u o \v o \H o \t oo \c o \d o \b o
+\oe\ \OE\ \ae\ \AE\ \aa\ \AA\ \o\ \O\ \l\ \L\ \ss\ \i\ \j}
+
+\rm
+Standard \TeX\ accents and foreign letters:
+\sometext
+
+PostScript accents and foreign letters:
+\PStext \tr \sometext \CMtext % \t \aa \AA \j will generate error messages
+
+\rm
+A PostScript font usually appears {\tr darker and larger} than
+an ``equivalent'' Computer Modern font.
+
+\bye
diff --git a/dviware/psprint/unix/psprint b/dviware/psprint/unix/psprint
new file mode 100644
index 0000000000..776f2a2708
--- /dev/null
+++ b/dviware/psprint/unix/psprint
@@ -0,0 +1,403 @@
+#!/bin/csh -f
+#
+# Andrew Trevorrow, October 1988
+# This shell script can print a DVI file, PostScript program, or text file
+# on an Apple LaserWriter, DEC PrintServer 40 or Linotronic 300.
+# Search for SYSDEP to locate site-specific values that you may want to change.
+#
+set tex_ps = (/usr/users/applied/staff/atrevorr/ps) # SYSDEP
+set tfminfo = (-T /usr/local/lib/tex/fonts/ -P ps-) # SYSDEP
+set dev = lw # SYSDEP: use LaserWriter if no -dev value
+#
+# DON'T change these values unless you know what you're doing:
+#
+set filename # changed by last argument without "-" prefix
+set filetype = UNKNOWN # changed by -dvi/-ps/-text/-two/-wide or filename
+set ps_queue = default # use device-specific default if no -q value
+set conserve = default # use device-specific default if no -con or -nocon
+set rev = default # use device-specific default if no -rev or -norev
+set copies = 1 # changed by -c value
+set output # changed by -o value
+set note # changed by -n value
+set hoff # changed by -ho value
+set voff # changed by -vo value
+set pages # changed by -p value
+set inc # changed by -i value
+set mag # changed by -m value
+set units # changed by -u value
+set stats # changed by -s
+set landscape # changed by -l
+set linores = 1270 # changed by -lowres (to 635)
+set size = a4p # changed by -size value
+set cutmarks = true # -cut = do cut marks; changed by -nocut
+set flag = true # -flag = flag page enabled; changed by -noflag
+set manual = false # no manual feed; changed by -manual
+#
+# Parse command line and set various parameters.
+#
+@ i = 1
+while ($i <= $#argv)
+ set arg = "$argv[$i]"
+ if ("$arg" =~ -*) then # arg must be an option
+ if ("$arg" == '-dvi') then
+ set filetype = DVI
+ else if ("$arg" == '-ps') then
+ set filetype = PS
+ else if ("$arg" == '-text') then
+ set filetype = TEXT
+ else if ("$arg" == '-two') then
+ set filetype = TWO
+ else if ("$arg" == '-wide') then
+ set filetype = WIDE
+ else if ("$arg" == '-dev' | "$arg" == '-device') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing string after -dev\!'
+ exit(1)
+ endif
+ set dev = "$argv[$i]"
+ else if ("$arg" == '-o') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing file after -o\!'
+ exit(1)
+ endif
+ set output = "$argv[$i]"
+ else if ("$arg" == '-n') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing string after -n\!'
+ exit(1)
+ endif
+ set note = "$argv[$i]"
+ else if ("$arg" == '-ho') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing dimension after -ho\!'
+ exit(1)
+ endif
+ set hoff = (-H"$argv[$i]")
+ else if ("$arg" == '-vo') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing dimension after -vo\!'
+ exit(1)
+ endif
+ set voff = (-V"$argv[$i]")
+ else if ("$arg" == '-c') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing integer after -c\!'
+ exit(1)
+ endif
+ set copies = "$argv[$i]"
+ if ("$copies" !~ [0,1,2,3,4,5,6,7,8,9]*) then
+ echo 'Bad -c value:' $copies
+ echo 'Specify a positive integer.'
+ exit(1)
+ else if ("$copies" < 1 | "$copies" > 25) then
+ echo 'Bad -c value:' $copies
+ echo 'Specify a positive integer from 1 to 25.'
+ exit(1)
+ endif
+ else if ("$arg" == '-i') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing integer after -i\!'
+ exit(1)
+ endif
+ set inc = (-i"$argv[$i]")
+ else if ("$arg" == '-m') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing integer after -m\!'
+ exit(1)
+ endif
+ set mag = (-m"$argv[$i]")
+ else if ("$arg" == '-u') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing units after -u\!'
+ exit(1)
+ endif
+ set units = (-u"$argv[$i]")
+ else if ("$arg" == '-p') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing page range after -p\!'
+ exit(1)
+ endif
+ set pages = (-p"$argv[$i]")
+ else if ("$arg" == '-s') then
+ set stats = -s # show stats (if DVI)
+ else if ("$arg" == '-con' | "$arg" == '-conserve') then
+ set conserve = -c # conserve VM (if DVI)
+ else if ("$arg" == '-nocon' | "$arg" == '-noconserve') then
+ set conserve # don't conserve VM
+ else if ("$arg" == '-rev' | "$arg" == '-reverse') then
+ set rev = -b # reverse page order (if DVI)
+ else if ("$arg" == '-norev' | "$arg" == '-noreverse') then
+ set rev # don't reverse
+ else if ("$arg" == '-l') then
+ set landscape = -l # swap paper dimens (if DVI)
+ else if ("$arg" == '-f' | "$arg" == '-flag') then
+ set flag = true # we want a flag page (if lw)
+ else if ("$arg" == '-nof' | "$arg" == '-noflag') then
+ set flag = false # no flag page
+ else if ("$arg" == '-man' | "$arg" == '-manual') then
+ set manual = true # wait for manual feed (if lw)
+ else if ("$arg" == '-low' | "$arg" == '-lowres') then
+ set linores = 635 # low resolution (if lino)
+ else if ("$arg" == '-cut' | "$arg" == '-cutmarks') then
+ set cutmarks = true # show cut marks (if lino)
+ else if ("$arg" == '-nocut' | "$arg" == '-nocutmarks') then
+ set cutmarks = false # no cut marks
+ else if ("$arg" == '-size') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing value after -size\!'
+ exit(1)
+ endif
+ set size = "$argv[$i]"
+ else if ("$arg" == '-q') then
+ @ i++
+ if ($i > $#argv) then
+ echo 'Missing queue after -q\!'
+ exit(1)
+ endif
+ set ps_queue = "$argv[$i]"
+ else
+ echo 'Unknown option:' $arg
+ exit(1)
+ endif
+ else
+ # arg does not start with '-' so assume it is filename
+ set filename = "$arg"
+ endif
+ @ i++
+end
+if ($filename == '') then
+ echo 'File not given\!'
+ exit(1)
+endif
+#
+# If filetype is still UNKNOWN then we check filename to determine filetype.
+# Note that if foo and foo.dvi exist then "psprint foo" will use foo.dvi
+# (and "psprint foo -text" will use foo):
+#
+if ($filetype == 'UNKNOWN') then
+ if ($filename =~ *.ps) then
+ set filetype = PS
+ else if ($filename =~ *.dvi) then
+ set filetype = DVI
+ else if (-e {$filename}.dvi) then
+ set filename = {$filename}.dvi
+ set filetype = DVI
+ else
+ set filetype = TEXT
+ endif
+endif
+#
+# Check that file exists:
+#
+if (-e $filename) then
+ # file exists
+else
+ echo File not found: $filename
+ exit(1)
+endif
+#
+# Check for valid device; if ok then set up some device-specific values:
+#
+if ("$dev" == 'lw') then
+ if ("$ps_queue" == 'default') then
+ set ps_queue = ps_local # SYSDEP: default LaserWriter queue
+ else
+ # SYSDEP: test for valid queue?
+ endif
+ if ("$rev" == 'default') set rev = -b # default is reverse pages
+ if ("$conserve" == 'default') set conserve # default is don't conserve VM
+ set papersize = "-x 210mm -y 297mm" # SYSDEP: A4
+ set res = 300
+ set dummyfont = (-d cmr10.300pk) # SYSDEP
+ set pkdir = (-f /usr/local/bin/dvitovdu/pk/) # SYSDEP
+else if ("$dev" == 'lino') then
+ if ("$ps_queue" == 'default') then
+ set ps_queue = lino_queue # SYSDEP: default Linotronic queue
+ else
+ # SYSDEP: test for valid queue?
+ endif
+ if ("$rev" == 'default') set rev # default is don't reverse
+ if ("$conserve" == 'default') set conserve = -c # default is conserve VM
+ if ("$size" == 'a3l') then
+ set pagesetup = A3Lsetup # defined in lino_header.ps
+ set papersize = "-x 297mm -y 420mm" # A3
+ else if ("$size" == 'a4p') then
+ set pagesetup = A4Psetup
+ set papersize = "-x 210mm -y 297mm" # A4
+ else if ("$size" == 'a4l') then
+ set pagesetup = A4Lsetup
+ set papersize = "-x 210mm -y 297mm"
+ else if ("$size" == 'a5p') then
+ set pagesetup = A5Psetup
+ set papersize = "-x 148mm -y 210mm" # A5
+ else if ("$size" == 'a5l') then
+ set pagesetup = A5Lsetup
+ set papersize = "-x 148mm -y 210mm"
+ else if ("$size" == 'b5p') then
+ set pagesetup = B5Psetup
+ set papersize = "-x 176mm -y 250mm" # B5
+ else if ("$size" == 'b5l') then
+ set pagesetup = B5Lsetup
+ set papersize = "-x 176mm -y 250mm"
+ else
+ echo 'Unknown -size value:' "$size" '(use a3l,a4p,a4l,a5p,a5l,b5p,b5l)'
+ exit(1)
+ endif
+ set res = $linores # 635 or 1270
+ set dummyfont = (-d cmr10.{$res}pk) # SYSDEP
+ set pkdir = (-f /usr/local/tex/linopk/) # SYSDEP
+else if ("$dev" == 'ps40') then
+ if ("$ps_queue" == 'default') then
+ set ps_queue = ps40_queue # SYSDEP: default PrintServer queue
+ else
+ # SYSDEP: test for valid queue?
+ endif
+ if ("$rev" == 'default') set rev # default is don't reverse pages
+ if ("$conserve" == 'default') set conserve # default is don't conserve VM
+ set papersize = "-x 210mm -y 297mm" # SYSDEP: A4
+ set res = 300
+ set dummyfont = (-d cmr10.300pk) # SYSDEP
+ set pkdir = (-f /usr/local/tex/write-white/) # SYSDEP
+else
+ echo 'Unknown device:' "$dev" '(specify lw, lino or ps40)'
+ exit(1)
+endif
+#
+# Linotronic should only be used to print DVI or PS files:
+#
+if ("$dev" == 'lino') then
+ if ($filetype != 'DVI' & $filetype != 'PS') then
+ echo 'Linotronic should not be used to print a text file\!'
+ exit(1)
+ endif
+endif
+#
+# Build temporary file in current directory:
+#
+set tmpfile = (psprint.tmp)
+echo Creating $tmpfile
+if ("$dev" == 'lw') then
+ #
+ # We no longer start with ^D because of problems encountered when
+ # a LaserWriter is connected to an X25 pad (due to echoing of ^D):
+ #
+ cp $tex_ps/lw_header.ps $tmpfile
+ echo '/@USER (USER :' $user ') def' >> $tmpfile
+ echo '/@NODE (NODE :' $HOST ') def' >> $tmpfile
+ echo '/@FILE (FILE :' $filename ') def' >> $tmpfile
+ echo '/@FORMAT (FORMAT :' $filetype ') def' >> $tmpfile
+ echo '/@QUEUED (QUEUED :' `date` ') def' >> $tmpfile
+ echo '/@NOTE (NOTE :' $note ') def' >> $tmpfile
+ if ($flag != 'true') then
+ echo '/@bannerpage { } def' >> $tmpfile # no flag page
+ endif
+ if ($manual == 'true') then
+ echo 'statusdict begin /manualfeed true def end' >> $tmpfile
+ endif
+else if ("$dev" == 'lino') then
+ echo '/@USER ('$user' '$filename') def' >> $tmpfile
+ echo '/@DATE ('`date`') def' >> $tmpfile
+ echo '/@NOTE ('$note') def' >> $tmpfile
+ cat $tex_ps/lino_header.ps >> $tmpfile
+ echo $pagesetup >> $tmpfile # call page setup procedure
+ if ($cutmarks != 'true') then
+ echo '/@cutmarks { } def' >> $tmpfile # no cutmarks
+ endif
+else # "$dev" must be 'ps40'
+ cp $tex_ps/ps40_header.ps $tmpfile
+endif
+#
+# The value of #copies will be used by PostScript's showpage operator to
+# print multiple copies of each page:
+#
+echo '/#copies '$copies' def' >> $tmpfile
+#
+# Here are some definitions used in the various prologues:
+#
+if ("$dev" == 'lw') echo '/dev (LW) def' >> $tmpfile
+if ("$dev" == 'lino') echo '/dev (LINO) def' >> $tmpfile
+if ("$dev" == 'ps40') echo '/dev (PS40) def' >> $tmpfile
+echo '/res '$res' def' >> $tmpfile
+echo '/fspec ('$filename') def' >> $tmpfile # used in two.ps and wide.ps
+if ("$landscape" == '-l') then
+ echo '/land true def' >> $tmpfile
+else
+ echo '/land false def' >> $tmpfile
+endif
+#
+# Each type of file has its own prologue:
+#
+if ($filetype == 'DVI') cat $tex_ps/tex.ps $tex_ps/{$dev}_fonts.ps >> $tmpfile
+if ($filetype == 'PS') cat $tex_ps/ps.ps >> $tmpfile
+if ($filetype == 'TEXT') cat $tex_ps/text.ps >> $tmpfile
+if ($filetype == 'TWO') cat $tex_ps/two.ps >> $tmpfile
+if ($filetype == 'WIDE') cat $tex_ps/wide.ps >> $tmpfile
+#
+# If DVI file then run psdvi and check exit status:
+#
+if ($filetype == 'DVI') then
+ set psdvifile = (psdvi.tmp)
+ $tex_ps/psdvi \
+ $rev $landscape $stats $conserve $pkdir $dummyfont $tfminfo \
+ "$pages" $inc $mag $units $hoff $voff $papersize \
+ -h $tmpfile -o $psdvifile -r $res \
+ $filename # best if last argument
+ #
+ # psdvi can exit with 0=success, 1=error, 2=warning:
+ #
+ if ($status >= '1') then # psdvi saw warning(s) or fatal error
+ rm $tmpfile # delete temporary header
+ echo 'Printing aborted due to error(s). '$tmpfile deleted.
+ if (-e $psdvifile) then # psdvi output file exists
+ rm $psdvifile # so delete it
+ endif
+ exit(1)
+ else # no errors
+ rm $tmpfile # delete header
+ mv $psdvifile $tmpfile # and use psdvi output as temporary file
+ endif
+endif
+#
+# Complete temporary file:
+#
+if ("$dev" == 'lw') then
+ if ($filetype == 'DVI') then
+ cat $tex_ps/lw_trailer.ps $tex_ps/ctrld >> $tmpfile
+ else if ($filetype == 'PS') then
+ cat $filename $tex_ps/lw_trailer.ps $tex_ps/ctrld >> $tmpfile
+ else # TEXT/TWO/WIDE
+ cat $filename $tex_ps/ctrld >> $tmpfile
+ endif
+else if ("$dev" == 'lino') then
+ if ($filetype == 'DVI') then
+ cat $tex_ps/lino_trailer.ps $tex_ps/ctrld >> $tmpfile
+ else if ($filetype == 'PS') then
+ cat $filename $tex_ps/lino_trailer.ps $tex_ps/ctrld >> $tmpfile
+ else # TEXT/TWO/WIDE not supported on Linotronic
+ endif
+else
+ # dev = 'ps40'; no trailer file or ^D needed for PrintServer
+endif
+#
+# If -o used then rename temporary file, else print it:
+#
+if ("$output" == '') then
+ lpr -P$ps_queue -h $tmpfile
+ echo Your output has been sent to $ps_queue
+ # echo debug: lpr '-P'$ps_queue '-h' $tmpfile
+ rm $tmpfile
+else
+ mv $tmpfile $output
+ echo PostScript code saved in $output
+endif
diff --git a/dviware/psprint/unix/psprint.man b/dviware/psprint/unix/psprint.man
new file mode 100644
index 0000000000..ae6cbedc00
--- /dev/null
+++ b/dviware/psprint/unix/psprint.man
@@ -0,0 +1,358 @@
+PSPRINT can be used to print a DVI file produced by TeX (or LaTeX),
+a raw PostScript file, or an ordinary text file, on a variety of PostScript
+printers. The currently supported devices include the Apple LaserWriter,
+the Linotronic 300 and DEC's PrintServer 40.
+
+USAGE: psprint file
+ [-dev[ice] printer_type]
+ [-dvi] [-ps] [-text] [-two] [-wide]
+ [-o file] [-q queue] [-n note] [-c copies] [-l]
+ [-low[res]] [-[no]cut[marks]] [-size page_setup]
+ [-man[ual]] [-[no]f[lag]]
+ [-m magnification] [-u units]
+ [-s] [-[no]rev[erse]] [-[no]con[serve]]
+ [-p first:final] [-i increment] [-ho dimension] [-vo dimension]
+
+TeX Output
+----------
+PSPRINT looks for a DVI file by default. To print foo.dvi, simply type:
+
+ psprint foo
+
+PSPRINT translates foo.dvi into a temporary PostScript file.
+The order in which pages are translated depends on the type of printer.
+(The default order can be overridden by -reverse or -noreverse.)
+If no errors are found, the temporary file is sent to an appropriate
+print queue and then deleted.
+
+PostScript Output
+-----------------
+PostScript is a complete programming language with a powerful set of
+operators for manipulating text and graphics. A PostScript program is an
+ordinary text file. If you give it a name like foo.ps then sending it to
+the printer is simple:
+
+ psprint foo.ps
+
+If you decide to use some other file extension you'll have to add the -ps
+option. The PSPRINT User Guide explains how to include PostScript
+graphics in a TeX or LaTeX document.
+
+People who want to write PostScript programs will need to get the
+PostScript Language Reference Manual and PostScript Language Tutorial
+and Cookbook. Both books are by Adobe Systems Incorporated and
+published by Addison-Wesley.
+
+Text Output
+-----------
+To print a normal text file, just use any file type except .dvi or .ps:
+
+ psprint foo.lis
+
+Your output will have 66 lines per page, and any lines more than 80
+characters long will be truncated. Use the -l option to rotate the paper
+so that you can have lines up to 132 characters long
+(but only 50 lines per page).
+
+Type "psprint foo.ps -text" if you want to print a PostScript program
+rather than have it interpreted. You'll also have to use -text if you
+want to print a text file called foo but foo.dvi also exists.
+
+The -two and -wide options also print text files but format the
+output so that two "pages" appear on each sheet of paper.
+In both cases there will be 60 lines per page, but for -two each line
+can be up to 80 characters long, or up to 132 characters for -wide.
+
+These text file facilities may not be available on all types of
+printers, especially the Linotronic.
+
+Options
+-------
+
+-device printer_type
+
+This option tells PSPRINT which type of PostScript printer is to be used.
+The currently supported devices are:
+
+ lw --- for an Apple LaserWriter (the default)
+ lino --- for a Linotronic 300
+ ps40 --- for DEC's PrintServer 40
+
+-dvi
+
+Force PSPRINT to assume the input file is a DVI file.
+
+-ps
+
+Force PSPRINT to assume the input file is a PostScript program.
+
+-text
+
+Force PSPRINT to assume the input file is an ordinary text file.
+
+-two
+
+Like -text but the output is formatted so that two "pages"
+(both 60 lines by 80 columns) appear on each sheet of paper.
+
+-wide
+
+Like -text but the output is formatted so that two wide "pages"
+(both 60 lines by 132 columns) appear on each sheet of paper.
+
+-flag or -noflag (only if LaserWriter)
+
+By default PSPRINT produces a flag page for each job sent to
+a LaserWriter. Use -noflag if you don't want such a page.
+
+-manual (only if LaserWriter)
+
+Use this option if you want to manually feed paper into the LaserWriter.
+As soon as the printer sees your job it will wait for you to feed in each
+sheet of paper (it will normally wait up to a minute).
+
+-lowres (only for a DVI file and if Linotronic)
+
+By default, TeX output on the Linotronic is printed at 1270 dots per inch.
+The temporary file created by PSPRINT will typically be very large.
+If -lowres is given then 635 dots per inch will be used, reducing both the
+size of the temporary file (by roughly three quarters) and the likelihood
+of memory problems. The print quality will of course be poorer but you'll
+probably need a magnifying glass to clearly see the difference.
+
+-size page_setup (only if Linotronic)
+
+This option specifies the page image size and orientation.
+Possible values are a4p (the default), a4l, a5p, a5l, b5p, b5l and a3l.
+The "p" stands for portrait and the "l" for landscape.
+(Don't confuse the landscape orientation with the -l option which rotates
+the output within the page image, regardless of the -size value.)
+
+-cutmarks or -nocutmarks (only if Linotronic)
+
+This option controls the appearance of cut marks on Linotronic output.
+These marks define the edges of the page image. -cutmarks is the default;
+use -nocutmarks to suppress them.
+
+-p first:final (only for a DVI file)
+
+Print a selected subrange of pages from the DVI file.
+"first" and "final" can select either DVI page numbers (positive integers)
+or TeX page numbers.
+
+Assuming TeX generated the pages "[0] [1] [2.1] [2.2] [3]"
+(DVI pages 1 to 5), here are some examples of how you could use -p:
+
+ psprint foo -p 2 --- prints the 2nd DVI page (=[1])
+ psprint foo -p '[2]' --- prints [2.1] and [2.2]
+ psprint foo -p :4 --- prints the first four pages
+ psprint foo -p '1:[2]' --- also prints the first four pages
+ psprint foo -p 4: --- prints the last two pages
+ psprint foo -p '[2.2]:' --- also prints the last two pages
+
+Note the need to enclose a TeX page specification in single quotes.
+Note also that "first" and "final" are optional; they default to
+the first and last DVI pages respectively.
+Omitting ":final" entirely sets "final" equal to "first".
+
+A TeX page specification is of the form [i0.i1...i9]. i0 to i9 are
+integers separated by periods and represent the 10 counter values that
+TeX stores with each DVI page. Any number of these integers may be absent
+and trailing periods may be omitted. An absent integer will match any
+value in the corresponding counter.
+Note that more than one DVI page may match a particular TeX page
+specification. If "first" is a TeX page then the LOWEST matching DVI page
+is selected, and if "final" then the HIGHEST matching page is selected.
+
+-i increment (only for a DVI file)
+
+Assuming f is the first DVI page selected (where f is either 1 or the start
+of a -p subrange) then an increment of i tells PSPRINT to print pages
+f, f+i, f+2i, f+3i, ... , f+ni, where f+ni is <= the final DVI page selected.
+The primary use of -i is to simplify the printing of a document on
+both sides of the paper. For example, if foo.dvi has 8 pages then the
+following steps will produce a two-sided document on a LaserWriter:
+
+ 1. psprint foo -i 2 -noflag # prints DVI pages 7, 5, 3, 1
+ Note that -reverse is the default printing order for a LaserWriter.
+
+ 2. Remove the 4 pages from the output tray and carefully put them back
+ into the input cassette so that page 1 remains face up and its
+ top edge goes into the printer first. (If foo.dvi had 7 pages then
+ you would only need to remove the top 3 pages from the output tray.)
+
+ 3. psprint foo -i 2 -p 2: -norev # prints DVI pages 2, 4, 6, 8
+
+Note that the use of -rev or -norev with -i has no effect on WHICH pages
+are printed; it simply changes the ORDER in which they are done.
+
+-reverse or -noreverse (only for a DVI file)
+
+Use -reverse to force PSPRINT to print pages in descending order,
+or -noreverse to force PSPRINT to print pages in ascending order.
+By default PSPRINT prints DVI pages in an order determined by the type of
+printer you are using. The Apple LaserWriter stacks output sheets face up,
+so PSPRINT normally prints pages in reverse order so that your output will
+be automatically collated. The PrintServer 40 stacks the output face down,
+so PSPRINT normally prints pages in ascending order. The default order
+on the Linotronic is largely irrelevant, since this printer produces pages
+on a continuous roll of paper (the default used is ascending order).
+
+-conserve or -noconserve (only for a DVI file)
+
+Use -conserve to force PSPRINT to conserve the printer's virtual memory
+at the expense of creating a larger output file (character bitmaps will be
+downloaded more often). On a Linotronic -conserve is the default;
+on a LaserWriter or PrintServer -noconserve is the default.
+
+-ho dimension and -vo dimension (only for a DVI file)
+
+These options allow you to shift the printed location of each page
+according to the given dimensions. For example, "-ho -.5in" would
+move each printed page half an inch to the left.
+A "dimension" is any integer or real number (possibly negative) followed
+by a two-letter unit: in,cm,mm,pc,pt,bp,px (same as those for -u).
+
+-m number (only for a DVI file)
+
+Override the DVI magnification with a number 1000 times the desired
+magnification. The given number should correspond to one of
+TeX's \magstep values; see chapter 4 of The TeXbook.
+
+-u units (only for a DVI file)
+
+Set the units of dimensions displayed in some PSPRINT messages
+(e.g., if the page is off the paper). Legal units are:
+ in for inches (the default)
+ cm for centimetres (2.54cm = 1in)
+ mm for millimetres (25.4mm = 1in)
+ pt for points (72.27pt = 1in)
+ pc for picas (12pc = 1pt)
+ bp for big points (72bp = 1in)
+ px for pixels (the Apple LaserWriter has 300 pixels per inch)
+
+-s (only for a DVI file)
+
+Display statistics on the number of rules/fonts/characters on each page.
+
+-l
+
+To get "landscaped" output instead of the normal "portrait" output.
+If given a DVI file, PSPRINT will check each page to make sure it fits
+within the rotated paper.
+
+-c number
+
+To specify up to 25 copies.
+Use of this facility is not encouraged. Note in particular that
+copies of a multiple-page document will NOT be collated.
+
+-n string (only if LaserWriter or Linotronic)
+
+To include the given string on your flag page.
+
+-q string
+
+To override the default queue used by PSPRINT.
+(Some sites may have more than one printer of the same type.)
+
+-o file
+
+To send the PostScript code generated by PSPRINT to a file rather than
+to a printer. Since PSPRINT generates device-specific PostScript code
+you should only send this file to a PostScript printer of the type
+that PSPRINT intended to use.
+
+Errors
+------
+PSPRINT may detect certain errors while translating a DVI file.
+The sort of errors you are most likely to see include:
+
+ Page off paper (paper is ...
+ The current page contains material beyond one or more paper edges.
+ Use DVItoVDU to see where the problem lies.
+
+ Couldn't open font file: ...
+ Your DVI file uses a font at a non-existent magnification.
+ Try a different font magnification in your source file.
+
+ Couldn't open \special file: ...
+ PSPRINT could not locate the given \special file.
+ Check the file's spelling and/or directory location.
+
+Error messages apply to the most recently displayed DVI/TeX page.
+Any message that does not make sense probably indicates some sort of bug.
+Please save a copy of the input file and report the problem to your
+local TeXnician.
+
+If a DVI file uses a large number of fonts (or a few very large fonts)
+then you might get an error page with the message "VMerror".
+This indicates that PostScript's "virtual memory" has been exhausted,
+and the rest of your job will be flushed.
+This problem is unlikely to worry most people, particularly on the
+PrintServer 40 which has much more VM than the LaserWriter or Linotronic.
+If the problem does occur, there are a few things you can try:
+
+ --- On a LaserWriter or PrintServer 40, try printing a few pages
+ at a time, or use -conserve.
+ --- On a Linotronic, try using -lowres.
+ (Note that -conserve is the default for this device.)
+
+An error in a PostScript program should produce some sort of message on
+your printed output. If this happens a lot, go back and read the
+PostScript Reference Manual more carefully.
+
+PostScript Fonts
+----------------
+PSPRINT allows the use of PostScript fonts in a TeX or LaTeX document.
+Such fonts can be used at any desired size and no character bitmaps need
+to be downloaded since the shape information is resident in the printer.
+The necessary typesetting information required by PSPRINT is extracted
+from TFM files (TeX Font Metric files). A TFM file name beginning
+with "ps-" is used to indicate a resident PostScript font.
+
+Each type of PostScript printer provides a different set of fonts.
+To be able to use a particular PostScript font you need to know the
+name of its corresponding TFM file and whether it actually exists in
+the printer you want to use. For each PostScript printer currently
+supported there exists a file containing just such information:
+
+ $tex_ps/lw_fonts.ps --- converts TFM names into LaserWriter fonts
+ $tex_ps/lino_fonts.ps --- converts TFM names into Linotronic 300 fonts
+ $tex_ps/ps40_fonts.ps --- converts TFM names into PrintServer 40 fonts
+
+PSPRINT also uses these files, so you can be reasonably confident
+about the validity of their contents.
+(The above file names assume that the environment variable tex_ps points
+to the public directory in which various PSPRINT-related files reside.
+To discover what tex_ps is at your site, type "which psprint" and
+examine the first few lines of the indicated file.)
+
+There are some important differences between PostScript fonts and
+the Computer Modern fonts normally used with TeX:
+
+ --- PostScript fonts usually contain up to 256 characters, with many
+ empty locations. Computer Modern fonts also have up to 256 characters
+ but typically use only the first 128 locations (with very few empty).
+ --- When a PostScript font is scaled to the same design size as a CM font
+ it tends to look darker and larger. You need to be a bit careful
+ when mixing the two font designs.
+ --- The standard TeX commands for accents and foreign letters need to be
+ redefined for a PostScript text font. The file $tex_ps/pstext.tex
+ contains the required macro definitions; note that a few commands
+ (\j, \aa, \AA, \t) cannot be used at all. Another file,
+ $tex_ps/psfonts.tex, inputs these macros and illustrates the use
+ (and abuse) of PostScript fonts in a TeX document.
+
+PostScript Graphics
+-------------------
+PSPRINT allows the inclusion of PostScript graphics using TeX's \special
+command. The \special argument is interpreted as a file name, possibly
+followed by a space and additional PostScript text that will be treated
+as a separate line at the start of the given file.
+For example, "\special{figure.ps 2 1 scale}" will cause PSPRINT to copy
+a line containing "2 1 scale" to the temporary output file, followed by
+the contents of figure.ps, a file assumed to be in your current directory
+and containing some sort of PostScript program. (The figure will be
+twice as wide as one included by \special{figure.ps}.)
+The PSPRINT User Guide has more details.
diff --git a/dviware/psprint/unix/pstext.tex b/dviware/psprint/unix/pstext.tex
new file mode 100644
index 0000000000..4c0f6bf272
--- /dev/null
+++ b/dviware/psprint/unix/pstext.tex
@@ -0,0 +1,73 @@
+% \PStext should be used before switching to a PostScript text font.
+% It allows the use of the standard macros for foreign letters and accents.
+% \PStext is best used inside a group so that these macro definitions
+% automatically revert to the standard definitions at the end of the group.
+% If it is undesirable to place \PStext inside a group then \CMtext should
+% be called before using a Computer Modern text font.
+
+\def\PStext
+{% PostScript foreign language locations:
+\chardef\ss="FB%
+\chardef\ae="F1%
+\chardef\oe="FA%
+\chardef\o="F9%
+\chardef\AE="E1%
+\chardef\OE="EA%
+\chardef\O="E9%
+\chardef\i="F5%
+\chardef\l="F8%
+\chardef\L="E8%
+\def\j{\write16{No dotless j in this font!}}%
+\def\aa{\write16{No a-with-circle in this font!}}%
+\def\AA{\write16{No A-with-circle in this font!}}%
+% PostScript accent locations:
+\def\`##1{{\accent193 ##1}}%
+\def\'##1{{\accent194 ##1}}%
+\def\v##1{{\accent207 ##1}}%
+\def\u##1{{\accent198 ##1}}%
+\def\=##1{{\accent197 ##1}}%
+\def\^##1{{\accent195 ##1}}%
+\def\.##1{{\accent199 ##1}}%
+\def\H##1{{\accent205 ##1}}%
+\def\~##1{{\accent196 ##1}}%
+\def\"##1{{\accent200 ##1}}%
+\def\b##1{\oalign{##1\crcr\hidewidth%
+\vbox to.2ex{\hbox{\char197}\vss}\hidewidth}}%
+\def\c##1{\setbox0\hbox{##1}\ifdim\ht0=1ex\accent203 ##1%
+\else{\ooalign{\hidewidth\char203\hidewidth\crcr\unhbox0}}\fi}%
+\def\t{\write16{No tie accent in this font!}}%
+}
+
+\def\CMtext
+{% Computer Modern foreign language locations:
+\chardef\ss="19%
+\chardef\ae="1A%
+\chardef\oe="1B%
+\chardef\o="1C%
+\chardef\AE="1D%
+\chardef\OE="1E%
+\chardef\O="1F%
+\chardef\i="10%
+\chardef\j="11%
+\def\l{\char32l}%
+\def\L{\leavevmode\setbox0\hbox{L}\hbox to\wd0{\hss\char32L}}%
+\def\aa{\accent23a}%
+\def\AA{\leavevmode\setbox0\hbox{h}\dimen0\ht0\advance\dimen0-1ex%
+\rlap{\raise.67\dimen0\hbox{\char'27}}A}%
+% Computer Modern accent locations:
+\def\`##1{{\accent18 ##1}}%
+\def\'##1{{\accent19 ##1}}%
+\def\v##1{{\accent20 ##1}}\let\^^_=\v%
+\def\u##1{{\accent21 ##1}}\let\^^S=\u%
+\def\=##1{{\accent22 ##1}}%
+\def\^##1{{\accent94 ##1}}\let\^^D=\^%
+\def\.##1{{\accent95 ##1}}%
+\def\H##1{{\accent"7D ##1}}%
+\def\~##1{{\accent"7E ##1}}%
+\def\"##1{{\accent"7F ##1}}%
+\def\b##1{\oalign{##1\crcr\hidewidth%
+\vbox to.2ex{\hbox{\char22}\vss}\hidewidth}}%
+\def\c##1{\setbox0\hbox{##1}\ifdim\ht0=1ex\accent24 ##1%
+\else{\ooalign{\hidewidth\char24\hidewidth\crcr\unhbox0}}\fi}%
+\def\t##1{{\edef\next{\the\font}\the\textfont1\accent"7F\next##1}}%
+}
diff --git a/dviware/psprint/unix/pswriter.h b/dviware/psprint/unix/pswriter.h
new file mode 100644
index 0000000000..25de3d095d
--- /dev/null
+++ b/dviware/psprint/unix/pswriter.h
@@ -0,0 +1,58 @@
+(* PSWriter routines are used by PSDVI to create the PostScript output file.
+ The following calling sequence is largely determined by the PostScript
+ definitions that must be prepended to the output:
+
+ OpenOutput
+ if -h used then OutputHeader
+ for each page selected do
+ BeginPage
+ if not conserving VM then
+ for each new bitmap font do NewBitmapFont
+ for each bitmap font used on this page do
+ BeginBitmapFont
+ for each new character do LoadBitmap
+ end
+ end
+ OutputPage
+ for each \special on this page do OutputSpecial
+ for each font used on this page do
+ if (conserving VM) and (not PostScript font) then SaveVM
+ if PostScript font then BeginPostScriptFont else BeginBitmapFont
+ if (conserving VM) and (not PostScript font) then
+ for each character used do LoadBitmap
+ end
+ if PostScript font then
+ for each character used do SetPostScriptChar
+ else
+ for each character used do SetBitmapChar
+ end
+ EndFont
+ if (conserving VM) and (not PostScript font) then RestoreVM
+ end
+ for each rule on this page do SetRule
+ EndPage
+ end
+ CloseOutput
+*)
+
+VAR PSfile : text; (* LoadBitmap routine in FontReader requires access to
+ output file to write out PostScript char definitions. *)
+
+FUNCTION OpenOutput (name : string) : BOOLEAN; EXTERNAL;
+FUNCTION OutputHeader (name : string) : BOOLEAN; EXTERNAL;
+PROCEDURE BeginPage (DVIpage : INTEGER); EXTERNAL;
+PROCEDURE NewBitmapFont (VAR fontid : string); EXTERNAL;
+PROCEDURE OutputPage (DVIpage : INTEGER); EXTERNAL;
+FUNCTION OutputSpecial (VAR name : string;
+ hpos, vpos : INTEGER) : BOOLEAN; EXTERNAL;
+PROCEDURE SaveVM (VAR fontid : string); EXTERNAL;
+PROCEDURE BeginBitmapFont (VAR fontid : string); EXTERNAL;
+PROCEDURE BeginPostScriptFont (VAR fontname : string;
+ scaledsize, mag : INTEGER); EXTERNAL;
+PROCEDURE SetBitmapChar (ch : CHAR; hpos, vpos, pwidth : INTEGER); EXTERNAL;
+PROCEDURE SetPostScriptChar (ch : CHAR; hpos, vpos, pwidth : INTEGER); EXTERNAL;
+PROCEDURE EndFont; EXTERNAL;
+PROCEDURE RestoreVM; EXTERNAL;
+PROCEDURE SetRule (wd, ht, hpos, vpos : INTEGER); EXTERNAL;
+PROCEDURE EndPage (DVIpage : INTEGER); EXTERNAL;
+PROCEDURE CloseOutput; EXTERNAL;
diff --git a/dviware/psprint/unix/pswriter.p b/dviware/psprint/unix/pswriter.p
new file mode 100644
index 0000000000..88c71f270f
--- /dev/null
+++ b/dviware/psprint/unix/pswriter.p
@@ -0,0 +1,340 @@
+(* PSWriter defines PostScript output routines used by PSDVI.
+ The output file consists of calls to various PostScript procedures
+ defined in a header file prefixed to the output.
+ Some of the PostScript procedures expect integer arguments that represent
+ page positions in TeX's coordinate system. Units are in "dots"
+ (i.e., device pixels, where resolution defines the number of dots per inch).
+ The origin (0,0) is a dot 1 inch in from both the top and left paper edges.
+ Horizontal coordinates increase to the right and vertical coordinates
+ increase down the page. The header file contains the necessary matrix
+ transformations to convert TeX coordinates back into device coordinates.
+*)
+
+#include 'globals.h';
+#include 'options.h';
+#include 'pswriter.h';
+
+CONST O_RDONLY = 0; (* SYSDEP: read-only flag for open *)
+ maxrbuf = 256;
+
+TYPE rbuf = PACKED ARRAY [1..maxrbuf] OF CHAR;
+
+FUNCTION open (VAR path : string; flags, mode : integer) : integer; EXTERNAL;
+FUNCTION read (f : integer; VAR buf : rbuf; n : integer) : integer; EXTERNAL;
+FUNCTION close(f : integer) : integer; EXTERNAL;
+
+VAR
+ curh, curv, (* for SetBitmapChar and SetPostScriptChar *)
+ stringlen : INTEGER; (* ditto; current string length *)
+ pendingch : CHAR; (* ditto; terminates current string *)
+
+(******************************************************************************)
+
+FUNCTION OpenOutput (name : string) : BOOLEAN;
+
+(* Returns TRUE if given file can be opened for output. *)
+
+BEGIN
+rewrite(PSfile,name); (* create a new file and open it for writing *)
+OpenOutput := TRUE; (* assume given file is created *)
+END; (* OpenOutput *)
+
+(******************************************************************************)
+
+FUNCTION OutputHeader (name : string) : BOOLEAN;
+
+(* Returns TRUE if given file can be copied to output.
+ Returns FALSE if file could not be opened.
+*)
+
+VAR f, length, result, buflen : integer; buf : rbuf;
+
+BEGIN
+(* try and open existing file for reading *)
+length := Len(name);
+IF length < maxstring THEN name[length] := CHR(0); (* terminate with NULL *)
+f := open(name, O_RDONLY, 0); (* read only *)
+IF length < maxstring THEN name[length] := ' '; (* restore space *)
+IF f >= 0 THEN BEGIN
+ (* copy f to PSfile *)
+ REPEAT
+ buflen := read(f,buf,maxrbuf);
+ IF buflen > 0 THEN write(PSfile,buf:buflen);
+ UNTIL buflen <= 0;
+ result := close(f);
+ OutputHeader := TRUE;
+END
+ELSE
+ OutputHeader := FALSE; (* couldn't open given file *)
+END; (* OutputHeader *)
+
+(******************************************************************************)
+
+PROCEDURE BeginPage (DVIpage : INTEGER);
+
+BEGIN
+writeln(PSfile,DVIpage:1,' @bop0');
+END; (* BeginPage *)
+
+(******************************************************************************)
+
+PROCEDURE NewBitmapFont (VAR fontid : string);
+
+BEGIN
+writeln(PSfile,'/',fontid:Len(fontid),' @newfont');
+END; (* NewBitmapFont *)
+
+(******************************************************************************)
+
+PROCEDURE OutputPage (DVIpage : INTEGER);
+
+BEGIN
+writeln(PSfile,DVIpage:1,' @bop1');
+END; (* OutputPage *)
+
+(******************************************************************************)
+
+FUNCTION OutputSpecial (VAR name : string;
+ hpos, vpos : INTEGER) : BOOLEAN;
+
+(* Returns TRUE if given file can be copied to output.
+ Returns FALSE if file could not be opened.
+ name can also include a space and additional PostScript text that will
+ be prefixed to the given file as a separate line. This allows users to
+ include a command like "\special{foo.ps 2 2 scale}" in their TeX source.
+ name is declared to be a variable parameter for efficiency reasons.
+ hpos and vpos define the page position of the \special command.
+ It's a good idea to do all specials on a page BEFORE chars and rules so that
+ users can do nifty things like overlaying TeX text onto a shaded box.
+*)
+
+LABEL 888, 999;
+
+VAR f, i, j, result, buflen : INTEGER; buf : rbuf; fspec : string;
+
+BEGIN
+(* check name for optional space (indicating additional PostScript text) *)
+i := 0;
+fspec := ' '; (* SYSDEP: fill with spaces *)
+WHILE i < maxstring DO BEGIN
+ IF name[i] = ' ' THEN goto 888;
+ fspec[i] := name[i]; (* extract file spec from name *)
+ i := i + 1;
+END;
+888:
+(* SYSDEP: test if i = 0 otherwise open will succeed and we'll read
+ some file (fspec = all spaces) full of mildly interesting junk!
+*)
+IF i = 0 THEN BEGIN
+ OutputSpecial := FALSE; goto 999;
+END;
+(* try and open existing file for reading *)
+IF i < maxstring THEN fspec[i] := CHR(0); (* terminate with NULL *)
+f := open(fspec, O_RDONLY, 0); (* read only *)
+IF i < maxstring THEN fspec[i] := ' '; (* restore space *)
+IF f >= 0 THEN BEGIN
+ writeln(PSfile, hpos:1, ' ', vpos:1, ' p');
+ writeln(PSfile, '@bsp');
+ (* use j to see if there is optional text after file name *)
+ j := maxstring - 1;
+ WHILE name[j] = ' ' DO j := j - 1;
+ j := j + 1;
+ IF i < j THEN BEGIN
+ (* name[i] is first ' '; skip this and copy rest of name to output *)
+ i := i + 1;
+ WHILE i < j DO BEGIN
+ write(PSfile,name[i]);
+ i := i + 1;
+ END;
+ writeln(PSfile); (* text becomes first line of file *)
+ END;
+ (* copy f to PSfile *)
+ REPEAT
+ buflen := read(f,buf,maxrbuf);
+ IF buflen > 0 THEN write(PSfile,buf:buflen);
+ UNTIL buflen <= 0;
+ result := close(f);
+ writeln(PSfile, '@esp');
+ OutputSpecial := TRUE;
+END
+ELSE
+ OutputSpecial := FALSE; (* couldn't open given file *)
+999:
+END; (* OutputSpecial *)
+
+(******************************************************************************)
+
+PROCEDURE SaveVM (VAR fontid : string);
+
+BEGIN
+writeln(PSfile,'/',fontid:Len(fontid),' @saveVM');
+END; (* SaveVM *)
+
+(******************************************************************************)
+
+PROCEDURE BeginPostScriptFont (VAR fontname : string;
+ scaledsize, mag : INTEGER);
+
+(* Output PostScript code to scale and set a resident PostScript font.
+ The fontname will be the name of a TFM file (beginning with psprefix value).
+ This TFM name will need to be converted into a PostScript font name.
+ The scaledsize and mag parameters represent the desired size of the font.
+*)
+
+BEGIN
+(* sp will convert scaled points to dots *)
+writeln(PSfile, scaledsize:1, ' sp ', mag:1, ' 1000 div mul ',
+ fontname:Len(fontname), ' PSfont');
+(* initialize some globals for first SetPostScriptChar in this font *)
+curh := 999999999;
+curv := 999999999;
+stringlen := 0;
+pendingch := '?';
+END; (* BeginPostScriptFont *)
+
+(******************************************************************************)
+
+PROCEDURE SetPostScriptChar (ch : CHAR; hpos, vpos, pwidth : INTEGER);
+
+(* Similar to SetBitmapChar but we cannot use RELATIVE horizontal positioning
+ because the advance widths of characters in a PostScript font are not
+ an integral number of dots, and we must avoid accumulated rounding errors.
+*)
+
+BEGIN
+IF curv = vpos THEN BEGIN (* don't update v position *)
+ IF curh <> hpos THEN BEGIN (* update h position *)
+ stringlen := 0;
+ writeln(PSfile,')',pendingch);
+ write(PSfile,hpos:1,'(');
+ pendingch := 'H';
+ END;
+END
+ELSE BEGIN (* update h and v position *)
+ IF stringlen > 0 THEN BEGIN
+ stringlen := 0;
+ writeln(PSfile,')',pendingch);
+ END;
+ write(PSfile,hpos:1,' ',vpos:1,'(');
+ pendingch := 'S';
+END;
+IF (ch >= ' ') AND (ch < CHR(127)) THEN BEGIN
+ IF (ch = '(') OR (ch = ')') OR (ch = '\') THEN (* prefix (,),\ with \ *)
+ write(PSfile,'\',ch)
+ ELSE
+ write(PSfile,ch);
+END
+ELSE
+ (* put out 3 octal digits representing ch *)
+ write(PSfile,'\', CHR(ORD('0') + (ORD(ch) DIV 64)),
+ CHR(ORD('0') + ((ORD(ch) DIV 8) MOD 8)),
+ CHR(ORD('0') + (ORD(ch) MOD 8)) );
+(* update current page position and string length for next call *)
+curh := hpos + pwidth;
+curv := vpos;
+stringlen := stringlen + 1;
+IF (stringlen MOD 72) = 0 THEN writeln(PSfile,'\');
+END; (* SetPostScriptChar *)
+
+(******************************************************************************)
+
+PROCEDURE BeginBitmapFont (VAR fontid : string);
+
+BEGIN
+writeln(PSfile,fontid:Len(fontid),' sf');
+(* Initialize some globals for first SetBitmapChar in this font.
+ This is not relevant when BeginBitmapFont is used before OutputPage.
+*)
+curh := 999999999;
+curv := 999999999;
+stringlen := 0;
+pendingch := '?';
+END; (* BeginBitmapFont *)
+
+(******************************************************************************)
+
+PROCEDURE SetBitmapChar (ch : CHAR; hpos, vpos, pwidth : INTEGER);
+
+BEGIN
+IF curv = vpos THEN BEGIN (* don't update v position *)
+ IF curh <> hpos THEN BEGIN (* update h position (kern or space) *)
+ stringlen := 0;
+ writeln(PSfile,')',pendingch);
+ write(PSfile,hpos-curh:1,'(');
+ pendingch := 'h';
+ END;
+END
+ELSE BEGIN (* update h and v position *)
+ IF stringlen > 0 THEN BEGIN
+ stringlen := 0;
+ writeln(PSfile,')',pendingch);
+ END;
+ write(PSfile,hpos:1,' ',vpos:1,'(');
+ pendingch := 's';
+END;
+IF (ch >= ' ') AND (ch < CHR(127)) THEN BEGIN
+ IF (ch = '(') OR (ch = ')') OR (ch = '\') THEN (* prefix (,),\ with \ *)
+ write(PSfile,'\',ch)
+ ELSE
+ write(PSfile,ch);
+END
+ELSE
+ (* put out 3 octal digits representing ch *)
+ write(PSfile,'\', CHR(ORD('0') + (ORD(ch) DIV 64)),
+ CHR(ORD('0') + ((ORD(ch) DIV 8) MOD 8)),
+ CHR(ORD('0') + (ORD(ch) MOD 8)) );
+(* update current page position and string length for next call *)
+curh := hpos + pwidth;
+curv := vpos;
+stringlen := stringlen + 1;
+IF (stringlen MOD 72) = 0 THEN writeln(PSfile,'\');
+END; (* SetBitmapChar *)
+
+(******************************************************************************)
+
+PROCEDURE EndFont;
+
+(* Terminate the last "h v(..." or "dh(..." for the current font. *)
+
+BEGIN
+IF stringlen > 0 THEN writeln(PSfile,')',pendingch);
+END; (* EndFont *)
+
+(******************************************************************************)
+
+PROCEDURE RestoreVM;
+
+BEGIN
+writeln(PSfile,'@restoreVM');
+END; (* RestoreVM *)
+
+(******************************************************************************)
+
+PROCEDURE SetRule (wd, ht, hpos, vpos : INTEGER);
+
+(* Output some PostScript to set the given rule at the given position. *)
+
+BEGIN
+writeln(PSfile, wd:1, ' ', ht:1, ' ', hpos:1, ' ', vpos:1, ' r');
+END; (* SetRule *)
+
+(******************************************************************************)
+
+PROCEDURE EndPage (DVIpage : INTEGER);
+
+(* Output some PostScript to end the current page. *)
+
+BEGIN
+writeln(PSfile, DVIpage:1, ' @eop');
+END; (* EndPage *)
+
+(******************************************************************************)
+
+PROCEDURE CloseOutput;
+
+(* Output some final PostScript. *)
+
+BEGIN
+writeln(PSfile, '@end');
+(* no need to close PSfile *)
+END; (* CloseOutput *)
diff --git a/dviware/psprint/unix/random.ps b/dviware/psprint/unix/random.ps
new file mode 100644
index 0000000000..3e69f4c16d
--- /dev/null
+++ b/dviware/psprint/unix/random.ps
@@ -0,0 +1,39 @@
+% This file is inserted into the PSPRINT User Guide using \special.
+% It plots 100 random dots.
+
+72 72 scale % units now inches
+
+% uncomment the next line if you want to "psprint random.ps"
+% 2 2 translate
+
+/xlen 1.3 def % length of x axis
+/ylen 1.3 def % length of y axis
+newpath
+0 0 moveto xlen 0 rlineto % x axis
+0 0 moveto 0 ylen rlineto % y axis
+.01 setlinewidth
+stroke % draw axes
+
+/fontsize 10 72 div def % use 10pt font for labels
+/Helvetica findfont
+fontsize scalefont setfont
+fontsize neg dup moveto (0) show
+fontsize neg ylen moveto (1) show
+xlen fontsize 2 div add fontsize neg moveto (1) show
+
+% draw 100 random dots
+
+/randlim 2 31 exp 1 sub def % rand will return integer from 0 to 2^31 - 1
+newpath
+1 1 100 % do the following procedure 100 times
+{ pop % we don't use control variable
+ /x rand randlim div xlen mul def % x is real number from 0 to xlen
+ /y rand randlim div ylen mul def % y is real number from 0 to ylen
+ x y moveto
+ x y lineto % create a dot
+} for
+1 setlinecap % round line ends
+.04 setlinewidth % diameter of dots
+stroke % draw all dots
+
+showpage
diff --git a/dviware/psprint/unix/setmargins.ps b/dviware/psprint/unix/setmargins.ps
new file mode 100644
index 0000000000..e43acacd9d
--- /dev/null
+++ b/dviware/psprint/unix/setmargins.ps
@@ -0,0 +1,7 @@
+% Permanently change LaserWriter's margin settings.
+% Use info.ps to see the current margin settings.
+
+serverdict begin 0 exitserver
+statusdict begin
+ 20 -10 setmargins % increase top by 20px and reduce left by 10px
+end
diff --git a/dviware/psprint/unix/test.tex b/dviware/psprint/unix/test.tex
new file mode 100644
index 0000000000..2811adcdc9
--- /dev/null
+++ b/dviware/psprint/unix/test.tex
@@ -0,0 +1,13 @@
+% A small test file: the top left corner of the upper rule should be
+% 1in from both the top and left edges of the paper.
+
+\nopagenumbers
+\topskip=0pt
+
+\hrule width 2in height 1mm
+
+\vskip 4in
+
+\hrule width 4in height 1mm
+
+\bye
diff --git a/dviware/psprint/unix/tex.ps b/dviware/psprint/unix/tex.ps
new file mode 100644
index 0000000000..5e7de3fb8c
--- /dev/null
+++ b/dviware/psprint/unix/tex.ps
@@ -0,0 +1,236 @@
+% Prologue for a DVI job.
+% It assumes psprint has defined dev (string), land (bool) and res (int).
+
+dev (LW) eq % LaserWriter?
+{ land
+ { % /landscape given
+ % rotate/scale/translate can cause scaling problems, so use setmatrix:
+ version cvr 38.0 le
+ { [ 0 -1 1 0 245 3135 ] setmatrix } % LaserWriter
+ { version cvr 47.0 lt
+ { [ 0 -1 1 0 235 3130 ] setmatrix } % LaserWriter Plus
+ { [ 0 -1 1 0 235 3160 ] setmatrix } % LaserWriter II NTX
+ % add y to move origin down by y pixels
+ % add x to move origin left by x pixels
+ ifelse } ifelse
+ }
+ { % /landscape not given
+ % scale/translate can cause scaling problems, so use setmatrix:
+ version cvr 38.0 le
+ { [ 1 0 0 1 235 190 ] setmatrix } % LaserWriter
+ { version cvr 47.0 lt
+ { [ 1 0 0 1 235 215 ] setmatrix } % LaserWriter Plus
+ { [ 1 0 0 1 235 265 ] setmatrix } % LaserWriter II NTX
+ % add x to move origin right by x pixels
+ % add y to move origin down by y pixels
+ ifelse } ifelse
+ } ifelse
+} if
+
+dev (PS40) eq % PrintServer?
+{ land
+ { [ 1 0 0 1 300 300 ] setmatrix % /landscape given
+ }
+ { [ 0 1 -1 0 3210 300 ] setmatrix % /landscape not given
+ } ifelse
+} if
+
+dev (LINO) eq % Linotronic?
+{ land
+ { initmatrix % /landscape given
+ 90 rotate % rotate axes 90deg anticlockwise
+ 72 res div dup neg scale % units now dots (y increases to right)
+ res res translate % move to TeX origin
+
+ % setmatrix won't work properly with a3/a4/a5/b5 page setups
+ % [1 0 0 1 1270 margin 72 div 1270 mul add 1270] setmatrix % res=1270
+ % [2 0 0 2 1270 margin 72 div 1270 mul add 1270] setmatrix % res=635
+ }
+ { initmatrix % /landscape not given
+ newpath clippath pathbbox % push LLx LLy URx URy
+ /paperht exch 72 div def % paper height in inches (URy = ht in pts)
+ pop pop pop % URx LLy LLx
+ 72 res div dup neg scale % units now dots (y increases down page)
+ res paperht res mul neg res add
+ translate % move to TeX origin
+
+ % setmatrix won't work properly with a3/a4/a5/b5 page setups
+ % [0 1 -1 0 paperht 1270 mul 1270 sub % res=1270
+ % margin 72 div 1270 mul add 1270] setmatrix
+ % [0 2 -2 0 paperht 1270 mul 1270 sub % res=635
+ % margin 72 div 1270 mul add 1270] setmatrix
+ } ifelse
+} if
+
+/mtrx 6 array def
+mtrx currentmatrix pop % save our new transformation matrix
+
+/@newfont % initialize new font dict
+{ /fontid exch def
+ fontid 7 dict def
+ fontid load begin
+ /FontType 3 def
+ /FontMatrix [1 0 0 -1 0 0] def % -1 because y scale is negative
+ /FontBBox [0 0 1 1] def
+ /BitMaps 128 array def
+ /BuildChar {CharBuilder} def
+ /Encoding 128 array def
+ 0 1 127 {Encoding exch /.notdef put} for
+ end
+ fontid fontid load definefont pop
+} def
+
+% @saveVM and @restoreVM are only used if we are conserving VM
+% by downloading font bitmaps more often:
+
+/@saveVM % save state of VM before using font
+{ /prefontVM save def
+ @newfont
+} def
+
+/@restoreVM {prefontVM restore} def
+
+% The char data, a bitmap descriptor, is an array with 6 elements:
+
+/ch-image {ch-data 0 get} def % the hex string image
+/ch-width {ch-data 1 get} def % the number of pixels across
+/ch-height {ch-data 2 get} def % the number of pixels tall
+/ch-xoff {ch-data 3 get} def % number of pixels to left of origin
+/ch-yoff {ch-data 4 get} def % number of pixels below origin
+/ch-advw {ch-data 5 get} def % advance width
+
+% The following character builder looks up the char data in the BitMaps array
+% and paints the character:
+
+/CharBuilder % image one char
+{ /ch-code exch def % save the char code
+ /font-dict exch def % and the font dict
+ /ch-data font-dict /BitMaps get
+ ch-code get def
+ ch-advw 0
+ ch-xoff neg ch-height ch-yoff sub 1 sub neg % -xo , -(ht-yo-1)
+ ch-width ch-xoff sub 1 sub ch-yoff % (wd-xo-1) , yo
+ setcachedevice
+ ch-width ch-height true
+ [1 0 0 -1 ch-xoff ch-yoff] % bitmap sent top to bottom
+ {ch-image}
+ imagemask
+} def
+
+/sf {setfont} def % set current font
+
+/dc % define new character
+{ /ch-code exch def
+ /ch-data exch def
+
+ % The following code should be enabled if you have an old LaserWriter.
+ % It attempts to overcome a bug that causes the printer to crash
+ % and print a test page rather then report a VMerror.
+ %
+ % vmstatus % returns: savelevel vmused vmmax
+ % 10000 sub gt % is vmused > (vmmax-10000)?
+ % { pop VMERROR } % causes error message (avoiding crash)
+ % { pop } % pop savelevel
+ % ifelse
+
+ currentfont /BitMaps get ch-code ch-data put
+ currentfont /Encoding get ch-code
+ dup ( ) cvs cvn put % generate unique name
+} bind def
+
+/@bop0 {pop} def % begin DVI page n
+
+/@bop1 % begin setting DVI page n
+{ pop % throw away page number
+ initgraphics % start with a clean slate
+ mtrx setmatrix % switch to our TeX coordinate system
+ /prepageVM save def % save state of VM at start of page
+} def
+
+/@eop % end DVI page n
+{ pop % throw away page number
+ prepageVM restore % restore VM to state at start of page
+ showpage
+} def
+
+/@end { } def % end of file
+
+% h and s are used to typeset downloaded bitmap fonts:
+
+/h {exch 0 rmoveto show} bind def % move right by dh and show (...)
+
+/s {3 1 roll moveto show} bind def % move to h,v and show (...)
+
+% H and S are used to typeset resident PostScript fonts.
+% We can't use relative horizontal positioning because the advance widths in
+% a PostScript font are not integers and rounding errors would accumulate:
+
+/H {exch v moveto show} bind def % move to h,v and show (...)
+
+/S % ditto, and save v position
+{ 3 1 roll dup /v exch def
+ moveto show
+} bind def
+
+% Some fine-tuning of the code used to draw a rule is necessary:
+
+dev (LW) eq % LaserWriter?
+version cvr 38.0 le and % and version <= 38.0?
+{
+ /r % set a wd by ht rule at h,v
+ { newpath
+ 1 add moveto % move to h,v+1 (don't ask me why)
+ /ht exch 1 sub def % reduce height by 1
+ /wd exch 1 sub def % ditto for width
+ wd 0 rlineto
+ 0 ht neg rlineto
+ wd neg 0 rlineto
+ fill
+ } bind def
+}
+{
+ /r % set a wd by ht rule at h,v
+ { newpath
+ moveto % move to h,v
+ /ht exch 1 sub def % reduce height by 1
+ /wd exch 1 sub def % ditto for width
+ wd 0 rlineto
+ 0 ht neg rlineto
+ wd neg 0 rlineto
+ fill
+ } bind def
+} ifelse
+
+% Following procedures are invoked as the result of a \special command.
+% We change all scaling and graphics back to defaults, but shift the origin
+% to the current position on the page:
+
+/p {moveto} bind def % move to h,v
+
+/@bsp % begin special mode
+{ gsave
+ /prespecialVM save def % save showpage, TeX procedures etc.
+ currentpoint transform
+ initgraphics itransform translate
+ land { 90 rotate } if % rotate axes if /landscape given
+ /showpage { } def % user does not have to remove showpage
+} bind def
+
+/@esp % end special mode
+{ prespecialVM restore % restore saved showpage value etc.
+ grestore
+} bind def
+
+% Here are the definitions needed to handle resident PostScript fonts:
+
+/sp % scaled pts to dots
+{ 16#10000 div % scaled pts to pts
+ res mul 72.27 div % pts to dots
+} bind def
+
+/PSfont % uses dot size and TFM name
+{ dup /Times-Slanted eq
+ {pop /Times-Roman findfont [1 0 .268 -1 0 0] makefont exch scalefont setfont}
+ {findfont [1 0 0 -1 0 0] makefont exch scalefont setfont}
+ ifelse
+} bind def
diff --git a/dviware/psprint/unix/text.ps b/dviware/psprint/unix/text.ps
new file mode 100644
index 0000000000..d3ff19e932
--- /dev/null
+++ b/dviware/psprint/unix/text.ps
@@ -0,0 +1,83 @@
+% Prologue for a -text job.
+% It assumes psprint has defined land and dev.
+% Every character after this file (until ^D) will be treated as a printing
+% character (or control character) instead of being interpreted as PostScript.
+
+land
+{ /setlocation % if /landscape
+ { 0 11.7 72 mul translate % shift origin up 11.7in
+ -90 rotate % rotate axes 90deg clockwise
+ 72 0 translate % 1in left margin
+ 0 535 moveto % start of top line
+ /line 0 def % initialize line counter
+ /char 0 def % initialize chars/line counter
+ } bind def
+ /maxline 50 def % maximum lines per page
+ /maxchar 132 def % maximum chars per line
+ /interline -10 def % baseline skip
+ /Courier findfont 9 scalefont setfont % use 9pt Courier
+}
+{ /setlocation % if no /landscape
+ { 72 0 translate % 1in left margin
+ 0 764 moveto % start of top line
+ /line 0 def % initialize line counter
+ /char 0 def % initialize chars/line counter
+ } bind def
+ /maxline 66 def % maximum lines per page
+ /maxchar 80 def % maximum chars per line
+ /interline -11 def % baseline skip
+ /Courier findfont 10 scalefont setfont % use 10pt Courier
+} ifelse
+
+/formfeed { line 0 gt { showpage setlocation } if } bind def
+
+/linefeed
+{ /char 0 def % reset chars/line counter
+ /line line 1 add def % increment line counter
+ line maxline eq % line = max lines per page?
+ { formfeed } % if so, show page
+ { currentpoint pop neg interline rmoveto } % else start next line
+ ifelse
+} bind def
+
+/backspace
+{ /char char 1 sub def
+ char 0 ge { charwidth neg 0 rmoveto } if % move back one character
+} def
+
+/showchar
+{ currentchar 0 thischar put % put thischar into 1-char string
+ /char char 1 add def % increment chars/line counter
+ char maxchar le { currentchar show } if % ignore chars > maxchar
+} bind def
+
+/eachchar
+{ infile read not {exit} if % get next char
+ /thischar exch def % save it in thischar
+ thischar 32 ge % thischar >= space?
+ { showchar } % if so, show it
+ { thischar 8 eq % or does thischar = backspace?
+ { backspace }
+ { thischar 10 eq % or does thischar = linefeed?
+ { linefeed }
+ { thischar 12 eq % or does thischar = formfeed?
+ { formfeed }
+ { % ignore any other control char
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+} bind def
+
+(%stdin) (r) file /infile exch def
+/currentchar 1 string def
+setlocation
+/charwidth (a) stringwidth pop def
+
+/charloop
+{ {eachchar} loop
+ line 0 gt { showpage } if % flush last page if necessary
+ dev (LW) eq { @bannerpage } if % print banner page if LaserWriter
+} def
+
+charloop
diff --git a/dviware/psprint/unix/two.ps b/dviware/psprint/unix/two.ps
new file mode 100644
index 0000000000..e2ecde4bf7
--- /dev/null
+++ b/dviware/psprint/unix/two.ps
@@ -0,0 +1,119 @@
+% Prologue for a -two job.
+% It assumes psprint has defined fspec and dev.
+% The following definitions produce two logical pages (80 cols by 60 lines)
+% on a single landscaped sheet of A4 paper.
+% Both pages have a headline showing fspec and page #.
+% Every character after this file (until ^D) will be treated as a printing
+% character (or control character) instead of being interpreted as PostScript.
+
+/maxlines 60 def % maximum lines per logical page
+/maxchar 80 def % maximum chars per line
+/interline -8 def % baseline skip
+/Courier findfont % Courier font (fixed-width chars)
+7 scalefont setfont % at 7pt
+/inch { 72 mul } def % convert inches to big points
+/topline { 7.3 inch } def % vertical location of top line (not headline)
+
+/page1pos
+{ 0 11.7 inch translate % shift origin up 11.7 inch (= A4 width)
+ -90 rotate % rotate axes 90deg clockwise
+ 1 inch 0 translate % 1 inch left margin for 1st logical page
+ 0 topline moveto % start of first line
+ /line 0 def % initialize line counter
+ /char 0 def % initialize chars/line counter
+} bind def
+
+/page2pos
+{ 5.1 inch 0 translate % set up left margin for 2nd logical page
+ 0 topline moveto % start of first line
+ /line maxlines def % in case formfeed occurred in 1st logical page
+} bind def
+
+/pagenum 0 def % initialize logical page number
+
+/headline
+{ gsave % save current pos and font
+ /Courier-Bold findfont 10 scalefont setfont % use Courier-Bold at 10pt
+ 0 topline moveto % move to top left corner
+ 0 interline 3 mul neg rmoveto % move up 3 lines
+ fspec show
+ % increment page number and show it right justified
+ /pagenum pagenum 1 add def
+ /pagestr pagenum 10 string cvs def
+ charwidth maxchar mul topline moveto % move to top right corner
+ (p.) stringwidth pop
+ pagestr stringwidth pop add neg % move left by page # width
+ interline 3 mul neg % move up 3 lines
+ rmoveto
+ (p.) show pagestr show
+ grestore % restore pos and font
+} bind def
+
+/formfeed % start next logical page unless already there
+{ line 0 gt
+ { line maxlines lt
+ { headline page2pos } % 0 < line < maxlines
+ { line maxlines gt
+ line maxlines 2 mul lt and
+ { headline showpage page1pos } if % maxlines < line < 2 * maxlines
+ } ifelse
+ } if
+} bind def
+
+/linefeed
+{ /char 0 def % reset chars/line counter
+ /line line 1 add def % increment line counter
+ line maxlines eq % if end of 1st page
+ { headline % show 1st headline
+ page2pos } % and start 2nd page
+ { line maxlines 2 mul eq % elsif end of 2nd page
+ { headline % then show 2nd headline
+ showpage page1pos } % and show both pages
+ { currentpoint pop neg interline rmoveto % else start next line
+ } ifelse
+ } ifelse
+} bind def
+
+/backspace
+{ /char char 1 sub def
+ char 0 ge { charwidth neg 0 rmoveto } if % move back one character
+} def
+
+/showchar
+{ currentchar 0 thischar put % put thischar into 1-char string
+ /char char 1 add def % increment chars/line counter
+ char maxchar le { currentchar show } if % ignore chars > maxchar
+} bind def
+
+/eachchar
+{ infile read not {exit} if % get next char
+ /thischar exch def % save it in thischar
+ thischar 32 ge % thischar >= space?
+ { showchar } % if so, show it
+ { thischar 8 eq % or does thischar = backspace?
+ { backspace }
+ { thischar 10 eq % or does thischar = linefeed?
+ { linefeed }
+ { thischar 12 eq % or does thischar = formfeed?
+ { formfeed }
+ { % ignore any other control char
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+} bind def
+
+(%stdin) (r) file /infile exch def
+/currentchar 1 string def
+/charwidth ( ) stringwidth pop def % assume fixed-width font
+page1pos % start 1st page
+
+/charloop
+{ {eachchar} loop
+ line 0 gt
+ { headline showpage } % flush last sheet with only 1st logical page
+ if
+ dev (LW) eq { @bannerpage } if % print banner page if LaserWriter
+} def
+
+charloop
diff --git a/dviware/psprint/unix/userguide.tex b/dviware/psprint/unix/userguide.tex
new file mode 100644
index 0000000000..fe3accffbf
--- /dev/null
+++ b/dviware/psprint/unix/userguide.tex
@@ -0,0 +1,563 @@
+% LaTeX source for PSPRINT User Guide.
+% System-dependent details are indicated by the string "SYSDEP".
+% Cross references are indicated by the string "XREF".
+% Feel free to make modifications applicable to your site.
+
+\documentstyle[11pt]{article}
+
+\nofiles % no auxiliary output
+
+% make sure leading/trailing spaces work correctly in \verb
+{\obeyspaces\gdef {\leavevmode\null\enskip\null}}
+
+% 1 inch margins at left and right:
+\oddsidemargin=0in
+\evensidemargin=0in
+\textwidth=6.25truein % A4 paper is 8.25in wide
+
+% 1 inch margins at top and bottom:
+\headheight=0pt
+\headsep=0pt
+\topmargin=0in
+\textheight=9.7in % A4 paper is 11.7in high
+
+\parindent=0pt
+\parskip=\medskipamount
+\renewcommand\labelitemii{ } % don't use en-dash in nested itemize
+\itemsep=0pt
+
+\def\DVItoVDU{DVIto\kern-.15em VDU}
+\def\aligneddots{\leaders\hbox to .75em{\hss.\hss}\hfill}
+
+\begin{document}
+
+\vspace*{\fill}
+
+\begin{center}
+\Huge\bf PSPRINT User Guide\\ [3mm]
+\normalsize\bf Version 3.0 for Pyramid/OSx\\
+\bf Andrew Trevorrow, October 1988
+\end{center}
+
+\bigskip
+\bigskip
+
+The PSPRINT command drives a variety of PostScript printers
+and can be used to print a DVI file (produced by \TeX\ or \LaTeX),
+a raw PostScript file, or an ordinary text file.
+The currently supported printers include the Apple LaserWriter,
+the Linotronic~300 and DEC's PrintServer~40.
+
+\bigskip
+\begin{center}
+\bf Contents
+\end{center}
+
+ % XREF: check that page #s are up-to-date
+\TeX\ Output \aligneddots\ 1\\
+PostScript Output \aligneddots\ 1\\
+Text Output \aligneddots\ 1\\
+Command Options \aligneddots\ 2\\
+Error Messages \aligneddots\ 5\\
+Using PostScript Fonts \aligneddots\ 6\\
+Using PostScript Graphics \aligneddots\ 7
+
+\vspace*{\fill}
+
+\thispagestyle{empty}
+
+\newpage
+\setcounter{page}{1}
+
+\subsection*{\TeX\ Output}
+
+PSPRINT looks for a DVI file by default. To print \verb|foo.dvi|, simply type:
+\begin{center}
+\verb|psprint foo|
+\end{center}
+PSPRINT will translate \verb|foo.dvi| into
+a temporary PostScript file called \verb|foo.tmp|.
+The DVI and \TeX\ page numbers are displayed as each page is translated.
+(The order in which pages are translated depends on the PostScript
+device being used.)
+If no errors are found, the temporary file is automatically sent to the
+appropriate queue where it is printed (and then deleted).
+
+\subsection*{PostScript Output}
+
+PostScript is a complete programming language with a powerful set of operators
+for manipulating text and graphics. A PostScript program is an ordinary text
+file. If you give it a name like \verb|foo.ps| then sending
+it to the printer is simple:
+\begin{center}
+\verb|psprint foo.ps|
+\end{center}
+If you decide to use some other file extension you'll have to add the
+\verb|-ps| option.
+The final section in this document % XREF
+describes how to merge a PostScript file with a \TeX\ source file.
+People who want to write PostScript programs will need to get the
+{\sl PostScript Language Reference Manual\/} and the
+{\sl PostScript Language Tutorial and Cookbook}. Both books are by
+Adobe Systems Incorporated and published by Addison-Wesley.
+
+\subsection*{Text Output}
+
+To print a normal text file, just use any file extension except
+\verb|.dvi| or \verb|.ps|:
+\begin{center}
+\verb|psprint foo.lis|~~~or~~~\verb|psprint foo.dat|~~~or~~~\dots
+\end{center}
+The output is {\em not\/} collated.
+By default you get 66 lines per page, and any lines more than 80
+characters long are truncated. The \verb|-l| option will
+rotate the paper so that you can have lines up to 132 characters long
+(but only 50 lines per page).
+
+Type `\verb|psprint foo.ps -text|' if you want to print a PostScript file
+rather than have it interpreted. You'll also have to use \verb|-text| if you
+want to print a text file called \verb|foo| but \verb|foo.dvi| also exists.
+
+The \verb|-two| and \verb|-wide| options are variants of \verb|-text|
+that use a smaller font to fit two logical pages on each sheet of
+paper.
+
+These text file facilities may not be available on all types of
+printers, especially the Linotronic.
+
+
+\newpage
+
+\subsection*{Command Options}
+
+The PSPRINT command can be followed by a variety of options:
+\begin{itemize}
+\item \verb|-device printer_type| ---
+tells PSPRINT which type of PostScript printer to use.
+The currently supported \verb|printer_type| values are:
+ \begin{itemize}
+ \item
+ \verb|lw | --- for an Apple LaserWriter (the default)\\ % SYSDEP
+ \verb|lino| --- for a Linotronic~300\\
+ \verb|ps40| --- for DEC's PrintServer~40
+ \end{itemize}
+\end{itemize}
+
+These options only take effect if \verb|-device lw|:
+\begin{itemize}
+
+\item \verb|-noflag| ---
+prevents PSPRINT producing a flag page.
+
+\item \verb|-manual| ---
+assumes you want to manually feed paper into the LaserWriter.
+As soon as the printer sees your job it will wait for you to feed in each
+sheet of paper (it will normally wait up to a minute).
+
+\end{itemize}
+
+These options only take effect if \verb|-device lino|:
+\begin{itemize}
+
+\item \verb|-lowres| ---
+prints a DVI file at low resolution (635 dots per inch).
+By default, \TeX\ output on the Linotronic is printed at 1270 dots per inch.
+The temporary file created by PSPRINT will typically be very large.
+Using \verb|-lowres| reduces both the size of the temporary file
+(by roughly three quarters) and the likelihood of memory problems.
+The print quality will of course be poorer but you'll
+probably need a magnifying glass to see the difference.
+
+\item \verb|-size page_size| ---
+sets the Linotronic page size and orientation.
+Possible \verb|page_size| values are
+\verb|A4P| (the default), \verb|A4L|, \verb|A5P|, \verb|A5L|,
+\verb|B5P|, \verb|B5L| and \verb|A3L|.
+The \verb|P| stands for portrait and the \verb|L| for landscape.
+(Don't confuse the landscape orientation with \verb|-l| which rotates
+the output within the page image, regardless of the \verb|-size| value.)
+The portrait orientations are less wasteful of paper.
+
+\item \verb|-cutmarks| ---
+produces small cut marks at the corners of the page image
+on Linotronic output.
+\verb|-cutmarks| is the default; use \verb|-nocutmarks| to suppress them.
+
+\end{itemize}
+
+The following five options override PSPRINT's assumptions
+about the format of the input file based on the given file specification:
+\begin{itemize}
+\item \verb|-dvi | --- for a DVI file.
+\item \verb|-ps | --- for a PostScript program.
+\item \verb|-text| --- for an ordinary text file.
+\item \verb|-two | ---
+like \verb|-text| but the output is formatted so that two ``pages''
+(both 60 lines by 80 columns) appear on each sheet of paper.
+\item \verb|-wide| ---
+like \verb|-text| but the output is formatted so that two wide ``pages''
+(both 60 lines by 132 columns) appear on each sheet of paper.
+\end{itemize}
+
+\newpage
+
+Some options can only be used with a DVI file:
+\begin{itemize}
+
+\item \verb|-p first:final| --- selects a subrange of pages for printing.
+\verb|first| and \verb|final| can select either DVI page numbers
+(positive integers) or \TeX\ page numbers.
+
+A \TeX\ page specification is of the form \verb|[i0.i1...i9]| where
+\verb|i0| to \verb|i9| are integers separated by periods and represent the
+10 counter values that \TeX\ stores with each DVI page.
+Any number of these integers may be absent and trailing periods may be omitted.
+An absent integer will match any value in the corresponding counter.
+Many DVI pages may match a particular \TeX\ page specification;
+if \verb|first| is a \TeX\ page then the {\em lowest\/}
+matching DVI page is selected, and if \verb|final| is a \TeX\ page then
+the {\em highest\/} matching page is selected.
+
+Assuming \TeX\ generated the 5 DVI pages `\verb|[0] [1] [2.1] [2.2] [3]|',
+here are some examples of how you could use \verb|-p|:
+ \begin{itemize}
+ \item
+ \verb|psprint foo -p 2 | --- prints the 2nd DVI page
+ (\TeX\ page \verb|[1]|)\\
+ \verb|psprint foo -p :4 | --- prints the first four pages\\
+ \verb|psprint foo -p 4: | --- prints the last two pages\\
+ \verb|psprint foo -p '[2]' | --- prints \verb|[2.1]| and \verb|[2.2]|\\
+ \verb|psprint foo -p 1:'[2]' | --- prints the first four pages\\
+ \verb|psprint foo -p '[2.2]':| --- prints the last two pages
+ \end{itemize}
+Note that \verb|first| and \verb|final| are optional; they default to
+the first and last DVI pages respectively.
+Omitting `\verb|:final|' entirely sets \verb|final| equal to \verb|first|.
+Note also the need for quote marks around a \TeX\ page specification.
+
+\item \verb|-i i| ---
+prints pages $f,f+i,f+2i,f+3i,\ldots,f+ni$, where
+$f$ is the first DVI page selected (either 1 or the start
+of a \verb|-p| subrange) and $f+ni$ is less than or equal to
+the final DVI page selected.
+
+The primary use of \verb|-i| is to simplify the printing of a document
+on both sides of the paper. For example, if \verb|foo.dvi| has 8 pages then the
+following steps will produce a double-sided document on a LaserWriter:
+ \begin{enumerate}
+ \item
+ \verb|psprint foo -i 2 -noflag | --- prints DVI pages 7, 5, 3, 1
+ \item
+ Remove the 4 pages from the output tray and carefully put them back
+ into the input cassette so that page 1 remains face up and its
+ top edge goes into the printer first.
+ (If \verb|foo.dvi| had 7 pages then you would only need to remove the
+ top 3 pages from the output tray.)
+ \item
+ \verb|psprint foo -i 2 -p 2: -norev| --- prints DVI pages 2, 4, 6, 8
+ \end{enumerate}
+Note that the use of \verb|-reverse| with \verb|-i| has no effect on
+{\em which\/} pages are printed; it simply changes the {\em order\/} in
+which they are done.
+
+\item \verb|-reverse| or \verb|-noreverse| ---
+forces PSPRINT to print pages in descending or ascending order respectively.
+By default PSPRINT prints DVI pages in an order determined by the type of
+printer you are using. The Apple LaserWriter stacks output sheets face up,
+so PSPRINT normally prints pages in reverse order so that your output will
+be automatically collated. The PrintServer 40 stacks the output face down,
+so PSPRINT normally prints pages in ascending order. The default order
+on the Linotronic is largely irrelevant, since this printer produces pages
+on a continuous roll of paper (the default used is ascending order).
+
+\item \verb|-m n| ---
+overrides the DVI magnification; \verb|n| is a positive integer 1000 times
+the desired magnification and should match one of \TeX's \verb|\magstep|
+values (see chapter 4 of {\sl The \TeX book\/}).
+
+\item \verb|-s| ---
+shows statistics on the rules, fonts, characters and \verb|\special| commands
+used on each page.
+
+\item \verb|-conserve| ---
+forces PSPRINT to conserve the printer's virtual memory at the
+expense of creating a larger output file (character bitmaps will be
+downloaded more often).
+If \verb|-device lino| then \verb|-conserve| is the default;
+if \verb|-device lw| or \verb|ps40| then \verb|-noconserve| is the default.
+
+\item \verb|-u xx| ---
+sets the units of dimensions displayed in some PSPRINT messages
+(e.g., if the page is off the paper).
+\verb|xx| can be one of:
+ \begin{itemize}
+ \item
+ \verb|in| --- for inches (the default)\\ % SYSDEP
+ \verb|cm| --- for centimetres (2.54\,cm = 1\,in)\\
+ \verb|mm| --- for millimetres (25.4\,mm = 1\,in)\\
+ \verb|pt| --- for points (72.27\,pt = 1\,in)\\
+ \verb|pc| --- for picas (1\,pc = 12\,pt)\\
+ \verb|bp| --- for big points (PostScript's default units; 72\,bp = 1\,in)\\
+ \verb|px| --- for pixels (depends on resolution of printer)
+ \end{itemize}
+
+\item \verb|-ho dimen| and \verb|-vo dimen| ---
+allow you to shift the printed location of each page.
+For example, \verb|-ho -0.5in| would
+shift each page half an inch to the left.
+A \verb|dimen| is any integer or real number, possibly negative, followed
+by a two-letter unit (the same as for \verb|-u|).
+
+\end{itemize}
+
+The remaining options apply to all types of input files:
+\begin{itemize}
+
+\item \verb|-l| --- specifies landscaped output
+\begin{picture}(10,7)
+\put(0,0){\framebox(10,7){}}
+\end{picture}\,,
+instead of the default portrait output
+\begin{picture}(7,10)
+\put(0,0){\framebox(7,10){}}
+\end{picture}\,.
+If~a DVI file, PSPRINT will check each page to make sure it fits
+within the rotated paper.
+
+\item \verb|-c n| --- specifies up to 100 copies.
+Use of this facility is not encouraged. Note in particular that
+copies of a multiple-page document will {\em not\/} be collated.
+
+\item \verb|-n string| --- includes a note on your flag page.
+
+\item \verb|-q string| --- overrides the default queue used by PSPRINT\@.
+(Some sites may have more than one printer of the same type). % SYSDEP
+
+\item \verb|-o file| --- sends the PostScript code generated by PSPRINT
+to a file rather than to a printer. Since some of this code is device-specific
+you should only send the file to a PostScript printer of the type that
+PSPRINT intended to use.
+
+\end{itemize}
+
+\newpage
+
+\subsection*{Error Messages}
+
+If PSPRINT detects one or more errors while translating a DVI file then
+the temporary PostScript file is automatically deleted and nothing
+is printed --- not even a flag page.
+The sort of errors you are most likely to see include:
+\begin{itemize}
+\item
+\verb|Page off paper (paper is ...| ---
+the current page contains material beyond one or more paper edges.
+Use \DVItoVDU\ to see where the problem lies.
+\item
+\verb|Couldn't open font file: ...| ---
+your DVI file uses a font at a non-existent size.
+Try a different font magnification in your source file.
+\item
+\verb|Couldn't open \special file: ...| ---
+PSPRINT could not locate the given \verb|\special| file.
+Check the file's spelling and/or directory location.
+\end{itemize}
+Error messages apply to the most recently displayed DVI/\TeX\ page.
+Any message that does not make sense probably indicates some sort of bug.
+Please save a copy of the input file and report the problem to your
+local \TeX nician.
+
+If your DVI file uses a large number of fonts or a few very large fonts then
+you might get an error page with the message ``\verb|VMerror|''.
+This indicates that PostScript's virtual memory has been exhausted,
+and the rest of your job will be flushed.
+This problem is unlikely to worry most people, particularly on the
+PrintServer~40 which has much more VM than the LaserWriter or Linotronic.
+If the problem does occur, there are a few things you can try:
+\begin{enumerate}
+\item
+On a LaserWriter or PrintServer, use \verb|-conserve|
+or print a few pages at a time.
+\item
+On a Linotronic, use \verb|-lowres|.
+(\verb|-conserve| is the default for this device.)
+\end{enumerate}
+If you are sending your own PostScript program then an error should
+produce some sort of message on the printed output.
+
+\newpage
+
+\subsection*{Using PostScript Fonts}
+
+PSPRINT allows the use of PostScript fonts within a \TeX\ or \LaTeX\ document.
+Such fonts can be used at any desired size and no character bitmaps need
+to be downloaded since the shape information is resident in the printer.
+The necessary typesetting information required by PSPRINT is extracted
+from TFM files (\TeX\ Font Metric files).
+A TFM file name beginning with ``\verb|ps-|'' is used to indicate a resident
+PostScript font. % SYSDEP; this prefix is set in psprint
+
+Each type of PostScript printer provides a different set of fonts.
+To be able to use a particular PostScript font you need to know the
+name of its corresponding TFM file and whether it actually exists in
+the printer you want to use. For each PostScript printer currently
+supported there exists a file containing just such information:
+\begin{itemize}
+\item [ ]
+\verb|$tex_ps/lw_fonts.ps | --- converts TFM names into LaserWriter fonts\\
+\verb|$tex_ps/lino_fonts.ps| --- converts TFM names into Linotronic~300 fonts\\
+\verb|$tex_ps/ps40_fonts.ps| --- converts TFM names into PrintServer~40 fonts
+\end{itemize}
+PSPRINT also uses these files, so you can be reasonably confident
+about the validity of their contents.
+To print a list of the PostScript fonts available in your printer you can type
+the command `\verb|psprint $tex_ps/fontlist.ps|'.
+
+(The above file names assume that the environment variable \verb|tex_ps|
+points to the public directory in which various PSPRINT-related files reside.
+To discover what \verb|tex_ps| is at your site, type `\verb|which psprint|'
+and examine the first few lines of the indicated file.)
+
+There are some important differences between PostScript fonts and
+the Computer Modern fonts normally used with \TeX:
+\begin{enumerate}
+\item
+When asking for a PostScript font it is best to use an `\verb|at| $dimen$'
+size specification (e.g., \verb|\font\helv=ps-helv at 13.5pt|) otherwise you
+might end up with a default 1pt font!
+\item
+PostScript fonts usually contain up to 256 characters, with many
+empty locations. Computer Modern fonts can also contain up to 256 characters
+but typically use only the first 128 locations (with very few empty).
+\item
+When a PostScript font is scaled to the same design size as a CM font
+it tends to look darker and larger. You need to be a bit careful
+when mixing the two font designs.
+\item
+The standard \TeX\ commands for accents and foreign letters need to be
+redefined for a PostScript text font. The file \verb|$tex_ps/pstext.tex|
+contains the required macro definitions; note that a few commands
+(\verb|\j|, \verb|\aa|, \verb|\AA|, \verb|\t|) cannot be used at all.
+Another file, \verb|$tex_ps/psfonts.tex|, inputs these macros and illustrates
+the use (and abuse) of PostScript fonts in a \TeX\ document.
+\end{enumerate}
+
+\newpage
+
+\subsection*{Using PostScript Graphics}
+
+Creating figures and illustrations with \TeX\ is very difficult.
+Although it is theoretically possible to place small dots
+anywhere on a page and build up an arbitrarily complex picture,
+time and memory limitations make such a scheme impractical.
+(\LaTeX\ provides a \verb|picture| environment, but it is very inefficient
+and only suitable for small, simple diagrams.)
+PSPRINT allows you to merge PostScript graphics with \TeX\ or \LaTeX\@.
+
+Let's assume you have a file called \verb|fig.ps| that contains
+suitable PostScript commands for generating some sort of figure.
+To include this figure in a \TeX\ or \LaTeX\ document, just type
+`\verb|\special{fig.ps}|' after leaving sufficient space:
+\begin{verbatim}
+ % in a TeX source file % in a LaTeX source file
+ \midinsert \begin{figure}[ht]
+ \vskip 3in \vspace{3in}
+ \special{fig.ps} \special{fig.ps}
+ \centerline{Figure 1: Pie Sales} \caption{Pie Sales}
+ \endinsert \end{figure}
+\end{verbatim}
+It may take a little practice to position the figure correctly.
+When you print a raw PostScript file (e.g., `\verb|psprint fig.ps|')
+the default origin is at the bottom left corner of the paper.
+However, when you include this file in a \TeX\ document the origin is
+automatically moved to the position of the \verb|\special| command.
+
+\verb|\special| can appear almost anywhere in your source file.
+It behaves like an invisible box of zero height and width.
+\TeX\ simply stores the given argument in the DVI file along with the current
+page position. PSPRINT interprets the argument as a file name and then
+includes this file in the information sent to the printer.
+(The included file is bracketed by \verb|save| and \verb|restore| commands
+to prevent any interference to the surrounding typesetting commands.)
+
+You can move the figure about by shifting the \verb|\special| position,
+or by including a \verb|translate| command in the PostScript file.
+The latter option is faster because you don't have to run \TeX\ again.
+For example, `\verb|72 36 translate|' at the start of \verb|fig.ps| would
+move the figure 1\,in right and 0.5\,in up
+(PostScript's default units are ``big points'' where 72\,bp = 1\,in).
+
+Alternatively, you may prefer to place your figure at an absolute position
+on the paper (i.e., at the same position produced by `\verb|psprint fig.ps|').
+Simply include an \verb|initgraphics| command at the start of \verb|fig.ps|.
+The position of the \verb|\special| command then becomes irrelevant;
+just make sure it's on the right page!
+
+The hardest part of the scheme is creating the PostScript file in the first
+place. You are faced with two possibilities:
+\begin{enumerate}
+\item
+Learn enough PostScript to be able to draw your own figures.
+You'll need to get the PostScript books mentioned on page~1.
+\item
+Use a program to convert an existing graphics file
+into a corresponding PostScript file.
+This assumes you are able to produce graphics of some sort
+(e.g., a Zeta plot file) and have access to a suitable conversion program.
+Ask your local graphics wizard whether any such programs are available.
+\end{enumerate}
+\DVItoVDU\ is unable to preview a PostScript file. All it can do is
+tell you the page position of the \verb|\special| command and display the
+given file name.
+
+\newpage
+
+Let's look at a few examples. The public directory \verb|$tex_ps| contains
+the \LaTeX\ source file for this User Guide, as well as a few PostScript
+files used to produce the figures below.
+These figures were created by calling
+\begin{verbatim}
+ \special{piechart.ps}
+ \special{greybox.ps}
+ \special{random.ps}
+\end{verbatim}
+at appropriate points in the source file.
+
+\begin{figure}[h] % produce figure here
+ \vspace{2.1in}
+ \special{piechart.ps} % origin at left margin of text
+ \caption{Pie Sales}
+\end{figure}
+
+\begin{figure}[h] % produce figure here
+ \begin{center}
+ \begin{minipage}{4in}
+ \special{greybox.ps} % origin at top left of minipage box
+ The text in this paragraph box was typeset by \LaTeX\@.
+ The shaded rectangle was created by PostScript.
+ \end{minipage}
+ \end{center}
+ \bigskip % leave additional room for shaded box
+ \caption{Shaded Text Box}
+\end{figure}
+
+\begin{figure}[h] % produce figure here
+ \begin{center}
+ \setlength{\unitlength}{1in}
+ \begin{picture}(1.3,1.3) % dimensions match axis lengths in random.ps
+ \put(0,0){\special{random.ps}} % origin at bottom left corner
+ \end{picture}
+ \end{center}
+ \caption{Random Dots}
+\end{figure}
+
+PSPRINT allows arbitrary PostScript text to appear after the file name in a
+\verb|\special| command. At least one space must be used to terminate the file
+name; further characters are included as a new line at the {\em start\/} of
+the given file. There is a limit of about 80 characters.
+For example, `\verb|\special{fig.ps 2 1 scale}|' could be used to double
+the width of the figure in \verb|fig.ps|.
+Note that it is possible to include the same PostScript file more than once,
+but with a different starting line each time.
+
+\end{document}
diff --git a/dviware/psprint/unix/wide.ps b/dviware/psprint/unix/wide.ps
new file mode 100644
index 0000000000..50b16b0de7
--- /dev/null
+++ b/dviware/psprint/unix/wide.ps
@@ -0,0 +1,117 @@
+% Prologue for a -wide job.
+% It assumes psprint has defined fspec and dev.
+% The following definitions produce two logical pages (132 cols by 60 lines)
+% on a single portrait sheet of A4 paper.
+% Both pages have a headline showing fspec and page #.
+% Every character after this file (until ^D) will be treated as a printing
+% character (or control character) instead of being interpreted as PostScript.
+
+/maxlines 60 def % maximum lines per logical page
+/maxchar 132 def % maximum chars per line
+/interline -6 def % baseline skip
+/Courier findfont % Courier font (fixed-width chars)
+6 scalefont setfont % at 6pt
+/inch { 72 mul } def % convert inches to big points
+
+/page1pos
+{ 1 inch 0 translate % 1 inch left margin
+ /topline { 10.9 inch } def % vertical location of top line (not headline)
+ 0 topline moveto % start of first line
+ /line 0 def % initialize line counter
+ /char 0 def % initialize chars/line counter
+} bind def
+
+/page2pos
+{ /topline { 5.4 inch } def % vertical location of top line (not headline)
+ 0 topline moveto % start of first line
+ /line maxlines def % in case formfeed occurred in 1st logical page
+} bind def
+
+/pagenum 0 def % initialize logical page number
+
+/headline
+{ gsave % save current pos and font
+ /Courier-Bold findfont 9 scalefont setfont % use Courier-Bold at 9pt
+ 0 topline moveto % move to top left corner
+ 0 interline 2 mul neg rmoveto % move up 2 lines
+ fspec show
+ % increment page number and show it right justified
+ /pagenum pagenum 1 add def
+ /pagestr pagenum 10 string cvs def
+ charwidth maxchar mul topline moveto % move to top right corner
+ (p.) stringwidth pop
+ pagestr stringwidth pop add neg % move left by page # width
+ interline 2 mul neg % move up 2 lines
+ rmoveto
+ (p.) show pagestr show
+ grestore % restore pos and font
+} bind def
+
+/formfeed % start next logical page unless already there
+{ line 0 gt
+ { line maxlines lt
+ { headline page2pos } % 0 < line < maxlines
+ { line maxlines gt
+ line maxlines 2 mul lt and
+ { headline showpage page1pos } if % maxlines < line < 2 * maxlines
+ } ifelse
+ } if
+} bind def
+
+/linefeed
+{ /char 0 def % reset chars/line counter
+ /line line 1 add def % increment line counter
+ line maxlines eq % if end of 1st page
+ { headline % show 1st headline
+ page2pos } % and start 2nd page
+ { line maxlines 2 mul eq % elsif end of 2nd page
+ { headline % then show 2nd headline
+ showpage page1pos } % and show both pages
+ { currentpoint pop neg interline rmoveto % else start next line
+ } ifelse
+ } ifelse
+} bind def
+
+/backspace
+{ /char char 1 sub def
+ char 0 ge { charwidth neg 0 rmoveto } if % move back one character
+} def
+
+/showchar
+{ currentchar 0 thischar put % put thischar into 1-char string
+ /char char 1 add def % increment chars/line counter
+ char maxchar le { currentchar show } if % ignore chars > maxchar
+} bind def
+
+/eachchar
+{ infile read not {exit} if % get next char
+ /thischar exch def % save it in thischar
+ thischar 32 ge % thischar >= space?
+ { showchar } % if so, show it
+ { thischar 8 eq % or does thischar = backspace?
+ { backspace }
+ { thischar 10 eq % or does thischar = linefeed?
+ { linefeed }
+ { thischar 12 eq % or does thischar = formfeed?
+ { formfeed }
+ { % ignore any other control char
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+} bind def
+
+(%stdin) (r) file /infile exch def
+/currentchar 1 string def
+/charwidth ( ) stringwidth pop def % assume fixed-width font
+page1pos % start 1st page
+
+/charloop
+{ {eachchar} loop
+ line 0 gt
+ { headline showpage } % flush last sheet with only 1st logical page
+ if
+ dev (LW) eq { @bannerpage } if % print banner page if LaserWriter
+} def
+
+charloop