summaryrefslogtreecommitdiff
path: root/dviware/psprint
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
Initial commit
Diffstat (limited to 'dviware/psprint')
-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
-rw-r--r--dviware/psprint/vms/00readme.txt79
-rw-r--r--dviware/psprint/vms/bad.ps19
-rw-r--r--dviware/psprint/vms/box.ps17
-rw-r--r--dviware/psprint/vms/build.com44
-rw-r--r--dviware/psprint/vms/clip.ps5
-rw-r--r--dviware/psprint/vms/ctrld.dat1
-rw-r--r--dviware/psprint/vms/dvireader.def392
-rw-r--r--dviware/psprint/vms/dvireader.mod1474
-rw-r--r--dviware/psprint/vms/fontlist.ps20
-rw-r--r--dviware/psprint/vms/fontreade.def52
-rw-r--r--dviware/psprint/vms/fontreade.mod1242
-rw-r--r--dviware/psprint/vms/global.ps18
-rw-r--r--dviware/psprint/vms/greybox.ps31
-rw-r--r--dviware/psprint/vms/info.ps99
-rw-r--r--dviware/psprint/vms/install.com37
-rw-r--r--dviware/psprint/vms/laserprep65.ps450
-rw-r--r--dviware/psprint/vms/laserprep68.ps405
-rw-r--r--dviware/psprint/vms/laserprep70.ps480
-rw-r--r--dviware/psprint/vms/lines.dat66
-rw-r--r--dviware/psprint/vms/lino_fonts.ps68
-rw-r--r--dviware/psprint/vms/lino_header.ps267
-rw-r--r--dviware/psprint/vms/lino_pages.ps16
-rw-r--r--dviware/psprint/vms/lino_print.com153
-rw-r--r--dviware/psprint/vms/lino_trailer.ps1
-rw-r--r--dviware/psprint/vms/lw_fonts.ps43
-rw-r--r--dviware/psprint/vms/lw_header.ps138
-rw-r--r--dviware/psprint/vms/lw_print.com178
-rw-r--r--dviware/psprint/vms/lw_trailer.ps1
-rw-r--r--dviware/psprint/vms/nasty.tex352
-rw-r--r--dviware/psprint/vms/options.def64
-rw-r--r--dviware/psprint/vms/options.mod499
-rw-r--r--dviware/psprint/vms/pass.ps22
-rw-r--r--dviware/psprint/vms/piechart.ps68
-rw-r--r--dviware/psprint/vms/ps.ps20
-rw-r--r--dviware/psprint/vms/ps40_fonts.ps39
-rw-r--r--dviware/psprint/vms/ps40_header.ps67
-rw-r--r--dviware/psprint/vms/ps40_list.ps19
-rw-r--r--dviware/psprint/vms/ps40_print.com109
-rw-r--r--dviware/psprint/vms/psdvi.cld64
-rw-r--r--dviware/psprint/vms/psdvi.hlp200
-rw-r--r--dviware/psprint/vms/psdvi.mod1207
-rw-r--r--dviware/psprint/vms/psfonts.tex71
-rw-r--r--dviware/psprint/vms/psnames.tex41
-rw-r--r--dviware/psprint/vms/psprint.cld95
-rw-r--r--dviware/psprint/vms/psprint.hlp438
-rw-r--r--dviware/psprint/vms/psprint.mod603
-rw-r--r--dviware/psprint/vms/pstext.tex73
-rw-r--r--dviware/psprint/vms/pswriter.def167
-rw-r--r--dviware/psprint/vms/pswriter.mod405
-rw-r--r--dviware/psprint/vms/random.ps39
-rw-r--r--dviware/psprint/vms/sysguide.tex563
-rw-r--r--dviware/psprint/vms/termout.def46
-rw-r--r--dviware/psprint/vms/termout.mod77
-rw-r--r--dviware/psprint/vms/test.tex13
-rw-r--r--dviware/psprint/vms/tex.ps236
-rw-r--r--dviware/psprint/vms/text.ps74
-rw-r--r--dviware/psprint/vms/two.ps111
-rw-r--r--dviware/psprint/vms/userguide.tex648
-rw-r--r--dviware/psprint/vms/wide.ps109
103 files changed, 20512 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
diff --git a/dviware/psprint/vms/00readme.txt b/dviware/psprint/vms/00readme.txt
new file mode 100644
index 0000000000..3aa15672e4
--- /dev/null
+++ b/dviware/psprint/vms/00readme.txt
@@ -0,0 +1,79 @@
+PSPRINT 3.1 for VAX/VMS, 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 (any model),
+DEC's PrintServer 40 and the Linotronic 300.
+
+The absolutely essential files in this directory are:
+
+USERGUIDE.TEX - LaTeX source for PSPRINT User Guide
+USERGUIDE.DVI - ready for users to print; it uses these \special files:
+ PIECHART.PS - to produce Figure 1
+ GREYBOX.PS - to produce Figure 2
+ RANDOM.PS - to produce Figure 3
+PSDVI.CLD - DCL interface to PSDVI command
+PSDVI.EXE - PSDVI image built under VAX/VMS 5.1
+PSPRINT.CLD - DCL interface to PSPRINT command
+PSPRINT.EXE - PSPRINT image built under VAX/VMS 5.1
+
+EMPTY.PS - empty file (used in all *_PRINT.COM files and NASTY.TEX)
+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.DAT - contains ^D (sent at end of each LW/LINO job)
+
+LW_PRINT.COM - run by PSPRINT/DEVICE=LW
+LW_HEADER.PS - defines @bannerpage and error handler
+LW_TRAILER.PS - calls @bannerpage
+LW_FONTS.PS - converts TFM names to resident LaserWriter font names
+
+LINO_PRINT.COM - run by PSPRINT/DEVICE=LINO
+LINO_HEADER.PS - defines @bannerpage, @footerpage, error handler, etc.
+LINO_TRAILER.PS - calls @footerpage
+LINO_FONTS.PS - converts TFM names to resident Linotronic font names
+
+PS40_PRINT.COM - run by PSPRINT/DEVICE=PS40
+PS40_HEADER.PS - defines error handler
+PS40_FONTS.PS - converts TFM names to resident PrintServer font names
+
+PSFONTS.TEX - illustrates use of PostScript fonts in a TeX document
+PSTEXT.TEX - used in PSFONTS.TEX (defines \PStext and \CMtext)
+PSNAMES.TEX - used in PSFONTS.TEX (defines macros for PostScript TFMs)
+
+Other important files are:
+
+SYSGUIDE.TEX - LaTeX source for PSPRINT System Guide
+INSTALL.COM - commands to install the PSPRINT system
+PSPRINT.MOD - Modula-2 source file for PSPRINT
+PSPRINT.HLP - on-line help for PSPRINT
+BUILD.COM - builds PSPRINT.EXE and/or PSDVI.EXE
+
+PSDVI.MOD - Modula-2 source file for PSDVI's main module
+OPTIONS.* - used by PSDVI to extract options from command line
+DVIREADER.* - used by PSDVI to access DVI files
+FONTREADE.* - used by PSDVI to access font files
+TERMOUT.* - used by PSDVI to do terminal output
+PSWRITER.* - used by PSDVI to create PostScript file
+PSDVI.HLP - on-line help for PSDVI
+
+LASERPREP70.PS - Modified Laser Prep v70 (for use with /PREP)
+LASERPREP68.PS - Modified Laser Prep v68 (ditto)
+LASERPREP65.PS - Modified Laser Prep v65 (ditto)
+GLOBAL.PS - shows how to get an image printed on every DVI page
+FONTLIST.PS - prints a list of the available fonts in your printer
+PS40_LIST.PS - lists PrintServer 40 fonts on your terminal
+LINO_PAGES.PS - tests various page setups available on Linotronic
+INFO.PS - to discover some printer details
+CLIP.PS - to discover the page image area (useful for LaserWriter)
+PASS.PS - to verify/change a PostScript printer's system password
+LINES.DAT - an ordinary text file with 66 lines
+TEST.TEX - TeX source for TEST.DVI (tests origin position)
+NASTY.TEX - TeX source for NASTY.DVI; it uses these \special files:
+ BAD.PS - contains deliberate PostScript error
+ BOX.PS - draws a box
+ EMPTY.PS - empty file
diff --git a/dviware/psprint/vms/bad.ps b/dviware/psprint/vms/bad.ps
new file mode 100644
index 0000000000..8c7de0b8e2
--- /dev/null
+++ b/dviware/psprint/vms/bad.ps
@@ -0,0 +1,19 @@
+% This file contains a deliberate error (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/vms/box.ps b/dviware/psprint/vms/box.ps
new file mode 100644
index 0000000000..33f5e0fa91
--- /dev/null
+++ b/dviware/psprint/vms/box.ps
@@ -0,0 +1,17 @@
+72 72 scale % units are now inches instead of big points
+
+userdict /@eop known % are we in a TeX job?
+not
+{ 1 1 translate % if not then move origin away from corner
+} if
+
+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 is included in TeX \special
diff --git a/dviware/psprint/vms/build.com b/dviware/psprint/vms/build.com
new file mode 100644
index 0000000000..f56e2bd5a7
--- /dev/null
+++ b/dviware/psprint/vms/build.com
@@ -0,0 +1,44 @@
+$! Build PSPRINT.EXE and/or PSDVI.EXE
+$
+$ on warning then goto stop
+$ inquire/nopunct yes "Compile and link PSPRINT?"
+$ if .not. yes then goto psdvi
+$ set ver
+$ mod/nocheck/log PSPRINT
+$ define/user lnk$library mod$system:modula.olb
+$ link/notrace PSPRINT
+$ set nover
+$
+$psdvi:
+$ inquire/nopunct yes "Compile modules used by PSDVI?"
+$ if .not. yes then goto justmain
+$ set ver
+$ mod/nocheck/log TERMOUT.DEF
+$ mod/nocheck/log TERMOUT
+$ mod/nocheck/log OPTIONS.DEF
+$ mod/nocheck/log OPTIONS
+$ mod/nocheck/log DVIREADER.DEF
+$ mod/nocheck/log DVIREADER
+$ mod/nocheck/log PSWRITER.DEF
+$ mod/nocheck/log PSWRITER
+$ mod/nocheck/log FONTREADE.DEF
+$ mod/nocheck/log FONTREADE
+$ set nover
+$
+$justmain:
+$ inquire/nopunct yes "Compile PSDVI?"
+$ if .not. yes then goto link
+$ set ver
+$ mod/nocheck/log PSDVI
+$ set nover
+$
+$link:
+$ inquire/nopunct yes "Link PSDVI?"
+$ if .not. yes then goto stop
+$ set ver
+$ define/user lnk$library mod$system:modula.olb
+$ link/notrace PSDVI, TERMOUT, OPTIONS, DVIREADER, FONTREADE, PSWRITER
+$ set nover
+$
+$stop:
+$ set nover
diff --git a/dviware/psprint/vms/clip.ps b/dviware/psprint/vms/clip.ps
new file mode 100644
index 0000000000..0bc77936ce
--- /dev/null
+++ b/dviware/psprint/vms/clip.ps
@@ -0,0 +1,5 @@
+% Send this program to determine the extent of the imaging area.
+
+initgraphics
+newpath clippath stroke
+showpage
diff --git a/dviware/psprint/vms/ctrld.dat b/dviware/psprint/vms/ctrld.dat
new file mode 100644
index 0000000000..ce9a8a9d59
--- /dev/null
+++ b/dviware/psprint/vms/ctrld.dat
@@ -0,0 +1 @@
+
diff --git a/dviware/psprint/vms/dvireader.def b/dviware/psprint/vms/dvireader.def
new file mode 100644
index 0000000000..e57909144b
--- /dev/null
+++ b/dviware/psprint/vms/dvireader.def
@@ -0,0 +1,392 @@
+DEFINITION MODULE DVIReader;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: August, 1984
+
+ Description:
+ DVIReader exports routines and data structures for moving about randomly
+ in a TeX82 DVI file and interpreting pages.
+
+ Revised:
+ August, 1986
+ - The SpecialRoutine has two new parameters to pass the current page position.
+ - The pixeltable record has a new flag that indicates if the character's
+ bitmap has been loaded.
+ - The fontinfo record has a new flag that indicates if the font exists,
+ and a new string that stores a unique font identifier needed by PostScript.
+ - Export CurrMatchesNew to help locate TeX page subrange.
+
+ December, 1986
+ - Increased maxTeXchar from 127 to 255.
+ - Lowered maxfontspec from 80 to 64.
+
+ November, 1987 (while at The Open University)
+ - Added psfont flag in fontinfo record. It is used to indicate a resident
+ PostScript font (for which character bitmaps do not exist).
+ For such a font, character metrics will have to be read from the TFM file.
+
+ Limitations:
+ - DVIReader does not look at the preamble and so ignores any comments there.
+ - DVIReader does not do any terminal i/o, even upon detecting a fatal error.
+ The client must write a DVIErrorRoutine that will be invoked at the time
+ an error is detected. See below for details.
+ - DVIReader knows nothing about the format of font files.
+ It only knows they contain crucial information for typesetting a DVI file.
+ The client must write a PixelTableRoutine to read some sort of font file
+ and fill in the pixel table information used to interpret a DVI page.
+ See below for details.
+ - The data structures used to represent an interpreted DVI page are best
+ suited to a client whose output device is randomly addressable.
+ Some clients may need to convert the information in the data structures
+ into a more suitable format.
+
+ Algorithm for a simple DVI translator:
+ < initialize the DVIErrorRoutine used to handle various errors >
+ < initialize filespec, resolution, etc. >
+ OpenDVIFile(filespec);
+ < initialize magnification, probably with DVImag >
+ SetConversionFactor(resolution,magnification);
+ < initialize the SpecialRoutine used in InterpretPage >
+ < initialize the PixelTableRoutine used in InterpretPage >
+ FOR p := 1 TO totalpages DO
+ MoveToDVIPage(p);
+ InterpretPage;
+ IF pageempty THEN
+ < process an empty page >
+ ELSE
+ < check that the page edges are within the paper edges >
+ < process the rule list >
+ < process the character list for each font used on the page >
+ END;
+ END;
+ CloseDVIFile;
+*)
+
+
+CONST
+ ruletablesize = 300; (* maximum number of rules in a ruletable *)
+ chartablesize = 3000; (* maximum number of chars in a chartable *)
+ maxfontspec = 64; (* maximum length of a font file specification *)
+ maxTeXchar = 255; (* ignore character codes > 255 *)
+
+
+TYPE
+ (* The major page structures are defined first.
+ 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. This is done so that when the client
+ 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 = POINTER TO ruleinfo;
+ ruleinfo = (* a node in a list of ruletables *)
+ RECORD
+ rulecount : CARDINAL; (* number of rules in ruletable *)
+ ruletable : ARRAY [0..ruletablesize-1] 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 = POINTER TO charinfo;
+ charinfo = (* a node in list of chartables *)
+ RECORD
+ charcount : CARDINAL; (* number of chars in chartable *)
+ chartable : ARRAY [0..chartablesize-1] 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;
+
+ (* pixeltable must be filled in by the client's PixelTableRoutine.
+ 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.
+ *)
+ pixeltableptr = POINTER TO 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 : CARDINAL; (* starting address of bitmap info in font file
+ (could be a word or byte offset) *)
+ loaded : BOOLEAN; (* has bitmap been downloaded? *)
+ END;
+
+ fontstring = ARRAY [0..maxfontspec-1] OF CHAR;
+ fontinfoptr = POINTER TO 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 : CARDINAL; (* scaled font size in DVI units *)
+ designsize : CARDINAL; (* design size in DVI units *)
+ fontarea : fontstring; (* explicit font directory *)
+ fontarealen : CARDINAL; (* length of fontarea *)
+ fontname : fontstring; (* font name; e.g., "amr10" *)
+ fontnamelen : CARDINAL; (* length of font name *)
+ fontspec : fontstring; (* client's font file specification *)
+ fontspeclen : CARDINAL; (* length of fontspec *)
+ fontexists : BOOLEAN; (* could fontspec be opened? *)
+ fontid : fontstring; (* unique font identifier *)
+ totalchars : CARDINAL; (* 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;
+
+ (* For the parameter in client's DVIErrorRoutine: *)
+ DVIerrorcodes = (
+ DVIunopened, (* OpenDVIFile could not open the given file *)
+ DVIempty, (* OpenDVIFile detected an empty file *)
+ DVIbadid, (* OpenDVIFile detected an invalid TeX82 DVI file *)
+ DVIstackoverflow, (* OpenDVIFile found DVIReader's stack is too small *)
+ DVIbadchar, (* InterpretPage is ignoring a char code > maxTeXchar
+ (detected while processing currfont^) *)
+ DVIcatastrophe); (* DVIReader detected a situation that should never
+ occur; client should scream for help and halt *)
+
+ (* For the function parameter in client's SpecialRoutine: *)
+ GetByteFunction = PROCEDURE () : INTEGER; (* returns next DVI byte *)
+
+
+VAR
+ (* Most of these should be treated as read-only parameters: *)
+ DVImag : CARDINAL; (* magnification stored in DVI file *)
+ totalpages : CARDINAL; (* number of pages in DVI file *)
+ totalfonts : CARDINAL; (* number of fonts in DVI file *)
+ currDVIpage : CARDINAL; (* updated by MoveTo... calls *)
+ currTeXpage : TeXcounters; (* ditto *)
+ totalrules : CARDINAL; (* number of rules on current page *)
+ rulelist : ruleinfoptr; (* head 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 *)
+
+ DVIErrorRoutine : PROCEDURE (DVIerrorcodes);
+ (* The client MUST assign a procedure before the first OpenDVIFile call.
+ Various DVIReader routines will call this procedure if they detect some
+ sort of problem; the given argument will be one of the error codes
+ described above.
+ The client's routine can use this code to see what sort of error
+ has occurred and take appropriate action. Most errors detected by
+ DVIReader are fatal; the client should print some sort of message
+ and halt. See PSDVI for an example DVIErrorRoutine.
+ *)
+
+ SpecialRoutine : PROCEDURE (INTEGER, INTEGER, INTEGER, GetByteFunction);
+ (* The client can assign a procedure before the first InterpretPage call.
+ InterpretPage will call this procedure to process the bytes belonging to
+ a \special command. The first two arguments give the (x,y)
+ pixel coordinates defining the position of the \special command.
+ The third argument gives the number of bytes; the last argument
+ argument is a function that returns the value of the next byte
+ (0..255, but usually the ordinal value of a displayable ASCII character).
+ If the client does not supply a SpecialRoutine, DVIReader will simply
+ ignore any \special bytes.
+ *)
+
+ PixelTableRoutine : PROC;
+ (* The client MUST assign a procedure before the first InterpretPage call.
+ InterpretPage will call this procedure immediately after allocating a
+ pixel table for currfont^. This will only occur once per font (the
+ very first time the font is used).
+ DVIReader only knows about DVI files; the task of the PixelTableRoutine is
+ to fill in the current font's pixel table by reading the fontspec file.
+ (The fontspec string must first be built using the fontname.)
+ This file could be a PXL file, or some other type of font file.
+ *)
+
+
+PROCEDURE OpenDVIFile (filespec : ARRAY OF CHAR);
+
+(* This must be the first DVIReader routine called. If the given filespec 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)
+*)
+
+PROCEDURE SetConversionFactor (resolution, magnification : CARDINAL);
+
+(* This routine must be called before the first InterpretPage call.
+ DVIReader needs to know the client's resolution and magnification values
+ before it attempts to convert DVI dimensions into pixel values.
+*)
+
+PROCEDURE MoveToDVIPage (n : CARDINAL);
+PROCEDURE MoveToNextPage (ascending : BOOLEAN);
+PROCEDURE MoveToTeXPage (VAR newTeXpage : TeXpageinfo) : BOOLEAN;
+
+(* Before calling InterpretPage, the client must position DVIReader to the
+ desired page by calling one of these MoveTo... routines.
+
+ MoveToDVIPage will select the nth page in the DVI file; nothing will
+ happen if n is not in 1..totalpages.
+
+ 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).
+
+ 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.
+ The client will probably need to first convert 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.
+
+ 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.
+*)
+
+PROCEDURE CurrMatchesNew (VAR newTeXpage : TeXpageinfo) : BOOLEAN;
+
+(* Return TRUE iff currTeXpage matches the \count information in newTeXpage. *)
+
+PROCEDURE PixelRound (DVIunits : INTEGER) : INTEGER;
+
+(* Converts the given DVI dimension (+ve or -ve) into pixels. *)
+
+PROCEDURE InterpretPage;
+
+(* This routine will interpret the current DVI page and update the major
+ 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)
+
+ 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 client'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 bitmap info (0 if absent or white)
+ loaded := FALSE
+ 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 AND all reference points 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.
+*)
+
+PROCEDURE SortFonts (VAR unusedlist : fontinfoptr);
+
+(* This routine will sort fontlist in ascending order of totalchars.
+ The client may wish to do this after interpreting a page so that fonts
+ with the least number of characters on the page will be processed first.
+ The routine will also move all unused fonts to the end of fontlist so that
+ the client need only process fonts up to (but excluding) unusedlist
+ and not have to worry about checking the fontused flag.
+ For example:
+ SortFont(unusedlist);
+ thisfont := fontlist;
+ WHILE thisfont <> unusedlist DO
+ < process the font information in thisfont^ >
+ thisfont := thisfont^.nextfont;
+ END;
+ If unusedlist is NIL then either 1) all fonts are used on the current page
+ or 2) fontlist is also NIL (totalfonts = 0).
+*)
+
+PROCEDURE CloseDVIFile;
+
+(* This routine closes the currently open DVI file; it is only mandatory if
+ OpenDVIFile is going to be called again.
+ All dynamic data structures are deallocated.
+*)
+
+END DVIReader.
diff --git a/dviware/psprint/vms/dvireader.mod b/dviware/psprint/vms/dvireader.mod
new file mode 100644
index 0000000000..0ff1ac3fa8
--- /dev/null
+++ b/dviware/psprint/vms/dvireader.mod
@@ -0,0 +1,1474 @@
+IMPLEMENTATION MODULE DVIReader;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: August, 1984
+
+ Description:
+ Implements 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.
+
+ Revised:
+ August, 1986
+ - PSDVI requires that MoveToDVIPage no longer assumes InterpretPage has
+ been called after any previous MoveTo... routine.
+
+ December, 1986
+ - Initialize fontexists flag to FALSE when reading postamble.
+
+ June--August, 1988 (while at Aston University)
+ - Import hoffset and voffset from Options to handle shifting of page.
+*)
+
+FROM SYSTEM IMPORT
+ ADDRESS, (* byte address *)
+ ADR, BYTE;
+
+FROM Storage IMPORT
+ ALLOCATE, DEALLOCATE; (* need for NEW and DISPOSE *)
+
+FROM VMS IMPORT
+ SYS$OPEN, SYS$CRMPSC, SYS$DASSGN, SYS$DELTVA;
+
+FROM SSDefinitions IMPORT
+ SS$_ENDOFFILE;
+
+FROM SECDefinitions IMPORT
+ SEC$V_EXPREG;
+
+FROM RMS IMPORT
+ FAB, InitFab,
+ FOPset, FOPtype,
+ FACset, FACtype,
+ SHRset, SHRtype;
+
+(* DEBUG
+(* DVIReader will only do terminal output while debugging. *)
+FROM TermOut IMPORT
+ Write, WriteString, WriteLn, WriteInt, WriteCard, Halt;
+GUBED *)
+
+FROM Options IMPORT
+ hoffset, voffset;
+
+
+(*******************************************************************************
+ DECLARATIONS FOR RANDOMLY ACCESSING A DVI FILE
+
+ A DVI file is considered to be an array of 8-bit bytes, ending with at
+ least 4 223 bytes and having a total length divisible by 4.
+ Under VAX/VMS a DVI file has fixed-length, 512-byte records (1 per block).
+ The last record/s will be padded with 223 bytes to ensure that the
+ above conditions hold. We will be randomly positioning to DVI bytes
+ by setting DVIoffset, and reading bytes via GetDVIByte, SignedDVIByte etc.
+*)
+
+TYPE
+ (* DVI file should never have more than MAX(INTEGER) bytes! *)
+ DVIfile = ARRAY [0..MAX(INTEGER)] OF BYTE;
+ DVIpointer = POINTER TO DVIfile; (* never allocated! *)
+
+VAR
+ vas : ARRAY [0..1] OF ADDRESS; (* start and end virtual addresses *)
+ DVIstart : DVIpointer;
+ DVIoffset : CARDINAL; (* current byte offset in DVIfile *)
+ channel : CARDINAL; (* fab.STV returned by SYS$OPEN *)
+ gsdnam : ARRAY [0..42] OF CHAR; (* unused argument in SYS$CRPMSC *)
+ status : CARDINAL;
+ fab : FAB;
+ postpostid : CARDINAL; (* offset of postpost's id byte *)
+
+(******************************************************************************)
+
+PROCEDURE OpenDVIFile (name : ARRAY OF CHAR);
+
+(* If the given file can be opened and is a valid TeX82 DVI file then we
+ process the postamble and initialize currDVIpage and currTeXpage.
+*)
+
+VAR i : CARDINAL;
+
+BEGIN
+InitFab(fab); (* initialize fab *)
+WITH fab DO
+ FNA := ADR(name); (* DVI file name *)
+ FNS := BYTE(LEN(name)); (* bytes in file name *)
+ FAC := FACset{FAC$BRO,FAC$GET}; (* read-only *)
+ SHR := SHRset{SHR$GET}; (* share file with other readers *)
+ FOP := FOPset{FOP$UFO}; (* need for SYS$CRMPSC *)
+ RTV := BYTE(-1); (* for more efficient mapping *)
+END;
+status := SYS$OPEN(ADR(fab),0,0); (* open the file *)
+IF ODD(status) THEN
+ WITH fab DO
+ channel := STV; (* channel on which file is open *)
+ END;
+ (* now map entire DVI file into virtual address space *)
+ vas[0] := 0;
+ vas[1] := 0;
+ status := SYS$CRMPSC
+ (ADR(vas), (* starting and ending addresses *)
+ ADR(vas), (* addresses returned *)
+ 0,
+ {SEC$V_EXPREG}, (* pages mapped into 1st available space *)
+ gsdnam,0,0,
+ channel, (* channel on which file has been opened *)
+ 0,0,0,
+ 36 (* large page fault cluster size *)
+ );
+ IF status = SS$_ENDOFFILE THEN
+ DVIErrorRoutine(DVIempty); (* given file is empty *)
+ ELSIF NOT ODD(status) THEN
+ (* DEBUG
+ WriteString('SYS$CRMPSC failed! status='); WriteCard(status);
+ WriteLn; Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+ ELSE
+ (* Now that the entire DVI file is mapped into virtual memory we can
+ access any DVI byte as an offset from the address in vas[0].
+ *)
+ DVIstart := vas[0];
+ (* move to last DVI byte *)
+ DVIoffset := CARDINAL(ADDRESS(vas[1]) - ADDRESS(DVIstart));
+ (* check for trailing NULs first in case DVI file has come
+ from non-VMS environment
+ *)
+ WHILE (DVIoffset > 0) AND (CARDINAL(DVIstart^[DVIoffset]) = 0) DO
+ DEC(DVIoffset); (* skip NUL byte *)
+ END;
+ WHILE (DVIoffset > 0) AND (CARDINAL(DVIstart^[DVIoffset]) = 223) DO
+ DEC(DVIoffset); (* skip 223 byte *)
+ END;
+ postpostid := DVIoffset; (* remember position of id byte *)
+ IF GetDVIByte() <> 2 THEN
+ (* DEBUG
+ WriteString('Bad DVI file! id byte is not 2.'); WriteLn;
+ Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIbadid); (* not a valid TeX82 DVI file *)
+ ELSE
+ 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;
+ END;
+ELSE
+ DVIErrorRoutine(DVIunopened); (* given file could not be opened *)
+END;
+END OpenDVIFile;
+
+(******************************************************************************)
+
+(* Here are the functions used to get byte/s from DVIfile.
+ They are essentially the same as those used in DVITYPE.
+*)
+
+PROCEDURE GetDVIByte () : INTEGER;
+
+(* Returns the value (unsigned) of the byte at DVIoffset and
+ advances DVIoffset for the next GetDVIByte.
+*)
+
+VAR b : CARDINAL;
+
+BEGIN
+b := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+RETURN b;
+END GetDVIByte;
+
+(******************************************************************************)
+
+PROCEDURE SignedDVIByte () : INTEGER; (* the next byte, signed *)
+
+VAR b : CARDINAL;
+
+BEGIN
+b := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+IF b < 128 THEN
+ RETURN b;
+ELSE
+ RETURN b - 256;
+END;
+END SignedDVIByte;
+
+(******************************************************************************)
+
+PROCEDURE GetTwoDVIBytes () : INTEGER; (* the next 2 bytes, unsigned *)
+
+VAR a, b : CARDINAL;
+
+BEGIN
+a := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+b := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+RETURN a * 256 + b;
+END GetTwoDVIBytes;
+
+(******************************************************************************)
+
+PROCEDURE SignedDVIPair () : INTEGER; (* the next 2 bytes, signed *)
+
+VAR a, b : CARDINAL;
+
+BEGIN
+a := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+b := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+IF a < 128 THEN
+ RETURN a * 256 + b;
+ELSE
+ RETURN (a - 256) * 256 + b;
+END;
+END SignedDVIPair;
+
+(******************************************************************************)
+
+PROCEDURE GetThreeDVIBytes () : INTEGER; (* the next 3 bytes, unsigned *)
+
+VAR a, b, c : CARDINAL;
+
+BEGIN
+a := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+b := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+c := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+RETURN (a * 256 + b) * 256 + c;
+END GetThreeDVIBytes;
+
+(******************************************************************************)
+
+PROCEDURE SignedDVITrio () : INTEGER; (* the next 3 bytes, signed *)
+
+VAR a, b, c : CARDINAL;
+
+BEGIN
+a := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+b := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+c := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+IF a < 128 THEN
+ RETURN (a * 256 + b) * 256 + c;
+ELSE
+ RETURN ((a - 256) * 256 + b) * 256 + c;
+END;
+END SignedDVITrio;
+
+(******************************************************************************)
+
+PROCEDURE SignedDVIQuad () : INTEGER; (* the next 4 bytes, signed *)
+
+VAR a, b, c, d : CARDINAL;
+
+BEGIN
+a := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+b := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+c := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+d := CARDINAL(DVIstart^[DVIoffset]); INC(DVIoffset);
+IF a < 128 THEN
+ RETURN ((a * 256 + b) * 256 + c) * 256 + d;
+ELSE
+ RETURN (((a - 256) * 256 + b) * 256 + c) * 256 + d;
+END;
+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 : CARDINAL;
+
+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
+ (* DEBUG
+ WriteString('Stack capacity exceeded! maxstack = ');
+ WriteCard(maxstack);
+ WriteString(' but maxstacksize only = '); WriteCard(maxstacksize);
+ WriteLn;
+ Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIstackoverflow);
+ (* now we don't need to test for stack overflow in DoPush *)
+END;
+(* DEBUG
+ WriteString('postamble opcode ='); WriteInt(postamble); WriteLn;
+ WriteString('postion of last bop ='); WriteInt(lastbop); WriteLn;
+ WriteString('num ='); WriteInt(num); WriteLn;
+ WriteString('den ='); WriteInt(den); WriteLn;
+ WriteString('DVI mag ='); WriteInt(DVImag); WriteLn;
+ WriteString('ht+dp of tallest page='); WriteInt(pagehtplusdp); WriteLn;
+ WriteString('width of widest page ='); WriteInt(pagewidth); WriteLn;
+ WriteString('max stack depth ='); WriteInt(maxstack); WriteLn;
+ WriteString('total # of pages ='); WriteInt(totalpages); WriteLn;
+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;
+ the client module must handle all this in its PixelTableRoutine.)
+ 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 : fontstring; (* 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
+ 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 := '';
+ FOR i := 0 TO a-1 DO (* read and store font area *)
+ ch := CHR(GetDVIByte());
+ IF i < maxfontspec THEN farea[i] := ch END;
+ END;
+ fname := '';
+ FOR i := 0 TO l-1 DO (* read and store font name *)
+ ch := CHR(GetDVIByte());
+ IF i < maxfontspec THEN fname[i] := ch END;
+ END;
+ NEW(currfont);
+ WITH currfont^ DO
+ fontused := FALSE;
+ fontnum := f;
+ scaledsize := s;
+ designsize := d;
+ fontarea := farea; fontarealen := CARDINAL(a);
+ fontname := fname; fontnamelen := CARDINAL(l);
+ fontspec := '';
+ fontspeclen := 0; (* fontspec has to be built by client *)
+ 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 *)
+ INC(totalfonts);
+ ELSIF DVIcommand = nop THEN
+ (* nop commands can occur between DVI commands *)
+ ELSIF DVIcommand = postpost THEN
+ (* we have reached end of postamble *)
+ ELSE
+ (* DEBUG
+ WriteString('Unexpected DVI command in postamble = ');
+ WriteCard(DVIcommand); WriteLn;
+ Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+ END;
+UNTIL DVIcommand = postpost;
+END ProcessFontDefs;
+
+
+(*******************************************************************************
+ 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 : CARDINAL; (* position of last bop byte *)
+ prevbop : INTEGER; (* position of bop byte of previous page;
+ note that prevbop of first page = -1 *)
+
+(******************************************************************************)
+
+PROCEDURE MoveToNextPage (ascending : BOOLEAN);
+
+(* Move to next DVI page; whether we can will depend on the current DVI page
+ and if we are ascending or descending.
+*)
+
+BEGIN
+IF (currDVIpage = 1) AND (NOT ascending) THEN (* do nothing *)
+ RETURN;
+ELSIF (currDVIpage = totalpages) AND ascending THEN (* do nothing *)
+ RETURN;
+ELSIF currDVIpage = 0 THEN (* we haven't processed a page yet *)
+ IF ascending THEN (* get first page *)
+ ReadFirstBop;
+ ELSE (* 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
+ (* move to bop pointed to by currbop's backpointer *)
+ currbop := prevbop;
+ DVIoffset := currbop + 1; (* move to byte after previous bop *)
+ DEC(currDVIpage);
+ END;
+END;
+ReadBopParameters; (* update currTeXpage and prevbop *)
+END MoveToNextPage;
+
+(******************************************************************************)
+
+PROCEDURE ReadFirstBop;
+
+(* Read first bop by skipping past preamble; update currbop and currDVIpage. *)
+
+VAR k, i, dummy : CARDINAL;
+
+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 *)
+END;
+REPEAT (* skip any nops and fntdefs *)
+ DVIcommand := GetDVIByte();
+ IF (DVIcommand = nop) OR (DVIcommand = bop) THEN
+ (* do nothing *)
+ ELSIF (DVIcommand >= fntdef1) AND (DVIcommand <= fntdef1+3) THEN
+ SkipFntdef(DVIcommand - fntdef1);
+ ELSE
+ (* DEBUG
+ WriteLn;
+ WriteString('Unexpected DVI command before first bop = ');
+ WriteCard(DVIcommand); WriteLn;
+ Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+ END;
+UNTIL DVIcommand = bop;
+currbop := DVIoffset - 1; (* position in DVI file of first bop *)
+currDVIpage := 1;
+END ReadFirstBop;
+
+(******************************************************************************)
+
+PROCEDURE SkipFntdef (which : CARDINAL);
+
+(* Read past a fntdef command without interpreting it. *)
+
+VAR dummy, a, l, i : CARDINAL;
+
+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 := 0 TO l+a-1 DO
+ dummy := GetDVIByte();
+END;
+END SkipFntdef;
+
+(******************************************************************************)
+
+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 *)
+ ELSIF (DVIcommand >= fntdef1) AND (DVIcommand <= fntdef1+3) THEN
+ SkipFntdef(DVIcommand - fntdef1);
+ ELSE
+ (* DEBUG
+ WriteLn;
+ WriteString('Unexpected DVI command between eop and bop = ');
+ WriteCard(DVIcommand); WriteLn;
+ Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+ END;
+UNTIL DVIcommand = bop;
+currbop := DVIoffset - 1; (* position in DVI file of this bop *)
+INC(currDVIpage);
+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 : CARDINAL;
+
+BEGIN
+FOR i := 0 TO 9 DO
+ currTeXpage[i] := SignedDVIQuad();
+END;
+prevbop := SignedDVIQuad(); (* position of previous bop in DVI file *)
+END ReadBopParameters;
+
+(******************************************************************************)
+
+PROCEDURE MoveToDVIPage (n : CARDINAL);
+
+(* Move to nth DVI page; n should be in 1..totalpages. *)
+
+BEGIN
+IF (n < 1) OR (n > totalpages) THEN (* do nothing *)
+ RETURN;
+END;
+IF n = 1 THEN
+ (* Note that this test must come before next ELSIF 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).
+ELSIF n = currDVIpage + 1 THEN
+ ReadNextBop;
+*)
+ELSE
+ IF n < currDVIpage THEN
+ currbop := prevbop; (* start searching backwards from previous page *)
+ DEC(currDVIpage);
+ ELSIF n > currDVIpage THEN
+ currbop := lastbop; (* start searching backwards from last page *)
+ currDVIpage := totalpages;
+ ELSE
+ (* n = currDVIpage so we'll just move back to currbop *)
+ END;
+ (* n is now <= currDVIpage so search by following backpointers *)
+ LOOP
+ IF n = currDVIpage THEN
+ DVIoffset := currbop + 1; (* move to byte after currbop *)
+ EXIT;
+ ELSE
+ DVIoffset := currbop + 41; (* move to location of backpointer *)
+ currbop := SignedDVIQuad(); (* get location of previous page *)
+ DEC(currDVIpage);
+ END;
+ END;
+END;
+ReadBopParameters; (* update currTeXpage and prevbop *)
+END MoveToDVIPage;
+
+(******************************************************************************)
+
+PROCEDURE MoveToTeXPage (VAR newTeXpage : TeXpageinfo) (* in *)
+ : BOOLEAN;
+
+(* Return TRUE iff the given TeX page exists.
+ If so then we move to the lowest matching page.
+*)
+
+VAR savecurrbop, savecurrDVIpage : CARDINAL;
+ nextbop : INTEGER;
+ i : CARDINAL;
+ 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 *)
+END;
+(* search backwards through all DVI pages for lowest matching page *)
+atleastone := FALSE;
+nextbop := lastbop;
+FOR i := totalpages TO 1 BY -1 DO
+ DVIoffset := nextbop + 1;
+ ReadBopParameters; (* update currTeXpage and prevbop *)
+ IF CurrMatchesNew(newTeXpage) THEN
+ currbop := nextbop;
+ currDVIpage := i;
+ atleastone := TRUE;
+ END;
+ nextbop := prevbop;
+END;
+IF NOT atleastone THEN (* no match, so restore currDVIpage *)
+ currDVIpage := savecurrDVIpage;
+ IF currDVIpage <> 0 THEN (* 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;
+ RETURN FALSE;
+ELSE (* we found lowest matching page *)
+ DVIoffset := currbop + 1;
+END;
+ReadBopParameters; (* update currTeXpage and prevbop *)
+RETURN TRUE;
+END MoveToTeXPage;
+
+(******************************************************************************)
+
+PROCEDURE CurrMatchesNew (VAR newTeXpage : TeXpageinfo) : BOOLEAN;
+
+(* Return TRUE iff currTeXpage matches newTeXpage. *)
+
+VAR i : [0..9];
+
+BEGIN
+WITH newTeXpage DO
+ FOR i := 0 TO lastvalue DO
+ IF present[i] AND (value[i] <> currTeXpage[i]) THEN
+ RETURN FALSE;
+ END;
+ END;
+END;
+RETURN TRUE;
+END CurrMatchesNew;
+
+
+(*******************************************************************************
+ 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 *)
+
+ maxint = 2147483647; (* SYSDEP: 2^31 - 1 *)
+ maxstacksize = 100; (* maximum stack size for state values *)
+ maxdrift = 2; (* prevent hh & vv from drifting too far *)
+
+VAR
+ DVIcommand : [0..255]; (* holds next DVI command *)
+ maxstack, (* max pushes over pops in DVI file *)
+ num, (* DVI numerator *)
+ den : CARDINAL; (* 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, (* h and v in pixels *)
+ 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..maxstacksize-1] 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 *)
+ ruletail : ruleinfoptr; (* tail of rule information list *)
+ thischar : charinfoptr; (* temporary pointer to node in charlist *)
+
+(******************************************************************************)
+
+PROCEDURE SetConversionFactor (resolution, magnification : CARDINAL);
+
+(* Client module must help calculate conv, the number of pixels per DVI unit. *)
+
+BEGIN
+conv := FLOAT(num)/254000.0 * FLOAT(resolution)/FLOAT(den) *
+ FLOAT(magnification)/1000.0;
+END SetConversionFactor;
+
+(******************************************************************************)
+
+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 various data structures exported by DVIReader.
+*)
+
+VAR param : 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 *)
+ ELSIF DVIcommand = w0 THEN DoRight(w);
+ ELSIF DVIcommand = right3 THEN DoRight(SignedDVITrio());
+ ELSIF DVIcommand = push THEN DoPush;
+ ELSIF DVIcommand = pop THEN DoPop;
+ ELSIF DVIcommand = x0 THEN DoRight(x);
+ ELSIF DVIcommand = w3 THEN w := SignedDVITrio(); DoRight(w);
+ ELSIF DVIcommand = y0 THEN DoDown(y);
+
+ ELSIF (DVIcommand > z4) AND (DVIcommand < fnt1) (* fntnum0..fntnum63 *)
+ THEN DoFont(DVIcommand - fntnum0);
+
+ (* catch all the remaining movement commands *)
+ ELSIF (DVIcommand > pop) AND (DVIcommand < fntnum0) THEN
+ IF DVIcommand = right2 THEN DoRight(SignedDVIPair());
+ ELSIF DVIcommand = right4 THEN DoRight(SignedDVIQuad());
+ ELSIF DVIcommand = x2 THEN x := SignedDVIPair(); DoRight(x);
+ ELSIF DVIcommand = x3 THEN x := SignedDVITrio(); DoRight(x);
+ ELSIF DVIcommand = down3 THEN DoDown(SignedDVITrio());
+ ELSIF DVIcommand = down4 THEN DoDown(SignedDVIQuad());
+ ELSIF DVIcommand = w2 THEN w := SignedDVIPair(); DoRight(w);
+ ELSIF DVIcommand = z0 THEN DoDown(z);
+ ELSIF DVIcommand = y3 THEN y := SignedDVITrio(); DoDown(y);
+ ELSIF DVIcommand = z3 THEN z := SignedDVITrio(); DoDown(z);
+ ELSIF DVIcommand = down2 THEN DoDown(SignedDVIPair());
+ (* the next DVI commands are used very rarely (by TeX 1.3 at least) *)
+ ELSIF DVIcommand = w1 THEN w := SignedDVIByte(); DoRight(w);
+ ELSIF DVIcommand = w4 THEN w := SignedDVIQuad(); DoRight(w);
+ ELSIF DVIcommand = x1 THEN x := SignedDVIByte(); DoRight(x);
+ ELSIF DVIcommand = x4 THEN x := SignedDVIQuad(); DoRight(x);
+ ELSIF DVIcommand = y1 THEN y := SignedDVIByte(); DoDown(y);
+ ELSIF DVIcommand = y2 THEN y := SignedDVIPair(); DoDown(y);
+ ELSIF DVIcommand = y4 THEN y := SignedDVIQuad(); DoDown(y);
+ ELSIF DVIcommand = z1 THEN z := SignedDVIByte(); DoDown(z);
+ ELSIF DVIcommand = z2 THEN z := SignedDVIPair(); DoDown(z);
+ ELSIF DVIcommand = z4 THEN z := SignedDVIQuad(); DoDown(z);
+ ELSIF DVIcommand = right1 THEN DoRight(SignedDVIByte());
+ ELSIF DVIcommand = down1 THEN DoDown(SignedDVIByte());
+ ELSE (* DEBUG
+ (* will only occur if we've missed a movement command *)
+ WriteLn; WriteString('Bug in InterpretPage!'); WriteLn; Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+ END;
+
+ ELSIF DVIcommand = setrule THEN DoSetRule(SignedDVIQuad(),SignedDVIQuad());
+ ELSIF DVIcommand = putrule THEN DoPutRule(SignedDVIQuad(),SignedDVIQuad());
+
+ ELSIF (DVIcommand >= put1) AND (DVIcommand <= put1+3) THEN
+ CASE DVIcommand - put1 OF
+ 0 : DoPutChar(GetDVIByte()) |
+ 1 : DoPutChar(GetTwoDVIBytes()) |
+ 2 : DoPutChar(GetThreeDVIBytes()) |
+ 3 : DoPutChar(SignedDVIQuad())
+ END;
+
+ ELSIF (DVIcommand >= set1) AND (DVIcommand <= set1+3) THEN
+ CASE DVIcommand - set1 OF
+ 0 : DoSetChar(GetDVIByte()) |
+ 1 : DoSetChar(GetTwoDVIBytes()) |
+ 2 : DoSetChar(GetThreeDVIBytes()) |
+ 3 : DoSetChar(SignedDVIQuad())
+ END;
+
+ ELSIF (DVIcommand >= fnt1) AND (DVIcommand <= fnt1+3) THEN
+ CASE DVIcommand - fnt1 OF
+ 0 : DoFont(GetDVIByte()) |
+ 1 : DoFont(GetTwoDVIBytes()) |
+ 2 : DoFont(GetThreeDVIBytes()) |
+ 3 : DoFont(SignedDVIQuad())
+ END;
+
+ ELSIF (DVIcommand >= xxx1) AND (DVIcommand <= xxx1+3) THEN
+ CASE DVIcommand - xxx1 OF
+ 0 : param := GetDVIByte() |
+ 1 : param := GetTwoDVIBytes() |
+ 2 : param := GetThreeDVIBytes() |
+ 3 : param := SignedDVIQuad()
+ END;
+ (* Pass current pixel position, number of bytes and
+ byte grabbing function for client to use.
+ We use IgnoreSpecial if client does not assign a procedure.
+ *)
+ SpecialRoutine(hh, vv, param, GetDVIByte);
+
+ (* skip fntdef command since we've got this info from postamble *)
+ ELSIF (DVIcommand >= fntdef1) AND (DVIcommand <= fntdef1+3)
+ THEN SkipFntdef(DVIcommand - fntdef1);
+
+ ELSIF DVIcommand = nop THEN (* do nothing *)
+ ELSIF DVIcommand = eop THEN (* do nothing *)
+ ELSE
+ (* DEBUG
+ WriteLn;
+ WriteString('Unexpected DVI command while interpreting page = ');
+ WriteCard(DVIcommand); WriteLn;
+ Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+ END;
+UNTIL DVIcommand = eop;
+(* save position of eop byte for use in MoveToTeXPage *)
+curreop := DVIoffset - 1;
+IF stackpos <> 0 THEN
+ (* DEBUG
+ WriteString('Stack not empty at eop!'); WriteLn;
+ Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+END;
+pageempty := (minhp = maxint) AND (minvp = maxint) AND
+ (maxhp = -maxint) AND (maxvp = -maxint); (* InitPage values *)
+END InterpretPage;
+
+(******************************************************************************)
+
+PROCEDURE InitStateValues;
+
+(* Initialize the 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(FLOAT(hoffset) / conv + 0.5);
+ELSE
+ h := - TRUNC(FLOAT(ABS(hoffset)) / conv + 0.5);
+END;
+IF voffset >= 0 THEN
+ v := TRUNC(FLOAT(voffset) / conv + 0.5);
+ELSE
+ v := - TRUNC(FLOAT(ABS(voffset)) / conv + 0.5);
+END;
+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 structures so there are no fonts, no chars and no rules. *)
+
+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
+ IF fontused THEN (* 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
+ thischar := charlist;
+ charlist := thischar^.nextchar;
+ DISPOSE(thischar);
+ END;
+ chartail := NIL;
+ (* pixel table remains allocated *)
+ END;
+ currfont := nextfont;
+ END;
+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
+ thisrule := rulelist;
+ rulelist := thisrule^.nextrule;
+ DISPOSE(thisrule);
+END;
+rulelist^.rulecount := 0; (* no rules in this node *)
+rulelist^.nextrule := NIL;
+END InitPage;
+
+(******************************************************************************)
+
+PROCEDURE DoSetChar (ch : CARDINAL);
+
+(* Add char info to current chartable, update our horizontal
+ position on the page and check the page edges.
+*)
+
+BEGIN
+WITH currfont^ DO
+ IF ch > maxTeXchar THEN
+ DVIErrorRoutine(DVIbadchar);
+ RETURN; (* ignore ch *)
+ END;
+ WITH chartail^ DO
+ IF charcount = chartablesize THEN (* 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;
+ END;
+ WITH chartail^ DO (* may be new chartable *)
+ WITH chartable[charcount] DO
+ hp := hh;
+ vp := vv;
+ code := ch;
+ END;
+ WITH pixelptr^[ch] DO
+ (* do page edges increase? *)
+ IF vv - yo < minvp THEN minvp := vv - yo END;
+ IF hh - xo < minhp THEN minhp := hh - xo END;
+ IF vv + (ht - yo - 1) > maxvp THEN maxvp := vv + (ht - yo - 1) END;
+ IF hh + (wd - xo - 1) > maxhp THEN maxhp := hh + (wd - xo - 1) END;
+ (* the above checks ensure that page edges include all black
+ pixels in glyph, but we also want to include reference point *)
+ IF hh < minhp THEN minhp := hh END;
+ IF vv < minvp THEN minvp := vv END;
+ IF hh > maxhp THEN maxhp := hh END;
+ IF vv > maxvp THEN maxvp := vv END;
+ (* 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;
+ END;
+ END;
+ (* add DVI width calculated in PixelTableRoutine *)
+ h := h + dwidth;
+ END;
+ INC(totalchars);
+ INC(charcount);
+ END;
+END;
+END DoSetChar;
+
+(******************************************************************************)
+
+PROCEDURE DoPutChar (ch : CARDINAL);
+
+(* Exactly the same as DoSetChar, but we DON'T update the horizontal
+ position on the page. (We still have to check page edges.)
+*)
+
+BEGIN
+WITH currfont^ DO
+ IF ch > maxTeXchar THEN
+ DVIErrorRoutine(DVIbadchar);
+ RETURN; (* ignore ch *)
+ END;
+ WITH chartail^ DO
+ IF charcount = chartablesize THEN (* 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;
+ END;
+ WITH chartail^ DO (* may be new chartable *)
+ WITH chartable[charcount] DO
+ hp := hh;
+ vp := vv;
+ code := ch;
+ END;
+ WITH pixelptr^[ch] DO
+ (* do page edges increase? *)
+ IF vv - yo < minvp THEN minvp := vv - yo END;
+ IF hh - xo < minhp THEN minhp := hh - xo END;
+ IF vv + (ht - yo - 1) > maxvp THEN maxvp := vv + (ht - yo - 1) END;
+ IF hh + (wd - xo - 1) > maxhp THEN maxhp := hh + (wd - xo - 1) END;
+ (* the above checks ensure that page edges include all black
+ pixels in glyph, but we also want to include reference point *)
+ IF hh < minhp THEN minhp := hh END;
+ IF vv < minvp THEN minvp := vv END;
+ IF hh > maxhp THEN maxhp := hh END;
+ IF vv > maxvp THEN maxvp := vv END;
+ END;
+ INC(totalchars);
+ INC(charcount);
+ END;
+END;
+END DoPutChar;
+
+(******************************************************************************)
+
+PROCEDURE PixelRound (DVIunits : INTEGER) : INTEGER;
+
+(* Return the nearest number of pixels in the given DVI dimension. *)
+
+BEGIN
+IF DVIunits > 0 THEN
+ RETURN TRUNC(conv * FLOAT(DVIunits) + 0.5);
+ELSE
+ RETURN - TRUNC(conv * FLOAT(ABS(DVIunits)) + 0.5);
+END;
+END PixelRound;
+
+(******************************************************************************)
+
+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;
+INC(stackpos); (* stackpos = next vacant position in stacks *)
+END DoPush;
+
+(******************************************************************************)
+
+PROCEDURE DoPop;
+
+(* Pop state values from top of stack. *)
+
+BEGIN
+(* DEBUG
+ IF stackpos = 0 THEN
+ WriteString('Stack empty!'); WriteLn;
+ Halt(2);
+ END;
+GUBED *)
+DEC(stackpos);
+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
+ 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;
+ END;
+ELSE
+ hh := PixelRound(h + amount);
+END;
+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
+ 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;
+ END;
+ELSE
+ vv := PixelRound(v + amount);
+END;
+v := v + amount;
+END DoDown;
+
+(******************************************************************************)
+
+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
+ WITH ruletail^ DO
+ IF rulecount = ruletablesize THEN (* 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;
+ END;
+ WITH ruletail^ DO (* may be new ruletable *)
+ WITH ruletable[rulecount] DO
+ hp := hh;
+ vp := vv;
+ wd := RulePixels(width);
+ ht := RulePixels(height);
+ (* do page edges increase? *)
+ IF vv - (ht - 1) < minvp THEN minvp := vv - (ht - 1) END;
+ IF hh + (wd - 1) > maxhp THEN maxhp := hh + (wd - 1) END;
+ (* ref pt of rule is bottom left black pixel *)
+ IF vv > maxvp THEN maxvp := vv END;
+ IF hh < minhp THEN minhp := hh END;
+ 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;
+ END;
+ END;
+ h := h + width;
+ END;
+ INC(totalrules);
+ INC(rulecount);
+ 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
+ WITH ruletail^ DO
+ IF rulecount = ruletablesize THEN (* 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;
+ END;
+ WITH ruletail^ DO (* may be new ruletable *)
+ WITH ruletable[rulecount] DO
+ hp := hh;
+ vp := vv;
+ wd := RulePixels(width);
+ ht := RulePixels(height);
+ (* do page edges increase? *)
+ IF vv - (ht - 1) < minvp THEN minvp := vv - (ht - 1) END;
+ IF hh + (wd - 1) > maxhp THEN maxhp := hh + (wd - 1) END;
+ (* ref pt of rule is bottom left black pixel *)
+ IF vv > maxvp THEN maxvp := vv END;
+ IF hh < minhp THEN minhp := hh END;
+ END;
+ INC(totalrules);
+ INC(rulecount);
+ END;
+END;
+END DoPutRule;
+
+(******************************************************************************)
+
+PROCEDURE 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 * FLOAT(DVIunits));
+IF FLOAT(n) < conv * FLOAT(DVIunits) THEN RETURN n + 1 ELSE RETURN n END;
+END RulePixels;
+
+(******************************************************************************)
+
+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 client routine to fill it in.
+*)
+
+BEGIN
+currfont := fontlist;
+WHILE (currfont <> NIL) AND (currfont^.fontnum <> externf) DO
+ currfont := currfont^.nextfont;
+END;
+IF currfont = NIL THEN
+ (* DEBUG
+ WriteLn; WriteString('Failed to find font #'); WriteInt(externf);
+ WriteLn; Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+END;
+WITH currfont^ DO
+ IF fontused THEN
+ (* do nothing since we've already used this font on this page *)
+ ELSE
+ fontused := TRUE;
+ NEW(charlist); (* allocate first chartable *)
+ WITH charlist^ DO
+ charcount := 0; (* for DoSet/PutChar *)
+ nextchar := NIL; (* this node is also last *)
+ END;
+ chartail := charlist;
+ IF pixelptr = NIL THEN (* first time we've seen this font requested *)
+ NEW(pixelptr);
+ PixelTableRoutine; (* call client routine to build pixel table *)
+ 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 IgnoreSpecial(xpos, ypos, (* in *)
+ specialbytes : INTEGER; (* in *)
+ GetNextByte : GetByteFunction); (* in *)
+
+(* Default SpecialRoutine simply skips bytes given to TeX's \special command. *)
+
+VAR i, unused : INTEGER;
+
+BEGIN
+FOR i := 1 TO specialbytes DO
+ unused := GetNextByte();
+END;
+END IgnoreSpecial;
+
+(******************************************************************************)
+
+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.
+*)
+
+VAR newfontlist, prevfont, largest, prevlargest : fontinfoptr;
+ mostchars : CARDINAL;
+
+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
+ prevfont := currfont; (* remember previous node *)
+ currfont := nextfont;
+ ELSE
+ (* move node from fontlist to head of newfontlist
+ and don't change prevfont
+ *)
+ IF prevfont = NIL THEN
+ fontlist := nextfont; (* remove first node in fontlist *)
+ nextfont := newfontlist;
+ newfontlist := currfont;
+ currfont := fontlist;
+ ELSE
+ prevfont^.nextfont := nextfont;
+ nextfont := newfontlist;
+ newfontlist := currfont;
+ currfont := prevfont^.nextfont;
+ END;
+ END;
+ END;
+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
+ prevfont := NIL;
+ currfont := fontlist;
+ prevlargest := NIL;
+ largest := fontlist;
+ mostchars := 0;
+ WHILE currfont <> NIL DO (* search for largest totalchars *)
+ WITH currfont^ DO
+ IF totalchars > mostchars THEN
+ prevlargest := prevfont;
+ largest := currfont;
+ mostchars := totalchars;
+ END;
+ prevfont := currfont;
+ currfont := nextfont;
+ END;
+ END;
+ (* move largest node from fontlist to head of newfontlist *)
+ WITH largest^ DO
+ IF prevlargest = NIL THEN
+ fontlist := nextfont; (* remove first node in fontlist *)
+ ELSE
+ prevlargest^.nextfont := nextfont;
+ END;
+ 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. *)
+
+BEGIN
+status := SYS$DELTVA(ADR(vas),ADR(vas),0);
+IF NOT ODD(status) THEN
+ (* DEBUG
+ WriteString('SYS$DELTVA failed! status='); WriteCard(status);
+ WriteLn; Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+END;
+status := SYS$DASSGN(channel);
+IF NOT ODD(status) THEN
+ (* DEBUG
+ WriteString('SYS$DASSGN failed! status='); WriteCard(status);
+ WriteLn; Halt(2);
+ GUBED *)
+ DVIErrorRoutine(DVIcatastrophe);
+END;
+WHILE fontlist <> NIL DO
+ currfont := fontlist;
+ WITH currfont^ DO
+ WHILE charlist <> NIL DO (* deallocate char list *)
+ thischar := charlist;
+ charlist := thischar^.nextchar;
+ DISPOSE(thischar);
+ END;
+ IF pixelptr <> NIL THEN
+ DISPOSE(pixelptr); (* deallocate pixel table *)
+ END;
+ fontlist := nextfont;
+ END;
+ DISPOSE(currfont); (* deallocate font information *)
+END;
+(* Deallocate rule information except for one node (in case client opens
+ another DVI file).
+*)
+WHILE rulelist <> ruletail DO
+ thisrule := rulelist;
+ rulelist := thisrule^.nextrule;
+ DISPOSE(thisrule);
+END;
+END CloseDVIFile;
+
+(******************************************************************************)
+
+BEGIN
+totalrules := 0;
+NEW(rulelist); (* for first InitPage *)
+ruletail := rulelist; (* ditto *)
+fontlist := NIL; (* safer for CloseDVIFile *)
+SpecialRoutine := IgnoreSpecial; (* client can reassign *)
+END DVIReader.
diff --git a/dviware/psprint/vms/fontlist.ps b/dviware/psprint/vms/fontlist.ps
new file mode 100644
index 0000000000..5175bdf4e4
--- /dev/null
+++ b/dviware/psprint/vms/fontlist.ps
@@ -0,0 +1,20 @@
+% Produces a list of all known fonts currently available in printer.
+
+/showline { gsave show grestore 0 -12 rmoveto } def
+/Times-Roman findfont 12 scalefont setfont
+/s40 40 string def
+
+36 700 moveto
+FontDirectory {pop s40 cvs showline} forall
+
+( ) showline
+(Total memory: ) showline
+vmstatus s40 cvs showline
+(Memory used: ) showline
+s40 cvs showline
+pop
+( Free memory: ) showline
+vmstatus exch sub s40 cvs showline
+pop
+
+showpage
diff --git a/dviware/psprint/vms/fontreade.def b/dviware/psprint/vms/fontreade.def
new file mode 100644
index 0000000000..43806cb203
--- /dev/null
+++ b/dviware/psprint/vms/fontreade.def
@@ -0,0 +1,52 @@
+DEFINITION MODULE FontReader;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: November, 1986
+
+ Description:
+ Routines for reading font files in a variety of formats.
+
+ Revised:
+ December, 1986
+ - GetBitmap is now called LoadBitmap and is used by PSDVI to send the
+ PostScript code representing the bitmap and metric information for a
+ given character from a given font.
+*)
+
+FROM DVIReader IMPORT
+ fontinfoptr;
+
+VAR
+ FillPixelTable : PROC;
+ (* Fill currfont^.pixelptr with info from the currently open font file. *)
+
+ LoadBitmap : PROCEDURE (fontinfoptr, (* for currently open font *)
+ CARDINAL); (* char code *)
+ (* Download PostScript bitmap and metrics for the given character
+ using raster info at mapadr in the currently open font file.
+ *)
+
+PROCEDURE InitFontReader;
+(* Use the /FONT_DIRECTORY and /DUMMY_FONT values to assign appropriate
+ routines to the above procedure variables, and to decide on the format
+ of file specifications created by BuildFontSpec.
+*)
+
+PROCEDURE BuildFontSpec (fontptr : fontinfoptr; VAR firstn, lastn : CARDINAL);
+(* Build a complete file specification in fontptr^.fontspec and
+ return the starting and ending positions of the font size substring.
+ This will only be done once per font; fontspeclen will no longer be 0.
+ fontptr^.fontexists becomes TRUE if the file can be found.
+*)
+
+PROCEDURE OpenFontFile (VAR filespec : ARRAY OF CHAR) : BOOLEAN;
+(* Return TRUE if given font file is successfully opened.
+ The value of filespec is not changed; it is declared a VAR parameter
+ for efficiency reasons.
+*)
+
+PROCEDURE CloseFontFile;
+(* Close the currently open font file. *)
+
+END FontReader.
diff --git a/dviware/psprint/vms/fontreade.mod b/dviware/psprint/vms/fontreade.mod
new file mode 100644
index 0000000000..223b76cef4
--- /dev/null
+++ b/dviware/psprint/vms/fontreade.mod
@@ -0,0 +1,1242 @@
+IMPLEMENTATION MODULE FontReader;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: May, 1985
+
+ Description:
+ This module can extract font information from PXL, PK or TFM files.
+ (GF files are not handled; it is assumed that sites with GF files will
+ decide to convert them to PK files sooner or later!)
+ Each type of font file is considered to be an array of 8-bit bytes.
+ Only one font file is open at any time. We move to byte positions using
+ byteoffset and read bytes and words using GetByte, SignedQuad, etc.
+
+ Revised:
+ June, 1985
+ - Use Halt(2) instead of HALT.
+
+ August, 1985
+ - Use ScreenIO routines when debugging.
+
+ September, 1985
+ - Added GetPXLGlyph and associated glyph cacheing code.
+
+ October, 1985
+ - Removed above cacheing stuff! Now use SYS$CRMPSC to map an
+ entire PXL file into virtual memory where it is treated as an array of bytes.
+
+ March, 1986
+ - Amendments to Modula-2 language required a few minor syntactic changes.
+
+ November, 1986
+ - PXLReader has been expanded and is now called FontReader.
+ All font-dependent code has been moved out of PSDVI's main module.
+ A new font format can be handled just by adding code to FontReader.
+ - Reduced page fault cluster size from 36 to 16 because PK files are smaller.
+ - Always start fontspec with fontdir; fontarea is really only for TFM files.
+
+ December, 1986
+ - GetBitmap now called LoadBitmap and uses Put routines from PSWriter to
+ send bitmap and metric info directly to output file.
+
+ November, 1987 (while at The Open University)
+ - Added charsperline code to LoadBitmap routines so that output lines
+ don't get too long.
+ - Added code to handle PostScript fonts (for which only TFM files exist).
+ BuildFontSpec now checks for a fontname beginning with "PS-" and sets the
+ font's psfont flag. If TRUE then we must construct a TFM filespec
+ (starting with tfmdir or fontarea if fontarealen > 0) and later fill
+ the font's pixeltable with character info from that TFM file.
+ - Renamed ConvertTFMWidth to FixToDVI.
+ - PXL/PKFillPixelTable now call TFMFillPixelTable if the font is
+ a PostScript font (and its TFM file could be opened).
+
+ June--August, 1988 (while at Aston University)
+ - Now use /psprefix value to check for a PostScript font.
+ - Changed BuildFontSpec so that the fontsize substring no longer has to
+ be the same length in all font files.
+
+ September--October, 1989 (while at Aston University, 2nd time)
+ - Fixed bug reported by Niel Kempson in FixToDVI.
+*)
+
+FROM SYSTEM IMPORT
+ ADDRESS, ADR, BYTE, WORD;
+
+FROM VMS IMPORT
+ SYS$OPEN, SYS$CRMPSC, SYS$DASSGN, SYS$DELTVA;
+
+FROM SECDefinitions IMPORT
+ SEC$V_EXPREG;
+
+FROM RMS IMPORT
+ FAB, InitFab,
+ FOPset, FOPtype,
+ FACset, FACtype,
+ SHRset, SHRtype;
+
+FROM FileSystem IMPORT
+ File, Open, Done, Close;
+
+FROM Options IMPORT
+ psprefix, tfmdir, fontdir, dummyfont, mag, resolution, Cap;
+
+FROM DVIReader IMPORT
+ (* CONST *)
+ maxfontspec, maxTeXchar,
+ (* TYPE *)
+ fontstring, fontinfo, fontinfoptr,
+ pixeltable, pixeltableptr,
+ (* VAR *)
+ currfont,
+ (* PROCEDURE *)
+ PixelRound;
+
+FROM PSWriter IMPORT
+ Put, PutString, PutInt, PutCard;
+
+FROM TermOut IMPORT
+ WriteString, WriteCard, WriteInt, WriteLn, Halt;
+
+CONST
+ NULL = 0C; (* SYSDEP: used to terminate a string if not full *)
+ CR = 15C; (* used in LoadBitmap *)
+
+TYPE
+ (* font files should never have more than MAX(INTEGER) bytes! *)
+ fontfile = ARRAY [0..MAX(INTEGER)] OF BYTE;
+ filepointer = POINTER TO fontfile; (* never allocated! *)
+
+VAR
+ vas : ARRAY [0..1] OF ADDRESS; (* start and end virtual addresses *)
+ filestart : filepointer; (* pointer to starting address of file *)
+ byteoffset, (* byte offset from start of file *)
+ channel : CARDINAL; (* fab.STV returned by SYS$OPEN *)
+ gsdnam : ARRAY [0..42] OF CHAR; (* unused argument in SYS$CRPMSC *)
+ status : CARDINAL;
+ fab : FAB;
+ psprefixlen, (* length of psprefix string *)
+ fontdirlen, (* length of fontdir string *)
+ dummyfontlen : CARDINAL; (* length of dummyfont string *)
+ formatstr : ARRAY [0..2] OF CHAR; (* PXL or PK *)
+ formatlen : CARDINAL; (* 3 or 2 *)
+ xfactor : REAL; (* resolution/200 or resolution/1000 *)
+ hexdigs : ARRAY [0..15] OF CHAR; (* 0..9ABCDEF for LoadBitmap *)
+ gpower : ARRAY [0..8] OF BITSET; (* 0,1,11,111,1111,...,11111111 *)
+ CompleteFontSpec : (* used by BuildFontSpec *)
+ PROCEDURE (fontinfoptr,
+ CARDINAL,
+ CARDINAL,
+ VAR CARDINAL) : BOOLEAN;
+
+(******************************************************************************)
+
+PROCEDURE InitFontReader;
+
+(* Assign font-dependent routines to various procedure variables
+ according to information present in fontdir and dummyfont:
+
+ - The last character in dummyfont defines the font format (PXL or PK).
+ All font files are assumed to be in the same format.
+ Note that the Options module has prefixed dummyfont with fontdir.
+
+ - The last two characters in fontdir define the structure of each file spec.
+ If ".]" then all font files are assumed to reside in subdirectories of
+ fontdir, and the name of each subdirectory is the font size.
+ A typical dummyfont value would be TEX_DISK:[TEX.PXL.][1500]CMR10.PXL.
+ This is the storage scheme used in K&S's old VMS TeX distributions.
+ If not ".]" then all font files are assumed to be in kept in fontdir,
+ and the font size is included in the file type.
+ A typical dummyfont value would be TEX_DISK:[TEX.PK]CMR10.300PK.
+ This type of scheme is used in the latest VMS TeX distributions.
+
+ - The dummyfont must contain a font size substring representing
+ an unmagnified font. Its value, along with /RESOLUTION, is used to
+ decide how to calculate the font sizes in all other font files.
+*)
+
+VAR
+ i,
+ fontsizelen, (* length of n...n in dummyfont *)
+ dummyfontsize : CARDINAL; (* value of n...n in dummyfont *)
+
+BEGIN
+hexdigs := "0123456789ABCDEF"; (* for LoadBitmap *)
+dummyfontlen := LEN(dummyfont);
+IF dummyfontlen = 0 THEN dummyfontlen := 1 END; (* last char will be NULL *)
+CASE Cap(dummyfont[dummyfontlen-1]) OF (* last char defines format *)
+ 'L' : formatstr := 'pxl';
+ formatlen := 3;
+ FillPixelTable := PXLFillPixelTable;
+ LoadBitmap := PXLLoadBitmap;
+ | 'K' : formatstr := 'pk';
+ formatlen := 2;
+ FillPixelTable := PKFillPixelTable;
+ LoadBitmap := PKLoadBitmap;
+ gpower[0] := {};
+ FOR i := 1 TO 8 DO
+ gpower[i] := gpower[i-1] + {i-1}; (* used in PKLoadBitmap *)
+ END;
+ELSE
+ WriteString('/DUMMY_FONT value should end with PXL or PK.'); WriteLn;
+ Halt(2);
+END;
+psprefixlen := LEN(psprefix);
+fontdirlen := LEN(fontdir);
+IF (fontdirlen > 1) AND (fontdir[fontdirlen-2] = '.') AND
+ (fontdir[fontdirlen-1] = ']') THEN
+ (* assume font files are kept in subdirectories of fontdir
+ and have fontspecs like TEX_DISK:[TEX.subdir.][n...n]CMR10.fmt
+ *)
+ CompleteFontSpec := OldFontSpec;
+ i := fontdirlen + 1; (* first n after .][ *)
+ELSE
+ (* assume font files are all kept in fontdir
+ and have fontspecs like TEX_DISK:[TEX.subdir]CMR10.n...nfmt
+ *)
+ CompleteFontSpec := NewFontSpec;
+ i := fontdirlen; (* first char after ] *)
+ WHILE (i < dummyfontlen) AND (dummyfont[i] <> '.') DO
+ INC(i);
+ END;
+ INC(i); (* first n after '.' *)
+END;
+fontsizelen := 0;
+dummyfontsize := 0;
+WHILE (i < dummyfontlen) AND (dummyfont[i] >= '0') AND (dummyfont[i] <= '9') DO
+ INC(fontsizelen);
+ dummyfontsize := dummyfontsize * 10 + (ORD(dummyfont[i]) - ORD('0'));
+ INC(i);
+END;
+IF fontsizelen > 0 THEN
+ (* The xfactor used to calculate fontsize in BuildFontSpec depends on the
+ fontsize in dummyfont (assumed to be an unmagnified font).
+ *)
+ IF FLOAT(dummyfontsize) / FLOAT(resolution) > 1.0 THEN
+ xfactor := FLOAT(resolution) / 200.0; (* old naming convention *)
+ ELSE
+ xfactor := FLOAT(resolution) / 1000.0; (* new naming convention *)
+ END;
+ELSE
+ WriteString('/DUMMY_FONT value does not contain font size!'); WriteLn;
+ Halt(2);
+END;
+END InitFontReader;
+
+(******************************************************************************)
+
+PROCEDURE BuildFontSpec (fontptr : fontinfoptr; VAR firstn, lastn : CARDINAL);
+
+VAR
+ f : File;
+ i, j, next, fontsize, tempsize, tempsizelen : CARDINAL;
+
+BEGIN
+WITH fontptr^ DO
+ (* 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;
+ LOOP
+ IF i = psprefixlen THEN EXIT END;
+ IF Cap(fontname[i]) <> Cap(psprefix[i]) THEN
+ psfont := FALSE;
+ EXIT;
+ END;
+ INC(i);
+ END;
+ IF psfont THEN
+ BuildTFMSpec(fontptr); (* build TFM file spec *)
+ RETURN;
+ END;
+ i := 0;
+ next := fontdirlen;
+ REPEAT
+ fontspec[i] := fontdir[i]; (* start fontspec with fontdir *)
+ INC(i);
+ UNTIL (i = next) OR (i > maxfontspec);
+ IF next >= maxfontspec THEN
+ fontspeclen := maxfontspec;
+ RETURN; (* fontspec truncated *)
+ END;
+ fontsize := TRUNC( FLOAT(mag) * (FLOAT(scaledsize) / FLOAT(designsize))
+ * xfactor + 0.5 );
+ IF fontsize = 0 THEN
+ INC(fontsize); (* allow for subtracting 1 *)
+ END;
+ tempsize := fontsize;
+ i := 1;
+ LOOP
+ (* Complete rest of fontspec starting at next
+ 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
+ INC(tempsizelen);
+ j := j DIV 10;
+ END;
+ IF NOT CompleteFontSpec(fontptr, next, tempsizelen, firstn) THEN
+ RETURN; (* fontspec truncated *)
+ END;
+ lastn := firstn + tempsizelen - 1;
+ (* put tempsize into fontspec[firstn..lastn] *)
+ FOR j := lastn TO firstn BY -1 DO
+ fontspec[j] := CHR(ORD('0') + (tempsize MOD 10));
+ tempsize := tempsize DIV 10;
+ END;
+ IF i > 3 THEN (* original fontsize has been restored *)
+ RETURN; (* could not open fontspec *)
+ END;
+ Open(f,fontspec,FALSE); (* SYSDEP: try to open for reading *)
+ IF Done() THEN
+ Close(f);
+ fontexists := TRUE; (* fontspec exists *)
+ RETURN;
+ ELSIF i = 1 THEN
+ tempsize := fontsize - 1; (* try fontsize - 1 *)
+ ELSIF i = 2 THEN
+ tempsize := fontsize + 1; (* try fontsize + 1 *)
+ ELSE
+ tempsize := fontsize; (* restore original fontsize *)
+ END;
+ INC(i);
+ END;
+END;
+END BuildFontSpec;
+
+(******************************************************************************)
+
+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.
+*)
+
+VAR f : File; i, next : CARDINAL;
+
+BEGIN
+WITH fontptr^ DO
+ i := 0;
+ IF fontarealen > 0 THEN
+ next := fontarealen;
+ REPEAT
+ fontspec[i] := fontarea[i]; (* start fontspec with fontarea *)
+ INC(i);
+ UNTIL (i = next) OR (i > maxfontspec);
+ ELSE
+ next := LEN(tfmdir); (* assume > 0 *)
+ REPEAT
+ fontspec[i] := tfmdir[i]; (* start fontspec with tfmdir *)
+ INC(i);
+ UNTIL (i = next) OR (i > maxfontspec);
+ END;
+ IF next >= maxfontspec THEN
+ fontspeclen := maxfontspec;
+ RETURN; (* fontspec truncated *)
+ END;
+ (* next is current length of fontspec; append fontname.tfm *)
+ i := 0;
+ WHILE (i < fontnamelen) AND (next < maxfontspec) DO
+ fontspec[next] := fontname[i]; (* append fontname *)
+ INC(i);
+ INC(next);
+ END;
+ IF next + 4 <= maxfontspec THEN (* append .tfm *)
+ fontspec[next] := '.'; INC(next);
+ fontspec[next] := 't'; INC(next);
+ fontspec[next] := 'f'; INC(next);
+ fontspec[next] := 'm'; INC(next);
+ ELSE
+ fontspeclen := maxfontspec;
+ RETURN; (* fontspec truncated *)
+ END;
+ fontspeclen := next;
+ (* SYSDEP: terminate fontspec with NULL *)
+ IF fontspeclen < maxfontspec THEN fontspec[fontspeclen] := NULL END;
+ Open(f,fontspec,FALSE); (* SYSDEP: try to open for reading *)
+ IF Done() THEN
+ Close(f);
+ fontexists := TRUE; (* fontspec exists *)
+ END;
+END;
+END BuildTFMSpec;
+
+(******************************************************************************)
+
+PROCEDURE OldFontSpec (fontptr : fontinfoptr;
+ next : CARDINAL;
+ fontsizelen : CARDINAL;
+ VAR firstn : CARDINAL) : BOOLEAN;
+
+(* Return TRUE if we can append "[n...n]fontname.fmt" to fontspec.
+ Such a scheme is used in old TeX distributions from Kellerman and Smith.
+*)
+
+VAR i : CARDINAL;
+
+BEGIN
+WITH fontptr^ DO
+ firstn := next + 1; (* position of 1st n *)
+ IF next + fontsizelen + 1 < maxfontspec THEN (* append [n...n] *)
+ fontspec[next] := '[';
+ INC(next,fontsizelen + 1); (* skip n...n *)
+ fontspec[next] := ']';
+ INC(next);
+ ELSE
+ fontspeclen := maxfontspec;
+ RETURN FALSE; (* fontspec truncated *)
+ END;
+ i := 0;
+ WHILE (i < fontnamelen) AND (next < maxfontspec) DO
+ fontspec[next] := fontname[i]; (* append fontname *)
+ INC(i);
+ INC(next);
+ END;
+ IF next + formatlen < maxfontspec THEN (* append .fmt *)
+ fontspec[next] := '.'; INC(next);
+ i := 0;
+ REPEAT
+ fontspec[next] := formatstr[i];
+ INC(i);
+ INC(next);
+ UNTIL i = formatlen;
+ ELSE
+ fontspeclen := maxfontspec;
+ RETURN FALSE; (* fontspec truncated *)
+ END;
+ fontspeclen := next;
+ (* SYSDEP: terminate fontspec with NULL *)
+ IF fontspeclen < maxfontspec THEN fontspec[fontspeclen] := NULL END;
+ RETURN TRUE;
+END;
+END OldFontSpec;
+
+(******************************************************************************)
+
+PROCEDURE NewFontSpec (fontptr : fontinfoptr;
+ next : CARDINAL;
+ fontsizelen : CARDINAL;
+ VAR firstn : CARDINAL) : BOOLEAN;
+
+(* Return TRUE if we can append "fontname.n...nfmt" to fontspec.
+ Such a scheme is used in the latest TeX distributions.
+*)
+
+VAR i : CARDINAL;
+
+BEGIN
+WITH fontptr^ DO
+ i := 0;
+ WHILE (i < fontnamelen) AND (next < maxfontspec) DO
+ fontspec[next] := fontname[i]; (* append fontname *)
+ INC(i);
+ INC(next);
+ END;
+ firstn := next + 1; (* position of 1st n *)
+ IF next + fontsizelen + formatlen < maxfontspec THEN (* append .n...nfmt *)
+ fontspec[next] := '.';
+ INC(next,fontsizelen + 1); (* skip n...n *)
+ i := 0;
+ REPEAT
+ fontspec[next] := formatstr[i];
+ INC(i);
+ INC(next);
+ UNTIL i = formatlen;
+ ELSE
+ fontspeclen := maxfontspec;
+ RETURN FALSE; (* fontspec truncated *)
+ END;
+ fontspeclen := next;
+ (* SYSDEP: terminate fontspec with NULL *)
+ IF fontspeclen < maxfontspec THEN fontspec[fontspeclen] := NULL END;
+ RETURN TRUE;
+END;
+END NewFontSpec;
+
+(******************************************************************************)
+
+PROCEDURE OpenFontFile (VAR fspec : ARRAY OF CHAR) : BOOLEAN;
+
+(* Return TRUE iff given file can be opened and mapped into virtual memory. *)
+
+BEGIN
+InitFab(fab); (* initialize fab *)
+WITH fab DO
+ FNA := ADR(fspec); (* file specification *)
+ FNS := BYTE(LEN(fspec)); (* bytes in file name *)
+ FAC := FACset{FAC$BRO,FAC$GET}; (* read-only *)
+ SHR := SHRset{SHR$GET}; (* share file with other readers *)
+ FOP := FOPset{FOP$UFO}; (* need for SYS$CRMPSC *)
+ RTV := BYTE(-1); (* for more efficient mapping *)
+END;
+status := SYS$OPEN(ADR(fab),0,0); (* open the file *)
+IF ODD(status) THEN
+ channel := fab.STV; (* channel on which file is open *)
+ vas[0] := 0;
+ vas[1] := 0;
+ status := SYS$CRMPSC (* map file into virtual address space *)
+ (ADR(vas), (* starting and ending addresses *)
+ ADR(vas), (* addresses returned *)
+ 0,
+ {SEC$V_EXPREG}, (* pages mapped into 1st available space *)
+ gsdnam,0,0,
+ channel, (* channel on which file has been opened *)
+ 0,0,0,
+ 16 (* page fault cluster size *)
+ );
+ IF NOT ODD(status) THEN
+ (* DEBUG
+ WriteString('SYS$CRMPSC failed in OpenFontFile! status=');
+ WriteCard(status); WriteLn; Halt(2);
+ GUBED *)
+ RETURN FALSE;
+ ELSE
+ (* The entire file is mapped into virtual memory so we can
+ access any byte as an offset from the address in vas[0].
+ *)
+ filestart := vas[0];
+ RETURN TRUE;
+ END;
+ELSE
+ RETURN FALSE;
+END;
+END OpenFontFile;
+
+(******************************************************************************)
+
+(* Here are the functions used to get byte/s from fontfile. *)
+
+PROCEDURE GetByte () : CARDINAL;
+
+(* Return the value (unsigned) of the byte at byteoffset in fontfile and
+ advance byteoffset for the next GetByte.
+*)
+
+VAR b : CARDINAL;
+
+BEGIN
+b := CARDINAL(filestart^[byteoffset]); INC(byteoffset);
+RETURN b;
+END GetByte;
+
+(******************************************************************************)
+
+PROCEDURE SignedByte () : INTEGER;
+
+(* Return the next byte, possibly signed. *)
+
+VAR b : CARDINAL;
+
+BEGIN
+b := CARDINAL(filestart^[byteoffset]); INC(byteoffset);
+IF b < 128 THEN
+ RETURN b;
+ELSE
+ RETURN b - 256;
+END;
+END SignedByte;
+
+(******************************************************************************)
+
+PROCEDURE GetTwoBytes () : CARDINAL;
+
+(* Return the next 2 bytes, unsigned. *)
+
+VAR a, b : CARDINAL;
+
+BEGIN
+a := CARDINAL(filestart^[byteoffset]); INC(byteoffset);
+b := CARDINAL(filestart^[byteoffset]); INC(byteoffset);
+RETURN a * 256 + b;
+END GetTwoBytes;
+
+(******************************************************************************)
+
+PROCEDURE SignedPair () : INTEGER;
+
+(* Return the next 2 bytes, possibly signed. *)
+
+VAR a, b : CARDINAL;
+
+BEGIN
+a := CARDINAL(filestart^[byteoffset]); INC(byteoffset);
+b := CARDINAL(filestart^[byteoffset]); INC(byteoffset);
+IF a < 128 THEN
+ RETURN a * 256 + b;
+ELSE
+ RETURN (a - 256) * 256 + b;
+END;
+END SignedPair;
+
+(******************************************************************************)
+
+PROCEDURE GetThreeBytes () : CARDINAL;
+
+(* Return the next 3 bytes, unsigned. *)
+
+VAR a, b, c : CARDINAL;
+
+BEGIN
+a := CARDINAL(filestart^[byteoffset]); INC(byteoffset);
+b := CARDINAL(filestart^[byteoffset]); INC(byteoffset);
+c := CARDINAL(filestart^[byteoffset]); INC(byteoffset);
+RETURN (a * 256 + b) * 256 + c;
+END GetThreeBytes;
+
+(******************************************************************************)
+
+PROCEDURE SignedQuad () : INTEGER;
+
+(* Return the value (possibly signed) of the 4 bytes at byteoffset and
+ advance byteoffset by 4.
+*)
+
+VAR overlay : RECORD
+ CASE :BOOLEAN OF
+ TRUE : i : INTEGER |
+ FALSE : a,b,c,d : BYTE
+ END;
+ END;
+
+BEGIN
+WITH overlay DO
+ (* SYSDEP: on a VAX, d is at least significant end of word *)
+ d := filestart^[byteoffset]; INC(byteoffset);
+ c := filestart^[byteoffset]; INC(byteoffset);
+ b := filestart^[byteoffset]; INC(byteoffset);
+ a := filestart^[byteoffset]; INC(byteoffset);
+ RETURN i;
+END;
+END SignedQuad;
+
+(******************************************************************************)
+
+PROCEDURE CloseFontFile;
+
+(* Close the currently open font file. *)
+
+BEGIN
+status := SYS$DELTVA(ADR(vas),ADR(vas),0);
+IF NOT ODD(status) THEN
+ (* DEBUG
+ WriteString('SYS$DELTVA failed in CloseFontFile! status=');
+ WriteCard(status); WriteLn; Halt(2);
+ GUBED *)
+END;
+status := SYS$DASSGN(channel);
+IF NOT ODD(status) THEN
+ (* DEBUG
+ WriteString('SYS$DASSGN failed in CloseFontFile! status=');
+ WriteCard(status); WriteLn; Halt(2);
+ GUBED *)
+END;
+END CloseFontFile;
+
+(******************************************************************************)
+(* Here are the routines for reading PXL files: *)
+(******************************************************************************)
+
+PROCEDURE PXLFillPixelTable;
+
+(* Fill the pixeltable for currfont^ using the font directory info
+ in the currently open PXL file.
+*)
+
+VAR i, b0, b1, b2, b3 : CARDINAL; (* 4 bytes in TFM width *)
+
+BEGIN
+WITH currfont^ DO
+ IF psfont AND fontexists THEN
+ TFMFillPixelTable; (* use TFM file instead *)
+ RETURN;
+ END;
+ (* to find font directory we first move to last byte in PXL file *)
+ byteoffset := CARDINAL(ADDRESS(vas[1]) - ADDRESS(filestart));
+ (* skip back over any 0 bytes *)
+ WHILE (byteoffset > 0) AND (CARDINAL(filestart^[byteoffset]) = 0) DO
+ DEC(byteoffset);
+ END;
+ (* move to byte at start of last non-zero word *)
+ WHILE byteoffset MOD 4 <> 0 DO
+ DEC(byteoffset);
+ END;
+ IF SignedQuad() <> 1001 THEN
+ WriteLn;
+ WriteString('Bad PXL file! id word <> 1001.');
+ WriteLn; Halt(2);
+ END;
+ DEC(byteoffset,4); (* SignedQuad will have added 4 *)
+ DEC(byteoffset,516 * 4); (* starting byte of font directory *)
+ FOR i := 128 TO maxTeXchar DO
+ pixelptr^[i].mapadr := 0; (* PXL files only have 128 chars *)
+ pixelptr^[i].loaded := FALSE;
+ END;
+ FOR i := 0 TO 127 DO
+ WITH pixelptr^[i] DO
+ wd := GetTwoBytes();
+ ht := GetTwoBytes();
+ xo := SignedPair();
+ yo := SignedPair();
+ loaded := FALSE; (* bitmap not yet downloaded *)
+ mapadr := SignedQuad(); (* word offset in PXL file *)
+ IF (wd = 0) OR (ht = 0) THEN
+ mapadr := 0; (* in case PXL file is incorrect *)
+ END;
+ b0 := GetByte(); (* should be 0 or 255 *)
+ b1 := GetByte();
+ b2 := GetByte();
+ b3 := GetByte();
+ dwidth := FixToDVI(b0,b1,b2,b3);
+ pwidth := PixelRound(dwidth); (* convert DVI units to pixels *)
+ END;
+ END;
+END;
+END PXLFillPixelTable;
+
+(******************************************************************************)
+
+PROCEDURE FixToDVI (b0, b1, b2, b3 : CARDINAL) : INTEGER;
+
+(* Convert the given fixword (made up of 4 bytes) into DVI units
+ using the method recommended in DVITYPE.
+*)
+
+VAR alpha, beta, s : CARDINAL; temp : INTEGER;
+
+BEGIN
+s := currfont^.scaledsize; (* so we don't change scaledsize! *)
+alpha := 16 * s;
+beta := 16;
+WHILE s >= 40000000B DO (* 2^23sp = 128pt *)
+ s := s DIV 2;
+ beta := beta DIV 2;
+END;
+temp := (((((b3 * s) DIV 400B) + (b2 * s)) DIV 400B) + (b1 * s)) DIV beta;
+IF b0 > 0 THEN
+ IF b0 = 255 THEN
+ RETURN temp - INTEGER(alpha);
+ ELSE
+ WriteLn;
+ WriteString('Bad fixword! 1st byte='); WriteCard(b0);
+ WriteLn; Halt(2);
+ END;
+ELSE
+ RETURN temp;
+END;
+END FixToDVI;
+
+(******************************************************************************)
+
+PROCEDURE PXLLoadBitmap (fontptr : fontinfoptr; code : CARDINAL);
+
+(* Download bitmap using raster information starting at mapadr
+ in currently open PXL file.
+*)
+
+VAR b, r, thisbyte, bytesperrow, usedperrow, charsperline : CARDINAL;
+
+BEGIN
+WITH fontptr^.pixelptr^[code] DO
+bytesperrow := ((wd + 31) DIV 32) * 4; (* words per row * 4 *)
+usedperrow := (wd + 7) DIV 8; (* not all bytes might be needed *)
+charsperline := 0;
+PutString('[<');
+(* output (ht * usedperrow * 2) hex digits, starting at top row of bitmap *)
+byteoffset := mapadr * 4; (* mapadr = word offset *)
+b := 0; (* byte count for one row *)
+r := 0; (* row count *)
+LOOP
+ INC(charsperline,2);
+ IF charsperline >= 72 THEN
+ Put(CR);
+ charsperline := 0;
+ END;
+ thisbyte := GetByte(); (* and increment byteoffset *)
+ Put(hexdigs[ thisbyte DIV 16 ]);
+ Put(hexdigs[ thisbyte MOD 16 ]);
+ INC(b);
+ IF b = usedperrow THEN
+ INC(r);
+ IF r = CARDINAL(ht) THEN EXIT END;
+ INC(byteoffset,bytesperrow - b); (* move to start of next row *)
+ b := 0; (* reset byte count *)
+ END;
+END;
+Put('>'); Put(CR);
+PutCard(usedperrow * 8); Put(' ');
+PutInt(ht); Put(' ');
+PutInt(xo); Put(' ');
+PutInt(yo); Put(' '); (* offset of origin from top row *)
+PutInt(pwidth);
+PutString('] ');
+PutCard(code);
+PutString(' dc'); Put(CR);
+END; (* WITH *)
+END PXLLoadBitmap;
+
+(******************************************************************************)
+(* Here are the routines for reading PK files: *)
+(******************************************************************************)
+
+PROCEDURE PKFillPixelTable;
+
+(* Fill the pixeltable for currfont^ using the font directory info
+ in the currently open PK file.
+*)
+
+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 : CARDINAL; (* 4 bytes in TFM width *)
+
+BEGIN
+WITH currfont^ DO
+ IF psfont AND fontexists THEN
+ TFMFillPixelTable; (* use TFM file instead *)
+ RETURN;
+ END;
+ byteoffset := 0; (* move to first byte *)
+ IF GetByte() <> pkpre THEN
+ WriteLn;
+ WriteString('Bad pre command in ');
+ WriteString(fontspec); WriteLn; Halt(2);
+ END;
+ IF GetByte() <> pkid THEN
+ WriteLn;
+ WriteString('Bad id byte in ');
+ WriteString(fontspec); WriteLn; Halt(2);
+ END;
+ j := GetByte(); (* length of comment *)
+ INC(byteoffset,j + 16); (* skip rest of preamble *)
+ FOR i := 0 TO maxTeXchar DO
+ WITH pixelptr^[i] DO
+ mapadr := 0; (* all chars absent initially *)
+ loaded := FALSE; (* bitmap not yet downloaded *)
+ END;
+ END;
+ LOOP
+ flagpos := byteoffset; (* remember position of flagbyte *)
+ flagbyte := GetByte();
+ IF flagbyte < 240 THEN (* read character definition *)
+ flagbyte := flagbyte MOD 8; (* value of bottom 3 bits *)
+ IF flagbyte < 4 THEN (* short char preamble *)
+ packetlen := flagbyte * 256 + GetByte();
+ chcode := GetByte();
+ endofpacket := packetlen + byteoffset;
+ WITH pixelptr^[chcode] DO
+ b1 := GetByte();
+ b2 := GetByte();
+ b3 := GetByte();
+ dwidth := FixToDVI(0,b1,b2,b3); (* b0 = 0 *)
+ pwidth := GetByte();
+ wd := GetByte();
+ ht := GetByte();
+ xo := SignedByte();
+ yo := SignedByte();
+ END;
+ ELSIF flagbyte < 7 THEN (* extended short char preamble *)
+ packetlen := (flagbyte - 4) * 65536 + GetTwoBytes();
+ chcode := GetByte();
+ endofpacket := packetlen + byteoffset;
+ WITH pixelptr^[chcode] DO
+ b1 := GetByte();
+ b2 := GetByte();
+ b3 := GetByte();
+ dwidth := FixToDVI(0,b1,b2,b3); (* b0 = 0 *)
+ pwidth := GetTwoBytes();
+ wd := GetTwoBytes();
+ ht := GetTwoBytes();
+ xo := SignedPair();
+ yo := SignedPair();
+ END;
+ ELSE (* long char preamble *)
+ packetlen := SignedQuad();
+ chcode := SignedQuad();
+ endofpacket := packetlen + byteoffset;
+ WITH pixelptr^[chcode] DO
+ b0 := GetByte();
+ b1 := GetByte();
+ b2 := GetByte();
+ b3 := GetByte();
+ dwidth := FixToDVI(b0,b1,b2,b3);
+ pwidth := SignedQuad() DIV 65536; (* dx in pixels *)
+ INC(byteoffset,4); (* skip dy *)
+ wd := SignedQuad();
+ ht := SignedQuad();
+ xo := SignedQuad();
+ yo := SignedQuad();
+ END;
+ END;
+ WITH pixelptr^[chcode] DO
+ IF (wd = 0) OR (ht = 0) THEN
+ mapadr := 0; (* no bitmap *)
+ ELSE
+ mapadr := flagpos; (* position of flagbyte *)
+ END;
+ END;
+ byteoffset := endofpacket; (* skip raster info *)
+ ELSE
+ CASE flagbyte OF
+ 240..243 : i := 0;
+ FOR j := 240 TO flagbyte DO i := 256 * i + GetByte() END;
+ INC(byteoffset,i); (* skip special parameter *)
+ | 244 : INC(byteoffset,4); (* skip numspecial parameter *)
+ | pknoop : (* do nothing *)
+ | pkpost : EXIT; (* no more character definitions *)
+ ELSE
+ WriteLn;
+ WriteString('Bad flag byte in ');
+ WriteString(fontspec); WriteLn; Halt(2);
+ END;
+ END;
+ END; (* LOOP; flagbyte = pkpost *)
+END;
+END PKFillPixelTable;
+
+(******************************************************************************)
+
+(* Routines to unpack raster info need some global variables: *)
+
+VAR
+ turnon : BOOLEAN; (* is current run black? *)
+ dynf, (* dynamic packing variable *)
+ repeatcount, (* how many times to repeat the next row *)
+ inputbyte, (* the current input byte *)
+ bitweight : CARDINAL; (* for getting bits or nybbles from inputbyte *)
+
+(******************************************************************************)
+
+PROCEDURE PKLoadBitmap (fontptr : fontinfoptr; code : CARDINAL);
+
+(* Download bitmap using information from character definition at mapadr
+ in currently open PK file.
+*)
+
+VAR i, j, flagbyte, bitpos, bytesperrow,
+ rowsleft, hbit, count, rp, charsperline : CARDINAL;
+ byte : BITSET;
+ row : ARRAY [0..400] OF BYTE; (* SYSDEP: max glyph width = 3200 bits *)
+
+BEGIN
+WITH fontptr^.pixelptr^[code] DO
+bytesperrow := (wd + 7) DIV 8; (* bytes in one row *)
+byteoffset := mapadr; (* mapadr = flagbyte offset in PK file *)
+flagbyte := GetByte(); (* 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 *)
+ INC(byteoffset,10);
+ELSIF flagbyte < 7 THEN (* skip extended short char preamble *)
+ INC(byteoffset,16);
+ELSE (* skip long char preamble *)
+ INC(byteoffset,36);
+END;
+charsperline := 0;
+PutString('[<'); (* start of hex string *)
+bitweight := 0; (* to get 1st inputbyte *)
+IF dynf = 14 THEN
+ (* raster info is a string of bits in the next (wd * ht + 7) DIV 8 bytes *)
+ FOR i := 1 TO CARDINAL(ht) DO
+ byte := {}; (* set all bits to 0 *)
+ bitpos := 7; (* leftmost bit *)
+ FOR j := 1 TO CARDINAL(wd) DO
+ IF bitweight = 0 THEN
+ (* next 2 lines equal inputbyte := GetByte(); *)
+ inputbyte := CARDINAL(filestart^[byteoffset]);
+ INC(byteoffset);
+ bitweight := 8;
+ END;
+ DEC(bitweight); (* 7..0 *)
+ IF bitweight IN BITSET(inputbyte) THEN
+ INCL(byte,bitpos); (* set bit *)
+ END;
+ IF bitpos > 0 THEN
+ DEC(bitpos); (* next bit *)
+ ELSE
+ INC(charsperline,2);
+ IF charsperline >= 72 THEN
+ Put(CR);
+ charsperline := 0;
+ END;
+ Put(hexdigs[ CARDINAL(byte) DIV 16 ]); (* high nybble *)
+ Put(hexdigs[ CARDINAL(byte) MOD 16 ]); (* low nybble *)
+ byte := {};
+ bitpos := 7;
+ END;
+ END;
+ IF bitpos < 7 THEN
+ INC(charsperline,2);
+ IF charsperline >= 72 THEN
+ Put(CR);
+ charsperline := 0;
+ END;
+ Put(hexdigs[ CARDINAL(byte) DIV 16 ]);
+ Put(hexdigs[ CARDINAL(byte) MOD 16 ]);
+ END;
+ END;
+ELSE
+ (* raster info is encoded as run and repeat counts *)
+ rowsleft := ht;
+ hbit := wd;
+ repeatcount := 0;
+ rp := 1;
+ bitpos := 8;
+ byte := {};
+ WHILE rowsleft > 0 DO
+ count := PackedNum();
+ WHILE count > 0 DO
+ IF (count < bitpos) AND (count < hbit) THEN
+ IF turnon THEN
+ byte := byte + gpower[bitpos] - gpower[bitpos - count];
+ END;
+ DEC(hbit,count);
+ DEC(bitpos,count);
+ count := 0;
+ ELSIF (count >= hbit) AND (hbit <= bitpos) THEN
+ IF turnon THEN
+ byte := byte + gpower[bitpos] - gpower[bitpos - hbit];
+ END;
+ row[rp] := BYTE(byte);
+ (* end of current row, so send it repeatcount+1 times *)
+ FOR i := 0 TO repeatcount DO
+ FOR j := 1 TO bytesperrow DO
+ INC(charsperline,2);
+ IF charsperline >= 72 THEN
+ Put(CR);
+ charsperline := 0;
+ END;
+ Put(hexdigs[ CARDINAL(row[j]) DIV 16 ]);
+ Put(hexdigs[ CARDINAL(row[j]) MOD 16 ]);
+ END;
+ END;
+ DEC(rowsleft,repeatcount + 1);
+ repeatcount := 0;
+ rp := 1;
+ byte := {};
+ bitpos := 8;
+ DEC(count,hbit);
+ hbit := wd;
+ ELSE
+ IF turnon THEN byte := byte + gpower[bitpos] END;
+ row[rp] := BYTE(byte);
+ INC(rp); (* we assume rp never overflows! *)
+ byte := {};
+ DEC(count,bitpos);
+ DEC(hbit,bitpos);
+ bitpos := 8;
+ END;
+ END;
+ turnon := NOT turnon;
+ END;
+END;
+Put('>'); Put(CR);
+PutCard(bytesperrow * 8); Put(' ');
+PutInt(ht); Put(' ');
+PutInt(xo); Put(' ');
+PutInt(yo); Put(' '); (* offset of origin from top row *)
+PutInt(pwidth);
+PutString('] ');
+PutCard(code);
+PutString(' dc'); Put(CR);
+END; (* WITH *)
+END PKLoadBitmap;
+
+(******************************************************************************)
+
+PROCEDURE PackedNum () : CARDINAL;
+
+(* 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 : CARDINAL;
+
+BEGIN
+i := GetNyb();
+IF i = 0 THEN
+ REPEAT j := GetNyb(); INC(i) UNTIL j <> 0;
+ WHILE i > 0 DO j := j * 16 + GetNyb(); DEC(i) END;
+ RETURN j - 15 + (13 - dynf) * 16 + dynf;
+ELSIF i <= dynf THEN
+ RETURN i;
+ELSIF i < 14 THEN
+ RETURN (i - dynf - 1) * 16 + GetNyb() + dynf + 1;
+ELSE
+ IF i = 14 THEN
+ repeatcount := PackedNum(); (* recursive *)
+ ELSE
+ repeatcount := 1; (* nybble = 15 *)
+ END;
+ RETURN PackedNum(); (* recursive *)
+END;
+END PackedNum;
+
+(******************************************************************************)
+
+PROCEDURE GetNyb () : CARDINAL;
+
+(* Return next nybble in PK file. *)
+
+BEGIN
+IF bitweight = 0 THEN
+ (* next 2 lines equal inputbyte := GetByte(); *)
+ inputbyte := CARDINAL(filestart^[byteoffset]);
+ INC(byteoffset);
+ bitweight := 16; (* for next call of GetNyb *)
+ RETURN inputbyte DIV 16; (* high nybble *)
+ELSE
+ bitweight := 0; (* for next call of GetNyb *)
+ RETURN inputbyte MOD 16; (* low nybble *)
+END;
+END GetNyb;
+
+(******************************************************************************)
+(* Here are the declarations and routines for reading TFM files: *)
+(******************************************************************************)
+
+VAR
+ lf, lh, bc, ec, nw, nh : INTEGER;
+ charinfo : ARRAY [0..255] OF
+ RECORD
+ wdindex, htindex, dpindex : INTEGER;
+ END;
+ charmetrics : ARRAY [0..255] OF
+ RECORD
+ (* 4 bytes making up fixword *)
+ width, height, depth : ARRAY [0..3] OF INTEGER;
+ END;
+
+(******************************************************************************)
+
+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 charinfo array *)
+ReadTFMCharMetrics; (* fill charmetrics array *)
+WITH currfont^ DO
+ FOR c := 0 TO bc - 1 DO
+ pixelptr^[c].mapadr := 0; (* chars < bc don't exist *)
+ END;
+ FOR c := ec + 1 TO 255 DO
+ pixelptr^[c].mapadr := 0; (* chars > ec don't exist *)
+ END;
+ FOR c := bc TO ec DO
+ WITH pixelptr^[c] DO
+ WITH charmetrics[c] DO
+ 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;
+ DEC(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 *)
+ END;
+ loaded := FALSE; (* no bitmap available *)
+ END;
+ END;
+ END;
+END;
+END TFMFillPixelTable;
+
+(******************************************************************************)
+
+PROCEDURE ReadTFMIntegers;
+
+(* Read the first 6 16-bit integers in the TFM file. See TFtoPL section 8. *)
+
+BEGIN
+byteoffset := 0; (* start reading at 1st byte in TFM file *)
+lf := GetTwoBytes();
+lh := GetTwoBytes();
+bc := GetTwoBytes();
+ec := GetTwoBytes();
+nw := GetTwoBytes();
+nh := GetTwoBytes();
+END ReadTFMIntegers;
+
+(******************************************************************************)
+
+PROCEDURE ReadTFMCharInfo;
+
+(* Read the charinfo array. See TFtoPL section 11. *)
+
+VAR c, i : INTEGER;
+
+BEGIN
+byteoffset := 24 + (lh * 4); (* offset of charinfo array *)
+FOR c := bc TO ec DO
+ WITH charinfo[c] DO
+ wdindex := GetByte() * 4; (* offset from start of width array *)
+ i := GetByte(); (* 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 *)
+ INC(byteoffset,2); (* skip itindex and remainder bytes *)
+ END;
+END;
+END ReadTFMCharInfo;
+
+(******************************************************************************)
+
+PROCEDURE ReadTFMCharMetrics;
+
+(* Read the charmetrics array using the indices in charinfo. *)
+
+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 charinfo[c] DO
+ WITH charmetrics[c] DO
+ byteoffset := wdbase + wdindex;
+ FOR b := 0 TO 3 DO width[b] := GetByte() END;
+ byteoffset := htbase + htindex;
+ FOR b := 0 TO 3 DO height[b] := GetByte() END;
+ byteoffset := dpbase + dpindex;
+ FOR b := 0 TO 3 DO depth[b] := GetByte() END;
+ END;
+ END;
+END;
+END ReadTFMCharMetrics;
+
+(******************************************************************************)
+
+BEGIN
+END FontReader.
diff --git a/dviware/psprint/vms/global.ps b/dviware/psprint/vms/global.ps
new file mode 100644
index 0000000000..ed026888ee
--- /dev/null
+++ b/dviware/psprint/vms/global.ps
@@ -0,0 +1,18 @@
+% When printing a DVI file, PSPRINT looks for a file called GLOBAL.PS
+% in your current directory and appends it to the PostScript prologue.
+% Copy this file to your current directory and uncomment the following
+% example code to print "DRAFT" in the same location on every DVI page.
+
+% /@bop0 % redefine @bop0 (see TEX_PS:TEX.PS)
+% { pop % throw away page number
+% /mysave save def
+% gsave
+% initgraphics % use PostScript's default coordinates
+% /Helvetica-Bold findfont
+% 72 scalefont setfont
+% 36 36 moveto
+% 0.95 setgray
+% (DRAFT) show
+% grestore
+% mysave restore
+% } def
diff --git a/dviware/psprint/vms/greybox.ps b/dviware/psprint/vms/greybox.ps
new file mode 100644
index 0000000000..220564810a
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/info.ps b/dviware/psprint/vms/info.ps
new file mode 100644
index 0000000000..86b4b82b27
--- /dev/null
+++ b/dviware/psprint/vms/info.ps
@@ -0,0 +1,99 @@
+% Print page showing various status values.
+
+/oldusertime usertime def
+
+initgraphics
+72 0 translate % move origin to the right
+/vpos 720 def % initial vertical pos
+0 vpos moveto % start near top left corner
+
+/str 12 string def
+
+/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
+ 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 str cvs show newline
+ (DISK STATUS = ) show str cvs show
+ ( ) show str cvs show newline
+ (USER DISK % = ) show str cvs show newline
+} if
+
+(PRODUCT = ) show show newline
+(REVISION = ) show str cvs show newline
+(VERSION = ) show version show newline
+
+version cvr 25.0 gt % PS version >= 25.0 ?
+{
+ newline
+ currentpacking % bool
+ (CURRENT PACKING = ) show
+ str cvs show newline
+
+ newline
+ currentcacheparams % mark lower upper
+ (CURRENT CACHE PARAMS) show newline
+ counttomark
+ { str cvs show newline }
+ repeat
+ pop % remove mark
+} if
+
+newline
+(DEFAULTMATRIX = ) show
+matrix defaultmatrix % [ ? ? ? ? ? ? ]
+dup 0 get str cvs show ( ) show
+dup 1 get str cvs show ( ) show
+dup 2 get str cvs show ( ) show
+dup 3 get str cvs show ( ) show
+dup 4 get str cvs show ( ) show
+dup 5 get str cvs show ( ) show
+newline
+pop
+
+newline
+currentscreen pop % freq angle proc
+(CURRENT ANGLE = ) show str cvs show newline
+(CURRENT FREQUENCY = ) show str cvs show newline
+
+newline
+(CACHE STATUS) show newline
+cachestatus % bsize bmax msize mmax csize cmax blimit
+(blimit = ) show str cvs show newline
+(cmax = ) show str cvs show newline
+(csize = ) show str cvs show newline
+(mmax = ) show str cvs show newline
+(msize = ) show str cvs show newline
+(bmax = ) show str cvs show newline
+(bsize = ) show str cvs show newline
+
+newline
+(VM STATUS) show newline
+vmstatus % savelevel vmused vmmax
+(vm max = ) show str cvs show newline
+(vm used = ) show str cvs show newline
+(save level = ) show str cvs show newline
+
+newline
+(JOB TIME (secs) = ) show
+usertime oldusertime sub 1000 div str cvs show newline
+
+showpage
diff --git a/dviware/psprint/vms/install.com b/dviware/psprint/vms/install.com
new file mode 100644
index 0000000000..fcac389a4d
--- /dev/null
+++ b/dviware/psprint/vms/install.com
@@ -0,0 +1,37 @@
+$! READ THE PSPRINT USER AND SYSTEM GUIDES FIRST.
+$! Before running this command file you may want to make some changes.
+$! See the "CHANGE" comments below.
+$! Some of the steps may need to be copied to SYS$MANAGER:SYSTARTUP.COM,
+$! depending on how you want to set up the PSPRINT and PSDVI commands.
+$
+$! Terminal characteristics for serial line to LaserWriter/Linotronic:
+$
+$ set proc/priv=log_io
+$ set terminal/permanent/fulldup/speed=9600 -
+ /nohang/notype_ahead/nobroad/nomodem/noecho/pasthru/noform/nowrap -
+ TXD6: ! CHANGE device!?
+$
+$! Define the postscript form for LaserWriter/Linotronic:
+$
+$ define/form postscript 30 - ! CHANGE number!? (must be unique)
+ /description="Default for PostScript device" -
+ /notruncate/nowrap ! prevents spurious newline characters
+$
+$! Initialize the print queue for LaserWriter/Linotronic:
+$
+$ init/queue/form=postscript/default=(nofeed,form=postscript) -
+ /prot=(s:wred,g:rw,w:rw)/on=TXD6: QNAME ! CHANGE device and queue!?
+$
+$! Make sure you turn on the LaserWriter/Linotronic BEFORE starting the queue,
+$! otherwise pending jobs will just disappear.
+$
+$! Define TEX_PS and set up the PSPRINT & PSDVI commands:
+$
+$ def/sys tex_ps TEX_DISK:[TEX.PS] ! CHANGE directory!?
+$ set command /tables=sys$library:dcltables /output=sys$library:dcltables -
+ TEX_PS:PSPRINT.CLD, TEX_PS:PSDVI.CLD ! CHANGE qualifier defaults!?
+$ set proc/priv=cmkrnl
+$ run sys$system:install
+sys$library:dcltables/replace
+/exit
+$ exit
diff --git a/dviware/psprint/vms/laserprep65.ps b/dviware/psprint/vms/laserprep65.ps
new file mode 100644
index 0000000000..53a4584d7f
--- /dev/null
+++ b/dviware/psprint/vms/laserprep65.ps
@@ -0,0 +1,450 @@
+% When printing a document on a PostScript printer, most Macintosh applications
+% will dump their PostScript code into a file called PostScript0 if you press
+% Command-F immediately after selecting OK in the Print dialogue box.
+% The PostScript code relies on definitions stored in a Mac system file called
+% Laser Prep. A modified version of Laser Prep (like the one you're reading)
+% must be included with PSPRINT's /PREP qualifier if you want to send
+% Command-F files via DVI \special commands.
+%
+% Since Apple keep changing Laser Prep, you might need to create your own
+% modified version some day. Here's how:
+% 1. Use a Mac application (such as MacWrite) to create a very small document.
+% 2. Print it, but immediately after selecting OK hold down Command-K.
+% Instead of printing the document, you should get a file called PostScript0
+% which contains Laser Prep prefixed to the Command-F code.
+% 3. Open the file with a text editor and remove the Command-F code by finding
+% the first occurrence of %%EOF and deleting everything below it.
+% 4. Duplicate the changes I've made to this file (search for %AKT).
+% 5. It's probably a good idea to rename PostScript0 to LaserPrepxx.ps where
+% xx is the version number appearing in comments at the top of the file.
+% 6. Type "PSPRINT /PREP=LaserPrepxx.ps ..." with your fingers crossed.
+
+%%Title: "Laser Prep -- The Apple PostScript Dictionary (md)"
+%%Creator: Apple Software Engineering
+%%CreationDate: Thursday, March 19, 1987
+%{appledict version #65
+% CopyRight Apple Computer, Inc. 1984,1985,1986,1987 All Rights Reserved.
+%%EndComments
+%%BeginProcSet: "(AppleDict md)" 65 0
+systemdict/currentpacking known{currentpacking true setpacking}if
+/LW{save statusdict/product get(LaserWriter)anchorsearch
+exch pop{length 0 eq{1}{2}ifelse}{0}ifelse exch restore}bind def
+/LW+{LW 2 eq}bind def
+/ok{systemdict/statusdict known dup{LW 0 gt and}if}bind def
+
+%AKT ok{statusdict begin 9 sccinteractive 3 ne exch 0 ne or{9 0 3 setsccinteractive}if end}if
+
+/md 250 dict def md begin
+/av 65 def
+/T true def/F false def/mtx matrix def/s75 75 string def/s8 8 string def/s1 ( ) def/pxs 1 def/pys 1 def
+1 0 mtx defaultmatrix dtransform exch atan/pa exch def/nlw .24 def/ppr [-32 -29.52 762 582.48] def
+/pgs 1 def/por true def/xb 500 array def/so true def/fillflag false def/pnm 1 def/fmv true def
+/sfl false def/ma 0 def/invertflag false def/xflip false def/yflip false def/noflips true def/scaleby96 false def/fNote true def/fBitStretch true def
+/fg (Rvd\001\001\000\000\177) def
+/bdf{bind def}bind def
+/xdf{exch def}bdf
+/xl{neg exch neg translate}bdf
+/fp{pnsh 0 ne pnsv 0 ne and}bdf
+/nop{}bdf/lnop[/nop load]cvx bdf
+/vrb[
+{fp{gsave 1 setlinewidth pnsh pnsv scale stroke grestore}if newpath}bind
+/eofill load
+dup
+/newpath load
+2 index
+dup
+{clip newpath}bind
+{}bind
+dup
+2 copy
+]def
+currentscreen/spf xdf/rot xdf/freq xdf
+/doop{vrb exch get exec}bdf
+/psu{/fNote xdf/fBitStretch xdf/scaleby96 xdf/yflip xdf/xflip xdf/invertflag xdf xflip yflip or{/noflips false def}if
+/pgs xdf 2 index .72 mul exch div/pys xdf div .72 mul/pxs xdf ppr astore pop/por xdf sn and/so xdf}bdf
+/txpose{fNote{smalls}{bigs}ifelse pgs get exec pxs pys scale ppr aload pop por{noflips{pop exch neg exch translate pop 1 -1 scale}if
+xflip yflip and{pop exch neg exch translate 180 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg translate}if
+xflip yflip not and{pop exch neg exch translate pop 180 rotate ppr 3 get ppr 1 get neg sub neg 0 translate}if yflip xflip not and{ppr 1 get neg ppr 0 get neg translate}if}
+{noflips{translate pop pop 270 rotate 1 -1 scale}if xflip yflip and{translate pop pop 90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg translate}if
+xflip yflip not and{translate pop pop 90 rotate ppr 3 get ppr 1 get neg sub neg 0 translate}if yflip xflip not and{translate pop pop 270 rotate ppr 2 get ppr 0 get neg sub neg 0 exch translate}if}ifelse
+statusdict begin waittimeout 300 lt{/waittimeout 300 def}if end scaleby96{ppr aload pop 4 -1 roll add 2 div 3 1 roll add 2 div 2 copy translate .96 dup scale neg exch neg exch translate}if}bdf
+/fr{3 index 3 index xl ppr aload pop 3 -1 roll 2 mul add 3 1 roll exch 2 mul add
+6 2 roll 3 -1 roll sub 3 1 roll exch sub 3 1 roll exch 3 -1 roll div 3 1 roll div exch scale} bdf
+/lws{show}bdf
+/tv{show pop pop}bdf
+/obl{{0.212557 mul}{pop 0}ifelse}bdf
+/sfd{ps fg 5 -1 roll get mul 100 div 0 ps 5 -1 roll obl ps neg 0 0 6a astore makefont setfont}bdf
+/fnt{findfont sfd}bdf
+/bt{sa 3 1 roll 3 index and put}bdf
+/sa(\000\000\000\000\000\000\000\000\000\000)def
+/fs{0 1 bt 1 2 bt 2 4 bt 3 8 bt 4 16 bt 5 32 bt 6 64 bt 7 128 bt sa exch 8 exch put}bdf
+/mx1 matrix def
+/mx2 matrix def
+/mx3 matrix def
+/bu{currentpoint currentgray currentlinewidth currentlinecap currentlinejoin currentdash exch aload length
+fg 5 sfl{1}{0}ifelse put pnsv pnsh
+2t aload pop 3a aload pop mx2 aload pop mx1 aload pop mtx currentmatrix aload pop
+mx3 aload pop ps pm restore/ps xdf mx3 astore pop}bdf
+/bn{/pm save def mx3 setmatrix newpath 0 0 moveto ct dup 39 get 0 exch getinterval cvx exec
+mtx astore setmatrix mx1 astore pop mx2 astore pop 3a astore pop
+2t astore pop/pnsh xdf/pnsv xdf gw
+/sfl fg 5 get 0 ne def array astore exch setdash setlinejoin setlinecap
+setlinewidth setgray moveto}bdf
+/fc{save vmstatus exch sub 50000 lt
+{(%%[|0|]%%)=print flush}if pop restore}bdf
+/tc{32768 div add 3 1 roll 32768 div add 2t astore pop}bdf
+/3a [0 0 0] def
+/2t 2 array def
+/tp{3a astore pop}bdf
+/tt{mx2 currentmatrix pop currentpoint 2 copy 2t aload pop qa 2 copy translate 3a aload pop exch dup 0 eq
+{pop}{1 eq{-1 1}{1 -1}ifelse scale}ifelse rotate pop neg exch neg exch translate moveto}bdf
+/te{mx2 setmatrix}bdf
+/th{3 -1 roll div 3 1 roll exch div 2 copy mx1 scale pop scale/sfl true def}bdf
+/tu{1 1 mx1 itransform scale/sfl false def}bdf
+/ts{1 1 mx1 transform scale/sfl true def}bdf
+/fz{/ps xdf}bdf
+/dv{dup 0 ne{div}{pop}ifelse}bdf
+/pop4{pop pop pop pop}bdf
+/it{sfl{mx1 itransform}if}bdf
+/gm{exch it moveto}bdf/rm{it rmoveto}bdf
+/lm{currentpoint sfl{mx1 transform}if exch pop sub 0 exch it rmoveto}bdf
+/fm{statusdict/manualfeed known}bdf
+/se{statusdict exch/manualfeed exch put}bdf
+/mf
+{dup /ma exch def % Copy argument to /ma.
+ 0 gt % Eat argument and push boolean (arg > 0).
+ {fm se
+ /t1 5 st % Define value t1
+ ok ma 1 gt and
+ {/t2 0 st % Define value t2.
+ /t3 0 st % Define value t3.
+ statusdict /manualfeedtimeout 3600 put % Set timeout value.
+ } if
+ } if
+} bdf
+/jn {/statusdict where exch pop{statusdict exch /jobname exch put}if} bdf
+/pen{pnm mul/pnsh xdf pnm mul/pnsv xdf pnsh setlinewidth}bdf
+/min{2 copy gt{exch}if pop}bdf
+/max{2 copy lt{exch}if pop}bdf
+/dh{fg 6 1 put array astore exch pop exch pop exch setdash}bdf
+/ih[currentdash]def
+/rh{fg 6 0 put ih aload pop setdash}bdf
+/dl{gsave nlw pys div setlinewidth 0 setgray}bdf
+/dlin{exch currentpoint currentlinewidth 2 div dup
+translate newpath moveto lineto currentpoint stroke grestore moveto}bdf
+/lin{fg 6 get 0 ne{exch lineto currentpoint 0 doop moveto}
+{exch currentpoint/pnlv xdf/pnlh xdf gsave newpath/@1 xdf/@2 xdf fp{pnlh @2 lt{pnlv @1 ge
+{pnlh pnlv moveto @2 @1 lineto pnsh 0 rlineto
+0 pnsv rlineto pnlh pnsh add pnlv pnsv add lineto pnsh neg 0 rlineto}
+{pnlh pnlv moveto pnsh 0 rlineto @2 pnsh add @1 lineto 0 pnsv rlineto
+pnsh neg 0 rlineto pnlh pnlv pnsv add lineto}ifelse}{pnlv @1 gt
+{@2 @1 moveto pnsh 0 rlineto pnlh pnsh add pnlv lineto 0 pnsv rlineto
+pnsh neg 0 rlineto @2 @1 pnsv add lineto}{pnlh pnlv moveto pnsh 0 rlineto
+0 pnsv rlineto @2 pnsh add @1 pnsv add lineto pnsh neg 0 rlineto
+0 pnsv neg rlineto}ifelse}ifelse
+closepath fill}if @2 @1 grestore moveto}ifelse}bdf
+/gw{/pnm fg 3 get fg 4 get div def}bdf
+/lw{fg exch 4 exch put fg exch 3 exch put gw pnsv pnsh pen}bdf
+/barc{/@1 xdf/@2 xdf/@3 xdf/@4 xdf/@5 xdf
+/@6 xdf/@7 xdf/@8 xdf gsave
+@5 @7 add 2 div @6 @8 add 2 div translate newpath 0 0 moveto
+@5 @7 sub @6 @8 sub mtx currentmatrix pop scale @1{newpath}if
+0 0 0.5 @4 @3 arc @4 @3 sub abs 360 ge{closepath}if
+mtx setmatrix @2 doop grestore}bdf
+/ar{dup 0 eq barc}bdf
+/ov{0 exch 360 exch true barc}bdf
+/rc{/@t xdf currentpoint 6 2 roll newpath 4 copy 4 2 roll exch moveto
+6 -1 roll lineto lineto lineto closepath @t doop moveto}bdf
+/mup{dup pnsh 2 div le exch pnsv 2 div le or}bdf
+/rr{/@1 xdf 2. div/@2 xdf 2. div/@3 xdf
+/@4 xdf/@5 xdf/@6 xdf/@7 xdf
+@7 @5 eq @6 @4 eq @2 mup or or{@7 @6 @5 @4 @1 rc}
+{@4 @6 sub 2. div dup @2 lt{/@2 xdf}{pop}ifelse
+@5 @7 sub 2. div dup @2 lt{/@2 xdf}{pop}ifelse
+@1 0 eq{/@2 @2 pnsh 2 div 2 copy gt{sub def}{0 pop4}ifelse}if
+currentpoint newpath
+@4 @6 add 2. div @7 moveto
+@4 @7 @4 @5 @2 arcto pop4
+@4 @5 @6 @5 @2 arcto pop4
+@6 @5 @6 @7 @2 arcto pop4
+@6 @7 @4 @7 @2 arcto pop4
+closepath @1 doop moveto}ifelse}bdf
+/pr{gsave newpath/pl{exch moveto/pl{exch lineto}def}def}bdf
+/pl{exch lineto}bdf
+/ep{dup 0 eq{{moveto}{exch lin}{}{(%%[|1|]%%)= flush}pathforall
+pop grestore}{doop grestore}ifelse currentpoint newpath moveto}bdf
+/gr{64. div setgray}bdf
+/pat{s8 copy pop 9.375 pa por not{90 add}if{1 add 4 mul cvi s8 exch get exch 1 add 4 mul cvi 7 sub bitshift 1 and}setscreen gr}bdf
+/sg{freq rot/spf load setscreen gr}bdf
+/dc{transform round .5 sub exch round .5 sub exch itransform}bdf
+/sn{userdict/smooth4 known}bdf
+/x8{3 bitshift}bdf
+/x4{2 bitshift}bdf
+/d4{-2 bitshift}bdf
+/d8{-3 bitshift}bdf
+/rb{15 add -4 bitshift 1 bitshift}bdf
+/db{/@7 save def/@1 xdf/@2 xdf/@3 xdf/@4 xdf/@5 xdf/@6 @5 @3 4 add mul def
+dc translate scale/xdbit 1 1 idtransform abs/ydbit exch def abs def{0 0 1 ydbit add 1 10 rc clip}if
+@1 0 eq @1 4 eq or{1 setgray ydbit 0 1 ydbit add 1 2 rc}if
+@1 3 eq @1 7 eq or{1}{0}ifelse setgray/@9 @1 0 eq @1 1 eq @1 3 eq or or invertflag xor def/@13 @6 def
+@2 fBitStretch or{/@10 @4 x4 def/@11 @3 x4 def/@12 @10 rb def/@13 @12 @11 mul def/@15 1 1 dtransform abs/calcY 1 index def round cvi/@14 exch def
+abs/calcX 1 index def round cvi scaleby96 not{1 add}if def/@16 @15 rb def/@17 @16 @14 mul def}if
+sn @13 60000 lt and @2 fBitStretch or and{mtx currentmatrix dup 1 get exch 2 get 0. eq exch 0. eq and @17 60000 lt and fBitStretch and{@16 3 bitshift @14 @9 [calcX 0 0 calcY 0 0]{@17 string @13 string
+currentfile @6 string readhexstring pop 1 index @4 @3 @5 @12 @2 smooth4
+@10 @11 @12 dup string 5 index @15 @14 @16 dup string stretch}imagemask}{@12 x8 @11 @9 [@10 0 0 @11 0 0]{@13 string
+currentfile @6 string readhexstring pop 1 index @4 @3 @5 @12 @2 smooth4}imagemask}ifelse}{@5 3 bitshift @3 4 add @9 [@4 0 0 @3 0 2]{currentfile @6 string readhexstring pop}imagemask}ifelse
+@7 restore}bdf
+/wd 16 dict def
+/mfont 14 dict def
+/mdf{mfont wcheck not{/mfont 14 dict def}if mfont begin xdf end}bdf
+/cf{{1 index/FID ne{def}{pop pop}ifelse}forall}bdf
+/rf{/@1 exch def/@2 exch def
+FontDirectory @2 known{cleartomark pop}{findfont dup begin dup length @1 add dict begin
+cf {/Encoding macvec def}{Encoding dup length array copy/Encoding exch def
+counttomark 2 idiv{Encoding 3 1 roll put}repeat}ifelse
+pop
+exec currentdict end end @2 exch definefont pop}ifelse}bdf
+/bmbc{exch begin wd begin
+/cr xdf
+save
+CharTable cr 6 mul 6 getinterval{}forall
+/bitheight xdf/bitwidth xdf
+.96 div/width xdf
+Gkernmax add/XOffset xdf Gdescent add/YOffset xdf/rowbytes xdf
+rowbytes 255 eq{0 0 0 0 0 0 setcachedevice}
+{Gnormsize dup scale
+width 0 XOffset YOffset bitwidth XOffset add bitheight YOffset add
+setcachedevice
+rowbytes 0 ne{
+XOffset YOffset translate newpath 0 0 moveto
+bitwidth bitheight scale
+sn{
+/xSmt bitwidth x4 def
+/ySmt bitheight x4 def
+/rSmt xSmt rb def
+rSmt x8 ySmt true
+[xSmt 0 0 ySmt neg 0 ySmt]
+{rSmt ySmt mul string CharData cr get
+1 index bitwidth bitheight rowbytes rSmt so smooth4}
+}{rowbytes 3 bitshift bitheight 4 add true
+[bitwidth 0 0 bitheight neg 0 bitheight 2 add]
+{CharData cr get}
+}ifelse
+imagemask
+}if
+}ifelse
+restore
+end end
+}bdf
+/bb{.96 exch div/Gnormsize mdf 2 index
+/Gkernmax mdf 1 index/Gdescent mdf
+3 index div 4 1 roll
+2 index div 1. 5 2 roll
+exch div 4 1 roll
+4 array astore/FontBBox mdf
+}bdf
+/cdf{mfont/CharData get 3 1 roll put}bdf
+/bf{
+mfont begin
+/FontType 3 def
+/FontMatrix [1 0 0 1 0 0] def
+/Encoding macvec def
+/BuildChar/bmbc load def
+end
+mfont definefont pop
+}bdf
+/wi LW 1 eq{{gsave 0 0 0 0 0 0 0 0 moveto lineto lineto lineto closepath clip stringwidth grestore}bind}{/stringwidth load}ifelse def
+/aps{0 get 124 eq}bdf
+/xc{s75 cvs dup}bdf
+/xp{put cvn}bdf
+/scs{xc 3 67 put dup 0 95 xp}bdf
+/sos{xc 3 79 xp}bdf
+/sbs{xc 1 66 xp}bdf
+/sis{xc 2 73 xp}bdf
+/sob{xc 2 79 xp}bdf
+/sss{xc 4 83 xp}bdf
+/dd{exch 1 index add 3 1 roll add exch}bdf
+/smc{moveto dup lws}bdf
+/kwn{FontDirectory 1 index known{findfont exch pop}}bdf
+/gl{1 currentgray sub setgray}bdf
+/mm{/mfont 10 dict def mfont begin
+/FontMatrix [1 0 0 1 0 0] def
+/FontType 3 def
+/Encoding macvec def
+/df 4 index findfont def
+/FontBBox [0 0 1 1] def
+/xda xdf/mbc xdf
+/BuildChar{wd begin/cr xdf/fd xdf/cs s1 dup 0 cr put def fd/mbc get exec end}def
+exec end mfont definefont}bdf
+/ac{dup scs kwn{exch findfont dup length 1 add dict begin
+cf fmv{/Encoding macvec def}if/StrokeWidth nlw 1000 mul pys div ps div dup 12 lt{pop 12}if def
+/PaintType 2 def currentdict /UniqueID known{/UniqueID UniqueID 16#A80000 xor def}if currentdict end definefont}ifelse}bdf
+/mb{dup sbs kwn{exch{pop}{bbc}{}mm}ifelse sfd}bdf
+/mo{dup sos kwn{exch{pop}{boc}{}mm}ifelse sfd}bdf
+/ms{dup sss kwn{exch{pop}{bsc}{}mm}ifelse sfd}bdf
+/ou{dup sos kwn{exch dup ac pop{scs findfont /df2 xdf}{aoc}{}mm}ifelse sfd}bdf
+/su{dup sss kwn{exch dup ac pop{scs findfont /df2 xdf}{asc}{}mm}ifelse sfd}bdf
+/ao{/fmv true def ou}bdf/as{/fmv true def su}bdf
+/vo{/fmv false def ou}bdf/vs{/fmv false def su}bdf
+/bbc{/da .03 def fd/df get setfont
+gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth
+cs 0 0 smc da 0 smc da da smc 0 da moveto lws}bdf
+/boc{/da 1 ps div def fd/df get setfont
+gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth
+cs 0 0 smc da 0 smc da da smc 0 da smc gl da 2. div dup moveto lws}bdf
+/bsc{/da 1 ps div def
+/ds .05 def/da2 da 2. div def fd/df get setfont
+gsave cs wi 1 index 0 ne{exch ds add da2 add exch}if grestore setcharwidth
+cs ds da2 add .01 add 0 smc 0 ds da2 sub translate 0 0 smc
+da 0 smc da da smc 0 da smc gl da 2. div dup moveto lws}bdf
+/aoc{fd/df get setfont
+gsave cs wi grestore setcharwidth
+gl cs 0 0 smc fd/df2 get setfont gl 0 0 moveto lws}bdf
+/asc{/da .05 def fd/df get setfont
+gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth
+cs da .01 add 0 smc 0 da translate gl 0 0 smc gl fd/df2 get setfont 0 0 moveto lws}bdf
+/st
+{1000 mul usertime add % arg=1000*arg+usertime
+ dup 2147483647 gt {2147483647 sub} if % arg=arg mod (2^31)
+ def % Define
+} bdf
+/the{usertime sub dup 0 lt exch -2147483648 gt and}bdf
+/6a 6 array def
+/2a 2 array def
+/3q 3 array def
+/qs{3 -1 roll sub exch 3 -1 roll sub exch}bdf
+/qa{3 -1 roll add exch 3 -1 roll add exch}bdf
+/qm{3 -1 roll 1 index mul 3 1 roll mul}bdf
+/qn{6a exch get mul}bdf
+/qA .166667 def/qB .833333 def/qC .5 def
+/qx{6a astore pop
+qA 0 qn qB 2 qn add qA 1 qn qB 3 qn add
+qB 2 qn qA 4 qn add qB 3 qn qA 5 qn add
+qC 2 qn qC 4 qn add qC 3 qn qC 5 qn add}bdf
+/qp{6 copy 12 -2 roll pop pop}bdf
+/qc{exch qp qx curveto}bdf
+/qi{{exch 4 copy 2a astore aload pop qa .5 qm newpath moveto}{exch 2 copy 6 -2 roll 2 qm qs 4 2 roll}ifelse}bdf
+/qq{{qc 2a aload pop qx curveto}{exch 4 copy qs qa qx curveto}ifelse}bdf
+/pt{currentpoint newpath moveto}bdf
+/qf{/fillflag true def}bdf
+/ec{1 and 0 ne{0 doop}if grestore currentpoint newpath moveto/fillflag false def}bdf
+/eu{currentpoint fp{0 ep}{grestore newpath}ifelse moveto/fillflag false def}bdf
+/bp{currentpoint newpath 2 copy moveto}bdf
+/ef{gsave fillflag{gsave eofill grestore}if}bdf
+/sm{0 exch{@1 eq{1 add}if}forall}bdf
+/lshow{4 1 roll exch/@1 exch def{1 index wi pop sub 1 index sm dv 0 @1 4 -1 roll widthshow}{1 index wi pop sub
+1 index dup sm 10 mul exch length 1 sub add dv dup 10. mul 0 @1 4 -1 roll 0 6 -1 roll awidthshow}ifelse}bdf
+/setTxMode{sa 9 2 index put 3 eq{1}{0}ifelse setgray}bdf
+/SwToSym{{}mark false/Symbol/|______Symbol 0 rf 0 sa 6 get 0 ne{pop 1}{sa 7 get 0 eq{pop 2}if}ifelse
+sa 1 get 0 ne/|______Symbol
+sa 4 get 0 ne{vs}{sa 3 get 0 ne{vo}{fnt}ifelse}ifelse}bdf
+/mc{0 3 1 roll transform neg exch pop}bdf
+/ul{dup 0 ne sa 2 get 0 ne and{gsave 0 0
+/UnderlinePosition kif{mc}{ps -10 div}ifelse/UnderlineThickness kif{mc}{ps 15 div}ifelse
+abs setlinewidth neg rmoveto
+sa 4 get 0 ne{gsave currentlinewidth 2. div dup rmoveto currentpoint newpath moveto
+2 copy rlineto stroke grestore}if
+sa 3 get sa 4 get or 0 ne{gsave gl 2 copy rlineto stroke grestore rlineto strokepath nlw pys div setlinewidth}{rlineto}ifelse
+stroke grestore}{pop}ifelse}bdf
+/sgt{2 copy known{get true}{pop pop false}ifelse}bdf
+/kif{currentfont dup/FontMatrix get exch/FontInfo sgt{true}{currentfont/df sgt
+{dup/FontInfo sgt{3 1 roll/FontMatrix get mtx concatmatrix exch true}{pop pop pop false}
+ifelse}{pop pop false}ifelse}ifelse{3 -1 roll sgt{exch true}{pop false}ifelse}{false}ifelse}bdf
+/blank/Times-Roman findfont/CharStrings get/space get def
+/macvec 256 array def
+/NUL/SOH/STX/ETX/EOT/ENQ/ACK/BEL/BS/HT/LF/VT/FF/CR/SO/SI
+/DLE/DC1/DC2/DC3/DC4/NAK/SYN/ETB/CAN/EM/SUB/ESC/FS/GS/RS/US
+macvec 0 32 getinterval astore pop
+macvec 32/Times-Roman findfont/Encoding get
+32 96 getinterval putinterval macvec dup 39/quotesingle put 96/grave put
+/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute
+/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave
+/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde/oacute
+/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis
+/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/notequal/AE/Oslash
+/infinity/plusminus/lessequal/greaterequal/yen/mu/partialdiff/summation
+/product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash
+/questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft
+/guillemotright/ellipsis/blank/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide/lozenge
+/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright/fi/fl
+/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand/Acircumflex/Ecircumflex/Aacute
+/Edieresis/Egrave/Iacute/Icircumflex/Idieresis/Igrave/Oacute/Ocircumflex
+/apple/Ograve/Uacute/Ucircumflex/Ugrave/dotlessi/circumflex/tilde
+/macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron
+macvec 128 128 getinterval astore pop
+{}mark true/Courier/|______Courier 0 rf
+{/Metrics 21 dict begin/zero 600 def/one 600 def/two 600 def/three 600 def/four 600 def/five 600 def/six 600 def/seven 600 def/eight 600 def
+/nine 600 def/comma 600 def/period 600 def/dollar 600 def/numbersign 600 def/percent 600 def/plus 600 def/hyphen 600 def/E 600 def/parenleft 600 def/parenright 600 def/space 600 def
+currentdict end def currentdict/UniqueID known{/UniqueID 16#800000 def}if/FontBBox FontBBox 4 array astore def}mark true/Helvetica/|______Seattle 1 rf
+/oldsettransfer/settransfer load def
+/concatprocs{/proc2 exch cvlit def/proc1 exch cvlit def/newproc proc1 length proc2 length add array def
+newproc 0 proc1 putinterval newproc proc1 length proc2 putinterval newproc cvx}def
+/settransfer{currenttransfer concatprocs oldsettransfer}def
+/PaintBlack{{1 exch sub}settransfer gsave newpath clippath 1 setgray fill grestore}def
+/od
+{
+ %AKT (Rvd\001\001\000\000\177) fg copy pop txpose
+ 1 -1 scale %AKT
+ 1 0 mtx defaultmatrix dtransform exch atan /pa exch def
+ newpath
+ clippath
+ mark
+ {transform {itransform moveto}}
+ {transform {itransform lineto}}
+ {6 -2 roll transform
+ 6 -2 roll transform
+ 6 -2 roll transform
+ {itransform
+ 6 2 roll itransform
+ 6 2 roll itransform
+ 6 2 roll curveto
+ }
+ }
+ {{closepath}}
+ pathforall
+ newpath
+ counttomark array astore /gc xdf pop ct 39 0 put
+ 10 fz 0 fs 2 F/|______Courier fnt invertflag {PaintBlack} if
+} bdf
+/cd {} bdf
+/op
+{/sfl false def
+ /pm save def
+} bdf
+/cp
+{
+ pop pop %AKT ignore arguments to cp
+ pm restore
+} bdf
+/px{0 3 1 roll tp tt}bdf
+/psb{/us save def}bdf
+/pse{us restore}bdf
+/ct 40 string def
+/nc{currentpoint initclip newpath gc{dup type dup/arraytype eq exch/packedarraytype eq or{exec}if}
+forall clip newpath moveto}bdf
+/kp{ct 0 2 index length 2 index 39 2 index put getinterval copy cvx exec mx3 currentmatrix pop}bdf
+end
+LW 1 eq userdict/a4small known not and{/a4small
+[[300 72 div 0 0 -300 72 div -120 3381]
+280 3255
+{statusdict/jobstate (printing) put 0 setblink
+margins
+exch 196 add exch 304 add 8 div round cvi frametoroket
+statusdict/jobstate (busy) put
+1 setblink}
+/framedevice load
+60 45{dup mul exch dup mul add 1.0 exch sub}/setscreen load
+{}/settransfer load/initgraphics load/erasepage load]cvx
+statusdict begin bind end readonly def}if
+md begin/bigs[lnop lnop/legal load userdict/a4 known{/a4 load}{lnop}ifelse lnop lnop lnop lnop lnop]def
+/smalls[lnop userdict/note known{/note load}{dup}ifelse lnop userdict/a4small known{/a4small load}{lnop}ifelse 2 index lnop lnop lnop lnop ]def end
+systemdict/currentpacking known{setpacking}if
+
+%AKT Removed /stretch and /smooth4 eexec patches to avoid flushfile problem
+%AKT if md previously downloaded.
+
+%%EndProcSet
+
+%%EOF
diff --git a/dviware/psprint/vms/laserprep68.ps b/dviware/psprint/vms/laserprep68.ps
new file mode 100644
index 0000000000..d41199cb57
--- /dev/null
+++ b/dviware/psprint/vms/laserprep68.ps
@@ -0,0 +1,405 @@
+% This modified LaserPrep came from Henning Schulzrinne (HGSCHULZ@edu.umass.cs).
+
+%%Title: "Laser Prep -- The Apple PostScript Dictionary (md)"
+%%Creator: Apple Software Engineering
+%%CreationDate: Thursday, March 19, 1987
+%{appledict version #68 0
+% ) CopyRight Apple Computer, Inc. 1984,1985,1986,1987,1988 All Rights Reserved.
+%%EndComments
+%%BeginProcSet: "(AppleDict md)" 68 0
+currentfile statusdict begin
+/sc {60 45 {abs exch abs 2 copy add 1 gt{1.0 sub dup mul exch 1.0 sub dup mul add 1.0 sub}{dup mul exch dup mul add 1.0 exch sub}
+ifelse}setscreen} bind def statusdict begin product(LaserWriter II)anchorsearch end
+{pop pop/letter [/letter load /exec load /sc load /exec load]cvx def/legal [/legal load /exec load /sc load /exec load]cvx def/a4 [/a4 load /exec load /sc load /exec load]cvx def/b5 [/b5 load /exec load /sc load /exec load]cvx def
+/lettersmall [/lettersmall load /exec load /sc load /exec load]cvx def/a4small [/a4small load /exec load /sc load /exec load]cvx def/note [/note load /exec load /sc load /exec load]cvx def}{pop}ifelse
+systemdict/currentpacking known{currentpacking true setpacking}if
+/LW{save statusdict/product get(LaserWriter)anchorsearch
+exch pop{length 0 eq{1}{2}ifelse}{0}ifelse exch restore}bind def
+/LW+{LW 2 eq}bind def
+/ok{systemdict/statusdict known dup{LW 0 gt and}if}bind def
+%-hsr-% ok{statusdict begin 9 sccinteractive 3 ne exch 0 ne or{9 0 3 setsccinteractive}if end}if
+/md 250 dict def md begin
+/av 0 def
+/T true def/F false def/mtx matrix def/s75 75 string def/s8 8 string def/s1 ( ) def/pxs 1 def/pys 1 def
+1 0 mtx defaultmatrix dtransform exch atan/pa exch def/nlw .24 def/ppr [-32 -29.52 762 582.48] def
+/pgs 1 def/por true def/xb 500 array def/so true def/tso true def/fillflag false def/pnm 1 def/fmv true def
+/sfl false def/ma 0 def/invertflag false def/dbinvertflag false def/xflip false def/yflip false def/noflips true def/scaleby96 false def/fNote true def/fBitStretch true def
+/fg (Rvd\001\001\000\000\177) def
+/bdf{bind def}bind def
+/xdf{exch def}bdf
+/xl{neg exch neg translate}bdf
+/fp{pnsh 0 ne pnsv 0 ne and}bdf
+/nop{}bdf/lnop[/nop load]cvx bdf
+/vrb[
+{fp{fg 6 get 0 ne{gsave stroke grestore}{gsave 1 setlinewidth pnsh pnsv scale stroke grestore}ifelse}if newpath}bind
+/eofill load
+dup
+/newpath load
+2 index
+dup
+{clip newpath}bind
+{}bind
+dup
+2 copy
+]def
+currentscreen/spf xdf/rot xdf/freq xdf
+/doop{vrb exch get exec}bdf
+/psu{/tso xdf /fNote xdf/fBitStretch xdf/scaleby96 xdf/yflip xdf/xflip xdf
+/invertflag xdf/dbinvertflag invertflag statusdict begin version cvr 47.0 ge product (LaserWriter) eq not and end invertflag and {not}if def
+xflip yflip or{/noflips false def}if
+/pgs xdf 2 index .72 mul exch div/pys xdf div .72 mul/pxs xdf ppr astore pop/por xdf sn and/so xdf}bdf
+/tab{statusdict /11x17 known{statusdict begin /11x17 load end}{statusdict /setpage known{statusdict begin 792 1224 1 setpage end}{statusdict /setpageparams known{statusdict begin 792 1224 0 1 setpageparams end}if}ifelse}ifelse}bdf
+/txpose{fNote{smalls}{bigs}ifelse pgs get exec pxs pys scale ppr aload pop por{noflips{pop exch neg exch translate pop 1 -1 scale}if
+xflip yflip and{pop exch neg exch translate 180 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg translate}if
+xflip yflip not and{pop exch neg exch translate pop 180 rotate ppr 3 get ppr 1 get neg sub neg 0 translate}if yflip xflip not and{ppr 1 get neg ppr 0 get neg translate}if}
+{noflips{translate pop pop 270 rotate 1 -1 scale}if xflip yflip and{translate pop pop 90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg translate}if
+xflip yflip not and{translate pop pop 90 rotate ppr 3 get ppr
+1 get neg sub neg 0 translate}if yflip xflip
+not and{translate pop pop 270 rotate ppr 2 get ppr 0
+get neg sub neg 0 exch translate}if}ifelse
+%-hsr-% statusdict begin waittimeout 300 lt{/waittimeout 300 def}if end
+scaleby96{ppr aload pop 4 -1 roll add 2 div 3 1 roll
+add 2 div 2 copy translate .96 dup scale neg exch neg exch translate}if}bdf
+/fr{4 copy ppr aload pop 3 -1 roll add 3 1 roll exch add 6 2 roll 3 -1 roll
+sub 3 1 roll exch sub 3 -1 roll exch div 3 1 roll div exch scale pop pop xl}bdf
+/obl{{0.212557 mul}{pop 0}ifelse}bdf
+/sfd{ps fg 5 -1 roll get mul 100 div 0 ps 5 -1 roll obl ps neg 0 0 6a astore makefont setfont}bdf
+/fnt{findfont sfd}bdf
+/bt{sa 3 1 roll 3 index and put}bdf
+/sa(\000\000\000\000\000\000\000\000\000\000)def
+/fs{0 1 bt 1 2 bt 2 4 bt 3 8 bt 4 16 bt 5 32 bt 6 64 bt 7 128 bt sa exch 8 exch put}bdf
+/mx1 matrix def
+/mx2 matrix def
+/mx3 matrix def
+/bu{currentpoint currentgray currentlinewidth currentlinecap currentlinejoin currentdash exch aload length
+fg 5 sfl{1}{0}ifelse put pnsv pnsh
+2t aload pop 3a aload pop mx2 aload pop mx1 aload pop mtx currentmatrix aload pop
+mx3 aload pop ps pm restore/ps xdf mx3 astore pop}bdf
+/bn{/pm save def mx3 setmatrix newpath 0 0 moveto ct dup 39 get 0 exch getinterval cvx exec
+mtx astore setmatrix mx1 astore pop mx2 astore pop 3a astore pop
+2t astore pop/pnsh xdf/pnsv xdf gw
+/sfl fg 5 get 0 ne def array astore exch setdash setlinejoin setlinecap
+setlinewidth setgray moveto}bdf
+/fc{save vmstatus exch sub 50000 lt
+{(%%[|0|]%%)=print flush}if pop restore}bdf
+/tc{32768 div add 3 1 roll 32768 div add 2t astore pop}bdf
+/3a [0 0 0] def
+/2t 2 array def
+/tp{3a astore pop}bdf
+/tt{mx2 currentmatrix pop currentpoint 2 copy 2t aload pop qa 2 copy translate 3a aload pop exch dup 0 eq
+{pop}{1 eq{-1 1}{1 -1}ifelse scale}ifelse rotate pop neg exch neg exch translate moveto}bdf
+/te{mx2 setmatrix}bdf
+/th{3 -1 roll div 3 1 roll exch div 2 copy mx1 scale pop scale/sfl true def}bdf
+/tu{1 1 mx1 itransform scale/sfl false def}bdf
+/ts{1 1 mx1 transform scale/sfl true def}bdf
+/fz{/ps xdf}bdf
+/dv{dup 0 ne{div}{pop}ifelse}bdf
+/pop4{pop pop pop pop}bdf
+/it{sfl{mx1 itransform}if}bdf
+/gm{exch it moveto}bdf/rm{it rmoveto}bdf
+/lm{currentpoint sfl{mx1 transform}if exch pop sub 0 exch it rmoveto}bdf
+/fm{statusdict/manualfeed known}bdf
+/se{statusdict exch/manualfeed exch put}bdf
+/mf{dup/ma exch def 0 gt{fm se/t1 5 st ok ma 1 gt and{/t2 0 st/t3 0 st
+statusdict/manualfeedtimeout 3600 put
+}if}if}bdf
+/jn{/statusdict where exch pop{statusdict exch /jobname exch put}if}bdf
+/pen{pnm mul/pnsh xdf pnm mul/pnsv xdf pnsh setlinewidth}bdf
+/min{2 copy gt{exch}if pop}bdf
+/max{2 copy lt{exch}if pop}bdf
+/dh{fg 6 1 put array astore dup {1 pxs div mul exch}forall astore exch pop exch pop exch setdash}bdf
+/ih[currentdash]def
+/rh{fg 6 0 put ih aload pop setdash}bdf
+/dl{gsave nlw pys div setlinewidth 0 setgray}bdf
+/dlin{exch currentpoint currentlinewidth 2 div dup
+translate newpath moveto lineto currentpoint stroke grestore moveto}bdf
+/lin{fg 6 get 0 ne{exch lineto currentpoint 0 doop moveto}
+{exch currentpoint/pnlv xdf/pnlh xdf gsave newpath/@1 xdf/@2 xdf fp{pnlh @2 lt{pnlv @1 ge
+{pnlh pnlv moveto @2 @1 lineto pnsh 0 rlineto
+0 pnsv rlineto pnlh pnsh add pnlv pnsv add lineto pnsh neg 0 rlineto}
+{pnlh pnlv moveto pnsh 0 rlineto @2 pnsh add @1 lineto 0 pnsv rlineto
+pnsh neg 0 rlineto pnlh pnlv pnsv add lineto}ifelse}{pnlv @1 gt
+{@2 @1 moveto pnsh 0 rlineto pnlh pnsh add pnlv lineto 0 pnsv rlineto
+pnsh neg 0 rlineto @2 @1 pnsv add lineto}{pnlh pnlv moveto pnsh 0 rlineto
+0 pnsv rlineto @2 pnsh add @1 pnsv add lineto pnsh neg 0 rlineto
+0 pnsv neg rlineto}ifelse}ifelse
+closepath fill}if @2 @1 grestore moveto}ifelse}bdf
+/gw{/pnm fg 3 get fg 4 get div def}bdf
+/lw{fg exch 4 exch put fg exch 3 exch put gw pnsv pnsh pen}bdf
+/barc{/@1 xdf/@2 xdf/@3 xdf/@4 xdf/@5 xdf
+/@6 xdf/@7 xdf/@8 xdf gsave
+@5 @7 add 2 div @6 @8 add 2 div translate newpath 0 0 moveto
+@5 @7 sub @6 @8 sub mtx currentmatrix pop scale @1{newpath}if
+0 0 0.5 @4 @3 arc @4 @3 sub abs 360 ge{closepath}if
+mtx setmatrix @2 doop grestore}bdf
+/ar{dup 0 eq barc}bdf
+/ov{0 exch 360 exch true barc}bdf
+/rc{/@t xdf currentpoint 6 2 roll newpath 4 copy 4 2 roll exch moveto
+6 -1 roll lineto lineto lineto closepath @t doop moveto}bdf
+/mup{dup pnsh 2 div le exch pnsv 2 div le or}bdf
+/rr{/@1 xdf 2. div/@2 xdf 2. div/@3 xdf
+/@4 xdf/@5 xdf/@6 xdf/@7 xdf
+@7 @5 eq @6 @4 eq @2 mup or or{@7 @6 @5 @4 @1 rc}
+{@4 @6 sub 2. div dup @2 lt{/@2 xdf}{pop}ifelse
+@5 @7 sub 2. div dup @2 lt{/@2 xdf}{pop}ifelse
+@1 0 eq{/@2 @2 pnsh 2 div 2 copy gt{sub def}{0 pop4}ifelse}if
+currentpoint newpath
+@4 @6 add 2. div @7 moveto
+@4 @7 @4 @5 @2 arcto pop4
+@4 @5 @6 @5 @2 arcto pop4
+@6 @5 @6 @7 @2 arcto pop4
+@6 @7 @4 @7 @2 arcto pop4
+closepath @1 doop moveto}ifelse}bdf
+/pr{gsave newpath/pl{exch moveto/pl{exch lineto}def}def}bdf
+/pl{exch lineto}bdf
+/ep{dup 0 eq{{moveto}{exch lin}{}{(%%[|1|]%%)= flush}pathforall
+pop grestore}{doop grestore}ifelse currentpoint newpath moveto}bdf
+/gr{64. div setgray}bdf
+/pat{s8 copy pop 9.375 pa por not{90 add}if{1 add 4 mul cvi s8 exch get exch 1 add 4 mul cvi 7 sub bitshift 1 and}setscreen gr}bdf
+/sg{freq rot/spf load setscreen gr}bdf
+/dc{transform round .5 sub exch round .5 sub exch itransform}bdf
+/sn{userdict/smooth4 known}bdf
+/x8{3 bitshift}bdf
+/x4{2 bitshift}bdf
+/d4{-2 bitshift}bdf
+/d8{-3 bitshift}bdf
+/rb{15 add -4 bitshift 1 bitshift}bdf
+/db{/@7 save def/@1 xdf/@2 xdf/@3 xdf/@4 xdf/@5 xdf/@6 @5 @3 4 add mul def
+dc translate scale/xdbit 1 1 idtransform abs/ydbit exch def abs def{0 0 1 ydbit add 1 10 rc clip}if
+@1 0 eq @1 4 eq or{1 setgray ydbit 0 1 ydbit add 1 2 rc}if
+@1 3 eq @1 7 eq or{1}{0}ifelse setgray/@9 @1 0 eq @1 1 eq @1 3 eq or or dbinvertflag xor def/@13 @6 def
+@2 fBitStretch or{/@10 @4 x4 def/@11 @3 x4 def/@12 @10 rb def/@13 @12 @11 mul def/@15 1 1 dtransform abs/calcY 1 index def round cvi/@14 exch def
+abs/calcX 1 index def round cvi scaleby96 not{1 add}if def/@16 @15 rb def/@17 @16 @14 mul def}if
+sn @13 60000 lt and @2 fBitStretch or and{mtx currentmatrix dup 1 get exch 2 get 0. eq exch 0. eq and @17 60000 lt and fBitStretch and{@16 3 bitshift @14 @9 [calcX 0 0 calcY 0 0]{@17 string @13 string
+currentfile @6 string readhexstring pop 1 index @4 @3 @5 @12 @2 smooth4
+@10 @11 @12 dup string 5 index @15 @14 @16 dup string stretch}imagemask}{@12 x8 @11 @9 [@10 0 0 @11 0 0]{@13 string
+currentfile @6 string readhexstring pop 1 index @4 @3 @5 @12 @2 smooth4}imagemask}ifelse}{@5 3 bitshift @3 4 add @9 [@4 0 0 @3 0 2]{currentfile @6 string readhexstring pop}imagemask}ifelse
+@7 restore}bdf
+/multibit{/mbdeep exch def/mbY exch def/mbX exch def
+save mbX mbY mbdeep[mbX 0 0 mbY 0 0]{currentfile picstr readhexstring pop}image
+restore}bdf
+/wd 16 dict def
+/mfont 14 dict def
+/mdf{mfont wcheck not{/mfont 14 dict def}if mfont begin xdf end}bdf
+/cf{{1 index/FID ne{def}{pop pop}ifelse}forall}bdf/rf{/@1 exch def/@2 exch def
+FontDirectory @2 known{cleartomark pop}{findfont dup begin dup length @1 add dict begin
+cf{/Encoding macvec def}{Encoding dup length array copy/Encoding exch def
+counttomark 2 idiv{Encoding 3 1 roll put}repeat}ifelse
+pop
+exec currentdict end end @2 exch definefont pop}ifelse}bdf
+/bmbc{exch begin wd begin
+/cr xdf
+save
+CharTable cr 6 mul 6 getinterval{}forall
+/bitheight xdf/bitwidth xdf
+.96 div/width xdf
+Gkernmax add/XOffset xdf Gdescent add/YOffset xdf/rowbytes xdf
+rowbytes 255 eq{0 0 0 0 0 0 setcachedevice}
+{Gnormsize dup scale
+width 0 XOffset YOffset bitwidth XOffset add bitheight YOffset add
+setcachedevice
+rowbytes 0 ne{
+XOffset YOffset translate newpath 0 0 moveto
+bitwidth bitheight scale
+sn{
+/xSmt bitwidth x4 def
+/ySmt bitheight x4 def
+/rSmt xSmt rb def
+rSmt x8 ySmt true
+[xSmt 0 0 ySmt neg 0 ySmt]
+{rSmt ySmt mul string CharData cr get
+1 index bitwidth bitheight rowbytes rSmt tso smooth4}
+}{rowbytes 3 bitshift bitheight 4 add true
+[bitwidth 0 0 bitheight neg 0 bitheight 2 add]
+{CharData cr get}
+}ifelse
+imagemask
+}if
+}ifelse
+restore
+end end
+}bdf
+/bb{.96 exch div/Gnormsize mdf 2 index
+/Gkernmax mdf 1 index/Gdescent mdf
+3 index div 4 1 roll
+2 index div 1. 5 2 roll
+exch div 4 1 roll
+4 array astore/FontBBox mdf
+}bdf
+/cdf{mfont/CharData get 3 1 roll put}bdf
+/bf{
+mfont begin
+/FontType 3 def
+/FontMatrix [1 0 0 1 0 0] def
+/Encoding macvec def
+/BuildChar/bmbc load def
+end
+mfont definefont pop
+}bdf
+/wi LW 1 eq{{gsave 0 0 0 0 0 0 0 0 moveto lineto lineto lineto closepath clip stringwidth grestore}bind}{/stringwidth load}ifelse def
+/aps{0 get 124 eq}bdf
+/xc{s75 cvs dup}bdf
+/xp{put cvn}bdf
+/scs{xc 3 67 put dup 0 95 xp}bdf
+/sos{xc 3 79 xp}bdf
+/sbs{xc 1 66 xp}bdf
+/sis{xc 2 73 xp}bdf
+/sob{xc 2 79 xp}bdf
+/sss{xc 4 83 xp}bdf
+/dd{exch 1 index add 3 1 roll add exch}bdf
+/smc{moveto dup show}bdf
+/kwn{FontDirectory 1 index known{findfont exch pop}}bdf
+/gl{1 currentgray sub setgray}bdf
+/mm{/mfont 10 dict def mfont begin
+/FontMatrix [1 0 0 1 0 0] def
+/FontType 3 def
+/Encoding macvec def
+/df 4 index findfont def
+/FontBBox [0 0 1 1] def
+/xda xdf/mbc xdf
+/BuildChar{wd begin/cr xdf/fd xdf/cs s1 dup 0 cr put def fd/mbc get exec end}def
+exec end mfont definefont}bdf
+/ac{dup scs kwn{exch findfont dup length 1 add dict begin{1 index/FID ne 2 index/UniqueID ne and{def}{pop pop}ifelse}forall
+fmv{/Encoding macvec def}if/StrokeWidth nlw 1000 mul pys div ps div dup 12 lt{pop 12}if def
+/PaintType 2 def currentdict end definefont}ifelse}bdf
+/mb{dup sbs kwn{exch{pop}{bbc}{}mm}ifelse sfd}bdf
+/mo{dup sos kwn{exch{pop}{boc}{}mm}ifelse sfd}bdf
+/ms{dup sss kwn{exch{pop}{bsc}{}mm}ifelse sfd}bdf
+/ou{dup sos kwn{exch dup ac pop{scs findfont /df2 xdf}{aoc}{}mm}ifelse sfd}bdf
+/su{dup sss kwn{exch dup ac pop{scs findfont /df2 xdf}{asc}{}mm}ifelse sfd}bdf
+/ao{/fmv true def ou}bdf/as{/fmv true def su}bdf
+/vo{/fmv false def ou}bdf/vs{/fmv false def su}bdf
+/bbc{/da .03 def fd/df get setfont
+gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth
+cs 0 0 smc da 0 smc da da smc 0 da moveto show}bdf
+/boc{/da 1 ps div def fd/df get setfont
+gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth
+cs 0 0 smc da 0 smc da da smc 0 da smc gl da 2. div dup moveto show}bdf
+/bsc{/da 1 ps div def
+/ds .05 def/da2 da 2. div def fd/df get setfont
+gsave cs wi 1 index 0 ne{exch ds add da2 add exch}if grestore setcharwidth
+cs ds da2 add .01 add 0 smc 0 ds da2 sub translate 0 0 smc
+da 0 smc da da smc 0 da smc gl da 2. div dup moveto show}bdf
+/aoc{fd/df get setfont
+gsave cs wi grestore setcharwidth
+gl cs 0 0 smc fd/df2 get setfont gl 0 0 moveto show}bdf
+/asc{/da .05 def fd/df get setfont
+gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth
+cs da .01 add 0 smc 0 da translate gl 0 0 smc gl fd/df2 get setfont 0 0 moveto show}bdf
+/st{1000 mul usertime add dup 2147483647 gt{2147483647 sub}if def}bdf
+/the{usertime sub dup 0 lt exch -2147483648 gt and}bdf
+/6a 6 array def
+/2a 2 array def
+/3q 3 array def
+/qs{3 -1 roll sub exch 3 -1 roll sub exch}bdf
+/qa{3 -1 roll add exch 3 -1 roll add exch}bdf
+/qm{3 -1 roll 1 index mul 3 1 roll mul}bdf
+/qn{6a exch get mul}bdf
+/qA .166667 def/qB .833333 def/qC .5 def
+/qx{6a astore pop
+qA 0 qn qB 2 qn add qA 1 qn qB 3 qn add
+qB 2 qn qA 4 qn add qB 3 qn qA 5 qn add
+qC 2 qn qC 4 qn add qC 3 qn qC 5 qn add}bdf
+/qp{6 copy 12 -2 roll pop pop}bdf
+/qc{exch qp qx curveto}bdf
+/qi{{exch 4 copy 2a astore aload pop qa .5 qm newpath moveto}{exch 2 copy 6 -2 roll 2 qm qs 4 2 roll}ifelse}bdf
+/qq{{qc 2a aload pop qx curveto}{exch 4 copy qs qa qx curveto}ifelse}bdf
+/pt{currentpoint newpath moveto}bdf
+/qf{/fillflag true def}bdf
+/ec{1 and 0 ne{0 doop}if grestore currentpoint newpath moveto/fillflag false def}bdf
+/eu{currentpoint fp{0 ep}{grestore newpath}ifelse moveto/fillflag false def}bdf
+/bp{currentpoint newpath 2 copy moveto}bdf
+/ef{gsave fillflag{gsave eofill grestore}if}bdf
+/sm{0 exch{@1 eq{1 add}if}forall}bdf
+/lshow{4 1 roll exch/@1 exch def{1 index wi pop sub 1 index sm dv 0 @1 4 -1 roll widthshow}{1 index wi pop sub
+1 index dup sm 10 mul exch length 1 sub add dv dup 10. mul 0 @1 4 -1 roll 0 6 -1 roll awidthshow}ifelse}bdf
+/setTxMode{sa 9 2 index put 3 eq{1}{0}ifelse setgray}bdf
+/SwToSym{{}mark false/Symbol/|______Symbol 0 rf 0 sa 6 get 0 ne{pop 1}{sa 7 get 0 eq{pop 2}if}ifelse
+sa 1 get 0 ne/|______Symbol
+sa 4 get 0 ne{vs}{sa 3 get 0 ne{vo}{fnt}ifelse}ifelse}bdf
+/mc{0 3 1 roll transform neg exch pop}bdf
+/ul{dup 0 ne sa 2 get 0 ne and{gsave 0 0
+/UnderlinePosition kif{mc}{ps -10 div}ifelse/UnderlineThickness kif{mc}{ps 15 div}ifelse
+abs setlinewidth neg rmoveto
+sa 4 get 0 ne{gsave currentlinewidth 2. div dup rmoveto currentpoint newpath moveto
+2 copy rlineto stroke grestore}if
+sa 3 get sa 4 get or 0 ne{gsave gl 2 copy rlineto stroke grestore rlineto strokepath nlw pys div setlinewidth}{rlineto}ifelse
+stroke grestore}{pop}ifelse}bdf
+/sgt{2 copy known{get true}{pop pop false}ifelse}bdf
+/kif{currentfont dup/FontMatrix get exch/FontInfo sgt{true}{currentfont/df sgt
+{dup/FontInfo sgt{3 1 roll/FontMatrix get mtx concatmatrix exch true}{pop pop pop false}
+ifelse}{pop pop false}ifelse}ifelse{3 -1 roll sgt{exch true}{pop false}ifelse}{false}ifelse}bdf
+/blank/Times-Roman findfont/CharStrings get/space get def
+/macvec 256 array def
+/NUL/SOH/STX/ETX/EOT/ENQ/ACK/BEL/BS/HT/LF/VT/FF/CR/SO/SI
+/DLE/DC1/DC2/DC3/DC4/NAK/SYN/ETB/CAN/EM/SUB/ESC/FS/GS/RS/US
+macvec 0 32 getinterval astore pop
+macvec 32/Times-Roman findfont/Encoding get
+32 96 getinterval putinterval macvec dup 39/quotesingle put 96/grave put
+/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute
+/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave
+/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde/oacute
+/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis
+/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/notequal/AE/Oslash
+/infinity/plusminus/lessequal/greaterequal/yen/mu/partialdiff/summation
+/product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash
+/questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft
+/guillemotright/ellipsis/blank/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide/lozenge
+/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright/fi/fl
+/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand/Acircumflex/Ecircumflex/Aacute
+/Edieresis/Egrave/Iacute/Icircumflex/Idieresis/Igrave/Oacute/Ocircumflex
+/apple/Ograve/Uacute/Ucircumflex/Ugrave/dotlessi/circumflex/tilde
+/macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron
+macvec 128 128 getinterval astore pop
+{}mark true/Courier/|______Courier 0 rf
+{/Metrics 21 dict begin/zero 600 def/one 600 def/two 600 def/three 600 def/four 600 def/five 600 def/six 600 def/seven 600 def/eight 600 def
+/nine 600 def/comma 600 def/period 600 def/dollar 600 def/numbersign 600 def/percent 600 def/plus 600 def/hyphen 600 def/E 600 def/parenleft 600 def/parenright 600 def/space 600 def
+currentdict end def currentdict/UniqueID known{/UniqueID 16#800000 def}if/FontBBox FontBBox 4 array astore def}mark true/Helvetica/|______Seattle 1 rf
+/oldsettransfer/settransfer load def
+/concatprocs{/proc2 exch cvlit def/proc1 exch cvlit def/newproc proc1 length proc2 length add array def
+newproc 0 proc1 putinterval newproc proc1 length proc2 putinterval newproc cvx}def
+/settransfer{currenttransfer concatprocs oldsettransfer}def
+/PaintBlack{{1 exch sub}settransfer gsave newpath clippath 1 setgray fill grestore}def
+/od{1 -1 scale %-AKT-% (Rvd\001\001\000\000\177) fg copy pop txpose
+1 0 mtx defaultmatrix dtransform exch atan/pa exch def
+newpath clippath mark
+{transform{itransform moveto}}{transform{itransform lineto}}
+{6 -2 roll transform 6 -2 roll transform 6 -2 roll transform
+{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll curveto}}
+{{closepath}}pathforall newpath counttomark array astore/gc xdf pop ct 39 0 put
+10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}if}bdf
+/cd{}bdf
+/op{/sfl false def/pm save def}bdf
+/cp{not{userdict/#copies 0 put}if ma 0 gt{{t1 the{exit}if}loop}if{copypage}{showpage}ifelse pm restore}def
+/px{0 3 1 roll tp tt}bdf
+/psb{/us save def}bdf
+/pse{us restore}bdf
+/ct 40 string def
+/nc{currentpoint initclip newpath gc{dup type dup/arraytype eq exch/packedarraytype eq or{exec}if}
+forall clip newpath moveto}def
+/kp{ct 0 2 index length 2 index 39 2 index put getinterval copy cvx exec mx3 currentmatrix pop}bdf
+/av 68 def
+end
+LW 1 eq userdict/a4small known not and{/a4small
+[[300 72 div 0 0 -300 72 div -120 3381]
+280 3255
+{statusdict/jobstate (printing) put 0 setblink
+margins
+exch 196 add exch 304 add 8 div round cvi frametoroket
+statusdict/jobstate (busy) put
+1 setblink}
+/framedevice load
+60 45{dup mul exch dup mul add 1.0 exch sub}/setscreen load
+{}/settransfer load/initgraphics load/erasepage load]cvx
+statusdict begin bind end readonly def}if
+md begin/bigs[lnop userdict/letter known{/letter load}{lnop}ifelse userdict/legal known{/legal load}{lnop}ifelse userdict/a4 known{/a4 load}{lnop}ifelse userdict/b5 known{/b5 load}{lnop}ifelse
+lnop lnop lnop /tab load]def
+/smalls[lnop userdict/lettersmall known{/lettersmall load}{userdict/note known{/note load}{lnop}ifelse}ifelse
+userdict/legal known{/legal load}{lnop}ifelse userdict/a4small known{/a4small load}{lnop}ifelse
+userdict/b5 known{/b5 load}{userdict/note known{/note load}{lnop}ifelse}ifelse lnop lnop lnop /tab load]def end
+systemdict/currentpacking known{setpacking}if
+%%EndProcSet
+
+%%EOF
diff --git a/dviware/psprint/vms/laserprep70.ps b/dviware/psprint/vms/laserprep70.ps
new file mode 100644
index 0000000000..c7c8316f44
--- /dev/null
+++ b/dviware/psprint/vms/laserprep70.ps
@@ -0,0 +1,480 @@
+% When printing a document on a PostScript printer, most Macintosh applications
+% will dump their PostScript code into a file called PostScript0 if you press
+% Command-F immediately after selecting OK in the Print dialogue box.
+% The PostScript code relies on definitions stored in a Mac system file called
+% Laser Prep. A modified version of Laser Prep (like the one you're reading)
+% must be included with PSPRINT's /PREP qualifier if you want to send
+% Command-F files via DVI \special commands.
+%
+% Since Apple keep changing Laser Prep, you might need to create your own
+% modified version some day. Here's how:
+% 1. Use a Mac application (such as MacWrite) to create a very small document.
+% 2. Print it, but immediately after selecting OK hold down Command-K.
+% Instead of printing the document, you should get a file called PostScript0
+% which contains Laser Prep prefixed to the Command-F code.
+% 3. Open the file with a text editor and remove the Command-F code by finding
+% the first occurrence of %%EOF and deleting everything below it.
+% 4. Duplicate the changes I've made to this file (search for %AKT).
+% 5. It's probably a good idea to rename PostScript0 to LaserPrepxx.ps where
+% xx is the version number appearing in comments at the top of the file.
+% 6. Type "PSPRINT /PREP=LaserPrepxx.ps ..." with your fingers crossed.
+
+%%Title: "Laser Prep -- The Apple PostScript Dictionary (md)"
+%%Creator: Apple Software Engineering
+%%CreationDate: Thursday, March 19, 1987
+%{appledict version #70 0
+% CopyRight Apple Computer, Inc. 1984-89 All Rights Reserved.
+%%EndComments
+%%BeginProcSet: "(AppleDict md)" 70 0
+statusdict begin product(LaserWriter II NT)eq revision 1 eq and
+{userdict begin/oldcds/cleardictstack load def/cleardictstack{31 sendpcmd 4 eq tonerlight/oldcds load exec}bind def
+end
+currentfile eexec
+}{save currentfile 359 string readhexstring pop pop restore}ifelse
+35de8eabfc7fa5eac0431edc501ad43f5fcbdf9fdd321cce93b525f4439dd94696bf56ac13a0a2aad1e6bcf444711e941d7217138d20ae0500145f815439cc14e697ad201df728ea4ccad4ac
+331aa03a7aacde10760bf4ee12bbf73c77cdcbf1796f26f0dd255d2407e1ac41
+d27489a69d6b69c6a841468b46720b75ad65650700e0c528e7af61e7e3e821b59445c44b69831ebc9deaf0e3aecc14b7a1c2e18bc1fa42a59219f1e36f236e3d6c89114b1f231999c3dbce6b43f3e2918fcb85575941a9d1e65c86aa08e6eea86cc66ce90e5e4add57f2585e
+7b1c0b5203cfc46868d6e3c0d66db79174e7091e32e307679732da062e440e41dabd36a161b611a7e4523a49694026206803dbfd5be5c5fe433f0f18a40057db6f1302848c8da4a10a7f14c6
+3d512806362b1be092ad5dbd36d75fe63e4cae2ba9b72390f580cac344a08bdf6eb9e36ec45bad2a0b82829a72e0efa2d87332c482196e690361168271c55053341ab3
+end
+/sc {60 45 {abs exch abs 2 copy add 1 gt{1.0 sub dup mul exch 1.0 sub dup mul add 1.0 sub}
+{dup mul exch dup mul add 1.0 exch sub}
+ifelse}setscreen} bind def statusdict begin product(LaserWriter II)anchorsearch end
+{pop pop/letter [/letter load /exec load /sc load /exec load]cvx def/legal [/legal load /exec
+load /sc load /exec load]cvx def/a4 [/a4 load /exec load /sc load /exec load]cvx def
+/b5 [/b5 load /exec load /sc load /exec load]cvx def
+/lettersmall [/lettersmall load /exec load /sc load /exec load]cvx def
+/a4small [/a4small load /exec load /sc load /exec load]cvx def
+/note [/note load /exec load /sc load /exec load]cvx def}{pop}ifelse
+systemdict/currentpacking known{currentpacking true setpacking}if
+/LW{save statusdict/product get(LaserWriter)anchorsearch
+exch pop{length 0 eq{1}{2}ifelse}{0}ifelse exch restore}bind def
+/LW+{LW 2 eq}bind def
+/ok{systemdict/statusdict known dup{LW 0 gt and}if}bind def
+
+%AKT ok{statusdict begin 9 sccinteractive 3 ne exch 0 ne or{9 0 3 setsccinteractive}if end}if
+
+/md 270 dict def md begin
+/av 0 def
+/T true def/F false def/mtx matrix def/s75 75 string def/sa8 8 string def/sb8 8 string def
+/sc8 8 string def/sd8 8 string def/s1 ( ) def/pxs 1 def/pys 1 def
+/ns false def
+1 0 mtx defaultmatrix dtransform exch atan/pa exch def/nlw .24 def/ppr [-32 -29.52 762 582.48] def
+/pgr [0 0 0 0] def
+/pgs 1 def/por true def/xb 500 array def/so true def/tso true def/fillflag false def/pnm 1 def/fmv true def
+/sfl false def/ma 0 def/invertflag false def/dbinvertflag false def/xflip false def/yflip false def/noflips true def/scaleby96 false def/fNote true def/fBitStretch true def
+/4colors false def/3colors false def/2colors false def
+/wtkey false def
+statusdict begin/waittimeout where{pop waittimeout 300 lt{md /wtkey true put}if}if end
+wtkey{statusdict begin/setdefaulttimeouts where{pop 0 60 300 setdefaulttimeouts}if end}if
+/fg (Rvd\001\001\000\000\177) def
+/bdf{bind def}bind def
+/xdf{exch def}bdf
+/xl{neg exch neg translate}bdf
+/fp{pnsh 0 ne pnsv 0 ne and}bdf
+/nop{}bdf/lnop[/nop load]cvx bdf
+/vrb[
+{fp{fg 6 get 0 ne{gsave stroke grestore}{gsave 1 setlinewidth pnsh pnsv scale stroke grestore}ifelse}if newpath}bind
+/eofill load
+dup
+/newpath load
+2 index
+dup
+{clip newpath}bind
+{}bind
+dup
+2 copy
+]def
+systemdict/currentcolorscreen known{currentcolorscreen/dkspf xdf/dkrot xdf/dkfreq xdf/dyspf xdf/dyrot xdf/dyfreq xdf/dmspf xdf/dmrot xdf/dmfreq xdf
+/dcspf xdf/dcrot xdf/dcfreq xdf}{currentscreen/spf xdf/rot xdf/freq xdf}ifelse
+/doop{vrb exch get exec}bdf
+/psu{/udf xdf/tso xdf /fNote xdf/fBitStretch xdf/scaleby96 xdf/yflip xdf/xflip xdf
+/invertflag xdf/dbinvertflag invertflag statusdict begin
+version cvr 47.0 ge product (LaserWriter) eq not and end invertflag and {not}if def
+xflip yflip or{/noflips false def}if
+/pgs xdf 2 index .72 mul exch div/pys xdf div .72 mul/pxs xdf ppr astore pop pgr astore pop/por xdf sn and/so xdf}bdf
+/tab{statusdict /11x17 known{statusdict begin /11x17 load end}{statusdict /setpage known{statusdict begin 792 1224 1 setpage end}{statusdict /setpageparams known{statusdict begin 792 1224 0 1 setpageparams end}if}ifelse}ifelse}bdf
+/a3Size{statusdict /a3 known{statusdict begin /a3 load end}{statusdict /setpageparams known{statusdict begin 842 1191 0 1 setpageparams end}if}ifelse}bdf
+/txpose{fNote{smalls}{bigs}ifelse pgs get exec pxs pys scale ppr aload pop por{noflips{pop exch neg exch translate pop 1 -1 scale}if
+xflip yflip and{pop exch neg exch translate 180 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg translate}if
+xflip yflip not and{pop exch neg exch translate pop 180 rotate ppr 3 get ppr 1 get neg sub neg 0 translate}if yflip xflip not and{ppr 1 get neg ppr 0 get neg translate}if}
+{noflips{translate pop pop 270 rotate 1 -1 scale}if xflip yflip and{translate pop pop 90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg translate}if
+xflip yflip not and{translate pop pop 90 rotate ppr 3 get ppr 1 get neg sub neg 0 translate}if yflip xflip not and{translate pop pop 270 rotate ppr 2 get ppr 0 get neg sub neg 0 exch translate}if}ifelse
+wtkey{statusdict/waittimeout 300 put}if
+scaleby96{ppr aload pop 4 -1 roll add 2 div 3 1 roll add 2 div 2 copy translate .96 dup scale neg exch neg exch translate}if}bdf
+/fr{4 copy pgr aload pop 3 -1 roll add 3 1 roll exch add 6 2 roll 3 -1 roll
+sub 3 1 roll exch sub 3 -1 roll exch div 3 1 roll div exch scale pop pop xl}bdf
+/obl{{0.212557 mul}{pop 0}ifelse}bdf
+/sfd{ps fg 5 -1 roll get mul 100 div 0 ps 5 -1 roll obl ps neg 0 0 6a astore makefont setfont}bdf
+/fnt{findfont sfd}bdf
+/bt{sa 3 1 roll 3 index and put}bdf
+/sa(\000\000\000\000\000\000\000\000\000\000)def
+/fs{0 1 bt 1 2 bt 2 4 bt 3 8 bt 4 16 bt 5 32 bt 6 64 bt 7 128 bt sa exch 8 exch put}bdf
+/mx1 matrix def
+/mx2 matrix def
+/mx3 matrix def
+/bu{currentpoint 4colors{currentcmykcolor}{currentrgbcolor}ifelse currentlinewidth currentlinecap currentlinejoin
+currentdash exch aload length fg 5 sfl{1}{0}ifelse put pnsv pnsh
+2t aload pop 3a aload pop mx2 aload pop mx1 aload pop mtx currentmatrix aload pop
+mx3 aload pop ps pm restore/ps xdf mx3 astore pop}bdf
+/bn{/pm save def mx3 setmatrix newpath 0 0 moveto ct dup 39 get 0 exch getinterval cvx exec mtx astore setmatrix mx1 astore pop mx2 astore pop 3a
+astore pop 2t astore pop/pnsh xdf/pnsv xdf gw
+/sfl fg 5 get 0 ne def array astore exch setdash setlinejoin setlinecap
+setlinewidth 4colors{setcmykcolor}{setrgbcolor}ifelse moveto}bdf
+/fc{save vmstatus exch sub 50000 lt
+{(%%[|0|]%%)=print flush}if pop restore}bdf
+/tc{32768 div add 3 1 roll 32768 div add 2t astore pop}bdf
+/3a [0 0 0] def
+/2t 2 array def
+/tp{3a astore pop}bdf
+/tt{mx2 currentmatrix pop currentpoint 2 copy 2t aload pop qa 2 copy translate 3a aload pop exch dup 0 eq
+{pop}{1 eq{-1 1}{1 -1}ifelse scale}ifelse rotate pop neg exch neg exch translate moveto}bdf
+/te{mx2 setmatrix}bdf
+/th{3 -1 roll div 3 1 roll exch div 2 copy mx1 scale pop scale/sfl true def}bdf
+/tu{1 1 mx1 itransform scale/sfl false def}bdf
+/ts{1 1 mx1 transform scale/sfl true def}bdf
+/fz{/ps xdf}bdf
+/dv{dup 0 ne{div}{pop}ifelse}bdf
+/pop4{pop pop pop pop}bdf
+/it{sfl{mx1 itransform}if}bdf
+/gm{exch it moveto}bdf/rm{it rmoveto}bdf
+/lm{currentpoint sfl{mx1 transform}if exch pop sub 0 exch it rmoveto}bdf
+/fm{statusdict/manualfeed known}bdf
+/se{statusdict exch/manualfeed exch put}bdf
+/mf{dup/ma exch def 0 gt{fm se/t1 5 st ok ma 1 gt and{/t2 0 st/t3 0 st
+statusdict/manualfeedtimeout 3600 put
+}if}if}bdf
+/jn{/statusdict where exch pop{statusdict exch /jobname exch put}if}bdf
+/pen{pnm mul/pnsh xdf pnm mul/pnsv xdf pnsh setlinewidth}bdf
+/min{2 copy gt{exch}if pop}bdf
+/max{2 copy lt{exch}if pop}bdf
+/dh{fg 6 1 put array astore dup {1 pxs div mul exch}forall astore exch pop exch pop exch setdash}bdf
+/ih[currentdash]def
+/rh{fg 6 0 put ih aload pop setdash}bdf
+/dl{gsave nlw pys div setlinewidth 0 setgray}bdf
+/dlin{exch currentpoint currentlinewidth 2 div dup
+translate newpath moveto lineto currentpoint stroke grestore moveto}bdf
+/lin{fg 6 get 0 ne{exch lineto currentpoint 0 doop moveto}
+{exch currentpoint/pnlv xdf/pnlh xdf gsave newpath/@1 xdf/@2 xdf fp{pnlh @2 lt{pnlv @1 ge
+{pnlh pnlv moveto @2 @1 lineto pnsh 0 rlineto
+0 pnsv rlineto pnlh pnsh add pnlv pnsv add lineto pnsh neg 0 rlineto}
+{pnlh pnlv moveto pnsh 0 rlineto @2 pnsh add @1 lineto 0 pnsv rlineto
+pnsh neg 0 rlineto pnlh pnlv pnsv add lineto}ifelse}{pnlv @1 gt
+{@2 @1 moveto pnsh 0 rlineto pnlh pnsh add pnlv lineto 0 pnsv rlineto
+pnsh neg 0 rlineto @2 @1 pnsv add lineto}{pnlh pnlv moveto pnsh 0 rlineto
+0 pnsv rlineto @2 pnsh add @1 pnsv add lineto pnsh neg 0 rlineto
+0 pnsv neg rlineto}ifelse}ifelse
+closepath fill}if @2 @1 grestore moveto}ifelse}bdf
+/gw{/pnm fg 3 get fg 4 get div def}bdf
+/lw{fg exch 4 exch put fg exch 3 exch put gw pnsv pnsh pen}bdf
+/barc{/@1 xdf/@2 xdf/@3 xdf/@4 xdf/@5 xdf
+/@6 xdf/@7 xdf/@8 xdf gsave
+@5 @7 add 2 div @6 @8 add 2 div translate newpath 0 0 moveto
+@5 @7 sub @6 @8 sub mtx currentmatrix pop scale @1{newpath}if
+0 0 0.5 @4 @3 arc @4 @3 sub abs 360 ge{closepath}if
+mtx setmatrix @2 doop grestore}bdf
+/ar{dup 0 eq barc}bdf
+/ov{0 exch 360 exch true barc}bdf
+/rc{/@t xdf currentpoint 6 2 roll newpath 4 copy 4 2 roll exch moveto
+6 -1 roll lineto lineto lineto closepath @t doop moveto}bdf
+/mup{dup pnsh 2 div le exch pnsv 2 div le or}bdf
+/rr{/@1 xdf 2. div/@2 xdf 2. div/@3 xdf
+/@4 xdf/@5 xdf/@6 xdf/@7 xdf
+@7 @5 eq @6 @4 eq @2 mup or or{@7 @6 @5 @4 @1 rc}
+{@4 @6 sub 2. div dup @2 lt{/@2 xdf}{pop}ifelse
+@5 @7 sub 2. div dup @2 lt{/@2 xdf}{pop}ifelse
+@1 0 eq{/@2 @2 pnsh 2 div 2 copy gt{sub def}{0 pop4}ifelse}if
+currentpoint newpath
+@4 @6 add 2. div @7 moveto
+@4 @7 @4 @5 @2 arcto pop4
+@4 @5 @6 @5 @2 arcto pop4
+@6 @5 @6 @7 @2 arcto pop4
+@6 @7 @4 @7 @2 arcto pop4
+closepath @1 doop moveto}ifelse}bdf
+/pr{gsave newpath/pl{exch moveto/pl{exch lineto}def}def}bdf
+/pl{exch lineto}bdf
+/ep{dup 0 eq{{moveto}{exch lin}{}{(%%[|1|]%%)= flush}pathforall
+pop grestore}{doop grestore}ifelse currentpoint newpath moveto}bdf
+/gr{64. div setgray}bdf
+/savescreen{ns not{/ns true def systemdict/currentcolorscreen known{currentcolorscreen/pkspf xdf/pkrot xdf/pkfreq xdf/pyspf xdf/pyrot xdf/pyfreq xdf/pmspf xdf/pmrot xdf/pmfreq xdf
+/pcspf xdf/pcrot xdf/pcfreq xdf}{currentscreen/sspf xdf/srot xdf/sfreq xdf}ifelse}if}bdf
+/restorescreen{/ns false def systemdict/setcolorscreen known{pcfreq pcrot/pcspf load pmfreq pmrot/pmspf load pyfreq pyrot/pyspf load
+pkfreq pkrot/pkspf load setcolorscreen}{sfreq srot/sspf load setscreen}ifelse}bdf
+/pat{savescreen sa8
+copy pop 9.375 pa por not{90 add}if{1 add 4 mul cvi sa8 exch get exch 1 add 4 mul cvi 7 sub bitshift 1 and}setscreen exch not{gr}{pop}ifelse}bdf
+/sg{restorescreen gr}bdf
+/cpat{savescreen 10 2 roll 7 -1 roll sa8 copy pop 9.375 pa por not{90 add}if{1 add 4 mul cvi sa8 exch get exch 1 add 4 mul cvi 7 sub bitshift 1 and}8 -1 roll sb8 copy pop 9.375 pa por not{90 add}if{1 add 4 mul cvi sb8
+exch get exch 1 add 4 mul cvi 7 sub bitshift 1 and}9 -1 roll sc8 copy pop 9.375 pa por not{90 add}if{1 add 4 mul cvi sc8 exch get exch 1 add 4 mul cvi 7 sub bitshift 1 and} %AKT broke long line
+10 -1 roll sd8 copy pop 9.375 pa por not{90 add}if{1 add 4 mul cvi sd8
+exch get exch 1 add 4 mul cvi 7 sub bitshift 1 and}psuedo1 dsc 4{4 -1 roll 1 exch 64 div sub}repeat setcmykcolor pop pop}bdf
+systemdict/setcolorscreen known{/psuedo1 lnop bdf/dsc/setcolorscreen load def}{/psuedo1{16{pop}repeat sa8 copy pop 9.375 pa por not{90 add}if{1 add 4 mul cvi sa8 exch get exch 1 add 4 mul cvi 7 sub bitshift 1 and}}bdf
+/bwsc{setscreen dup gr 0 exch 0 exch 64 exch 64 exch 64 exch}bdf/dsc/bwsc load def
+}ifelse
+systemdict/setcmykcolor known not{/setcmykcolor{1 sub 4 1 roll 3{3 index add neg dup 0 lt{pop 0}if 3 1 roll}repeat setrgbcolor pop}bdf}if
+/dc{transform round .5 sub exch round .5 sub exch itransform}bdf
+/sn{userdict/smooth4 known}bdf
+/x8{3 bitshift}bdf
+/x4{2 bitshift}bdf
+/d4{-2 bitshift}bdf
+/d8{-3 bitshift}bdf
+/rb{15 add -4 bitshift 1 bitshift}bdf
+/db{/@7 save def/@1 xdf/@2 xdf/@3 xdf/@4 xdf/@5 xdf/@6 @5 @3 4 add mul def
+dc translate scale/xdbit 1 1 idtransform abs/ydbit exch def abs def{0 0 1 ydbit add 1 10 rc clip}if
+@1 0 eq @1 4 eq or{currentrgbcolor 1 setgray ydbit 0 1 ydbit add 1 2 rc setrgbcolor}if
+@1 3 eq @1 7 eq or{1 setgray}{currentrgbcolor 2 index eq exch 2 index eq and exch pop{0 setgray}if}ifelse/@9 @1 0 eq @1 1 eq @1 3 eq or or dbinvertflag xor def/@13 @6 def
+@2 fBitStretch or{/@10 @4 x4 def/@11 @3 x4 def/@12 @10 rb def/@13 @12 @11 mul def/@15 1 1 dtransform abs/calcY 1 index def round cvi/@14 exch def
+abs/calcX 1 index def round cvi scaleby96 not{1 add}if def/@16 @15 rb def/@17 @16 @14 mul def}if
+sn @13 60000 lt and @2 fBitStretch or and{mtx currentmatrix dup 1 get exch 2 get 0. eq exch 0. eq and @17 60000 lt and fBitStretch and{@16 3 bitshift @14 @9 [calcX 0 0 calcY 0 0]{@17 string @13 string
+currentfile @6 string readhexstring pop 1 index @4 @3 @5 @12 @2 smooth4
+@10 @11 @12 dup string 5 index @15 @14 @16 dup string stretch}imagemask}{@12 x8 @11 @9 [@10 0 0 @11 0 0]{@13 string
+currentfile @6 string readhexstring pop 1 index @4 @3 @5 @12 @2 smooth4}imagemask}ifelse}{@5 3 bitshift @3 4 add @9 [@4 0 0 @3 0 2]{currentfile @6 string readhexstring pop}imagemask}ifelse
+@7 restore}bdf
+systemdict/setcmykcolor known{/psuedo lnop bdf/di/colorimage load def}{/routines[{.3 mul add 1}bind{.59 mul add 2}bind{.11 mul add round cvi str exch i exch put/i i 1 add def 0 0}bind]def
+/psuedo{/i 0 def 0 exch 0 exch{exch routines exch get exec}forall pop pop str}bdf/bwi{pop pop image}bdf/di/bwi load def}ifelse
+/cdb{/@7 save def/@1 xdf/@2 xdf/@3 xdf/@4 xdf/@5 xdf
+systemdict/setcmykcolor known not{dc}if translate scale /@6 xdf
+/@18 @5 dup 60000 ge{pop 60000}if string def @6 not{/str @18 0 @18 length 3 idiv getinterval def}if @4 @3 8 [@4 0 0 @3 0 0]@6{{currentfile @18 readhexstring pop}image} %AKT broke long line
+{{currentfile @18 readhexstring pop psuedo}false 3 di}ifelse @7 restore}bdf
+/wd 16 dict def
+/mfont 14 dict def
+/mdf{mfont wcheck not{/mfont 14 dict def}if mfont begin xdf end}bdf
+/cf{{1 index/FID ne{def}{pop pop}ifelse}forall}bdf/rf{/@1 exch def/@2 exch def
+FontDirectory @2 known{cleartomark pop}{findfont dup begin dup length @1 add dict begin
+cf{/Encoding macvec def}{Encoding dup length array copy/Encoding exch def
+counttomark 2 idiv{Encoding 3 1 roll put}repeat}ifelse
+pop
+exec currentdict end end @2 exch definefont pop}ifelse}bdf
+/bmbc{exch begin wd begin
+/cr xdf
+save
+CharTable cr 6 mul 6 getinterval{}forall
+/bitheight xdf/bitwidth xdf
+.96 div/width xdf
+Gkernmax add/XOffset xdf Gdescent add/YOffset xdf/rowbytes xdf
+rowbytes 255 eq{0 0 0 0 0 0 setcachedevice}
+{Gnormsize dup scale
+width 0 XOffset YOffset bitwidth XOffset add bitheight YOffset add
+setcachedevice
+rowbytes 0 ne{
+XOffset YOffset translate newpath 0 0 moveto
+bitwidth bitheight scale
+sn{
+/xSmt bitwidth x4 def
+/ySmt bitheight x4 def
+/rSmt xSmt rb def
+rSmt x8 ySmt true
+[xSmt 0 0 ySmt neg 0 ySmt]
+{rSmt ySmt mul string CharData cr get
+1 index bitwidth bitheight rowbytes rSmt tso smooth4}
+}{rowbytes 3 bitshift bitheight 4 add true
+[bitwidth 0 0 bitheight neg 0 bitheight 2 add]
+{CharData cr get}
+}ifelse
+imagemask
+}if
+}ifelse
+restore
+end end
+}bdf
+/bb{.96 exch div/Gnormsize mdf 2 index
+/Gkernmax mdf 1 index/Gdescent mdf
+3 index div 4 1 roll
+2 index div 1. 5 2 roll
+exch div 4 1 roll
+4 array astore/FontBBox mdf
+}bdf
+/cdf{mfont/CharData get 3 1 roll put}bdf
+/bf{
+mfont begin
+/FontType 3 def
+/FontMatrix [1 0 0 1 0 0] def
+/Encoding macvec def
+/MFontType 0 def
+/BuildChar/bmbc load def
+end
+mfont definefont pop
+}bdf
+/wi LW 1 eq{{gsave 0 0 0 0 0 0 0 0 moveto lineto lineto lineto closepath clip stringwidth grestore}bind}{/stringwidth load}ifelse def
+/aps{0 get 124 eq}bdf
+/xc{s75 cvs dup}bdf
+/xp{put cvn}bdf
+/scs{xc 3 67 put dup 0 95 xp}bdf
+/sos{xc 3 79 xp}bdf
+/sbs{xc 1 66 xp}bdf
+/sis{xc 2 73 xp}bdf
+/sob{xc 2 79 xp}bdf
+/sss{xc 4 83 xp}bdf
+/dd{exch 1 index add 3 1 roll add exch}bdf
+/smc{moveto dup show}bdf
+/ndf2{udf{dup /FontType get 0 eq{/FDepVector get{dup /FontType get 0 eq{ndf2}{dup /df2 known{begin df2 0 null put end
+}{pop}ifelse}ifelse}forall}{/df2 known{dup begin df2 0 null put end}if}ifelse}{pop}ifelse}bdf
+/kwn{FontDirectory 1 index known{findfont dup ndf2 exch pop}}bdf
+/gl{1 currentgray sub setgray}bdf
+/newmm{dup /FontType get 0 eq{dup maxlength dict begin{1 index/FID ne 2 index/UniqueID ne and{def}{pop pop}ifelse}forall currentdict end
+dup /FDepVector 2 copy get[exch 6 index exch 6 index exch{newmm 3 1 roll}forall pop pop] put dup
+}{/mfont 10 dict def mfont begin/FontMatrix [1 0 0 1 0 0] def
+/FontType 3 def/Encoding macvec def/df 1 index def/df2 1 array def/FontBBox [0 0 1 1] def/StyleCode 2 index def
+/mbc{bcarray StyleCode get}def/BuildChar{exch begin wd begin/cr exch def/cs s1 dup 0 cr put def df /MFontType known not{
+df2 0 get null eq{df dup length 2 add dict begin{1 index/FID ne 2 index/UniqueID ne and{def}{pop pop}ifelse}forall
+/StrokeWidth nlw 1000 mul pys div ps div dup 12 lt{pop 12}if def/PaintType 2 def currentdict end
+/q exch definefont df2 exch 0 exch put}if}if mbc exec end end}def end mfont}ifelse
+3 index exch definefont exch pop}bdf
+/mb{dup sbs kwn{0 2 index findfont newmm exch pop exch pop exch pop}ifelse sfd}bdf
+/mo{dup sos kwn{2 2 index findfont newmm exch pop exch pop exch pop}ifelse sfd}bdf
+/ms{dup sss kwn{4 2 index findfont newmm exch pop exch pop exch pop}ifelse sfd}bdf
+/ou{dup sos kwn{mfont/df2 known{mfont begin df2 0 null put end}if 3 2 index findfont newmm exch pop exch pop exch pop}ifelse sfd}bdf
+/su{dup sss kwn{mfont/df2 known{mfont begin df2 0 null put end}if 5 2 index findfont newmm exch pop exch pop exch pop}ifelse sfd}bdf
+/ao{/fmv true def ou}bdf/as{/fmv true def su}bdf
+/vo{/fmv false def ou}bdf/vs{/fmv false def su}bdf
+/c{currentrgbcolor dup 4 1 roll eq 3 1 roll eq and/gray xdf}bdf
+/bcarray[{/da .03 def df setfont gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth
+cs 0 0 smc da 0 smc da da smc 0 da moveto show}bind dup{/da 1 ps div def df setfont gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth
+cs 0 0 smc da 0 smc da da smc 0 da smc c gray{gl}{1 setgray}ifelse da 2. div dup moveto show}bind
+{df setfont gsave cs wi grestore setcharwidth c gray{gl}{currentrgbcolor 1 setgray}ifelse cs 0 0 smc df2 0 get setfont
+gray{gl}{4 1 roll setrgbcolor}ifelse 0 0 moveto show}bind
+{/da 1 ps div def/ds .05 def/da2 da 2. div def df setfont gsave cs wi 1 index 0 ne{exch ds add da2 add exch}if grestore setcharwidth
+cs ds da2 add .01 add 0 smc 0 ds da2 sub translate 0 0 smc da 0 smc da da smc 0 da smc c gray{gl}{1 setgray}ifelse da 2. div dup moveto show}bind
+{/da .05 def df setfont gsave cs wi 1 index 0 ne{exch da add exch}if grestore setcharwidth c cs da .01 add 0 smc 0 da translate
+gray{gl}{currentrgbcolor 1 setgray 4 -1 roll}ifelse 0 0 smc gray{gl}{4 1 roll setrgbcolor}ifelse df2 0 get setfont 0 0 moveto show}bind]def
+/st{1000 mul usertime add dup 2147483647 gt{2147483647 sub}if def}bdf
+/the{usertime sub dup 0 lt exch -2147483648 gt and}bdf
+/6a 6 array def
+/2a 2 array def
+/3q 3 array def
+/qs{3 -1 roll sub exch 3 -1 roll sub exch}bdf
+/qa{3 -1 roll add exch 3 -1 roll add exch}bdf
+/qm{3 -1 roll 1 index mul 3 1 roll mul}bdf
+/qn{6a exch get mul}bdf
+/qA .166667 def/qB .833333 def/qC .5 def
+/qx{6a astore pop
+qA 0 qn qB 2 qn add qA 1 qn qB 3 qn add
+qB 2 qn qA 4 qn add qB 3 qn qA 5 qn add
+qC 2 qn qC 4 qn add qC 3 qn qC 5 qn add}bdf
+/qp{6 copy 12 -2 roll pop pop}bdf
+/qc{exch qp qx curveto}bdf
+/qi{{exch 4 copy 2a astore aload pop qa .5 qm newpath moveto}{exch 2 copy 6 -2 roll 2 qm qs 4 2 roll}ifelse}bdf
+/qq{{qc 2a aload pop qx curveto}{exch 4 copy qs qa qx curveto}ifelse}bdf
+/pt{currentpoint newpath moveto}bdf
+/qf{/fillflag true def}bdf
+/ec{dup 4 and 0 ne{closepath}if 1 and 0 ne{0 doop}if grestore currentpoint newpath moveto/fillflag false def}bdf
+/eu{currentpoint fp{0 ep}{grestore newpath}ifelse moveto/fillflag false def}bdf
+/bp{currentpoint newpath 2 copy moveto}bdf
+/ef{gsave fillflag{gsave eofill grestore}if}bdf
+/sm{0 exch{@1 eq{1 add}if}forall}bdf
+/lshow{4 1 roll exch/@1 exch def{1 index wi pop sub 1 index sm dv 0 @1 4 -1 roll widthshow}{1 index wi pop sub
+1 index dup sm 10 mul exch length 1 sub add dv dup 10. mul 0 @1 4 -1 roll 0 6 -1 roll awidthshow}ifelse}bdf
+/setTxMode{sa 9 2 index put exch not{3 eq{1}{0}ifelse setgray}{pop}ifelse}bdf
+/SwToSym{{}mark false/Symbol/|______Symbol 0 rf 0 sa 6 get 0 ne{pop 1}{sa 7 get 0 eq{pop 2}if}ifelse
+sa 1 get 0 ne/|______Symbol
+sa 4 get 0 ne{vs}{sa 3 get 0 ne{vo}{fnt}ifelse}ifelse}bdf
+/mc{0 3 1 roll transform neg exch pop}bdf
+/ul{dup 0 ne sa 2 get 0 ne and{gsave 0 0
+/UnderlinePosition kif{mc}{ps -10 div}ifelse/UnderlineThickness kif{mc}{ps 15 div}ifelse
+abs setlinewidth neg rmoveto
+sa 4 get 0 ne{gsave currentlinewidth 2. div dup rmoveto currentpoint newpath moveto
+2 copy rlineto stroke grestore}if
+sa 3 get sa 4 get or 0 ne{gsave currentrgbcolor dup 4 1 roll eq 3 1 roll eq and{gl}{1 setgray}ifelse 2 copy rlineto stroke grestore rlineto strokepath nlw pys div setlinewidth}{rlineto}ifelse
+stroke grestore}{pop}ifelse}bdf
+/sgt{2 copy known{get true}{pop pop false}ifelse}bdf
+/kif{currentfont dup/FontMatrix get exch/FontInfo sgt{true}{currentfont/df sgt
+{dup/FontInfo sgt{3 1 roll/FontMatrix get mtx concatmatrix exch true}{pop pop pop false}
+ifelse}{pop pop false}ifelse}ifelse{3 -1 roll sgt{exch true}{pop false}ifelse}{false}ifelse}bdf
+/blank/Times-Roman findfont/CharStrings get/space get def
+/macvec 256 array def
+/NUL/SOH/STX/ETX/EOT/ENQ/ACK/BEL/BS/HT/LF/VT/FF/CR/SO/SI
+/DLE/DC1/DC2/DC3/DC4/NAK/SYN/ETB/CAN/EM/SUB/ESC/FS/GS/RS/US
+macvec 0 32 getinterval astore pop
+macvec 32/Times-Roman findfont/Encoding get
+32 96 getinterval putinterval macvec dup 39/quotesingle put 96/grave put
+/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute
+/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave
+/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde/oacute
+/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex/udieresis
+/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/notequal/AE/Oslash
+/infinity/plusminus/lessequal/greaterequal/yen/mu/partialdiff/summation
+/product/pi/integral/ordfeminine/ordmasculine/Omega/ae/oslash
+/questiondown/exclamdown/logicalnot/radical/florin/approxequal/Delta/guillemotleft
+/guillemotright/ellipsis/blank/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide/lozenge
+/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright/fi/fl
+/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand/Acircumflex/Ecircumflex/Aacute
+/Edieresis/Egrave/Iacute/Icircumflex/Idieresis/Igrave/Oacute/Ocircumflex
+/apple/Ograve/Uacute/Ucircumflex/Ugrave/dotlessi/circumflex/tilde
+/macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron
+macvec 128 128 getinterval astore pop
+{}mark true/Courier/|______Courier 0 rf
+{/Metrics 21 dict begin/zero 600 def/one 600 def/two 600 def/three 600 def/four 600 def/five 600 def/six 600 def/seven 600 def/eight 600 def
+/nine 600 def/comma 600 def/period 600 def/dollar 600 def/numbersign 600 def/percent 600 def/plus 600 def/hyphen 600 def/E 600 def/parenleft 600 def/parenright 600 def/space 600 def
+currentdict end def currentdict/UniqueID known{/UniqueID 16#800000 def}if/FontBBox FontBBox 4 array astore def}mark true/Helvetica/|______Seattle 1 rf
+/oldsettransfer/settransfer load def
+/concatprocs{/proc2 exch cvlit def/proc1 exch cvlit def/newproc proc1 length proc2 length add array def
+newproc 0 proc1 putinterval newproc proc1 length proc2 putinterval newproc cvx}def
+/settransfer{currenttransfer concatprocs oldsettransfer}def
+/PaintBlack{{1 exch sub}settransfer gsave newpath clippath 1 setgray fill grestore}def
+/od{
+
+%AKT replace this line: (Rvd\001\001\000\000\177) fg copy pop txpose
+1 -1 scale %AKT with this
+
+1 0 mtx defaultmatrix dtransform exch atan/pa exch def
+newpath clippath mark
+{transform{itransform moveto}}{transform{itransform lineto}}
+{6 -2 roll transform 6 -2 roll transform 6 -2 roll transform
+{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll curveto}}
+{{closepath}}pathforall newpath counttomark array astore/gc xdf pop ct 39 0 put
+10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}if
+statusdict/processcolors known{statusdict begin processcolors end dup 4 eq
+{/4colors true def pop}{3 eq{/3colors true def}{/2color true def}ifelse}ifelse}
+{/2colors true def}ifelse}bdf
+/cd{}bdf
+/op{/sfl false def systemdict/currentcolorscreen known{dcfreq dcrot/dcspf load
+dmfreq dmrot/dmspf load dyfreq dyrot/dyspf load
+dkfreq dkrot/dkspf load setcolorscreen}{freq rot/spf load setscreen}ifelse savescreen
+/ns false def/pm save def}bdf
+/cp{not{userdict/#copies 0 put}if ma 0 gt
+{{t1 the{exit}if}loop}if{copypage}{showpage}ifelse pm restore}def %AKT was }bdf
+/px{0 3 1 roll tp tt}bdf
+/psb{/us save def}bdf
+/pse{us restore}bdf
+/ct 40 string def
+/nc{currentpoint initclip newpath gc{dup type dup/arraytype eq exch/packedarraytype eq or{exec}if}
+forall clip newpath moveto}def
+/kp{ct 0 2 index length 2 index 39 2 index put getinterval copy cvx exec mx3 currentmatrix pop}bdf
+/av 70 def
+end
+LW 1 eq userdict/a4small known not and{/a4small
+[[300 72 div 0 0 -300 72 div -120 3381]
+280 3255
+{statusdict/jobstate (printing) put 0 setblink
+margins
+exch 196 add exch 304 add 8 div round cvi frametoroket
+statusdict/jobstate (busy) put
+1 setblink}
+/framedevice load
+60 45{dup mul exch dup mul add 1.0 exch sub}/setscreen load
+{}/settransfer load/initgraphics load/erasepage load]cvx
+statusdict begin bind end readonly def}if
+md begin/bigs[lnop userdict/letter known{/letter load}{lnop}ifelse userdict/legal known{/legal load}{lnop}ifelse userdict/a4 known{/a4 load}{lnop}ifelse userdict/b5 known{/b5 load}{lnop}ifelse
+lnop lnop lnop /tab load/a3Size load]def
+/smalls[lnop userdict/lettersmall known{/lettersmall load}{userdict/note known{/note load}{lnop}ifelse}ifelse
+userdict/legal known{/legal load}{lnop}ifelse userdict/a4small known{/a4small load}{lnop}ifelse
+userdict/b5 known{/b5 load}{userdict/note known{/note load}{lnop}ifelse}ifelse lnop lnop lnop /tab load/a3Size load]def end
+systemdict/currentpacking known{setpacking}if
+
+%AKT /checkload{{currentfile eexec} {/junk save def/mystring 65000 string def
+%AKT /endexec (%endeexec) def{currentfile mystring readline not{stop}if endexec eq{exit}if}loop junk restore}ifelse}bind def
+%AKT ok userdict/stretch known not and checkload
+%AKT ...
+%AKT (removed long lines of hex data)
+%AKT ...
+%AKT cleartomark
+%AKT ok userdict/smooth4 known not and checkload
+%AKT ...
+%AKT (removed long lines of hex data)
+%AKT ...
+%AKT cleartomark
+
+%%EndProcSet
+
+%%EOF
diff --git a/dviware/psprint/vms/lines.dat b/dviware/psprint/vms/lines.dat
new file mode 100644
index 0000000000..d358a72637
--- /dev/null
+++ b/dviware/psprint/vms/lines.dat
@@ -0,0 +1,66 @@
+1 This text file has 66 lines, one of which is 132 characters wide.
+2
+3
+123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012
+5
+6
+7
+8
+9
+10
+1
+2
+3
+4
+5
+6
+7
+8
+9
+20
+1
+2
+3
+4
+5
+6
+7
+8
+9
+30
+1
+2
+3
+4
+5
+6
+7
+8
+9
+40
+1
+2
+3
+4
+5
+6
+7
+8
+9
+50
+1
+2
+3
+4
+5
+6
+7
+8
+9
+60
+1
+2
+3
+4
+5
+6
diff --git a/dviware/psprint/vms/lino_fonts.ps b/dviware/psprint/vms/lino_fonts.ps
new file mode 100644
index 0000000000..e0c18a2fcc
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/lino_header.ps b/dviware/psprint/vms/lino_header.ps
new file mode 100644
index 0000000000..0ef14bdeb4
--- /dev/null
+++ b/dviware/psprint/vms/lino_header.ps
@@ -0,0 +1,267 @@
+% 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
+{ 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
+ 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
+
+% margin is offset (in pts) from paper edge.
+% LINO_PRINT.COM 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
+
+% LINO_PRINT.COM will override this default if user asks for /NOCUTMARKS:
+
+/@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/vms/lino_pages.ps b/dviware/psprint/vms/lino_pages.ps
new file mode 100644
index 0000000000..f9af8a3913
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/lino_print.com b/dviware/psprint/vms/lino_print.com
new file mode 100644
index 0000000000..9e5219280e
--- /dev/null
+++ b/dviware/psprint/vms/lino_print.com
@@ -0,0 +1,153 @@
+$! This command file is run by PSPRINT/DEV=LINO with the following parameters:
+$! P1 = complete file specification
+$! P2 = file format (DVI or PS or TEXT or TWO or WIDE)
+$! P3 = options for PSDVI
+$! P4 = options for PRINT
+$! P5 = /NOTE value ("" if not used)
+$! P6 = /COPIES value (1 if not used)
+$! P7 = /OUTPUT value ("" if not used)
+$! P8 = "bbbbbsss<prep>" where b = Y or N and represents the status of the
+$! boolean qualifiers /DELETE, /LANDSCAPE, /CUTMARKS, /LOWRES, /BANNER
+$! and sss = /SIZE value (one of those defined in PSPRINT.CLD)
+$! and <prep> is the /PREP value, possibly empty
+$
+$ on control_y then exit
+$ set symbol/scope=(nolocal,noglobal) ! avoid symbol collision
+$
+$! Don't allow text files to be printed on Linotronic:
+$ if (p2 .eqs. "DVI") .or. (p2 .eqs. "PS") then goto CONT0
+$ write sys$output "Linotronic should not be used to print text files."
+$ exit
+$
+$ CONT0:
+$ delflag = f$extract(0,1,p8) ! Y or N
+$ landflag = f$extract(1,1,p8) ! Y or N
+$ cutflag = f$extract(2,1,p8) ! Y or N
+$ lowflag = f$extract(3,1,p8) ! Y or N
+$ bannerflag = f$extract(4,1,p8) ! Y or N
+$ size = f$extract(5,3,p8) ! /SIZE value
+$ prepfile = f$extract(8,999,p8) ! /PREP value
+$ pagesetup = ""
+$ if size .eqs. "A3L" then pagesetup = "A3Lsetup" ! defined in lino_header.ps
+$ if size .eqs. "A4P" then pagesetup = "A4Psetup" ! ditto
+$ if size .eqs. "A4L" then pagesetup = "A4Lsetup" ! ditto
+$ if size .eqs. "A5P" then pagesetup = "A5Psetup" ! ditto
+$ if size .eqs. "A5L" then pagesetup = "A5Lsetup" ! ditto
+$ if size .eqs. "B5P" then pagesetup = "B5Psetup" ! ditto
+$ if size .eqs. "B5L" then pagesetup = "B5Lsetup" ! ditto
+$ if pagesetup .nes. "" then goto CONT1
+$! CLD file should prevent us ever getting here:
+$ write sys$output "Unknown /SIZE value: " + size
+$ exit
+$
+$ CONT1:
+$ if (p6 .gt. 0) .and. (p6 .lt. 101) then goto CONT2
+$ write sys$output "Bad /COPIES value. Specify 1 to 100."
+$ exit
+$
+$ CONT2:
+$ copies = f$string(p6)
+$ job = f$parse(p1,,,"NAME")
+$
+$ copy tex_ps:empty.ps sys$scratch:'job'.tmp
+$ tmpfile = f$search("sys$scratch:''job'.tmp")
+$ write sys$output -
+ "Creating SYS$SCRATCH:''job'.TMP" + f$parse(tmpfile,,,"VERSION")
+$ open/append tmp 'tmpfile'
+$ write tmp "/@USER (" + f$getjpi(0,"USERNAME") -
+ + " " + f$trnlnm("SYS$NODE") + p1 + ") def"
+$ write tmp "/@DATE (" + f$time() + ") def"
+$ write tmp "/@NOTE (" + p5 + ") def"
+$ close tmp
+$ append tex_ps:lino_header.ps 'tmpfile' ! uses above definitions
+$
+$ open/append tmp 'tmpfile'
+$ write tmp "/dev (LINO) def"
+$ res = "1270"
+$ if lowflag .eqs. "Y" then res = "635" ! res also used below
+$ write tmp "/res " + res + " def"
+$ write tmp "/fspec (" + p1 + ") def"
+$ if landflag .eqs. "Y" then write tmp "/land true def"
+$ if landflag .eqs. "N" then write tmp "/land false def"
+$ if bannerflag .eqs. "N" then write tmp "/@bannerpage { } def"
+$ if bannerflag .eqs. "N" then write tmp "/@footerpage { } def"
+$ write tmp "@bannerpage"
+$ write tmp "/@oldpagecount statusdict begin pagecount end def"
+$ write tmp "/#copies " + copies + " def" ! set # of copies
+$ write tmp pagesetup ! call page setup procedure
+$ if cutflag .eqs. "N" then -
+ write tmp "/@cutmarks { } def" ! override default
+$ close tmp
+$
+$ if p2 .eqs. "DVI" then append tex_ps:tex.ps, tex_ps:lino_fonts.ps 'tmpfile'
+$ if p2 .eqs. "PS" then append tex_ps:ps.ps 'tmpfile'
+$
+$ if prepfile .eqs. "" then goto SKIPPREP
+$ write sys$output "Including " + prepfile
+$ append 'prepfile' 'tmpfile'
+$ SKIPPREP:
+$
+$ global = f$search("global.ps")
+$ if (global .eqs. "") .or. (p2 .nes. "DVI") then goto SKIPGLOBAL
+$ write sys$output "Including GLOBAL.PS"
+$ append 'global' 'tmpfile'
+$ SKIPGLOBAL:
+$
+$ if p2 .nes. "DVI" then goto PRINT ! skip DVI processing
+$
+$ ver = 1
+$ LOOP:
+$ psdvifile = "sys$scratch:psdvi.tmp;''f$string(ver)'"
+$ if f$search(psdvifile) .eqs. "" then goto ENDLOOP
+$ ver = ver + 1
+$ goto LOOP
+$
+$ ENDLOOP:
+$ if size .eqs. "A3L" then land = "/x=297mm/y=420mm"
+$ if size .eqs. "A4P" then land = "/x=210mm/y=297mm"
+$ if size .eqs. "A4L" then land = "/x=210mm/y=297mm"
+$ if size .eqs. "A5P" then land = "/x=148mm/y=210mm"
+$ if size .eqs. "A5L" then land = "/x=148mm/y=210mm"
+$ if size .eqs. "B5P" then land = "/x=176mm/y=250mm"
+$ if size .eqs. "B5L" then land = "/x=176mm/y=250mm"
+$! offset: 012345678901
+$! If /LANDSCAPE given then we have to swap /xsize and /ysize values.
+$! Following stmt assumes /x value starts at offset 3 and /y value at offset 11.
+$ if landflag .eqs. "Y" then -
+ land = "/x=" + f$extract(11,5,land) + "/y=" + f$extract(3,5,land)
+$ on warning then goto BADDVI
+$ PSDVI 'p1' 'land' /HEADER='tmpfile' -
+ /OUTPUT='psdvifile' -
+ /RES='res' -
+ /FONT=disk$utils:[utilities.tex.'res'pk] -
+ /DUMMY=cmr10.'res'pk -
+ /CONSERVE -
+ /NOREVERSE 'p3'
+$ delete/nolog 'tmpfile'
+$ rename/nolog 'psdvifile' 'tmpfile'
+$ goto PRINT
+$
+$ BADDVI:
+$ delete/nolog 'tmpfile'
+$ if f$search(psdvifile) .nes. "" then delete/nolog 'psdvifile'
+$ write sys$output ""
+$ write sys$output "Printing aborted due to error(s). Temporary file deleted."
+$ exit
+$
+$ PRINT:
+$ on error then exit
+$ if p2 .eqs. "PS" then append 'p1' 'tmpfile'
+$ ctrld = "tex_ps:ctrld.dat"
+$ if p7 .nes. "" then ctrld = "tex_ps:empty.ps"
+$ append tex_ps:lino_trailer.ps, 'ctrld' 'tmpfile'
+$
+$ if p7 .eqs. "" then goto PRINTJOB
+$ copy tex_ps:empty.ps, 'tmpfile' 'p7'
+$ delete/log 'tmpfile'
+$ write sys$output ""
+$ write sys$output "Nothing printed. PostScript saved in " + p7
+$ exit
+$
+$ PRINTJOB:
+$ print/queue=LINOTRONICS/form=postscript/name='job' 'tmpfile'/delete 'p4'
+$ if delflag .eqs. "Y" then delete/log 'p1'
diff --git a/dviware/psprint/vms/lino_trailer.ps b/dviware/psprint/vms/lino_trailer.ps
new file mode 100644
index 0000000000..26534f7984
--- /dev/null
+++ b/dviware/psprint/vms/lino_trailer.ps
@@ -0,0 +1 @@
+@footerpage % print footer page at end of Linotronic job
diff --git a/dviware/psprint/vms/lw_fonts.ps b/dviware/psprint/vms/lw_fonts.ps
new file mode 100644
index 0000000000..56589c8cd0
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/lw_header.ps b/dviware/psprint/vms/lw_header.ps
new file mode 100644
index 0000000000..66da648430
--- /dev/null
+++ b/dviware/psprint/vms/lw_header.ps
@@ -0,0 +1,138 @@
+% LW_PRINT.COM 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.1 **********************) show newline
+ @USER show newline
+ @ACCOUNT show newline
+ @JOB 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 500 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/vms/lw_print.com b/dviware/psprint/vms/lw_print.com
new file mode 100644
index 0000000000..fc07e54199
--- /dev/null
+++ b/dviware/psprint/vms/lw_print.com
@@ -0,0 +1,178 @@
+$! This command file is run by PSPRINT/DEV=LW with the following parameters:
+$! P1 = complete file specification
+$! P2 = file format (DVI or PS or TEXT or TWO or WIDE)
+$! P3 = options for PSDVI
+$! P4 = options for PRINT
+$! P5 = /NOTE value ("" if not used)
+$! P6 = /COPIES value (1 if not used)
+$! P7 = /OUTPUT value ("" if not used)
+$! P8 = "bbbb<prep>" where b = Y or N and represents the status of the
+$! boolean qualifiers /DELETE, /LANDSCAPE, /BANNER, /MANUALFEED
+$! and <prep> is the /PREP value, possibly empty
+$
+$ on control_y then exit
+$ set symbol/scope=(nolocal,noglobal) ! avoid symbol collision
+$ delflag = f$extract(0,1,p8) ! Y or N
+$ landflag = f$extract(1,1,p8) ! Y or N
+$ bannerflag = f$extract(2,1,p8) ! Y or N
+$ manualflag = f$extract(3,1,p8) ! Y or N
+$ prepfile = f$extract(4,999,p8) ! /PREP value
+$
+$! We arbitrarily restrict /COPIES to <= 100. Other sites might want to
+$! increase this limit or restrict it even further:
+$
+$ if (p6 .gt. 0) .and. (p6 .lt. 101) then goto CONTINUE
+$ write sys$output "Bad /COPIES value. Specify 1 to 100."
+$ exit
+$
+$ CONTINUE:
+$ copies = f$string(p6)
+$ job = f$parse(p1,,,"NAME")
+$
+$! Build temporary file in sys$scratch.
+$! We no longer start with ^D because of problems encountered when
+$! a LaserWriter is connected to an X25 pad (due to echoing of ^D).
+$! We now assume that any previous job has been terminated.
+$! (The LaserWriter server uses ^D to end a job and restore virtual memory.)
+$
+$ copy tex_ps:lw_header.ps sys$scratch:'job'.tmp
+$ tmpfile = f$search("sys$scratch:''job'.tmp") ! include version number
+$ write sys$output -
+ "Creating SYS$SCRATCH:''job'.TMP" + f$parse(tmpfile,,,"VERSION")
+$
+$! tex_ps:lw_header.ps defines @bannerpage and a PostScript error handler.
+$! It also stores the current LaserWriter page count; when @bannerpage
+$! is finally called we can work out how many pages were printed.
+$! Now append various strings that will eventually appear on banner page:
+$
+$ open/append tmp 'tmpfile'
+$ write tmp "/@USER (USER : " + f$getjpi(0,"USERNAME") + ") def"
+$ write tmp "/@ACCOUNT (ACCOUNT : " + f$getjpi(0,"ACCOUNT") + ") def"
+$ write tmp "/@JOB (JOB : " + job + ") def"
+$ write tmp "/@NODE (NODE : " + f$trnlnm("SYS$NODE")-"::" + ") def"
+$ write tmp "/@FILE (FILE : " + p1 + ") def"
+$ write tmp "/@FORMAT (FORMAT : " + p2 + ") def"
+$ write tmp "/@QUEUED (QUEUED : " + f$time() + ") def"
+$
+$! Note that PSPRINT.MOD has prefixed each (,),\ in p5 with \.
+$! Such characters should never occur in the above strings!!!
+$
+$ write tmp "/@NOTE (NOTE : " + p5 + ") def"
+$
+$! The value of #copies will be used by PostScript's showpage operator to
+$! print multiple copies of each page.
+$! This is very efficient but means that copies are not collated.
+$! (Good; we don't want the LaserWriter to be treated like a copier.)
+$
+$ write tmp "/#copies " + copies + " def"
+$
+$! Check for /NOBANNER and /MANUALFEED:
+$
+$ if bannerflag .eqs. "N" then write tmp "/@bannerpage { } def"
+$ if manualflag .eqs. "Y" then write tmp -
+ "statusdict begin /manualfeed true def end"
+$
+$! Here are the definitions used in the job prologues:
+$
+$ write tmp "/dev (LW) def"
+$ write tmp "/res 300 def"
+$ write tmp "/fspec (" + p1 + ") def"
+$ if landflag .eqs. "Y" then write tmp "/land true def"
+$ if landflag .eqs. "N" then write tmp "/land false def"
+$
+$ close tmp
+$
+$! Each type of job requires its own prologue:
+$
+$ if p2 .eqs. "DVI" then append tex_ps:tex.ps, tex_ps:lw_fonts.ps 'tmpfile'
+$ if p2 .eqs. "PS" then append tex_ps:ps.ps 'tmpfile'
+$ if p2 .eqs. "TEXT" then append tex_ps:text.ps 'tmpfile'
+$ if p2 .eqs. "TWO" then append tex_ps:two.ps 'tmpfile'
+$ if p2 .eqs. "WIDE" then append tex_ps:wide.ps 'tmpfile'
+$
+$! /PREP qualifier is only allowed for DVI or PS job:
+$
+$ if (p2 .nes. "DVI") .and. (p2 .nes. "PS") then goto SKIPPREP
+$ if prepfile .eqs. "" then goto SKIPPREP
+$ write sys$output "Including " + prepfile
+$ append 'prepfile' 'tmpfile'
+$ SKIPPREP:
+$
+$! If global.ps exists in the user's current directory then append it
+$! to the prologue for a DVI job:
+$
+$ global = f$search("global.ps")
+$ if (global .eqs. "") .or. (p2 .nes. "DVI") then goto SKIPGLOBAL
+$ write sys$output "Including GLOBAL.PS"
+$ append 'global' 'tmpfile'
+$ SKIPGLOBAL:
+$
+$ if p2 .nes. "DVI" then goto PRINT ! skip PSDVI if non-DVI file
+$
+$! Else run PSDVI.
+$! psdvifile must be a completely new file spec to avoid file name conflicts:
+$
+$ ver = 1
+$ LOOP:
+$ psdvifile = "sys$scratch:psdvi.tmp;''f$string(ver)'"
+$ if f$search(psdvifile) .eqs. "" then goto ENDLOOP
+$ ver = ver + 1
+$ goto LOOP
+$
+$ ENDLOOP: ! psdvifile does not exist
+$ land = ""
+$ if landflag .eqs. "Y" then land = "/xsize=297mm /ysize=210mm" ! rotated A4
+$ on warning then goto BADDVI
+$ PSDVI 'p1' 'land' /HEADER='tmpfile' -
+ /OUTPUT='psdvifile' -
+ /RES=300 -
+ /FONT="disk$utils:[utilities.tex.300pk]" -
+ /DUMMY="cmr10.300pk" -
+ /NOCONSERVE -
+ /NOREVERSE 'p3' ! p3 may override above defaults
+$ delete/nolog 'tmpfile'
+$ rename/nolog 'psdvifile' 'tmpfile'
+$ goto PRINT ! output file is okay
+$
+$! We decide not to print anything if the DVI file has errors.
+$! Sites that don't care about wasting paper may wish to do something else.
+$
+$ BADDVI:
+$ delete/nolog 'tmpfile' ! delete header
+$ if f$search(psdvifile) .nes. "" then - ! delete bad output file
+$ delete/nolog 'psdvifile'
+$ write sys$output ""
+$ write sys$output "Printing aborted due to error(s). Temporary file deleted."
+$ exit
+$
+$ PRINT:
+$ on error then exit
+$
+$! Now complete tmpfile.
+$! For TEXT/TWO/WIDE jobs we must end with ^D.
+$! For DVI/PS jobs we must end with tex_ps:lw_trailer.ps before ^D.
+$! But if /OUTPUT is used we don't append ^D.
+$
+$ ctrld = "tex_ps:ctrld.dat"
+$ if p7 .nes. "" then ctrld = "tex_ps:empty.ps"
+$
+$ if (p2 .eqs. "TEXT") .or. (p2 .eqs. "TWO") .or. (p2 .eqs. "WIDE") then -
+ append 'p1', 'ctrld' 'tmpfile'
+$ if p2 .eqs. "PS" then -
+ append 'p1', tex_ps:lw_trailer.ps, 'ctrld' 'tmpfile'
+$ if p2 .eqs. "DVI" then -
+ append tex_ps:lw_trailer.ps, 'ctrld' 'tmpfile'
+$
+$! If /OUTPUT given then rename tmpfile instead of sending it to printer.
+$! Use copy & delete rather than rename since tmpfile may be on another disk:
+$
+$ if p7 .eqs. "" then goto PRINTJOB ! /OUTPUT not used
+$ copy tex_ps:empty.ps, 'tmpfile' 'p7' ! empty.ps avoids version conflict
+$ delete/log 'tmpfile'
+$ write sys$output ""
+$ write sys$output "Nothing printed. PostScript saved in " + p7
+$ exit
+$
+$ PRINTJOB:
+$ print/queue=APPLE/form=postscript/name='job' 'tmpfile'/delete 'p4'
+$ if delflag .eqs. "Y" then delete/log 'p1'
diff --git a/dviware/psprint/vms/lw_trailer.ps b/dviware/psprint/vms/lw_trailer.ps
new file mode 100644
index 0000000000..6ab5dcd5e2
--- /dev/null
+++ b/dviware/psprint/vms/lw_trailer.ps
@@ -0,0 +1 @@
+@bannerpage
diff --git a/dviware/psprint/vms/nasty.tex b/dviware/psprint/vms/nasty.tex
new file mode 100644
index 0000000000..bd13f4ad93
--- /dev/null
+++ b/dviware/psprint/vms/nasty.tex
@@ -0,0 +1,352 @@
+% 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 [-.dvitovdu]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%
+12345678901234567890123456789012345678901234567890%
+12345678901234567890123456789012345678901234567890%
+12345678901234567890123456789012345678901234567890%
+12345678901234567890123456789012345678901234567890%
+1234567} % one character too many (see specialstring in PSWRITER.DEF)
+\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 and TEXLAND.PS try 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/vms/options.def b/dviware/psprint/vms/options.def
new file mode 100644
index 0000000000..349158f7e0
--- /dev/null
+++ b/dviware/psprint/vms/options.def
@@ -0,0 +1,64 @@
+DEFINITION MODULE Options;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: August, 1986
+
+ Description:
+ Exports the DVI file name and qualifier values given in the PSDVI command
+ line. Syntax checking is done by DCL according to PSDVI.CLD.
+
+ Revised:
+ November, 1987 (while at The Open University)
+ - Added tfmdir qualifier that indicates the default location of TFM files.
+ This allows PSDVI to handle resident PostScript fonts.
+ - Added conserveVM qualifier which tells PSDVI to conserve PostScript's
+ "virtual memory" at the expense of downloading character bitmaps more often.
+
+ June--August, 1988 (while at Aston University)
+ - Added psprefix qualifier that specifies the prefix in TFM file names
+ for resident PostScript fonts.
+ - Added increment qualifier that allows user to choose every ith page from
+ (and including) the first page selected for printing. Users can easily
+ select all odd pages or all even pages (for duplex printing).
+ - Added hoffset and voffset qualifiers to allow shifting of page.
+*)
+
+TYPE
+ validunits = (in,cm,mm,pc,pt,bp,px);
+ stringvalue = ARRAY [0..127] OF CHAR;
+
+VAR
+ units (* /UNITS value defines how dimensions will be displayed *)
+ : validunits;
+ conserveVM, (* /CONSERVE_VM indicates to conserve virtual memory *)
+ stats, (* /STATS indicates to show some statistics *)
+ reverse, (* /REVERSE indicates to output pages in reverse order *)
+ subrange (* /PAGES has been used to select a subrange *)
+ : BOOLEAN;
+ firstDVIpage, (* first DVI page number given to /PAGES (0 if TeX page) *)
+ finalDVIpage, (* final DVI page number given to /PAGES (0 if TeX page) *)
+ increment, (* /INCREMENT value further restricts page selection *)
+ resolution, (* /RESOLUTION value defines pixels per inch *)
+ mag, (* /MAGNIFICATION value replaces DVI mag; 0 = use DVI mag *)
+ paperwd, (* /XSIZE value defines paper width; converted to pixels *)
+ paperht (* /YSIZE value defines paper height; converted to pixels *)
+ : CARDINAL;
+ hoffset, (* /HOFFSET value is horizontal shift in pixels *)
+ voffset (* /VOFFSET value is vertical shift in pixels *)
+ : INTEGER;
+ firstTeXpage, (* first TeX page specification given to /PAGES *)
+ finalTeXpage, (* final TeX page specification given to /PAGES *)
+ psprefix, (* /PSPREFIX value defines TFM files for PostScript fonts *)
+ tfmdir, (* /TFM_DIRECTORY value defines location of TFM files *)
+ fontdir, (* /FONT_DIRECTORY value defines location of font files *)
+ dummyfont, (* /DUMMY_FONT value defines dummy font file *)
+ header, (* /HEADER value defines header file prefixed to output *)
+ PSname, (* /OUTPUT value gives expicit name to PostScript output *)
+ DVIname (* DVI file specification *)
+ : stringvalue;
+
+PROCEDURE Cap (ch : CHAR) : CHAR;
+(* If ch is in 'a'..'z' then return capitalized version, else return ch. *)
+
+END Options.
diff --git a/dviware/psprint/vms/options.mod b/dviware/psprint/vms/options.mod
new file mode 100644
index 0000000000..b5e0bfad23
--- /dev/null
+++ b/dviware/psprint/vms/options.mod
@@ -0,0 +1,499 @@
+IMPLEMENTATION MODULE Options;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: August, 1986
+
+ Description:
+ This module uses CLI routines to extract the DVI file parameter
+ and qualifier values from the PSDVI command line.
+
+ Revised:
+ November, 1987 (while at The Open University)
+ - Added /TFM_DIRECTORY and /CONSERVE_VM qualifiers.
+
+ June--August, 1988 (while at Aston University)
+ - Added /PSPREFIX, /INCREMENT, /HOFFSET and /VOFFSET qualifiers.
+*)
+
+FROM CommandLanguageInterface IMPORT
+ CLI$PRESENT,
+ CLI$GET_VALUE;
+
+FROM Conversions IMPORT
+ StringToCard, StringToReal, Done;
+
+FROM TermOut IMPORT
+ Write, WriteString, WriteLn, Halt;
+
+CONST
+ NULL = 0C; (* SYSDEP: terminates a string *)
+
+VAR
+ value : stringvalue; (* temporary string *)
+
+(******************************************************************************)
+
+PROCEDURE GetDVIFile;
+
+(* Get DVI file name from command line. *)
+
+VAR i, status : CARDINAL;
+
+BEGIN
+DVIname := '';
+status := CLI$GET_VALUE('FILESPEC',DVIname); (* CLD ensures it is there *)
+i := HIGH(DVIname);
+WHILE (i > 0) AND (DVIname[i] = ' ') DO (* remove trailing blanks *)
+ DVIname[i] := NULL; (* SYSDEP: pad with NULLs *)
+ DEC(i);
+END;
+IF DVIname[i] = ':' THEN (* assume logical name *)
+ (* no need to translate *)
+ELSE
+ INC(i); (* = LEN(DVIname) *)
+ IF NOT ExplicitExt(DVIname) THEN (* append .DVI *)
+ IF i + 3 <= HIGH(DVIname) THEN
+ DVIname[i] := '.';
+ DVIname[i+1] := 'D';
+ DVIname[i+2] := 'V';
+ DVIname[i+3] := 'I';
+ ELSE (* user has given a mighty long file spec! *)
+ WriteString('DVI file specification is too long!'); WriteLn;
+ WriteString(DVIname); WriteLn;
+ Halt(2);
+ END;
+ END;
+END;
+(* bad DVIname will be detected upon open in main module *)
+END GetDVIFile;
+
+(******************************************************************************)
+
+PROCEDURE ExplicitExt (fname : ARRAY OF CHAR) : BOOLEAN;
+
+(* SYSDEP: VAX/VMS files have an extension of the form ".xxx", also known as
+ the file type. If given file specification contains an extension then
+ TRUE is returned, otherwise FALSE.
+*)
+
+VAR pos : CARDINAL; ch : CHAR;
+
+BEGIN
+pos := LEN(fname);
+WHILE pos > 0 DO (* search backwards looking for . or : or ] *)
+ DEC(pos);
+ ch := fname[pos];
+ IF ch = '.' THEN
+ RETURN TRUE
+ ELSIF (ch = ':') OR (ch = ']') THEN (* don't need to look further *)
+ RETURN FALSE
+ END;
+END;
+RETURN FALSE;
+END ExplicitExt;
+
+(******************************************************************************)
+
+PROCEDURE GetCardinal (qualifier : ARRAY OF CHAR; VAR n : CARDINAL);
+
+(* Check if qualifier is present. If so, then make sure given value is
+ a positive integer, and return via n. If not present then return 0.
+*)
+
+VAR i, status : CARDINAL;
+
+BEGIN
+IF ODD(CLI$PRESENT(qualifier)) THEN (* CLD ensures it has a value *)
+ status := CLI$GET_VALUE(qualifier,value);
+ i := HIGH(value);
+ WHILE (i > 0) AND (value[i] = ' ') DO (* remove trailing blanks *)
+ value[i] := NULL; (* SYSDEP: pad with NULLs *)
+ DEC(i);
+ END;
+ n := StringToCard(value);
+ IF Done() AND (n > 0) THEN
+ (* return *)
+ ELSE
+ WriteString('Bad /'); WriteString(qualifier);
+ WriteString(' value: '); WriteString(value); WriteLn;
+ WriteString('Specify a positive integer.'); WriteLn;
+ Halt(2);
+ END;
+ELSE
+ n := 0; (* qualifier not present *)
+END;
+END GetCardinal;
+
+(******************************************************************************)
+
+PROCEDURE GetPosDimension (qualifier : ARRAY OF CHAR; VAR pixels : CARDINAL);
+
+(* Check if qualifier is present. If so, then make sure given value is
+ a valid positive dimension, convert and return via pixels.
+ A valid positive dimension consists of a positive integer or real number
+ followed by a two-letter unit in any case.
+*)
+
+VAR
+ i, status : CARDINAL;
+ r : REAL;
+ ch1, ch2 : CHAR;
+ units : validunits;
+
+BEGIN
+IF ODD(CLI$PRESENT(qualifier)) THEN (* CLD ensures it has a value *)
+ status := CLI$GET_VALUE(qualifier,value);
+ i := HIGH(value);
+ WHILE (i > 0) AND (value[i] = ' ') DO (* remove trailing blanks *)
+ value[i] := NULL; (* SYSDEP: pad with NULLs *)
+ DEC(i);
+ END;
+ IF i = 0 THEN i := 1 END;
+ (* extract units *)
+ IF (Cap(value[i-1]) = 'I') AND (Cap(value[i]) = 'N') THEN
+ units := in;
+ ELSIF (Cap(value[i-1]) = 'C') AND (Cap(value[i]) = 'M') THEN
+ units := cm;
+ ELSIF (Cap(value[i-1]) = 'M') AND (Cap(value[i]) = 'M') THEN
+ units := mm;
+ ELSIF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'C') THEN
+ units := pc;
+ ELSIF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'T') THEN
+ units := pt;
+ ELSIF (Cap(value[i-1]) = 'B') AND (Cap(value[i]) = 'P') THEN
+ units := bp;
+ ELSIF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'X') THEN
+ units := px;
+ ELSE
+ WriteString('Bad units in /'); WriteString(qualifier);
+ WriteString(' dimension: '); WriteString(value); WriteLn;
+ WriteString('Last two letters should be IN, CM, MM, PC, PT, BP or PX.');
+ WriteLn;
+ Halt(2);
+ END;
+ ch1 := value[i-1]; (* remember letters in units *)
+ ch2 := value[i];
+ value[i] := NULL; (* remove units *)
+ value[i-1] := NULL;
+ r := StringToReal(value);
+ IF Done() AND (r > 0.0) THEN (* convert r to pixels *)
+ CASE units OF
+ in : pixels := TRUNC(r * FLOAT(resolution) + 0.5) |
+ cm : pixels := TRUNC((r / 2.54) * FLOAT(resolution) + 0.5) |
+ mm : pixels := TRUNC((r / 25.4) * FLOAT(resolution) + 0.5) |
+ pc : pixels := TRUNC((r / 72.27) * 12.0 * FLOAT(resolution) + 0.5) |
+ pt : pixels := TRUNC((r / 72.27) * FLOAT(resolution) + 0.5) |
+ bp : pixels := TRUNC((r / 72.0) * FLOAT(resolution) + 0.5) |
+ px : pixels := TRUNC(r + 0.5)
+ END;
+ ELSE
+ value[i-1] := ch1; (* restore units *)
+ value[i] := ch2;
+ WriteString('Bad /'); WriteString(qualifier);
+ WriteString(' value: '); WriteString(value); WriteLn;
+ WriteString('Specify a positive dimension.'); WriteLn;
+ Halt(2);
+ END;
+ELSE
+ pixels := 0; (* qualifier not present *)
+END;
+END GetPosDimension;
+
+(******************************************************************************)
+
+PROCEDURE GetDimension (qualifier : ARRAY OF CHAR; VAR pixels : INTEGER);
+
+(* Check if qualifier is present. If so, then make sure given value is
+ a valid dimension, convert and return via pixels.
+ A valid dimension consists of an integer or real number (possibly negative)
+ followed by a two-letter unit in any case.
+*)
+
+VAR
+ i, status : CARDINAL;
+ r : REAL;
+ ch1, ch2 : CHAR;
+ units : validunits;
+
+BEGIN
+IF ODD(CLI$PRESENT(qualifier)) THEN (* CLD ensures it has a value *)
+ status := CLI$GET_VALUE(qualifier,value);
+ i := HIGH(value);
+ WHILE (i > 0) AND (value[i] = ' ') DO (* remove trailing blanks *)
+ value[i] := NULL; (* SYSDEP: pad with NULLs *)
+ DEC(i);
+ END;
+ IF i = 0 THEN i := 1 END;
+ (* extract units *)
+ IF (Cap(value[i-1]) = 'I') AND (Cap(value[i]) = 'N') THEN
+ units := in;
+ ELSIF (Cap(value[i-1]) = 'C') AND (Cap(value[i]) = 'M') THEN
+ units := cm;
+ ELSIF (Cap(value[i-1]) = 'M') AND (Cap(value[i]) = 'M') THEN
+ units := mm;
+ ELSIF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'C') THEN
+ units := pc;
+ ELSIF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'T') THEN
+ units := pt;
+ ELSIF (Cap(value[i-1]) = 'B') AND (Cap(value[i]) = 'P') THEN
+ units := bp;
+ ELSIF (Cap(value[i-1]) = 'P') AND (Cap(value[i]) = 'X') THEN
+ units := px;
+ ELSE
+ WriteString('Bad units in /'); WriteString(qualifier);
+ WriteString(' dimension: '); WriteString(value); WriteLn;
+ WriteString('Last two letters should be IN, CM, MM, PC, PT, BP or PX.');
+ WriteLn;
+ Halt(2);
+ END;
+ ch1 := value[i-1]; (* remember letters in units *)
+ ch2 := value[i];
+ value[i] := NULL; (* remove units *)
+ value[i-1] := NULL;
+ r := StringToReal(value);
+ IF Done() THEN (* convert r to pixels *)
+ CASE units OF
+ in : pixels := TRUNC(ABS(r) * FLOAT(resolution) + 0.5) |
+ cm : pixels := TRUNC((ABS(r)/2.54) * FLOAT(resolution) + 0.5) |
+ mm : pixels := TRUNC((ABS(r)/25.4) * FLOAT(resolution) + 0.5) |
+ pc : pixels := TRUNC((ABS(r)/72.27) * 12.0 * FLOAT(resolution) + 0.5) |
+ pt : pixels := TRUNC((ABS(r)/72.27) * FLOAT(resolution) + 0.5) |
+ bp : pixels := TRUNC((ABS(r)/72.0) * FLOAT(resolution) + 0.5) |
+ px : pixels := TRUNC(ABS(r) + 0.5)
+ END;
+ IF r < 0.0 THEN pixels := -pixels END;
+ ELSE
+ value[i-1] := ch1; (* restore units *)
+ value[i] := ch2;
+ WriteString('Bad /'); WriteString(qualifier);
+ WriteString(' value: '); WriteString(value); WriteLn;
+ WriteString('Specify a valid dimension.'); WriteLn;
+ Halt(2);
+ END;
+ELSE
+ pixels := 0; (* qualifier not present *)
+END;
+END GetDimension;
+
+(******************************************************************************)
+
+PROCEDURE Cap (ch : CHAR) : CHAR;
+
+(* Hamburg's CAP is stupid; do my own. *)
+
+BEGIN
+IF (ch < 'a') OR (ch > 'z') THEN
+ RETURN ch;
+ELSE
+ RETURN CAP(ch);
+END;
+END Cap;
+
+(******************************************************************************)
+
+PROCEDURE GetString (qualifier : ARRAY OF CHAR;
+ VAR s : ARRAY OF CHAR);
+
+(* Check if qualifier is present. If so, then get value and return via s.
+ If qualifier not present then return empty string.
+*)
+
+VAR i, status : CARDINAL;
+
+BEGIN
+IF ODD(CLI$PRESENT(qualifier)) THEN (* CLD ensures it has a value *)
+ status := CLI$GET_VALUE(qualifier,s);
+ i := HIGH(s);
+ WHILE (i > 0) AND (s[i] = ' ') DO (* remove trailing blanks *)
+ s[i] := NULL; (* SYSDEP: pad with NULLs *)
+ DEC(i);
+ END;
+ELSE
+ s[0] := NULL; (* SYSDEP: LEN(s) will be 0 *)
+END;
+(* the main module will detect bad s value sooner or later *)
+END GetString;
+
+(******************************************************************************)
+
+PROCEDURE Append (VAR s1 : ARRAY OF CHAR; s2 : ARRAY OF CHAR);
+
+(* Append s2 to s1. *)
+
+VAR i, j : CARDINAL;
+
+BEGIN
+i := LEN(s1); (* SYSDEP: assumes s1 ends with NULL, unless full *)
+j := 0;
+WHILE (i <= HIGH(s1)) AND (j <= HIGH(s2)) AND (s2[j] <> NULL) DO
+ s1[i] := s2[j];
+ INC(i);
+ INC(j);
+END;
+(* DEBUG
+IF (i > HIGH(s1)) AND (j <= HIGH(s2)) AND (s2[j] <> NULL) THEN
+ WriteString('No room to append '); WriteString(s2); WriteLn;
+ Halt(2);
+END;
+GUBED *)
+IF i <= HIGH(s1) THEN s1[i] := NULL END;
+END Append;
+
+(******************************************************************************)
+
+PROCEDURE GetUnits;
+
+(* Check if /UNITS is present. If so, then make sure given value is
+ valid and set units.
+*)
+
+VAR i, status : CARDINAL; ch1, ch2 : CHAR;
+
+BEGIN
+IF ODD(CLI$PRESENT('UNITS')) THEN (* CLD ensures it has a value *)
+ status := CLI$GET_VALUE('UNITS',value);
+ i := HIGH(value);
+ WHILE (i > 0) AND (value[i] = ' ') DO (* remove trailing blanks *)
+ value[i] := NULL; (* SYSDEP: pad with NULLs *)
+ DEC(i);
+ END;
+ ch1 := Cap(value[0]);
+ ch2 := Cap(value[1]);
+ IF (ch1 = 'I') AND (ch2 = 'N') THEN
+ units := in;
+ ELSIF (ch1 = 'C') AND (ch2 = 'M') THEN
+ units := cm;
+ ELSIF (ch1 = 'M') AND (ch2 = 'M') THEN
+ units := mm;
+ ELSIF (ch1 = 'P') AND (ch2 = 'C') THEN
+ units := pc;
+ ELSIF (ch1 = 'P') AND (ch2 = 'T') THEN
+ units := pt;
+ ELSIF (ch1 = 'B') AND (ch2 = 'P') THEN
+ units := bp;
+ ELSIF (ch1 = 'P') AND (ch2 = 'X') THEN
+ units := px;
+ ELSE
+ WriteString('Bad /UNITS value: '); WriteString(value); WriteLn;
+ WriteString('Specify IN, CM, MM, PC, PT, BP or PX.'); WriteLn;
+ Halt(2);
+ END;
+ELSE
+ units := px; (* if /UNITS not present *)
+END;
+END GetUnits;
+
+(******************************************************************************)
+
+PROCEDURE GetPages;
+
+(* Check if /PAGES is present. If so then subrange will be TRUE.
+ /PAGES can accept 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 = MAX(CARDINAL). 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).
+*)
+
+VAR i, j, status, len : CARDINAL;
+
+BEGIN
+IF ODD(CLI$PRESENT('PAGES')) THEN (* CLD ensures it has a value *)
+ status := CLI$GET_VALUE('PAGES',value);
+ i := HIGH(value);
+ WHILE (i > 0) AND (value[i] = ' ') DO (* remove trailing blanks *)
+ value[i] := NULL; (* SYSDEP: pad with NULLs *)
+ DEC(i);
+ END;
+ len := i + 1; (* length of value *)
+ firstTeXpage := '';
+ finalTeXpage := '';
+ i := 0;
+ WHILE (i < len) AND (value[i] <> ':') DO (* extract first page *)
+ firstTeXpage[i] := value[i];
+ INC(i);
+ END;
+ IF value[0] = ':' THEN (* first page not given *)
+ firstDVIpage := 1;
+ ELSIF firstTeXpage[0] = '[' THEN (* TeX page given *)
+ firstDVIpage := 0;
+ ELSE (* DVI page given *)
+ firstDVIpage := StringToCard(firstTeXpage);
+ IF NOT Done() OR (firstDVIpage = 0) THEN
+ WriteString('/PAGES error! Bad first page: ');
+ WriteString(firstTeXpage); WriteLn;
+ Halt(2);
+ END;
+ END;
+ IF i = len THEN (* no colon; /PAGES=n or [t] *)
+ IF firstTeXpage[0] = '[' THEN
+ finalTeXpage := firstTeXpage; (* [t] = [t]:[t] *)
+ finalDVIpage := 0;
+ ELSE
+ finalDVIpage := firstDVIpage; (* n = n:n *)
+ END;
+ ELSE (* value[i] = ':' *)
+ INC(i);
+ j := 0;
+ WHILE i < len DO (* extract final page *)
+ finalTeXpage[j] := value[i];
+ INC(i); INC(j);
+ END;
+ IF j = 0 THEN (* no page after ':' *)
+ finalDVIpage := MAX(CARDINAL);
+ ELSIF finalTeXpage[0] = '[' THEN (* TeX page given *)
+ finalDVIpage := 0;
+ ELSE (* DVI page given *)
+ finalDVIpage := StringToCard(finalTeXpage);
+ IF NOT Done() OR (finalDVIpage = 0) THEN
+ WriteString('/PAGES error! Bad final page: ');
+ WriteString(finalTeXpage); WriteLn;
+ Halt(2);
+ END;
+ END;
+ END;
+ subrange := TRUE; (* main module will check page range *)
+ELSE
+ subrange := FALSE; (* if /PAGES not present *)
+END;
+END GetPages;
+
+(******************************************************************************)
+
+(* SYSDEP: CLD file must supply some qualifiers with default values. *)
+
+BEGIN
+GetDVIFile; (* initialize DVIname *)
+GetString('OUTPUT',PSname); (* initialize PSname *)
+IF LEN(PSname) = 0 THEN (* /OUTPUT not specified *)
+ PSname := 'OUT.PS';
+ (* It would be nicer to use DVIname with .PS instead of .DVI but
+ things get messy if DVIname is a logical name or includes a directory.
+ Note that PSPRINT.COM specifies an explicit /OUTPUT file.
+ *)
+END;
+GetCardinal('MAGNIFICATION',mag); (* 0 if no /MAG override *)
+GetCardinal('RESOLUTION',resolution); (* get resolution BEFORE dimens *)
+GetPosDimension('XSIZE',paperwd);
+GetPosDimension('YSIZE',paperht);
+GetDimension('HOFFSET',hoffset); (* 0 if not given *)
+GetDimension('VOFFSET',voffset); (* ditto *)
+GetString('HEADER',header); (* empty string if no /HEADER *)
+GetString('PSPREFIX',psprefix);
+GetString('TFM_DIRECTORY',tfmdir);
+GetString('FONT_DIRECTORY',fontdir);
+GetString('DUMMY_FONT',value);
+dummyfont := fontdir; (* prefix dummyfont with fontdir *)
+Append(dummyfont,value);
+GetUnits; (* initialize units *)
+GetPages; (* initialize subrange etc. *)
+GetCardinal('INCREMENT',increment); (* 0 if /INC not used *)
+IF increment = 0 THEN increment := 1 END; (* do normal page selection *)
+stats := ODD(CLI$PRESENT('STATS'));
+reverse := ODD(CLI$PRESENT('REVERSE'));
+conserveVM := ODD(CLI$PRESENT('CONSERVE_VM'));
+END Options.
diff --git a/dviware/psprint/vms/pass.ps b/dviware/psprint/vms/pass.ps
new file mode 100644
index 0000000000..9910654ad4
--- /dev/null
+++ b/dviware/psprint/vms/pass.ps
@@ -0,0 +1,22 @@
+% Verify and/or change a LaserWriter's system password.
+% The following code would also work on a Linotronic but not on a
+% PrintServer 40 (which uses a string instead of an integer).
+
+72 72 translate 0 0 moveto
+/Times-Roman findfont 10 scalefont setfont
+
+0 % current system password?
+serverdict begin
+statusdict begin
+ checkpassword
+ { (Password correct. ) show }
+ { (Password incorrect! ) show }
+ ifelse
+% uncomment to change the password to 999999 (use some other large number!)
+% 0 999999 setpassword
+% { (Password changed.) show }
+% { (Password NOT changed!) show }
+% ifelse
+end
+
+showpage
diff --git a/dviware/psprint/vms/piechart.ps b/dviware/psprint/vms/piechart.ps
new file mode 100644
index 0000000000..1d9d6137ea
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/ps.ps b/dviware/psprint/vms/ps.ps
new file mode 100644
index 0000000000..a4de517297
--- /dev/null
+++ b/dviware/psprint/vms/ps.ps
@@ -0,0 +1,20 @@
+% Prologue for a PostScript job.
+% It assumes *_print.com 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/vms/ps40_fonts.ps b/dviware/psprint/vms/ps40_fonts.ps
new file mode 100644
index 0000000000..a24e0651ff
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/ps40_header.ps b/dviware/psprint/vms/ps40_header.ps
new file mode 100644
index 0000000000..524d07137b
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/ps40_list.ps b/dviware/psprint/vms/ps40_list.ps
new file mode 100644
index 0000000000..a13412eea2
--- /dev/null
+++ b/dviware/psprint/vms/ps40_list.ps
@@ -0,0 +1,19 @@
+% Type PSPRINT/DEV=PS40/NOTIFY <this file>
+% to see (on terminal) a list of all known PrintServer fonts, and memory usage.
+
+/showline { print (\n) print } def
+/Times-Roman findfont 12 scalefont setfont
+/s40 40 string def
+
+36 700 moveto
+FontDirectory {pop s40 cvs showline} forall
+
+( ) showline
+(Total memory: ) showline
+vmstatus s40 cvs showline
+(Memory used: ) showline
+s40 cvs showline
+pop
+( Free memory: ) showline
+vmstatus exch sub s40 cvs showline
+pop
diff --git a/dviware/psprint/vms/ps40_print.com b/dviware/psprint/vms/ps40_print.com
new file mode 100644
index 0000000000..58e205b803
--- /dev/null
+++ b/dviware/psprint/vms/ps40_print.com
@@ -0,0 +1,109 @@
+$! This command file is run by PSPRINT/DEV=PS40 with the following parameters:
+$! P1 = complete file specification
+$! P2 = file format (DVI or PS or TEXT or TWO or WIDE)
+$! P3 = options for PSDVI
+$! P4 = options for PRINT
+$! P5 = /NOTE value ("" if not used)
+$! P6 = /COPIES value (1 if not used)
+$! P7 = /OUTPUT value ("" if not used)
+$! P8 = "bb<prep>" where b = Y or N and represents the status of the
+$! boolean qualifiers /DELETE, /LANDSCAPE
+$! and <prep> is the /PREP value, possibly empty
+$!
+$! This file is much like LW_PRINT.COM, but differs in the following ways:
+$! * ^D cannot be sent to the PS40.
+$! * No banner page need be created since the PS40 produces one (and a trailer).
+$! * /NOTIFY will send PostScript messages back to the user.
+$! * PSDVI uses write-white fonts appropriate for a Ricoh engine.
+$! * /BANNER and /MANUALFEED are not implemented.
+$
+$ on control_y then exit
+$ set symbol/scope=(nolocal,noglobal)
+$ delflag = f$extract(0,1,p8)
+$ landflag = f$extract(1,1,p8)
+$ prepfile = f$extract(2,999,p8)
+$
+$ if (p6 .gt. 0) .and. (p6 .lt. 101) then goto CONTINUE
+$ write sys$output "Bad /COPIES value. Specify 1 to 100."
+$ exit
+$
+$ CONTINUE:
+$ copies = f$string(p6)
+$ job = f$parse(p1,,,"NAME")
+$
+$ copy tex_ps:ps40_header.ps sys$scratch:'job'.tmp
+$ tmpfile = f$search("sys$scratch:''job'.tmp")
+$ write sys$output -
+ "Creating SYS$SCRATCH:''job'.TMP" + f$parse(tmpfile,,,"VERSION")
+$ open/append tmp 'tmpfile'
+$ write tmp "/#copies " + copies + " def"
+$ write tmp "/dev (PS40) def"
+$ write tmp "/res 300 def"
+$ write tmp "/fspec (" + p1 + ") def"
+$ if landflag .eqs. "Y" then write tmp "/land true def"
+$ if landflag .eqs. "N" then write tmp "/land false def"
+$ close tmp
+$
+$ if p2 .eqs. "DVI" then append tex_ps:tex.ps, tex_ps:ps40_fonts.ps 'tmpfile'
+$ if p2 .eqs. "PS" then append tex_ps:ps.ps 'tmpfile'
+$ if p2 .eqs. "TEXT" then append tex_ps:text.ps 'tmpfile'
+$ if p2 .eqs. "TWO" then append tex_ps:two.ps 'tmpfile'
+$ if p2 .eqs. "WIDE" then append tex_ps:wide.ps 'tmpfile'
+$
+$ if (p2 .nes. "DVI") .and. (p2 .nes. "PS") then goto SKIPPREP
+$ if prepfile .eqs. "" then goto SKIPPREP
+$ write sys$output "Including " + prepfile
+$ append 'prepfile' 'tmpfile'
+$ SKIPPREP:
+$
+$ global = f$search("global.ps")
+$ if (global .eqs. "") .or. (p2 .nes. "DVI") then goto SKIPGLOBAL
+$ write sys$output "Including GLOBAL.PS"
+$ append 'global' 'tmpfile'
+$ SKIPGLOBAL:
+$
+$ if p2 .nes. "DVI" then goto PRINT
+$
+$ ver = 1
+$ LOOP:
+$ psdvifile = "sys$scratch:psdvi.tmp;''f$string(ver)'"
+$ if f$search(psdvifile) .eqs. "" then goto ENDLOOP
+$ ver = ver + 1
+$ goto LOOP
+$
+$ ENDLOOP:
+$ land = ""
+$ if landflag .eqs. "Y" then land = "/xsize=297mm /ysize=210mm"
+$ on warning then goto BADDVI
+$ PSDVI 'p1' 'land' /HEADER='tmpfile' -
+ /OUTPUT='psdvifile' -
+ /RES=300 -
+ /FONT="write_white_fonts:" -
+ /DUMMY="cmr10.300pk" -
+ /NOCONSERVE -
+ /NOREVERSE 'p3'
+$ delete/nolog 'tmpfile'
+$ rename/nolog 'psdvifile' 'tmpfile'
+$ goto PRINT
+$
+$ BADDVI:
+$ delete/nolog 'tmpfile'
+$ if f$search(psdvifile) .nes. "" then delete/nolog 'psdvifile'
+$ write sys$output ""
+$ write sys$output "Printing aborted due to error(s). Temporary file deleted."
+$ exit
+$
+$ PRINT:
+$ on error then exit
+$ if p2 .nes. "DVI" then append 'p1' 'tmpfile'
+$
+$ if p7 .eqs. "" then goto PRINTJOB
+$ copy tex_ps:empty.ps, 'tmpfile' 'p7'
+$ delete/log 'tmpfile'
+$ write sys$output ""
+$ write sys$output "Nothing printed. PostScript saved in " + p7
+$ exit
+$
+$ PRINTJOB:
+$ print/note="''p5'"/queue=PS40/name='job' 'tmpfile'/delete 'p4'
+$ if delflag .eqs. "Y" then delete/log 'p1'
diff --git a/dviware/psprint/vms/psdvi.cld b/dviware/psprint/vms/psdvi.cld
new file mode 100644
index 0000000000..4f9c03e5d2
--- /dev/null
+++ b/dviware/psprint/vms/psdvi.cld
@@ -0,0 +1,64 @@
+define verb PSDVI
+image TEX_PS:PSDVI.EXE
+ parameter p1,label=filespec,prompt="DVI file",value(required,type=$infile)
+ qualifier output, value(required,type=$file) ! default is OUT.PS
+ qualifier header, value(required,type=$file) ! default is no header
+ qualifier pages, value(required) ! default is all pages
+ qualifier increment, value(required,type=$number) ! default is 1
+ qualifier magnification, value(required,type=$number) ! default is DVI mag
+ qualifier stats, ! default is FALSE
+ qualifier reverse, ! default is FALSE
+ qualifier conserve_VM, ! default is FALSE
+ qualifier hoffset, value(required) ! default is 0
+ qualifier voffset, value(required) ! default is 0
+ qualifier units, nonnegatable,default,
+ value(default=IN) ! IN,CM,MM,PC,PT,BP,PX
+ qualifier resolution, nonnegatable,default,
+ value(default=300) ! for LaserWriter
+ qualifier xsize, nonnegatable,default,
+ value(default=210MM) ! A4 width
+ qualifier ysize, nonnegatable,default,
+ value(default=297MM) ! A4 height
+ qualifier psprefix, nonnegatable,default,
+ value(default="ps-")
+ qualifier tfm_directory, nonnegatable,default,
+ value(default="disk$utils:[utilities.tex.fonts]")
+ qualifier font_directory, nonnegatable,default,
+ value(default="disk$utils:[utilities.tex.300pk]")
+ qualifier dummy_font, nonnegatable,default,
+ value(default="cmr10.300pk")
+!
+! The Options module automatically prefixes dummy_font with font_directory.
+! The FontReader module then uses the font_directory and dummy_font values
+! to decide on the location, format and naming convention of all font files.
+! The above values assume you use PK files and keep them in one big directory.
+! Note that the dummy_font file type has a font size equal to the resolution.
+! If you are using Kellerman & Smith's old TeX system in which PXL files are
+! kept in separate subdirectories then you'll need something like:
+!
+! qualifier font_directory, nonnegatable,default,
+! value(default="tex_disk:[tex.fonts.]")
+! qualifier dummy_font, nonnegatable,default,
+! value(default="[1500]cmr10.pxl")
+!
+! Note the important differences:
+! 1. The font_directory value ends with ".]".
+! 2. The dummy_font value ends with "PXL".
+! 3. The font size is NOT in the file type; it is the subdirectory name.
+! 4. The font size = resolution * 1000 / 200.
+!
+! PSDVI can handle any font scheme that obeys the following rules:
+! - The dummy_font value ends in either "PXL" or "PK" and all font files
+! use the same coding format.
+! - If the font_directory value ends in ".]" then all font files reside in
+! various subdirectories of font_directory. Each subdirectory name is
+! a different font size and dummy_font must start with "[fontsize]".
+! - If the font_directory value does NOT end in ".]" then all font files
+! reside in font_directory. Each file type begins with a font size and
+! dummy_font must start with "fontname.fontsize".
+! - The dummy_font value must represent an unmagnified font. Its font size
+! substring matches either the resolution or (resolution * 1000 / 200).
+!
+! The above hackery is an attempt to cope with the various font schemes
+! used by VAX/VMS TeX sites. Note that GF files are not handled; I figured
+! any sites using GF files would convert them to PK files sooner or later.
diff --git a/dviware/psprint/vms/psdvi.hlp b/dviware/psprint/vms/psdvi.hlp
new file mode 100644
index 0000000000..fce1d8363f
--- /dev/null
+++ b/dviware/psprint/vms/psdvi.hlp
@@ -0,0 +1,200 @@
+1 PSDVI
+
+USAGE: PSDVI filename[.DVI] [qualifiers]
+
+PSDVI is not really meant to be used by itself; it is part of the PSPRINT
+system. PSDVI reads a given DVI file (produced by TeX or LaTeX) and
+creates a PostScript output file called OUT.PS (unless /OUTPUT is used
+to specify some other name). The output file uses PostScript procedures
+whose definitions must be sent to the printer first. The /HEADER qualifier
+can be used to include an appropriate file of definitions at the start of
+the output. PSDVI displays the DVI page number and TeX page counter(s)
+as each page is translated.
+
+2 Errors
+
+PSDVI can 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 size.
+ Try a different \magstep value in your TeX source file.
+
+ Couldn't open \special file: ...
+ PSDVI 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.
+
+2 Graphics
+
+PSDVI allows the inclusion of PostScript graphics using TeX's \special
+command. The given 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 PSDVI to write a
+line containing "2 1 scale" to the output file, then copy the contents
+of FIGURE.PS. (Such a figure will be twice as wide as one included
+by \special{figure.ps}.) The PSPRINT User Guide has more details.
+
+2 Qualifiers
+
+/OUTPUT=file
+(default=OUT.PS)
+
+Give an explicit file specification to the output file.
+
+/HEADER=file
+(default=no header)
+
+Include the given file at the start of the output file.
+
+/PAGES=first:final
+(default=all pages)
+
+Translate 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 5 DVI pages `[0] [1] [2.1] [2.2] [3]',
+here are some examples of how you could use /PAGES:
+
+ $ PSDVI FOO /PAGES=2 --- translates the second DVI page ([1])
+ $ PSDVI FOO /PAGES=2: --- translates the last four pages
+ $ PSDVI FOO /PAGES=:4 --- translates the first four pages
+ $ PSDVI FOO /PAGES=[2] --- translates [2.1] and [2.2]
+ $ PSDVI FOO /PAGES=1:[2] --- translates the first four pages
+ $ PSDVI FOO /PAGES=[2.2]: --- translates the last two pages
+
+Note that "first" and "final" are optional; they default to
+the first and last DVI pages respectively.
+
+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. Many DVI pages 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.
+
+/INCREMENT=i
+(default=1)
+
+Assuming f is the first DVI page selected (where f is either 1 or the
+start of a /PAGE subrange) then an increment of i tells PSDVI to translate
+pages f, f+i, f+2i, f+3i, ... , f+ni, where f+ni is <= the final DVI page
+selected. The primary use of /INCREMENT is to simplify the printing of a
+document on both sides of the paper. E.g., if FOO.DVI has 7 pages then:
+
+ $ PSDVI FOO /INC=2 --- will translate DVI pages 1, 3, 5, 7
+ $ PSDVI FOO /INC=2 /PAG=2: --- will translate DVI pages 2, 4, 6
+ $ PSDVI FOO /INC=2 /PAG=2: /REV --- will translate DVI pages 6, 4, 2
+
+Note that the use of /REVERSE with /INCREMENT has no effect on WHICH pages
+are translated; it simply changes the ORDER in which they are done.
+
+/MAGNIFICATION=i
+(default=use DVI magnification)
+
+Override the DVI magnification with a number representing 1000 times the
+desired magnification. The given integer should correspond to
+TeX's \magstep values; see chapter 4 of The TeXbook.
+
+/UNITS=XX
+(default=IN)
+
+Set the units of dimensions displayed in some PSDVI messages
+(e.g., if the page is off the paper). XX can be one of:
+
+ 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 (e.g., an Apple LaserWriter has 300 pixels per inch)
+
+/REVERSE
+/NOREVERSE
+(default=/noreverse)
+
+By default PSDVI translates pages in ascending order.
+Use /REVERSE to translate pages in descending order.
+
+/STATS
+/NOSTATS
+(default=/nostats)
+
+Use /STATS to see statistics on the number of rules/fonts/characters
+appearing on each page, and other useful(?) information.
+
+/CONSERVE_VM
+/NOCONSERVE_VM
+(default=/noconserve_vm)
+
+Use /CONSERVE_VM if your document won't print because of a "VM error"
+(i.e., Virtual Memory is exhausted). This qualifier will tell PSDVI to
+conserve VM at the expense of downloading character bitmaps more often
+(resulting in a larger output file that takes longer to print).
+
+/RESOLUTION=i
+(default=300)
+
+i is a positive integer specifying the resolution of your printer
+in pixels per inch (horizontally and vertically).
+
+/HOFFSET=dimension
+/VOFFSET=dimension
+(default=0in)
+(default=0in)
+
+These qualifiers allow you to shift the printed location of each page
+according to the given dimensions. For example, "/hoffset=-0.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 /UNITS).
+
+/XSIZE=posdimen
+/YSIZE=posdimen
+(default=210mm)
+(default=297mm)
+
+PSDVI will automatically check each DVI page to make sure it fits
+within the given paper dimensions. The default values describe
+A4 paper with the usual "portrait" orientation.
+Swap these values if you plan to use "landscaped" paper.
+A "posdimen" is any positive integer or real number followed by a
+two-letter unit: IN,CM,MM,PC,PT,BP,PX (same as those for /UNITS).
+
+/PSPREFIX=string
+(default="ps-")
+
+PSDVI needs to read TFM files if your document uses resident PostScript
+fonts (for which bitmapped information does not exist).
+All such fonts must have names beginning with this prefix.
+
+/TFM_DIRECTORY=directory
+(default=disk$utils:[utilities.tex.fonts])
+
+Specifies the location of TFM files for resident PostScript fonts.
+
+/FONT_DIRECTORY=directory
+(default=disk$utils:[utilities.tex.300pk])
+
+PSDVI gets all its character bitmap information from font files located
+in the given directory.
+
+/DUMMY_FONT=file
+(default=cmr10.300pk)
+
+This qualifier indicates the naming convention and format of all font files.
+PSDVI will warn you about non-existent fonts. Rather than abort, it will
+use the font file specified by /DUMMY_FONT and continue as best it can.
+Unlike DVItoVDU, dummy font characters do NOT appear in the output.
+
+! See PSDVI.CLD for details on how these last two qualifiers are used by PSDVI
+! to determine the location, naming convention and format of font files.
diff --git a/dviware/psprint/vms/psdvi.mod b/dviware/psprint/vms/psdvi.mod
new file mode 100644
index 0000000000..79c664ab3c
--- /dev/null
+++ b/dviware/psprint/vms/psdvi.mod
@@ -0,0 +1,1207 @@
+MODULE PSDVI;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: August, 1986
+ Released: September, 1986 (version 1.0)
+
+ Description:
+ PSDVI reads a TeX DVI file and creates a corresponding PostScript file.
+ This output file needs to be prefixed with some PostScript code.
+ The /HEADER option can be used to include any desired file.
+ PSDVI can be used by itself (see PSDVI.HLP) or as part of the
+ PSPRINT system (see the PSPRINT User Guide and System Guide).
+ Much of the code has been borrowed from DVItoVDU.
+
+ Notes:
+ - Debugging code is bracketed by (* DEBUG *) ... (* GUBED *).
+ This code will be disabled in the final working version.
+ - System-dependent code is indicated by the string "SYSDEP".
+ - Uncertain or unfinished code is indicated by the strings "???" and "!!!".
+ - Procedures are defined in a top-down manner: each procedure is usually
+ defined as soon as possible after its first use.
+ - The above notes also apply to the local modules used by PSDVI.
+
+ Revised:
+ December, 1986
+ - PXLReader has become FontReader and can handle other font formats.
+ All font-dependent code has been moved into FontReader.
+ - Use LoadBitmap from FontReader instead of LoadPSChar from PSWriter
+ to output PostScript code for each character bitmap.
+ Unlike DVItoVDU, PSDVI does not need to store each bitmap for later use.
+ - Released version 1.1 in January, 1987
+
+ November, 1987 (while at The Open University)
+ - Import tfmdir (for display in ShowOptions) and conserveVM from Options.
+ - Import SaveVM and RestoreVM from PSWriter.
+ - Import SetPostScriptChar from PSWriter; it is used (instead of
+ SetBitmapChar) to typeset characters from a resident PostScript font.
+ - Use conserveVM flag to call a different sequence of PSWriter
+ routines if the user wants to conserve virtual memory.
+ - Use psfont flag (set in BuildFontSpec in FontReader) to control the
+ sequence of PSWriter routines for resident PostScript fonts.
+ - Added ShowPtSize routine to show requested pt size for PostScript fonts.
+ - Added PSDVI banner line to start of ShowOptions showing version number.
+ - Released version 2.0 in December, 1987
+
+ June--August, 1988 (while at Aston University)
+ - Added /psprefix qualifier so that sites have some flexibility in choosing
+ the prefix that indicates a PostScript font.
+ - Added /increment qualifier to enhance page selection for duplex printing.
+ - Added /hoffset and /voffset qualifiers to allow shifting of page.
+ - Removed "Creating ..." message due to changes in *_PRINT.COM files.
+ - No longer use StartLn/WriteBuffer/pagesperline.
+ Page numbers now appear on separate lines.
+ - Released version 3.0 in August, 1988
+
+ September--October, 1989 (while at Aston University, 2nd time)
+ - \special info now added to tail of speciallist.
+ - Released version 3.1 in October, 1989
+*)
+
+
+FROM Storage IMPORT
+ ALLOCATE, DEALLOCATE; (* for NEW and DISPOSE *)
+
+
+(* SYSDEP: Modula-2 avoids the problem of system dependence by simply
+ not providing any input/output routines etc. The above importations
+ are highly system-dependent.
+
+ The following modules are kept with the file you are now reading.
+ See the .DEF files for details on how the imported identifiers should be
+ used; implementation details can be found in the corresponding .MOD files.
+*)
+
+
+(* The TermOut module is used to do all terminal output. *)
+FROM TermOut IMPORT
+ Write, WriteString, WriteInt, WriteCard, WriteLn, Halt;
+
+
+(* The Options module carries out the task of reading the DCL command
+ line and extracting the DVI file parameter and qualifiers.
+*)
+FROM Options IMPORT
+ validunits, units,
+ reverse, stats, conserveVM,
+ subrange, firstTeXpage, finalTeXpage, firstDVIpage, finalDVIpage,
+ increment, resolution, mag, paperwd, paperht, hoffset, voffset,
+ psprefix, tfmdir, fontdir, dummyfont, header, PSname, DVIname;
+
+
+(* PSDVI uses the routines and data structures defined in DVIReader to move
+ about randomly in the DVI file and to interpret pages.
+ The reference points of characters and rules on a page are stored as
+ pairs of horizontal and vertical pixel coordinates.
+ The coordinate scheme is described in detail in DVIREADER.DEF.
+*)
+FROM DVIReader IMPORT
+ ruletablesize, chartablesize, maxfontspec, maxTeXchar,
+ ruleinfo, ruleinfoptr,
+ fontstring, fontinfo, fontinfoptr,
+ charinfo, charinfoptr, pixeltable, pixeltableptr,
+ TeXcounters, TeXpageinfo,
+ DVIerrorcodes, GetByteFunction,
+ DVImag, totalpages, totalfonts,
+ currDVIpage, currTeXpage,
+ rulelist, totalrules, fontlist, currfont,
+ minhp, minvp, maxhp, maxvp, pageempty,
+ DVIErrorRoutine, SpecialRoutine, PixelTableRoutine,
+ OpenDVIFile, SetConversionFactor, MoveToDVIPage, CurrMatchesNew,
+ PixelRound, InterpretPage, SortFonts, CloseDVIFile;
+
+
+(* PSDVI gets character metrics and bitmaps from font files.
+ The FontReader module can handle a variety of different font formats.
+ No more than one font file will be open at any given time.
+*)
+FROM FontReader IMPORT
+ FillPixelTable, LoadBitmap,
+ InitFontReader, BuildFontSpec,
+ OpenFontFile, CloseFontFile;
+
+
+(* The PSWriter routines are used to create an output file containing
+ the appropriate PostScript code.
+*)
+FROM PSWriter IMPORT
+ OpenOutput, OutputHeader, BeginPage, NewBitmapFont,
+ OutputPage, specialstring, OutputSpecial,
+ SaveVM, BeginPostScriptFont, SetPostScriptChar,
+ BeginBitmapFont, SetBitmapChar, EndFont, RestoreVM,
+ SetRule, EndPage, CloseOutput;
+
+
+(*******************************************************************************
+ GLOBAL DECLARATIONS
+*)
+
+CONST
+ NULL = 0C; (* SYSDEP: NULL terminates a string, unless full *)
+ warning = 0; (* SYSDEP: Halt parameter to set VMS $SEVERITY *)
+ success = 1; (* ditto *)
+ error = 2; (* ditto *)
+
+TYPE
+ specialinfoptr = POINTER TO specialinfo;
+ specialinfo = RECORD
+ special : specialstring;
+ hp, vp : INTEGER;
+ nextspecial : specialinfoptr;
+ END;
+
+VAR
+ speciallist : specialinfoptr; (* for storing \special info *)
+ specialtail : specialinfoptr; (* tail of speciallist *)
+ papertop,
+ paperleft,
+ paperbottom,
+ paperright : INTEGER; (* these define the edges of the paper *)
+ warncount, (* count of problems detected *)
+ pagecount : CARDINAL; (* count of pages actually output *)
+ unusedfont : fontinfoptr; (* first unused font in sorted fontlist *)
+
+
+(******************************************************************************)
+
+PROCEDURE TopLevel;
+
+(* Note that the implementation blocks of all imported modules have already
+ been executed. In particular, the Options module has read the DCL command
+ line and initialized the DVI file parameter and qualifier values.
+*)
+
+VAR i : CARDINAL;
+
+BEGIN
+Initialize;
+DVIErrorRoutine := MyDVIErrorRoutine; (* called by DVIReader *)
+OpenDVIFile(DVIname); (* and read DVImag etc. *)
+IF mag = 0 THEN mag := DVImag END; (* no /MAG value so use DVImag *)
+SetConversionFactor(resolution,mag); (* for DVIReader *)
+SpecialRoutine := MySpecialRoutine; (* called by InterpretPage *)
+PixelTableRoutine := MyPixelTableRoutine; (* called by InterpretPage *)
+InitFontReader; (* assign font-dependent routines *)
+IF stats THEN ShowOptions END;
+CheckPageRange; (* set firstDVIpage, finalDVIpage *)
+IF OpenOutput(PSname) THEN
+ (* DEBUG
+ WriteString('Creating ');
+ WriteString(PSname);
+ WriteLn;
+ GUBED *)
+ELSE
+ WriteString("Couldn't open output file: ");
+ WriteString(PSname);
+ WriteLn;
+ Halt(error);
+END;
+IF LEN(header) > 0 THEN (* output header file first *)
+ IF NOT OutputHeader(header) THEN
+ WriteString("Couldn't open header file: ");
+ WriteString(header);
+ WriteLn;
+ Halt(error);
+ END;
+END;
+IF increment > 1 THEN (* finalDVIpage may need reducing *)
+ WHILE (finalDVIpage - firstDVIpage) MOD increment > 0 DO
+ DEC(finalDVIpage);
+ END;
+END;
+IF reverse THEN
+ MoveToDVIPage(finalDVIpage); (* start with finalDVIpage *)
+ finalDVIpage := firstDVIpage; (* and end with firstDVIpage *)
+ELSE
+ MoveToDVIPage(firstDVIpage); (* start with firstDVIpage *)
+END;
+LOOP
+ DoPage; (* do at least one page *)
+ IF stats THEN ShowPageStats END;
+ IF currDVIpage = finalDVIpage THEN EXIT END;
+ IF reverse THEN
+ MoveToDVIPage(currDVIpage - increment);
+ ELSE
+ MoveToDVIPage(currDVIpage + increment);
+ END;
+END;
+IF stats THEN ShowFinalStats END;
+CloseDVIFile;
+CloseOutput;
+IF warncount > 0 THEN
+ Halt(warning);
+ELSE
+ Halt(success);
+END;
+END TopLevel;
+
+(******************************************************************************)
+
+PROCEDURE Initialize;
+
+BEGIN
+(* we don't bother checking for crazy resolution/paperht/paperwd values *)
+(* top left corner of paper is fixed at (-1",-1") *)
+papertop := -INTEGER(resolution);
+paperleft := -INTEGER(resolution);
+paperbottom := papertop + INTEGER(paperht) - 1;
+paperright := paperleft + INTEGER(paperwd) - 1;
+warncount := 0;
+pagecount := 0;
+speciallist := NIL; (* for first MySpecialRoutine *)
+END Initialize;
+
+(******************************************************************************)
+
+PROCEDURE MyDVIErrorRoutine (DVIerror : DVIerrorcodes);
+
+(* DVIErrorRoutine for DVIReader; see DVIREADER.DEF. *)
+
+BEGIN
+CASE DVIerror OF
+(* these errors are detected in OpenDVIFile; they are considered fatal *)
+ DVIunopened :
+ WriteString("Couldn't open DVI file: ");
+ WriteString(DVIname); WriteLn;
+ Halt(error); |
+ DVIempty :
+ WriteString(DVIname);
+ WriteString(' is empty!'); WriteLn;
+ Halt(error); |
+ DVIbadid :
+ WriteString(DVIname);
+ WriteString(' is not a valid DVI file!'); WriteLn;
+ Halt(error); |
+ DVIstackoverflow :
+ WriteString('Stack capacity exceeded!'); WriteLn;
+ PleaseReport;
+ Halt(error); |
+(* this error is detected in InterpretPage; we warn user but continue *)
+ DVIbadchar :
+ WITH currfont^ DO
+ WriteString('Ignoring unknown character from ');
+ WriteString(fontspec); Write('!');
+ WriteLn;
+ END; |
+(* this error should never happen *)
+ DVIcatastrophe :
+ WriteLn;
+ WriteString('Something awful has happened!'); WriteLn;
+ PleaseReport;
+ Halt(error);
+ELSE
+ (* this will only happen if we've missed a DVI error *)
+ WriteLn;
+ WriteString('Bug in MyDVIErrorRoutine!'); WriteLn;
+ PleaseReport;
+ Halt(error);
+END;
+END MyDVIErrorRoutine;
+
+(******************************************************************************)
+
+PROCEDURE PleaseReport;
+
+BEGIN
+WriteString('Please tell your local TeXnician.'); WriteLn;
+END PleaseReport;
+
+(******************************************************************************)
+
+PROCEDURE MySpecialRoutine (hpos, vpos,
+ totalbytes : INTEGER;
+ NextDVIByte : GetByteFunction);
+
+(* DVIReader has seen a \special command while interpreting the current page.
+ It will call this routine and pass the current page position, the number
+ of bytes in the command and a function to return their values one at a time.
+ Instead of calling OutputSpecial directly, we have to save the necessary
+ info away for later use (see DoPage).
+*)
+
+VAR i, flush : INTEGER; temp : specialinfoptr;
+
+BEGIN
+NEW(temp);
+WITH temp^ DO
+ special := ''; (* SYSDEP: fill with NULLs *)
+ FOR i := 0 TO totalbytes-1 DO
+ IF i <= HIGH(special) THEN
+ special[i] := CHR(NextDVIByte());
+ END;
+ END;
+ (* DVIReader demands that we read ALL the \special bytes *)
+ IF totalbytes > HIGH(special) + 1 THEN
+ INC(warncount);
+ WriteString('\special command is too long: ');
+ WriteString(special);
+ WriteLn;
+ WriteString('Truncating: ');
+ FOR i := 1 TO totalbytes - (HIGH(special) + 1) DO
+ Write(CHR(NextDVIByte())); (* display the truncated bytes *)
+ END;
+ WriteLn;
+ END;
+ hp := hpos;
+ vp := vpos;
+ nextspecial := NIL;
+END;
+(* add new node to tail of list *)
+IF speciallist = NIL THEN
+ speciallist := temp;
+ELSE
+ specialtail^.nextspecial := temp;
+END;
+specialtail := temp;
+END MySpecialRoutine;
+
+(******************************************************************************)
+
+PROCEDURE ShowDimension (pixels : INTEGER);
+
+(* Show the given pixel dimension in terms of units. *)
+
+VAR realdim : REAL; fracpart : CARDINAL;
+
+BEGIN
+CASE units OF
+ in : realdim := FLOAT(pixels) / FLOAT(resolution) |
+ cm : realdim := FLOAT(pixels) / FLOAT(resolution) * 2.54 |
+ mm : realdim := FLOAT(pixels) / FLOAT(resolution) * 25.4 |
+ pc : realdim := FLOAT(pixels) / FLOAT(resolution) * 72.27 / 12.0 |
+ pt : realdim := FLOAT(pixels) / FLOAT(resolution) * 72.27 |
+ bp : realdim := FLOAT(pixels) / FLOAT(resolution) * 72.0 |
+ px : WriteInt(pixels); WriteString('px'); RETURN;
+END;
+(* show realdim to an accuracy of 1 decimal place *)
+IF ABS(realdim) < 0.05 THEN
+ WriteString('0.0');
+ELSE
+ IF realdim < 0.0 THEN
+ Write('-');
+ realdim := ABS(realdim);
+ END;
+ realdim := realdim + 0.05; (* round up to 1 decimal place *)
+ WriteCard(TRUNC(realdim)); (* whole part *)
+ Write('.');
+ fracpart := TRUNC((realdim - FLOAT(TRUNC(realdim))) * 10.0);
+ (* fracpart is now 0..9 *)
+ WriteCard(fracpart);
+END;
+ShowUnits;
+END ShowDimension;
+
+(**********************************************************************)
+
+PROCEDURE ShowUnits;
+
+BEGIN
+CASE units OF
+ in : WriteString('in') |
+ cm : WriteString('cm') |
+ mm : WriteString('mm') |
+ pc : WriteString('pc') |
+ pt : WriteString('pt') |
+ bp : WriteString('bp') |
+ px : WriteString('px') |
+END;
+END ShowUnits;
+
+(******************************************************************************)
+
+PROCEDURE MyPixelTableRoutine;
+
+(* PixelTableRoutine for DVIReader which has just allocated a new pixeltable
+ for currfont^. DVIReader 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.
+ 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 : CARDINAL;
+
+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
+ IF OpenFontFile(fontspec) THEN
+ (* only need fontid for a bitmapped font *)
+ IF NOT psfont THEN
+ fontid := fontname;
+ fontsizelen := lastn - firstn + 1;
+ IF fontnamelen + fontsizelen < maxfontspec THEN
+ (* append ".fontsize" to fontid *)
+ fontid[fontnamelen] := '.';
+ FOR i := 1 TO fontsizelen DO
+ fontid[fontnamelen + i] := fontspec[firstn + i - 1];
+ END;
+ IF fontnamelen + fontsizelen + 1 < maxfontspec THEN
+ fontid[fontnamelen + fontsizelen + 1] := NULL;
+ END;
+ ELSE
+ (* in the unlikely event that there is no room to append ".fontsize"
+ we simply leave fontid = fontname and hope it's unique *)
+ WriteString("fontname too long: "); WriteString(fontname); WriteLn;
+ WriteString("Increase maxfontspec in DVIReader."); WriteLn;
+ END;
+ IF NOT conserveVM THEN
+ NewBitmapFont(fontid);
+ END;
+ END;
+ (* DEBUG
+ WriteString('Reading font data from '); WriteString(fontspec); WriteLn;
+ GUBED *)
+ ELSIF OpenFontFile(dummyfont) THEN
+ (* fontid is left undefined; it will not be used *)
+ INC(warncount);
+ WriteString("Couldn't open font file: "); WriteString(fontspec); WriteLn;
+ (* use dummy font info instead *)
+ ELSE
+ WriteString("Couldn't open dummy font: "); WriteString(dummyfont);
+ WriteLn; Halt(error);
+ END;
+ FillPixelTable;
+ CloseFontFile;
+END;
+END MyPixelTableRoutine;
+
+(******************************************************************************)
+
+PROCEDURE ShowOptions;
+
+(* Show DVI file name and qualifier values set in Options module. *)
+
+BEGIN
+WriteString('This is PSDVI, version 3.1');
+WriteLn; WriteLn;
+WriteString('DVI file = '); WriteString(DVIname);
+WriteLn;
+WriteString('PostScript file = '); WriteString(PSname);
+WriteLn;
+WriteString('Header file = '); WriteString(header);
+WriteLn;
+WriteString('Resolution = '); WriteCard(resolution);
+WriteString(' pixels per inch');
+WriteLn;
+WriteString('Magnification = '); WriteCard(mag);
+IF mag <> DVImag THEN
+ WriteString(' (DVI mag of '); WriteCard(DVImag);
+ WriteString(' was overridden)');
+ELSE
+ WriteString(' (DVI mag)');
+END;
+WriteLn;
+WriteString('TFM directory = '); WriteString(tfmdir);
+WriteLn;
+WriteString('PS font prefix = '); WriteString(psprefix);
+WriteLn;
+WriteString('Font directory = '); WriteString(fontdir);
+WriteLn;
+WriteString('Dummy font = '); WriteString(dummyfont);
+WriteLn;
+WriteString('Horizontal offset = '); ShowDimension(hoffset);
+WriteLn;
+WriteString('Vertical offset = '); ShowDimension(voffset);
+WriteLn;
+WriteString('Paper width = '); ShowDimension(paperwd);
+WriteLn;
+WriteString('Paper height = '); ShowDimension(paperht);
+WriteLn;
+WriteString('Units = '); ShowUnits;
+WriteLn;
+WriteString('Reverse = ');
+IF reverse THEN WriteString('true') ELSE WriteString('false') END;
+WriteLn;
+WriteString('Stats = ');
+IF stats THEN WriteString('true') ELSE WriteString('false') END;
+WriteLn;
+WriteString('Conserve VM = ');
+IF conserveVM THEN WriteString('true') ELSE WriteString('false') END;
+WriteLn;
+WriteString('Pages = ');
+IF subrange THEN
+ IF firstDVIpage = 0 THEN
+ WriteString(firstTeXpage);
+ ELSE
+ WriteCard(firstDVIpage);
+ END;
+ Write(':');
+ IF finalDVIpage = 0 THEN
+ WriteString(finalTeXpage);
+ ELSE
+ WriteCard(finalDVIpage);
+ END;
+ELSE
+ WriteString('all pages');
+END;
+IF increment > 1 THEN
+ WriteString(', but with an increment of ');
+ WriteCard(increment);
+END;
+WriteLn;
+WriteLn;
+END ShowOptions;
+
+(******************************************************************************)
+
+PROCEDURE CheckPageRange;
+
+(* If user requested a page subrange then we make sure it is valid. *)
+
+VAR newTeXpage : TeXpageinfo;
+
+BEGIN
+IF NOT subrange THEN (* translate all pages *)
+ firstDVIpage := 1;
+ finalDVIpage := totalpages;
+ELSE
+ IF firstDVIpage = 0 THEN (* parse and locate firstTeXpage *)
+ IF ParseTeXPage(firstTeXpage,newTeXpage) THEN
+ MoveToDVIPage(1);
+ (* go forwards until newTeXpage matches currTeXpage *)
+ LOOP
+ IF CurrMatchesNew(newTeXpage) THEN
+ firstDVIpage := currDVIpage;
+ EXIT;
+ ELSIF currDVIpage = totalpages THEN
+ WriteString('First TeX page does not exist!'); WriteLn;
+ Halt(error);
+ ELSE
+ MoveToDVIPage(currDVIpage + 1);
+ END;
+ END;
+ ELSE
+ WriteString('Error in first TeX page!'); WriteLn;
+ Halt(error);
+ END;
+ END;
+ IF finalDVIpage = 0 THEN (* parse and locate finalTeXpage *)
+ IF ParseTeXPage(finalTeXpage,newTeXpage) THEN
+ MoveToDVIPage(totalpages);
+ (* go backwards until newTeXpage matches currTeXpage *)
+ LOOP
+ IF CurrMatchesNew(newTeXpage) THEN
+ finalDVIpage := currDVIpage;
+ EXIT;
+ ELSIF currDVIpage = 1 THEN
+ WriteString('Final TeX page does not exist!'); WriteLn;
+ Halt(error);
+ ELSE
+ MoveToDVIPage(currDVIpage - 1);
+ END;
+ END;
+ ELSE
+ WriteString('Error in final TeX page!'); WriteLn;
+ Halt(error);
+ END;
+ END;
+ IF firstDVIpage > finalDVIpage THEN
+ WriteString('First page > final page!'); WriteLn; Halt(error);
+ ELSIF firstDVIpage > totalpages THEN
+ WriteString('First page > total number of pages!'); WriteLn; Halt(error);
+ END;
+ (* allow user to give a final page > totalpages *)
+ IF finalDVIpage > totalpages THEN finalDVIpage := totalpages END;
+END;
+END CheckPageRange;
+
+(******************************************************************************)
+
+PROCEDURE ParseTeXPage (VAR pagestring : ARRAY OF CHAR;
+ 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.
+*)
+
+VAR pos, len : CARDINAL;
+
+BEGIN
+WITH newTeXpage DO
+ pos := 0;
+ IF pagestring[pos] <> '[' THEN
+ WriteString('[ expected!'); WriteLn;
+ RETURN FALSE;
+ END;
+ lastvalue := 0;
+ len := LEN(pagestring);
+ LOOP
+ INC(pos);
+ present[lastvalue] := GetInteger(pagestring, len, pos, value[lastvalue]);
+ (* pos now at len, space, period, non-digit or ']' *)
+ WHILE (pos < len) AND (pagestring[pos] = ' ') DO
+ INC(pos); (* skip any spaces *)
+ END;
+ IF pos = len THEN (* check this first! *)
+ WriteString('] expected!'); WriteLn;
+ RETURN FALSE;
+ END;
+ IF pagestring[pos] = ']' THEN (* end of TeX page specification *)
+ EXIT;
+ END;
+ IF lastvalue < 9 THEN
+ INC(lastvalue);
+ ELSE
+ WriteString("] expected after 10 integers!"); WriteLn;
+ RETURN FALSE;
+ END;
+ IF pagestring[pos] <> '.' THEN
+ WriteString('Period, integer or ] expected!'); WriteLn;
+ RETURN FALSE;
+ END;
+ END;
+ WHILE (lastvalue > 0) AND (NOT present[lastvalue]) DO
+ DEC(lastvalue);
+ END;
+END;
+RETURN TRUE;
+END ParseTeXPage;
+
+(******************************************************************************)
+
+PROCEDURE GetInteger (VAR str : ARRAY OF CHAR; (* in *)
+ strlen : CARDINAL; (* in *)
+ VAR pos : CARDINAL; (* 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.
+*)
+
+CONST limit = 2147483647; (* 2^31 - 1 *)
+ threshold = limit DIV 10; (* nearing overflow *)
+
+VAR absval, last : CARDINAL;
+ sign : INTEGER;
+ inttoobig : BOOLEAN;
+
+BEGIN
+WHILE (pos < strlen) AND (str[pos] = ' ') DO (* skip any spaces *)
+ INC(pos);
+END;
+absval := 0; sign := 1; last := pos;
+inttoobig := FALSE;
+IF pos < strlen THEN
+ IF str[pos] = '-' THEN
+ sign := -1; INC(last);
+ ELSIF str[pos] = '+' THEN
+ INC(last);
+ END;
+ WHILE (last < strlen) AND
+ (str[last] >= '0') AND (str[last] <= '9') DO
+ IF (absval > threshold) OR ((absval = threshold) AND (str[last] > '7'))
+ THEN
+ inttoobig := TRUE;
+ ELSE
+ absval := absval * 10 + (ORD(str[last]) - ORD('0'));
+ END;
+ INC(last);
+ END;
+END;
+IF pos = last THEN
+ n := 0;
+ RETURN FALSE;
+ELSE
+ pos := last;
+ IF inttoobig THEN absval := limit END;
+ n := sign * INTEGER(absval);
+ RETURN TRUE;
+END;
+END GetInteger;
+
+(******************************************************************************)
+
+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
+INC(pagecount);
+WriteCard(currDVIpage); (* show the current DVI page *)
+Write('/'); ShowTeXPage; (* and TeX page *)
+WriteLn;
+
+BeginPage(currDVIpage);
+InterpretPage; (* MyPixelTableRoutine calls NewBitmapFont *)
+IF pageempty THEN
+ OutputPage(currDVIpage); (* must be called even if no chars/rules *)
+ DoSpecials;
+ELSE
+ (* check that the page edges are within the paper edges *)
+ IF (minhp < paperleft) OR (minvp < papertop) OR
+ (maxhp > paperright) OR (maxvp > paperbottom) THEN
+ PageOffPaper;
+ END;
+ (* 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;
+ END;
+ OutputPage(currDVIpage);
+ DoSpecials;
+ DoFonts;
+ DoRules;
+END;
+EndPage(currDVIpage); (* final PostScript for current page *)
+END DoPage;
+
+(******************************************************************************)
+
+PROCEDURE ShowTeXPage;
+
+(* Show current TeX page counter(s). *)
+
+VAR i, lastnonzero : CARDINAL;
+
+BEGIN
+Write('[');
+lastnonzero := 9;
+WHILE (lastnonzero > 0) AND (currTeXpage[lastnonzero] = 0) DO
+ DEC(lastnonzero); (* find last counter with non-zero value *)
+END;
+(* always show \count0 but don't show trailing 0 counters *)
+FOR i := 0 TO lastnonzero DO
+ WriteInt(currTeXpage[i]);
+ IF i <> lastnonzero THEN
+ Write('.');
+ END;
+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
+INC(warncount);
+WriteString('Page off paper (paper is ');
+ShowDimension(paperwd); WriteString(' wide by ');
+ShowDimension(paperht); WriteString(' high)');
+WriteLn;
+IF minhp < paperleft THEN
+ WriteString('Beyond left edge by ');
+ ShowDimension(paperleft - minhp);
+ WriteLn;
+END;
+IF maxhp > paperright THEN
+ WriteString('Beyond right edge by ');
+ ShowDimension(maxhp - paperright);
+ WriteLn;
+END;
+IF minvp < papertop THEN
+ WriteString('Above top edge by ');
+ ShowDimension(papertop - minvp);
+ WriteLn;
+END;
+IF maxvp > paperbottom THEN
+ WriteString('Below bottom edge by ');
+ ShowDimension(maxvp - paperbottom);
+ WriteLn;
+END;
+END PageOffPaper;
+
+(******************************************************************************)
+
+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 : CARDINAL; (* 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
+ (* do nothing if resident PostScript font or bitmapped font doesn't exist *)
+ IF (NOT psfont) AND fontexists THEN
+ fontopen := FALSE; (* avoid opening font unnecessarily *)
+ thischarinfo := charlist;
+ WHILE thischarinfo <> NIL DO (* process unloaded chars in chartable *)
+ WITH thischarinfo^ DO
+ thischar := 0;
+ WHILE thischar < charcount DO
+ WITH chartable[thischar] DO
+ WITH pixelptr^[code] DO
+ IF (NOT loaded) AND (mapadr > 0) THEN (* load bitmap *)
+ IF NOT fontopen THEN
+ OpenFont(thisfontinfo);
+ BeginBitmapFont(fontid);
+ fontopen := TRUE; (* only open once *)
+ END;
+ LoadBitmap(thisfontinfo,code);
+ loaded := TRUE; (* only load once *)
+ END;
+ END;
+ END;
+ INC(thischar);
+ END;
+ thischarinfo := nextchar;
+ END;
+ END;
+ IF fontopen THEN CloseFontFile END;
+ END;
+ thisfontinfo := nextfont;
+END; (* WITH *)
+END; (* WHILE *)
+END LoadFonts;
+
+(******************************************************************************)
+
+PROCEDURE OpenFont (thisfontinfo : fontinfoptr);
+
+BEGIN
+WITH thisfontinfo^ DO
+ IF OpenFontFile(fontspec) THEN
+ (* DEBUG
+ WriteString("Loading characters for ");
+ WriteString(fontspec);
+ WriteLn;
+ GUBED *)
+ ELSE
+ (* this should never happen since we avoid loading dummy font chars *)
+ WriteLn;
+ WriteString('Bug in OpenFont! Could not open: ');
+ WriteString(fontspec);
+ WriteLn; Halt(error);
+ END;
+END;
+END OpenFont;
+
+(******************************************************************************)
+
+PROCEDURE DoSpecials;
+
+(* Call OutputSpecial for each \special command on the current page.
+ (The speciallist is built by MySpecialRoutine during InterpretPage.)
+*)
+
+VAR temp : specialinfoptr;
+
+BEGIN
+WHILE speciallist <> NIL DO
+ WITH speciallist^ DO
+ (* 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
+ INC(warncount);
+ WriteString("Couldn't open \special file: ");
+ WriteString(special); (* includes optional text *)
+ WriteLn;
+ ELSIF stats THEN
+ WriteString('\special command at (');
+ ShowDimension(hp); Write(',');
+ ShowDimension(vp); WriteString('): ');
+ WriteString(special); WriteLn;
+ END;
+ temp := speciallist;
+ speciallist := nextspecial;
+ DISPOSE(temp); (* speciallist must be NIL for next page *)
+ END;
+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.
+ See PSWRITER.DEF for details.
+*)
+
+VAR
+ thisfontinfo : fontinfoptr; (* current font info in fontlist *)
+ thischarinfo : charinfoptr; (* current char info in charlist *)
+ thischar : CARDINAL; (* current index into current chartable *)
+
+BEGIN
+thisfontinfo := fontlist;
+WHILE thisfontinfo <> unusedfont DO
+(* SortFonts makes sure we only consider used fonts! *)
+WITH thisfontinfo^ DO
+ IF fontexists THEN (* won't be dummy font info *)
+ IF psfont THEN
+ BeginPostScriptFont(fontname,scaledsize,mag);
+ ELSE
+ IF conserveVM THEN SaveVM(fontid) END;
+ BeginBitmapFont(fontid);
+ END;
+
+ IF conserveVM AND (NOT psfont) THEN (* download bitmaps *)
+ OpenFont(thisfontinfo);
+ thischarinfo := charlist;
+ WHILE thischarinfo <> NIL DO (* process unique chars *)
+ WITH thischarinfo^ DO
+ thischar := 0;
+ WHILE thischar < charcount DO
+ WITH chartable[thischar] DO
+ WITH pixelptr^[code] DO
+ IF (NOT loaded) AND (mapadr > 0) THEN (* load bitmap *)
+ LoadBitmap(thisfontinfo,code);
+ loaded := TRUE; (* but only once *)
+ END;
+ END;
+ END;
+ INC(thischar);
+ END;
+ thischarinfo := nextchar;
+ END;
+ END;
+ CloseFontFile;
+ (* reset loaded flags to FALSE for next page *)
+ FOR thischar := 0 TO maxTeXchar DO
+ pixelptr^[thischar].loaded := FALSE;
+ END;
+ END;
+
+ IF psfont THEN
+ thischarinfo := charlist;
+ WHILE thischarinfo <> NIL DO
+ WITH thischarinfo^ DO
+ thischar := 0;
+ WHILE thischar < charcount DO
+ WITH chartable[thischar] DO
+ WITH pixelptr^[code] DO
+ IF mapadr > 0 THEN (* char exists *)
+ SetPostScriptChar(CHR(code),
+ hp,vp, (* reference point *)
+ pwidth); (* advance width *)
+ END;
+ END;
+ END;
+ INC(thischar);
+ END;
+ thischarinfo := nextchar;
+ END;
+ END;
+ ELSE
+ thischarinfo := charlist;
+ WHILE thischarinfo <> NIL DO
+ WITH thischarinfo^ DO
+ thischar := 0;
+ WHILE thischar < charcount DO
+ WITH chartable[thischar] DO
+ WITH pixelptr^[code] DO
+ IF mapadr > 0 THEN (* char exists *)
+ SetBitmapChar(CHR(code),
+ hp,vp, (* reference point *)
+ pwidth); (* advance width *)
+ END;
+ END;
+ END;
+ INC(thischar);
+ END;
+ thischarinfo := nextchar;
+ END;
+ END;
+ END;
+ EndFont;
+
+ IF conserveVM AND (NOT psfont) THEN RestoreVM END;
+ END;
+ thisfontinfo := nextfont;
+END; (* WITH *)
+END; (* WHILE *)
+END DoFonts;
+
+(******************************************************************************)
+
+PROCEDURE DoRules;
+
+(* Call SetRule for each rule on the current page. *)
+
+VAR thisrule : CARDINAL;
+ thisruleinfo : ruleinfoptr;
+
+BEGIN
+thisruleinfo := rulelist;
+WHILE thisruleinfo <> NIL DO
+ WITH thisruleinfo^ DO
+ thisrule := 0;
+ WHILE thisrule < rulecount DO
+ WITH ruletable[thisrule] DO
+ SetRule(wd,ht, (* width and height of rule *)
+ hp,vp); (* bottom left corner of rule *)
+ END;
+ INC(thisrule);
+ END;
+ thisruleinfo := nextrule;
+ END;
+END;
+END DoRules;
+
+(******************************************************************************)
+
+PROCEDURE ShowPageStats;
+
+(* Show rule/font/character statistics for current page. *)
+
+VAR fontcount : CARDINAL;
+ thisfontinfo : fontinfoptr;
+
+BEGIN
+WriteString('Total rules on current page = '); WriteCard(totalrules);
+WriteLn;
+WriteString('Fonts on current page:');
+WriteLn;
+fontcount := 0;
+thisfontinfo := fontlist;
+WHILE thisfontinfo <> NIL DO
+ WITH thisfontinfo^ DO
+ IF fontused THEN
+ WriteString(fontspec);
+ IF psfont THEN ShowPtSize(scaledsize) END;
+ IF NOT fontexists THEN WriteString(' DOES NOT EXIST!') END;
+ INC(fontcount);
+ WriteString(' total chars = '); WriteCard(totalchars); WriteLn;
+ END;
+ thisfontinfo := nextfont;
+ END;
+END;
+WriteString('Total fonts on current page = '); WriteCard(fontcount);
+WriteLn;
+WriteLn;
+END ShowPageStats;
+
+(******************************************************************************)
+
+PROCEDURE ShowFinalStats;
+
+(* Show some overall statistics. *)
+
+VAR fontsused, c, loadcount, loadtotal, bitmapbytes : CARDINAL;
+ thisfontinfo : fontinfoptr;
+
+BEGIN
+WriteString('Summary'); WriteLn;
+WriteString('======='); WriteLn;
+WriteLn;
+WriteString('Total pages output = '); WriteCard(pagecount);
+WriteLn;
+WriteString('Total pages in DVI file = '); WriteCard(totalpages);
+WriteLn;
+WriteString('Total fonts in DVI file = '); WriteCard(totalfonts);
+WriteLn;
+(* go thru fontlist showing info for EVERY font *)
+fontsused := 0;
+loadtotal := 0;
+bitmapbytes := 0;
+thisfontinfo := fontlist;
+WHILE thisfontinfo <> NIL DO
+ WITH thisfontinfo^ DO
+ IF fontspeclen > 0 THEN
+ WriteString(fontspec);
+ IF psfont THEN ShowPtSize(scaledsize) END;
+ IF fontexists THEN
+ INC(fontsused);
+ IF (NOT conserveVM) AND (NOT psfont) THEN
+ loadcount := 0;
+ FOR c := 0 TO maxTeXchar DO
+ WITH pixelptr^[c] DO
+ IF loaded AND (mapadr > 0) THEN
+ INC(loadcount);
+ INC(bitmapbytes, ht * ((wd + 7) DIV 8) );
+ END;
+ END;
+ END;
+ WriteString(' loaded chars = '); WriteCard(loadcount);
+ INC(loadtotal,loadcount);
+ END;
+ ELSE
+ WriteString(' DOES NOT EXIST!');
+ END;
+ ELSE
+ WriteString(fontname);
+ WriteString(' scaled ');
+ WriteCard(TRUNC( FLOAT(mag) *
+ FLOAT(scaledsize)/FLOAT(designsize) + 0.5 ));
+ WriteString(' not used');
+ END;
+ WriteLn;
+ thisfontinfo := nextfont;
+ END;
+END;
+WriteString('Total fonts actually used = '); WriteCard(fontsused);
+WriteLn;
+IF NOT conserveVM THEN
+ WriteString('Total characters loaded = '); WriteCard(loadtotal);
+ WriteLn;
+ WriteString('Hex digits in loaded bitmaps = 2 * '); WriteCard(bitmapbytes);
+ WriteLn;
+END;
+END ShowFinalStats;
+
+(******************************************************************************)
+
+PROCEDURE ShowPtSize (scaledsize : INTEGER);
+
+(* Show given font size (in DVI units) in terms of (possibly magnified) pts. *)
+
+VAR realdim : REAL; fracpart : CARDINAL;
+
+BEGIN
+WriteString(' at ');
+realdim := (FLOAT(scaledsize) / FLOAT(10000H)) * (FLOAT(mag) / 1000.0);
+(* show realdim to an accuracy of 1 decimal place *)
+IF ABS(realdim) < 0.05 THEN
+ WriteString('0');
+ELSE
+ IF realdim < 0.0 THEN
+ Write('-');
+ realdim := ABS(realdim);
+ END;
+ realdim := realdim + 0.05; (* round up to 1 decimal place *)
+ WriteCard(TRUNC(realdim)); (* whole part *)
+ fracpart := TRUNC((realdim - FLOAT(TRUNC(realdim))) * 10.0); (* 0..9 *)
+ IF fracpart > 0 THEN
+ Write('.');
+ WriteCard(fracpart);
+ END;
+END;
+WriteString('pt');
+END ShowPtSize;
+
+(******************************************************************************)
+
+BEGIN
+TopLevel;
+END PSDVI.
diff --git a/dviware/psprint/vms/psfonts.tex b/dviware/psprint/vms/psfonts.tex
new file mode 100644
index 0000000000..6df7ba02d4
--- /dev/null
+++ b/dviware/psprint/vms/psfonts.tex
@@ -0,0 +1,71 @@
+% This TeX source file illustrates the use (and abuse) of PostScript fonts.
+
+\input psnames % defines macros for names of PostScript fonts used by PSPRINT
+\input pstext % defines \PStext and \CMtext
+
+\nopagenumbers
+\parindent=0pt
+\parskip=\bigskipamount
+
+The following fonts should be available in all PostScript printers:
+
+\font\cour=\Courier at 10pt
+\font\courb=\CourierB at 10pt
+\font\couro=\CourierO at 10pt
+\font\courbo=\CourierBO at 10pt
+\font\helv=\Helv at 10pt
+\font\helvb=\HelvB at 10pt
+\font\helvo=\HelvO at 10pt
+\font\helvbo=\HelvBO at 10pt
+\font\ts=\TimesS at 10pt
+\font\tr=\TimesR at 10pt
+\font\tb=\TimesB at 10pt
+\font\ti=\TimesI at 10pt
+\font\tbi=\TimesBI at 10pt
+\font\sy=\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=\TimesR at 12pt
+\font\trB=\TimesR at 20.5pt
+\font\trC=\TimesR at 144pt
+
+\bigskip
+\leftline{\trA Times-Roman at 12pt}
+\leftline{\trB Times-Roman at 20.5pt}
+\leftline{\trC At 144pt}
+
+\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 % \t, \aa, \AA and \j will generate error messages
+\CMtext
+
+\rm
+A PostScript font usually appears {\tr darker and larger} than
+an ``equivalent'' Computer Modern font.
+
+\bye
diff --git a/dviware/psprint/vms/psnames.tex b/dviware/psprint/vms/psnames.tex
new file mode 100644
index 0000000000..f715278d9f
--- /dev/null
+++ b/dviware/psprint/vms/psnames.tex
@@ -0,0 +1,41 @@
+% Macros for PostScript TFM names used by PSPRINT under VAX/VMS.
+% The space after the TFM name allows users to do things like
+% "\font\hugetr=\TimesR at 50pt".
+% This file should be put into TeX's default input directory.
+%
+\def\Symbol {ps-symbol } % Symbol
+\def\Courier {ps-courier } % Courier
+\def\CourierB {ps-courier-b } % Courier-Bold
+\def\CourierO {ps-courier-o } % Courier-Oblique
+\def\CourierBO {ps-courier-bo } % Courier-BoldOblique
+\def\Helv {ps-helv } % Helvetica
+\def\HelvB {ps-helv-b } % Helvetica-Bold
+\def\HelvO {ps-helv-o } % Helvetica-Oblique
+\def\HelvBO {ps-helv-bo } % Helvetica-BoldOblique
+\def\TimesR {ps-times-r } % Times-Roman
+\def\TimesS {ps-times-s } % Times-Slanted
+\def\TimesB {ps-times-b } % Times-Bold
+\def\TimesI {ps-times-i } % Times-Italic
+\def\TimesBI {ps-times-bi } % Times-BoldItalic
+\def\AvantB {ps-avantg-b } % AvantGarde-Book
+\def\AvantBO {ps-avantg-bo } % AvantGarde-BookOblique
+\def\AvantD {ps-avantg-d } % AvantGarde-Demi
+\def\AvantDO {ps-avantg-do } % AvantGarde-DemiOblique
+\def\BookD {ps-bookman-d } % Bookman-Demi
+\def\BookDI {ps-bookman-di } % Bookman-DemiItalic
+\def\BookL {ps-bookman-l } % Bookman-Light
+\def\BookLI {ps-bookman-li } % Bookman-LightItalic
+\def\HelvN {ps-helv-n } % Helvetica-Narrow
+\def\HelvNB {ps-helv-nb } % Helvetica-Narrow-Bold
+\def\HelvNO {ps-helv-no } % Helvetica-Narrow-Oblique
+\def\HelvNBO {ps-helv-nbo } % Helvetica-Narrow-BoldOblique
+\def\NCSR {ps-ncs-r } % NewCenturySchlbk-Roman
+\def\NCSB {ps-ncs-b } % NewCenturySchlbk-Bold
+\def\NCSI {ps-ncs-i } % NewCenturySchlbk-Italic
+\def\NCSBI {ps-ncs-bo } % NewCenturySchlbk-BoldItalic
+\def\PalR {ps-pal-r } % Palatino-Roman
+\def\PalB {ps-pal-b } % Palatino-Bold
+\def\PalI {ps-pal-i } % Palatino-Italic
+\def\PalBI {ps-pal-bi } % Palatino-BoldItalic
+\def\ZapfChMI {ps-zapfch-mi } % ZapfChancery-MediumItalic
+\def\ZapfD {ps-zapfdb } % ZapfDingbats
diff --git a/dviware/psprint/vms/psprint.cld b/dviware/psprint/vms/psprint.cld
new file mode 100644
index 0000000000..e34844f7c2
--- /dev/null
+++ b/dviware/psprint/vms/psprint.cld
@@ -0,0 +1,95 @@
+define verb PSPRINT
+image TEX_PS:PSPRINT.EXE
+ parameter p1,label=filespec,prompt="File",value(required,type=$infile)
+ qualifier prep, value(type=$infile,default="TEX_PS:LASERPREP70.PS")
+ qualifier output, value(required,type=$infile) ! default is print
+ qualifier landscape, nonnegatable ! default is portrait
+!
+! User can override the selection of file format based on file extension:
+!
+ qualifier dvi, nonnegatable
+ qualifier ps, nonnegatable
+ qualifier text, nonnegatable
+ qualifier two, nonnegatable
+ qualifier wide, nonnegatable
+ disallow any2(dvi,ps,text,two,wide)
+!
+! PSPRINT only provides a few of the normal PRINT qualifiers:
+!
+ qualifier delete, ! default is /NODELETE
+ qualifier notify, ! default is /NONOTIFY
+ qualifier copies, value(required,type=$number) ! default is 1
+ qualifier note, value(required)
+ qualifier form, value(required)
+ qualifier queue, value(required)
+!
+! We currently do not use different forms. Other sites might want to use
+! /FORM to handle transparencies, manual feeding, proof/final copy, etc:
+!
+ disallow form
+!
+! Here are the allowed PSDVI qualifiers (default values are set in PSDVI.CLD):
+!
+ qualifier pages, nonnegatable,value(required)
+ qualifier increment, nonnegatable,value(required,type=$number)
+ qualifier magnification, nonnegatable,value(required,type=$number)
+ qualifier resolution, nonnegatable,value(required,type=$number)
+ qualifier units, nonnegatable,value(required)
+ qualifier hoffset, nonnegatable,value(required)
+ qualifier voffset, nonnegatable,value(required)
+ qualifier xsize, nonnegatable,value(required)
+ qualifier ysize, nonnegatable,value(required)
+ qualifier psprefix, nonnegatable,value(required)
+ qualifier tfm_directory, nonnegatable,value(required)
+ qualifier font_directory, nonnegatable,value(required)
+ qualifier dummy_font, nonnegatable,value(required)
+ qualifier stats,
+!
+! The /CONSERVE_VM and /REVERSE qualifiers are handled differently because
+! we want PSPRINT to use default settings that depend on the /DEVICE value:
+!
+ qualifier conserve_vm, nonnegatable
+ qualifier noconserve_vm, nonnegatable
+ disallow conserve_vm and noconserve_vm
+!
+ qualifier reverse, nonnegatable
+ qualifier noreverse, nonnegatable
+ disallow reverse and noreverse
+!
+!
+! PSPRINT runs a different command file for each different PostScript device:
+!
+ qualifier device, nonnegatable,default,value(type=psprinter,required)
+!
+! This qualifier is only relevant if /DEVICE=LW or LINO:
+!
+ qualifier banner, default ! default is print banner page
+!
+! This qualifier is only relevant if /DEVICE=LW:
+!
+ qualifier manualfeed, nonnegatable ! default is auto feed
+!
+! These qualifiers are only relevant if /DEVICE=LINO:
+!
+ qualifier cutmarks, default ! default is do them
+ qualifier lowres, nonnegatable ! default is high-res
+ qualifier size, nonnegatable,default,value(type=pagesize,required)
+!
+! The Linotronic supports a number of different page sizes and orientations.
+! The /SIZE values defined below are used in LINO_PRINT.COM:
+!
+define type pagesize
+ keyword A3L ! A3 page size with landscape orientation
+ keyword A4P, default ! A4 page size with portrait orientation
+ keyword A4L ! A4 page size with landscape orientation
+ keyword A5P ! A5 page size with portrait orientation
+ keyword A5L ! A5 page size with landscape orientation
+ keyword B5P ! B5 page size with portrait orientation
+ keyword B5L ! B5 page size with landscape orientation
+!
+! Here are the different /DEVICE values currently supported:
+!
+define type psprinter
+ keyword LW , default ! LaserWriter
+ keyword LINO ! Linotronic 300
+ keyword PS40 ! PrintServer 40
diff --git a/dviware/psprint/vms/psprint.hlp b/dviware/psprint/vms/psprint.hlp
new file mode 100644
index 0000000000..f80a58e9d0
--- /dev/null
+++ b/dviware/psprint/vms/psprint.hlp
@@ -0,0 +1,438 @@
+1 PSPRINT
+
+USAGE: PSPRINT file [qualifiers]
+
+The PSPRINT command 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.
+
+To print your own copy of the "PSPRINT User Guide" just type:
+
+ $ PSPRINT TEX_PS:USERGUIDE
+
+2 TeX_Output
+
+PSPRINT looks for a DVI file by default. To print FOO.DVI, simply type:
+
+ $ PSPRINT FOO
+
+PSPRINT first translates FOO.DVI into a temporary PostScript file called
+FOO.TMP. The order in which pages are translated depends on the printer
+(the default order can be overridden by the /REVERSE or /NOREVERSE options).
+If no errors are found, FOO.TMP is sent to an appropriate queue
+where it is printed (and then deleted).
+
+2 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
+qualifier. 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.
+
+2 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 /LANDSCAPE qualifier 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.
+
+The /TWO and /WIDE qualifiers also print text files but format the
+output so that two "pages" appear on each sheet of paper; each page
+has a header line showing the file name and page number.
+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.
+
+2 Errors
+
+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 banner page.
+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_VM.
+ - On a Linotronic, try using /LOWRES.
+ (Note that /CONSERVE_VM is the default for this device.)
+
+If you are sending your own PostScript program then an error should
+produce some sort of message on the printed output.
+If you are using a PrintServer 40 then specify /NOTIFY to get all
+PostScript messages sent back to your terminal.
+
+2 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.
+
+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.
+
+2 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 write
+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.
+
+2 Qualifiers
+
+/DEVICE=printer_type
+
+This qualifier 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,
+along with a header line showing the file name and page number.
+
+/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,
+along with a header line showing the file name and page number.
+
+/BANNER
+(only if /DEVICE=LW or LINO)
+
+By default PSPRINT produces a banner page for each job sent to
+a LaserWriter or Linotronic. Use /NOBANNER if you don't want such a page.
+
+/MANUALFEED
+(only if /DEVICE=LW)
+
+Use this qualifier 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 /DEVICE=LINO)
+
+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_size
+(only if /DEVICE=LINO)
+
+This qualifier 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 /LANDSCAPE which rotates
+the output within the page image, regardless of the /SIZE value.)
+
+/CUTMARKS
+(only if /DEVICE=LINO)
+
+This qualifier 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.
+
+/CONSERVE_VM
+(only for a DVI file)
+
+Use /CONSERVE_VM 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). If /DEVICE=LINO then /CONSERVE_VM is the default;
+if /DEVICE=LW or PS40 then /NOCONSERVE_VM is the default.
+
+/PAGES=first:final
+(only for a DVI file)
+
+Print a selected subrange from the DVI file. "first" and "final" can
+select either DVI page numbers (positive integers) or TeX page numbers.
+Assuming TeX generated the 5 pages `[0] [1] [2.1] [2.2] [3]', here are some
+examples of how you could use /PAGES:
+
+ $ PSPRINT FOO /PAGES=2 --- prints the 2nd DVI page (as would [1])
+ $ PSPRINT FOO /PAGES=4: --- prints the last two pages
+ $ PSPRINT FOO /PAGES=:4 --- prints the first four pages
+ $ PSPRINT FOO /PAGES=[2] --- prints [2.1] and [2.2]
+ $ PSPRINT FOO /PAGES=1:[2] --- prints the first four pages
+ $ PSPRINT FOO /PAGES=[2.2]: --- prints the last two pages
+
+Note 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. Many DVI pages 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.
+
+/INCREMENT=i
+(only for a DVI file)
+
+Assuming f is the first DVI page selected (where f is either 1 or the start
+of a /PAGES 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 /INCREMENT 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 /INC=2 /REV /NOBANNER ! prints DVI pages 7, 5, 3, 1
+
+ 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 /INC=2 /PAG=2: /NOREV ! prints DVI pages 2, 4, 6, 8
+
+Note that the use of /REVERSE with /INCREMENT has no effect on WHICH pages
+are printed; it simply changes the ORDER in which they are done.
+
+If you intend doing a lot of two-sided printing then it is a good idea to
+define some symbols in your LOGIN.COM file to avoid making mistakes:
+
+ $ ODDPAGES :== PSPRINT/PAG=1:/INC=2/REV/NOBANNER
+ $ EVENPAGES :== PSPRINT/PAG=2:/INC=2/NOREV
+
+/REVERSE
+(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. /NOREVERSE is the default for all devices
+currently supported by PSPRINT.
+
+/MAGNIFICATION=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.
+
+/UNITS=xx
+(only for a DVI file)
+
+Set the units of dimensions displayed in some PSPRINT messages
+(e.g., if the page is off the paper). "xx" can be one of:
+
+ 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 (depends on resolution of printer)
+
+/STATS
+(only for a DVI file)
+
+Display statistics on the rules, fonts, characters and \special commands
+used on each page.
+
+/RESOLUTION=i
+(only for a DVI file)
+
+i is a positive integer specifying the resolution of your printer
+in pixels per inch (horizontally and vertically).
+
+/HOFFSET=dimension
+/VOFFSET=dimension
+(only for a DVI file)
+
+These qualifiers allow you to shift the printed location of each page
+according to the given dimensions. For example, "/hoffset=-0.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 /UNITS).
+
+/XSIZE=posdimen
+/YSIZE=posdimen
+(only for a DVI file)
+
+PSPRINT will automatically check each DVI page to make sure it fits
+within the given paper dimensions.
+A "posdimen" is any positive integer or real number followed by a
+two-letter unit: IN,CM,MM,PC,PT,BP,PX (same as those for /UNITS).
+
+/PSPREFIX=string
+(only for a DVI file)
+
+PSPRINT needs to read TFM files if your DVI file uses printer-resident
+PostScript fonts (for which bitmapped information does not exist).
+All such fonts must have names beginning with the given prefix.
+
+/TFM_DIRECTORY=directory
+(only for a DVI file)
+
+Specifies the location of TFM files for printer-resident PostScript fonts.
+
+/DUMMY_FONT=file
+(only for a DVI file)
+
+This qualifier indicates the naming convention and format of all font files.
+The given file must represent an unmagnified font.
+
+/FONT_DIRECTORY=directory
+(only for a DVI file)
+
+Use this qualifier to override the default directory from which PSPRINT
+gets all its character bitmap information. You'll probably never need to
+use this facility, but it might come in handy if you are using Metafont
+to create your own fonts or modify existing ones. The following commands
+tell PSPRINT to first search for fonts in the current directory ([]) before
+looking in the default directory (assumed to be TEX_DISK:[TEX.PK]):
+
+ $ DEFINE DIRLIST [],TEX_DISK:[TEX.PK]
+ $ PSPRINT FOO.DVI /FONT="DIRLIST:"
+
+Use /STATS to see the default font directory at your site.
+
+/LANDSCAPE
+
+To get "landscaped" output.
+(Normal output is said to have a "portrait" orientation.)
+If given a DVI file, PSPRINT will check each page to make sure it fits
+within the rotated paper.
+
+/DELETE
+
+To delete the input file after printing.
+
+/NOTIFY
+
+To be notified when the print job has finished.
+On the PrintServer 40 you'll also see any PostScript messages,
+a particularly useful feature when debugging a PostScript program.
+
+/COPIES=number
+
+To specify up to 100 copies.
+Use of this facility is not encouraged. Note in particular that
+copies of a multiple-page document will NOT be collated.
+
+/NOTE=string
+
+To include a note on your banner page. For example, to get your output
+put in box 99, just type `PSPRINT /NOTE="BOX 99" ...'.
+
+/QUEUE=string
+
+To override the default queue used by PSPRINT.
+(Some sites may have more than one printer of the same type.)
+
+/OUTPUT=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.
+
+/PREP=file
+(only for a DVI or PS file)
+
+To include a modified Laser Prep file that will allow you to send
+PostScript files created on a Macintosh by the Command-F method.
+If you just type /PREP then a default file (TEX_PS:LASERPREP70.PS) will
+be used.
diff --git a/dviware/psprint/vms/psprint.mod b/dviware/psprint/vms/psprint.mod
new file mode 100644
index 0000000000..80661b1e23
--- /dev/null
+++ b/dviware/psprint/vms/psprint.mod
@@ -0,0 +1,603 @@
+MODULE PSPRINT;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4.x
+ Date Started: July, 1986
+ Released: September, 1986 (version 1.0)
+
+ Description:
+ PSPRINT can print a variety of file formats on a range of PostScript
+ printers. See the PSPRINT User Guide and System Guide for more details.
+ Much of the command line parsing is done by DCL according to PSPRINT.CLD.
+ Most of the semantic checking is done here. If everything seems okay then
+ we run a device-specific command file.
+
+ If /DEVICE=LW then we do @TEX_PS:LW_PRINT P1 P2 P3 P4 P5 P6 P7 P8
+ where
+ P1 = complete file specification
+ P2 = file format (DVI or PS or TEXT or TWO or WIDE)
+ P3 = options for PSDVI
+ P4 = options for PRINT
+ P5 = /NOTE value ("" if not used)
+ P6 = /COPIES value (1 if not used)
+ P7 = /OUTPUT value ("" if not used)
+ P8 = "bbbb<prep>" where b = Y or N and represents the status of the
+ boolean qualifiers /DELETE, /LANDSCAPE, /BANNER, /MANUALFEED
+ and <prep> is the /PREP value
+
+ If /DEVICE=PS40 then we do @TEX_PS:PS40_PRINT P1 P2 P3 P4 P5 P6 P7 P8
+ where P1 to P7 are as above but
+ P8 = "bb<prep>" where b = Y or N and represents the status of the
+ boolean qualifiers /DELETE, /LANDSCAPE
+ and <prep> is the /PREP value
+
+ If /DEVICE=LINO then we do @TEX_PS:LINO_PRINT P1 P2 P3 P4 P5 P6 P7 P8
+ where P1 to P7 are as above but
+ P8 = "bbbbbsss<prep>" where b = Y or N and represents the status of the
+ boolean qualifiers /DELETE, /LANDSCAPE, /CUTMARKS, /LOWRES, /BANNER
+ and sss = /SIZE value (PSPRINT.CLD defines legal values and default)
+ and <prep> is the /PREP value
+
+ Note that DCL allows a maximum of 8 parameters, so a lot of information
+ has to be packed into P8.
+
+ Revised:
+ January, 1987
+ - The /REVERSE qualifier is no longer used. The order in which DVI pages
+ are translated (by PSDVI) is best left specified in the COM file.
+ (Note that /NOREVERSE on PSPRINT never actually worked!)
+ - Released version 1.1 in January, 1987
+
+ November, 1987 (while at The Open University)
+ - Added /DEVICE qualifier. PSPRINT needs to run a different command file
+ for each type of PostScript printer currently supported.
+ - Added /CONSERVE_VM and /NOCONSERVE_VM qualifiers. If neither is present
+ then a default setting is used that depends on the /DEVICE value.
+ - Added Linotronic-specific qualifiers (/CUTMARKS, /LOWRES, /SIZE).
+ These are simply ignored if /DEVICE does not equal LINO.
+ - Released version 2.0 in December, 1987
+
+ June--August, 1988 (while at Aston University)
+ - Added /QUEUE qualifier for sites with more than one printer.
+ - Added /BANNER and /MANUALFEED qualifiers for LW.
+ - Added /TWO and /WIDE text formats.
+ - Added /OUTPUT qualifer so user can save PostScript output in a given file
+ rather than send it to a print queue.
+ - The /REVERSE qualifier is back in again! It is treated like /CONSERVE_VM.
+ - Added /INCREMENT qualifier to simplify both-sided printing.
+ - Added /FONT_DIRECTORY qualifier to allow users to override the default
+ font directory used by PSDVI. This could be handy for Metafont users.
+ - Added more PSDVI qualifiers: /HOFFSET, /VOFFSET, /XSIZE, /YSIZE,
+ /RESOLUTION, /PSPREFIX, /TFM_DIRECTORY and /DUMMY_FONT.
+ Most users will never need to use any of these.
+ - All these new qualifiers have required some reorganisation of the
+ parameters passed into the various command files.
+ - Released version 3.0 in August, 1988
+
+ September--October, 1989 (while at Aston University, 2nd time)
+ - Added /BANNER qualifier for LINO.
+ - Added /PREP qualifier so user can include a modified Laser Prep.
+ - /REVERSE and /CONSERVE_VM defaults are now specified in the
+ device-specific COM files.
+ - Released version 3.1 in October, 1989
+*)
+
+FROM VMS IMPORT
+ SYS$EXIT;
+
+FROM CommandLanguageInterface IMPORT
+ CLI$PRESENT, CLI$GET_VALUE;
+
+FROM CommonInputOutputProcedures IMPORT
+ LIB$DO_COMMAND;
+
+FROM FileSystem IMPORT
+ File, Open, Name, Done, Close;
+
+FROM InOut IMPORT
+ Write, WriteString, WriteLn;
+
+
+CONST
+ NULL = 0C; (* SYSDEP: terminates a non-full string *)
+
+TYPE
+ string = ARRAY [0..79] OF CHAR;
+
+VAR
+ filespec, ext, device, value : string;
+ status : CARDINAL;
+ f : File;
+ command : ARRAY [0..255] OF CHAR;
+ format : (dvifile,psfile,textfile,twofile,widefile);
+ printer : (LINO,LW,PS40);
+
+
+(******************************************************************************)
+
+PROCEDURE GetValue (qualifier : ARRAY OF CHAR;
+ VAR s : ARRAY OF CHAR) : BOOLEAN;
+
+(* GetValue should only be called for those qualifiers that have a value.
+ If given qualifier is present then we get value and return TRUE,
+ otherwise FALSE.
+*)
+
+VAR i, status : CARDINAL;
+
+BEGIN
+IF ODD(CLI$PRESENT(qualifier)) THEN
+ status := CLI$GET_VALUE(qualifier,s); (* PSPRINT.CLD ensures value *)
+ i := HIGH(s);
+ WHILE (i > 0) AND (s[i] = ' ') DO (* remove trailing blanks *)
+ s[i] := NULL; (* SYSDEP: pad with NULLs *)
+ DEC(i);
+ END;
+ RETURN TRUE;
+ELSE
+ s[0] := NULL;
+ RETURN FALSE;
+END;
+END GetValue;
+
+(******************************************************************************)
+
+PROCEDURE ExplicitExt (fname : ARRAY OF CHAR;
+ VAR ext : ARRAY OF CHAR) : BOOLEAN;
+
+(* SYSDEP: VAX/VMS files have an extension of the form ".xxx...xxx;version".
+ If the given file specification contains an extension then
+ TRUE is returned (and ext will be string after '.' but before any ';').
+*)
+
+VAR i, l, pos : CARDINAL; ch : CHAR;
+
+BEGIN
+pos := LEN(fname);
+l := pos;
+ext[0] := NULL;
+WHILE pos > 0 DO (* search backwards looking for . or : or ] *)
+ DEC(pos);
+ ch := fname[pos];
+ IF ch = '.' THEN (* extract extension *)
+ i := 0;
+ INC(pos);
+ WHILE (pos <= HIGH(fname))
+ AND (fname[pos] <> NULL) AND (fname[pos] <> ';') DO
+ ext[i] := fname[pos];
+ INC(i); INC(pos);
+ END;
+ IF i <= HIGH(ext) THEN ext[i] := NULL END;
+ RETURN TRUE;
+ ELSIF (ch = ':') OR (ch = ']') THEN (* don't need to look further *)
+ RETURN FALSE;
+ END;
+END;
+RETURN FALSE;
+END ExplicitExt;
+
+(******************************************************************************)
+
+PROCEDURE Append (VAR s1 : ARRAY OF CHAR; s2 : ARRAY OF CHAR);
+
+(* Append s2 to s1. *)
+
+VAR i, j : CARDINAL;
+
+BEGIN
+i := LEN(s1);
+j := 0;
+WHILE (i <= HIGH(s1)) AND (j <= HIGH(s2)) AND (s2[j] <> NULL) DO
+ s1[i] := s2[j];
+ INC(i);
+ INC(j);
+END;
+(* check for overflow *)
+IF (i > HIGH(s1)) AND (j <= HIGH(s2)) AND (s2[j] <> NULL) THEN
+ WriteString('No room to append '); WriteString(s2); WriteLn;
+ ErrorHalt;
+END;
+IF i <= HIGH(s1) THEN s1[i] := NULL END;
+END Append;
+
+(******************************************************************************)
+
+PROCEDURE Equal (s1 : ARRAY OF CHAR; s2 : ARRAY OF CHAR) : BOOLEAN;
+
+(* Return TRUE iff s1 = s2. *)
+
+VAR i : CARDINAL;
+
+BEGIN
+i := 0;
+LOOP
+ IF (i > HIGH(s1)) OR (s1[i] = NULL) THEN (* end of s1 *)
+ RETURN (i > HIGH(s2)) OR (s2[i] = NULL);
+ ELSIF (i > HIGH(s2)) OR (s2[i] = NULL) THEN (* end of s2 *)
+ RETURN s1[i] = NULL;
+ ELSIF s1[i] <> s2[i] THEN
+ RETURN FALSE;
+ END;
+ INC(i);
+END;
+END Equal;
+
+(******************************************************************************)
+
+PROCEDURE ErrorHalt;
+
+(* Call SYS$EXIT with a magic number that will set ERROR status without
+ causing any spurious CLI message.
+*)
+
+VAR dummy : CARDINAL;
+
+BEGIN
+dummy := SYS$EXIT(10000002H);
+END ErrorHalt;
+
+(******************************************************************************)
+
+PROCEDURE AppendFilespec;
+
+BEGIN
+IF GetValue('FILESPEC',filespec) THEN
+ IF NOT ExplicitExt(filespec,ext) THEN (* assume DVI file if no extension *)
+ Append(filespec,'.DVI'); (* append .DVI *)
+ format := dvifile;
+ ELSIF Equal(ext,'DVI') THEN
+ format := dvifile;
+ ELSIF Equal(ext,'PS') THEN
+ format := psfile; (* PostScript file *)
+ ELSE
+ format := textfile; (* ordinary text file *)
+ END;
+ Open(f,filespec,FALSE);
+ IF Done() THEN (* given file exists *)
+ Name(f,filespec); (* full file specification *)
+ Append(command,filespec);
+ Close(f);
+ ELSE
+ WriteString("Couldn't open ");
+ WriteString(filespec); Write('!'); WriteLn;
+ ErrorHalt;
+ END;
+ELSE
+ (* PSPRINT.CLD should prevent this ever happening, but play safe *)
+ WriteString('File not given!'); WriteLn;
+ ErrorHalt;
+END;
+END AppendFilespec;
+
+(******************************************************************************)
+
+PROCEDURE AppendFormat;
+
+(* /DVI, /PS, /TEXT, /TWO or /WIDE can override the implicit file format.
+ PSPRINT.CLD should ensure that only one of these is allowed.
+*)
+
+BEGIN
+IF ODD(CLI$PRESENT('DVI')) THEN
+ format := dvifile;
+ELSIF ODD(CLI$PRESENT('PS')) THEN
+ format := psfile;
+ELSIF ODD(CLI$PRESENT('TEXT')) THEN
+ format := textfile;
+ELSIF ODD(CLI$PRESENT('TWO')) THEN
+ format := twofile;
+ELSIF ODD(CLI$PRESENT('WIDE')) THEN
+ format := widefile;
+END;
+CASE format OF
+ dvifile : Append(command,' DVI');
+ | psfile : Append(command,' PS');
+ | textfile : Append(command,' TEXT');
+ | twofile : Append(command,' TWO');
+ | widefile : Append(command,' WIDE');
+ELSE
+ WriteString('BUG! Unknown file format!'); WriteLn;
+ ErrorHalt;
+END;
+END AppendFormat;
+
+(******************************************************************************)
+
+PROCEDURE DVIcheck (qual : ARRAY OF CHAR);
+
+(* The given qualifier is only allowed with a DVI file. *)
+
+BEGIN
+IF format <> dvifile THEN
+ WriteString(qual);
+ WriteString(' is only allowed with a DVI file!'); WriteLn;
+ ErrorHalt;
+END;
+END DVIcheck;
+
+(******************************************************************************)
+
+PROCEDURE AppendPSDVIoptions;
+
+(* Check for the PSDVI qualifiers allowed by PSPRINT.CLD. *)
+
+BEGIN
+Append(command,' "');
+IF GetValue('PAGES',value) THEN
+ DVIcheck('/PAGES'); Append(command,'/PAG='); Append(command,value);
+END;
+IF GetValue('INCREMENT',value) THEN
+ DVIcheck('/INC'); Append(command,'/INC='); Append(command,value);
+END;
+IF GetValue('MAGNIFICATION',value) THEN
+ DVIcheck('/MAG'); Append(command,'/MAG='); Append(command,value);
+END;
+IF GetValue('UNITS',value) THEN
+ DVIcheck('/UNITS'); Append(command,'/UN='); Append(command,value);
+END;
+IF GetValue('HOFFSET',value) THEN
+ DVIcheck('/HOFF'); Append(command,'/HOFF='); Append(command,value);
+END;
+IF GetValue('VOFFSET',value) THEN
+ DVIcheck('/VOFF'); Append(command,'/VOFF='); Append(command,value);
+END;
+IF GetValue('XSIZE',value) THEN
+ DVIcheck('/XSIZE'); Append(command,'/XSIZ='); Append(command,value);
+END;
+IF GetValue('YSIZE',value) THEN
+ DVIcheck('/YSIZE'); Append(command,'/YSIZ='); Append(command,value);
+END;
+IF GetValue('TFM_DIRECTORY',value) THEN
+ DVIcheck('/TFM'); Append(command,'/TFM='); Append(command,value);
+END;
+IF GetValue('PSPREFIX',value) THEN
+ DVIcheck('/PSPRE'); Append(command,'/PSPR='); Append(command,value);
+END;
+IF GetValue('FONT_DIRECTORY',value) THEN
+ DVIcheck('/FONT'); Append(command,'/FONT='); Append(command,value);
+END;
+IF GetValue('DUMMY_FONT',value) THEN
+ DVIcheck('/DUMMY'); Append(command,'/DUMM='); Append(command,value);
+END;
+IF GetValue('RESOLUTION',value) THEN
+ DVIcheck('/RES'); Append(command,'/RES='); Append(command,value);
+END;
+IF ODD(CLI$PRESENT('STATS')) THEN
+ DVIcheck('/STATS'); Append(command,'/ST');
+END;
+IF ODD(CLI$PRESENT('CONSERVE_VM')) THEN
+ DVIcheck('/CONS'); Append(command,'/CONS');
+ELSIF ODD(CLI$PRESENT('NOCONSERVE_VM')) THEN
+ DVIcheck('/NOCONS'); Append(command,'/NOCONS');
+END;
+IF ODD(CLI$PRESENT('REVERSE')) THEN
+ DVIcheck('/REV'); Append(command,'/REV');
+ELSIF ODD(CLI$PRESENT('NOREVERSE')) THEN
+ DVIcheck('/NOREV'); Append(command,'/NOREV');
+END;
+Append(command,'"');
+END AppendPSDVIoptions;
+
+(******************************************************************************)
+
+PROCEDURE AppendPRINToptions;
+
+BEGIN
+Append(command,' "');
+IF ODD(CLI$PRESENT('NOTIFY')) THEN (* /NOTIFY given *)
+ Append(command,'/NOTI');
+ELSE
+ Append(command,'/NONOTI');
+END;
+IF GetValue('FORM',value) THEN (* /FORM=formtype given *)
+ Append(command,'/FORM=');
+ Append(command,value);
+END;
+IF GetValue('QUEUE',value) THEN (* /QUEUE=qname given *)
+ Append(command,'/QUE=');
+ Append(command,value);
+END;
+Append(command,'"');
+END AppendPRINToptions;
+
+(******************************************************************************)
+
+PROCEDURE AppendNote;
+
+VAR i : INTEGER;
+
+BEGIN
+Append(command,' "');
+IF GetValue('NOTE',value) THEN
+ IF printer = PS40 THEN
+ (* PrintServer 40 handles any (,),\ characters in /NOTE value *)
+ Append(command,value);
+ ELSE
+ (* For LaserWriter and Linotronic we must
+ make sure that any (,),\ characters are prefixed with \
+ otherwise we'll probably get a PostScript error when storing
+ the /NOTE value into a string. This kludge should not be necessary
+ for the other string values that appear on the banner page.
+ *)
+ FOR i := 0 TO LEN(value)-1 DO
+ CASE value[i] OF
+ '(' : Append(command,'\(');
+ | ')' : Append(command,'\)');
+ | '\' : Append(command,'\\');
+ ELSE Append(command,value[i]);
+ END;
+ END;
+ END;
+END;
+Append(command,'"');
+END AppendNote;
+
+(******************************************************************************)
+
+PROCEDURE AppendCopies;
+
+BEGIN
+IF GetValue('COPIES',value) THEN
+ Append(command,' ');
+ Append(command,value);
+ELSE
+ Append(command,' 1');
+END;
+END AppendCopies;
+
+(******************************************************************************)
+
+PROCEDURE AppendOutput;
+
+BEGIN
+IF GetValue('OUTPUT',value) THEN
+ Append(command,' ');
+ Append(command,value);
+ELSE
+ Append(command,' ""');
+END;
+END AppendOutput;
+
+(******************************************************************************)
+
+PROCEDURE AppendPrep;
+
+BEGIN
+IF GetValue('PREP',value) THEN
+ Append(command,value);
+END;
+END AppendPrep;
+
+(******************************************************************************)
+
+PROCEDURE AppendLWFlags;
+
+BEGIN
+Append(command,' "');
+IF ODD(CLI$PRESENT('DELETE')) THEN
+ Append(command,'Y'); (* /DELETE *)
+ELSE
+ Append(command,'N');
+END;
+IF ODD(CLI$PRESENT('LANDSCAPE')) THEN
+ Append(command,'Y'); (* /LANDSCAPE *)
+ELSE
+ Append(command,'N');
+END;
+IF ODD(CLI$PRESENT('BANNER')) THEN
+ Append(command,'Y'); (* /BANNER *)
+ELSE
+ Append(command,'N');
+END;
+IF ODD(CLI$PRESENT('MANUALFEED')) THEN
+ Append(command,'Y'); (* /MANUALFEED *)
+ELSE
+ Append(command,'N');
+END;
+AppendPrep; (* /PREP *)
+Append(command,'"');
+END AppendLWFlags;
+
+(******************************************************************************)
+
+PROCEDURE AppendLINOFlags;
+
+BEGIN
+Append(command,' "');
+IF ODD(CLI$PRESENT('DELETE')) THEN
+ Append(command,'Y'); (* /DELETE *)
+ELSE
+ Append(command,'N');
+END;
+IF ODD(CLI$PRESENT('LANDSCAPE')) THEN
+ Append(command,'Y'); (* /LANDSCAPE *)
+ELSE
+ Append(command,'N');
+END;
+IF ODD(CLI$PRESENT('CUTMARKS')) THEN
+ Append(command,'Y'); (* /CUTMARKS *)
+ELSE
+ Append(command,'N');
+END;
+IF ODD(CLI$PRESENT('LOWRES')) THEN
+ Append(command,'Y'); (* /LOWRES *)
+ELSE
+ Append(command,'N');
+END;
+IF ODD(CLI$PRESENT('BANNER')) THEN
+ Append(command,'Y'); (* /BANNER *)
+ELSE
+ Append(command,'N');
+END;
+IF GetValue('SIZE',value) THEN (* /SIZE value *)
+ Append(command,value);
+ELSE
+ Append(command,'???'); (* PSPRINT.CLD should prevent this *)
+END;
+AppendPrep; (* /PREP *)
+Append(command,'"');
+END AppendLINOFlags;
+
+(******************************************************************************)
+
+PROCEDURE AppendPS40Flags;
+
+BEGIN
+Append(command,' "');
+IF ODD(CLI$PRESENT('DELETE')) THEN
+ Append(command,'Y'); (* /DELETE *)
+ELSE
+ Append(command,'N');
+END;
+IF ODD(CLI$PRESENT('LANDSCAPE')) THEN
+ Append(command,'Y'); (* /LANDSCAPE *)
+ELSE
+ Append(command,'N');
+END;
+AppendPrep; (* /PREP *)
+Append(command,'"');
+END AppendPS40Flags;
+
+(******************************************************************************)
+
+BEGIN
+IF GetValue('DEVICE',device) THEN
+ IF Equal(device,'LW') THEN
+ printer := LW;
+ command := '@TEX_PS:LW_PRINT ';
+ ELSIF Equal(device,'LINO') THEN
+ printer := LINO;
+ command := '@TEX_PS:LINO_PRINT ';
+ ELSIF Equal(device,'PS40') THEN
+ printer := PS40;
+ command := '@TEX_PS:PS40_PRINT ';
+ ELSE
+ (* PSPRINT.CLD should prevent this ever happening, but play safe *)
+ WriteString('Unexpected /DEVICE value: ');
+ WriteString(device); WriteLn;
+ ErrorHalt;
+ END;
+ELSE
+ (* PSPRINT.CLD should prevent this ever happening, but play safe *)
+ WriteString('/DEVICE value not present!'); WriteLn;
+ ErrorHalt;
+END;
+AppendFilespec; (* P1 *)
+AppendFormat; (* P2 *)
+AppendPSDVIoptions; (* P3 *)
+AppendPRINToptions; (* P4 *)
+AppendNote; (* P5 *)
+AppendCopies; (* P6 *)
+AppendOutput; (* P7 *)
+CASE printer OF (* P8 is device-specific *)
+ LW : AppendLWFlags;
+| LINO : AppendLINOFlags;
+| PS40 : AppendPS40Flags;
+END;
+(* DEBUG
+WriteString(command); WriteLn;
+GUBED *)
+status := LIB$DO_COMMAND(command);
+(* we should never get here *)
+WriteString('BUG! Error in DO_COMMAND!'); WriteLn; ErrorHalt;
+END PSPRINT.
diff --git a/dviware/psprint/vms/pstext.tex b/dviware/psprint/vms/pstext.tex
new file mode 100644
index 0000000000..4c0f6bf272
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/pswriter.def b/dviware/psprint/vms/pswriter.def
new file mode 100644
index 0000000000..714564fcac
--- /dev/null
+++ b/dviware/psprint/vms/pswriter.def
@@ -0,0 +1,167 @@
+DEFINITION MODULE PSWriter;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: August, 1986
+
+ Description:
+ These 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 (possibly by /HEADER) to the output:
+
+ OpenOutput
+ if /HEADER given then OutputHeader end
+ for each page selected do
+ BeginPage
+ if not conserving VM then
+ for each new bitmap font do NewBitmapFont end
+ for each bitmap font used on this page do
+ BeginBitmapFont
+ for each new character do LoadBitmap end
+ end
+ end
+ OutputPage
+ for each \special on this page do OutputSpecial end
+ for each font used on this page do
+ if (conserving VM) and (not PostScript font) then SaveVM end
+ if PostScript font then BeginPostScriptFont else BeginBitmapFont end
+ if (conserving VM) and (not PostScript font) then
+ for each character used do LoadBitmap end
+ end
+ if PostScript font then
+ for each character used do SetPostScriptChar end
+ else
+ for each character used do SetBitmapChar end
+ end
+ EndFont
+ if (conserving VM) and (not PostScript font) then RestoreVM end
+ end
+ for each rule on this page do SetRule end
+ EndPage
+ end
+ CloseOutput
+
+ Revised:
+ December, 1986
+ - LoadPSChar has been replaced by LoadBitmap from FontReader.
+ Various Put routines are now exported so that LoadBitmap can use them
+ to send PostScript code to the output file.
+
+ November, 1987 (while at The Open University)
+ - Renamed most routines to make a clear distinction between routines
+ applicable to bitmap fonts or to resident PostScript fonts.
+ - Added BeginPostScriptFont to generate appropriate code for switching
+ to a resident PostScript font. The main module should call this routine
+ after OutputPage for a font whose psfont flag is TRUE.
+ - Added SetPostScriptChar to position and show a character from a resident
+ PostScript font. We cannot use SetBitmapChar because the advance widths
+ for PostScript fonts are not an integer number of pixels
+ (and we'd get accumulated rounding errors).
+ - Added SaveVM and RestoreVM routines. The main module should call these
+ routines around bitmap fonts when conserving virtual memory.
+
+ June--August, 1988 (while at Aston University)
+ - EndBitmapFont now called EndFont as it is used for both font types.
+*)
+
+PROCEDURE OpenOutput (name : ARRAY OF CHAR) : BOOLEAN;
+(* Return TRUE if given file can be opened for output. *)
+
+PROCEDURE OutputHeader (name : ARRAY OF CHAR) : BOOLEAN;
+(* Return TRUE if given file can be copied to output.
+ Return FALSE if file could not be opened.
+*)
+
+PROCEDURE BeginPage (DVIpage : CARDINAL);
+(* Output some PostScript to indicate the start of a new page. *)
+
+PROCEDURE NewBitmapFont (VAR fontid : ARRAY OF CHAR);
+(* Output some PostScript to define a new bitmap font.
+ The string parameter is declared to be a variable for efficiency reasons;
+ PSWriter will never change its value.
+*)
+
+(* Here are the Put routines needed by LoadBitmap in FontReader: *)
+PROCEDURE Put (ch : CHAR);
+PROCEDURE PutString (s : ARRAY OF CHAR);
+PROCEDURE PutInt (i : INTEGER);
+PROCEDURE PutCard (c : CARDINAL);
+
+PROCEDURE OutputPage (DVIpage : CARDINAL);
+(* Output some PostScript to prepare showing specials, chars and rules on
+ the current page.
+*)
+
+TYPE specialstring = ARRAY [0..255] OF CHAR;
+
+PROCEDURE OutputSpecial (VAR name : specialstring;
+ hpos, vpos : INTEGER) : BOOLEAN;
+(* Return TRUE if given file can be copied to output.
+ Return 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.
+*)
+
+PROCEDURE SaveVM (VAR fontid : ARRAY OF CHAR);
+(* Output some PostScript to remember the current state of VM just before
+ downloading the given bitmap font.
+ The main module should only call this routine if /CONSERVE_VM is given.
+ The string parameter is declared to be a variable for efficiency reasons;
+ PSWriter will never change its value.
+*)
+
+PROCEDURE BeginBitmapFont (VAR fontid : ARRAY OF CHAR);
+(* Output some PostScript to switch to the given bitmap font.
+ The string parameter is declared to be a variable for efficiency reasons;
+ PSWriter will never change its value.
+*)
+
+PROCEDURE BeginPostScriptFont (VAR fontname : ARRAY OF CHAR;
+ scaledsize, mag : INTEGER);
+(* Output some PostScript to switch to the given resident PostScript font.
+ The string parameter is declared to be a variable for efficiency reasons;
+ PSWriter will never change its value.
+ The scaledsize and mag parameters are needed to determine the requested
+ font scale.
+*)
+
+PROCEDURE SetBitmapChar (ch : CHAR; hpos, vpos, pwidth : INTEGER);
+(* Output some PostScript to set the given character at the given position.
+ pwidth (the advance width in pixels) is used to output PostScript strings,
+ minimizing the need to position single characters.
+*)
+
+PROCEDURE SetPostScriptChar (ch : CHAR; hpos, vpos, pwidth : INTEGER);
+(* Output some PostScript to set the given character at the given position.
+ pwidth (the advance width in pixels) is used to output PostScript strings,
+ but we have to generate slightly different PostScript code to avoid
+ accumulated rounding errors since the true advance width is not
+ necessarily an integer number of pixels.
+*)
+
+PROCEDURE EndFont;
+(* Output some PostScript to end the current font. This routine must appear
+ after the last SetBitmap/PostScriptChar call for this font.
+*)
+
+PROCEDURE RestoreVM;
+(* Output some PostScript to restore VM to the state saved by the most recent
+ SaveVM call.
+ The main module should only call this routine if /CONSERVE_VM is given.
+*)
+
+PROCEDURE SetRule (wd, ht : CARDINAL; hpos, vpos : INTEGER);
+(* Output some PostScript to set the given rule at the given position. *)
+
+PROCEDURE EndPage (DVIpage : CARDINAL);
+(* Output some PostScript to end the current page. *)
+
+PROCEDURE CloseOutput;
+(* Output any final PostScript and close the file. *)
+
+END PSWriter.
diff --git a/dviware/psprint/vms/pswriter.mod b/dviware/psprint/vms/pswriter.mod
new file mode 100644
index 0000000000..a18ccc2df1
--- /dev/null
+++ b/dviware/psprint/vms/pswriter.mod
@@ -0,0 +1,405 @@
+IMPLEMENTATION MODULE PSWriter;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: August, 1986
+
+ Description:
+ PostScript output routines used by PSDVI.
+ The output file consists of calls to various PostScript procedures
+ defined in a header file that must be prepended 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 must contain the necessary matrix
+ transformations to convert TeX coordinates back into device coordinates.
+
+ Revised:
+ November, 1987 (while at The Open University)
+ - Output file is now normal text file rather than fixed-length record file.
+ - Added SaveVM and RestoreVM routines to support the conserveVM flag
+ used by the main module.
+ - Added SetPostScriptChar to overcome rounding problems if we try to
+ use SetBitmapChar for a PostScript font.
+
+ June--August, 1988 (while at Aston University)
+ - Modified SetPostScriptChar to output strings like SetBitmapChar.
+ - EndBitmapFont now called EndFont as it is used for both font types.
+
+ September--October, 1989 (while at Aston University, 2nd time)
+ - Modified SendBitmapChar and SetPostScriptChar so they can't create
+ a string too long for WriteChar's output buffer.
+ Adrian Clark can now use his half-tone font with PSPRINT.
+*)
+
+FROM FileSystem IMPORT
+ File, Create, Open, Done,
+ ReadChar, WriteChar,
+ Eof, Close;
+
+CONST
+ NULL = 0C;
+ CR = 15C;
+ DEL = 177C;
+
+VAR
+ PSfile : File; (* output file *)
+ curh, curv : INTEGER; (* for SetBitmapChar and SetPostScriptChar *)
+ stringlen : CARDINAL; (* ditto; current string length *)
+ pendingch : CHAR; (* ditto; terminates current string *)
+
+(******************************************************************************)
+
+PROCEDURE OpenOutput (name : ARRAY OF CHAR) : BOOLEAN;
+
+BEGIN
+(* SYSDEP: create a normal VAX/VMS text file *)
+Create(PSfile,name,TRUE,TRUE);
+RETURN Done();
+END OpenOutput;
+
+(******************************************************************************)
+
+PROCEDURE OutputHeader (name : ARRAY OF CHAR) : BOOLEAN;
+
+VAR f : File; ch : CHAR;
+
+BEGIN
+Open(f,name,FALSE); (* SYSDEP: read only *)
+IF Done() THEN
+ LOOP
+ ReadChar(f,ch); (* next char or Eof *)
+ IF Eof(f) THEN
+ EXIT;
+ ELSE
+ Put(ch); (* copy verbatim, including any ctrl chars *)
+ END;
+ END;
+ Close(f);
+ RETURN TRUE;
+ELSE
+ RETURN FALSE; (* couldn't open given file *)
+END;
+END OutputHeader;
+
+(******************************************************************************)
+
+PROCEDURE BeginPage (DVIpage : CARDINAL);
+
+BEGIN
+PutCard(DVIpage); PutString(' @bop0'); Put(CR);
+END BeginPage;
+
+(******************************************************************************)
+
+PROCEDURE NewBitmapFont (VAR fontid : ARRAY OF CHAR);
+
+BEGIN
+Put('/'); PutString(fontid); PutString(' @newfont'); Put(CR);
+END NewBitmapFont;
+
+(******************************************************************************)
+
+PROCEDURE OutputPage (DVIpage : CARDINAL);
+
+BEGIN
+PutCard(DVIpage); PutString(' @bop1'); Put(CR);
+END OutputPage;
+
+(******************************************************************************)
+
+PROCEDURE OutputSpecial (VAR name : specialstring;
+ hpos, vpos : INTEGER) : BOOLEAN;
+
+VAR f : File; fspec : specialstring; ch : CHAR; i : CARDINAL;
+
+BEGIN
+(* check name for optional space (indicating additional PostScript text) *)
+i := 0;
+fspec := ''; (* SYSDEP: fill with NULLs *)
+WHILE (i <= HIGH(name)) AND (name[i] <> ' ') DO
+ fspec[i] := name[i]; (* extract file spec from name *)
+ INC(i);
+END;
+Open(f,fspec,FALSE); (* SYSDEP: read only *)
+IF Done() THEN
+ PutInt(hpos); Put(' '); PutInt(vpos); PutString(' p'); Put(CR);
+ PutString('@bsp'); Put(CR);
+ IF i <= HIGH(name) THEN
+ (* name[i] is first ' '; skip this and copy rest of name to output *)
+ INC(i);
+ WHILE (i <= HIGH(name)) AND (name[i] <> NULL) DO
+ Put(name[i]);
+ INC(i);
+ END;
+ Put(CR); (* text becomes first line of file *)
+ END;
+ LOOP
+ ReadChar(f,ch); (* next char or Eof *)
+ IF Eof(f) THEN
+ EXIT;
+ ELSE
+ Put(ch); (* copy verbatim, including any ctrl chars *)
+ END;
+ END;
+ Close(f);
+ PutString('@esp'); Put(CR);
+ RETURN TRUE;
+ELSE
+ RETURN FALSE; (* couldn't open given file *)
+END;
+END OutputSpecial;
+
+(******************************************************************************)
+
+PROCEDURE SaveVM (VAR fontid : ARRAY OF CHAR);
+
+BEGIN
+Put('/'); PutString(fontid); PutString(' @saveVM'); Put(CR);
+END SaveVM;
+
+(******************************************************************************)
+
+PROCEDURE BeginPostScriptFont (VAR fontname : ARRAY OF CHAR;
+ 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 *)
+PutInt(scaledsize); PutString(' sp ');
+PutInt(mag); PutString(' 1000 div mul ');
+PutString(fontname); PutString(' PSfont'); Put(CR);
+(* initialize some globals for first SetPostScriptChar in this font *)
+curh := MAX(INTEGER);
+curv := MAX(INTEGER);
+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 (* don't update v position *)
+ IF curh <> hpos THEN (* update h position *)
+ stringlen := 0;
+ Put(')'); Put(pendingch); Put(CR);
+ PutInt(hpos); Put('(');
+ pendingch := 'H';
+ END;
+ELSE (* update h and v position *)
+ IF stringlen > 0 THEN
+ stringlen := 0;
+ Put(')'); Put(pendingch); Put(CR);
+ END;
+ PutInt(hpos); Put(' '); PutInt(vpos); Put('(');
+ pendingch := 'S';
+END;
+IF (ch >= ' ') AND (ch < DEL) THEN
+ IF (ch = '(') OR (ch = ')') OR (ch = '\') THEN (* prefix (,),\ with \ *)
+ Put('\'); Put(ch);
+ ELSE
+ Put(ch);
+ END;
+ELSE
+ Put('\');
+ (* and put out 3 octal digits representing ch *)
+ Put( CHR(ORD('0') + (ORD(ch) DIV 64)) );
+ Put( CHR(ORD('0') + ((ORD(ch) DIV 8) MOD 8)) );
+ Put( CHR(ORD('0') + (ORD(ch) MOD 8)) );
+END;
+(* update current page position and string length for next call *)
+curh := hpos + pwidth;
+curv := vpos;
+INC(stringlen);
+IF (stringlen MOD 72) = 0 THEN Put('\'); Put(CR) END;
+END SetPostScriptChar;
+
+(******************************************************************************)
+
+PROCEDURE BeginBitmapFont (VAR fontid : ARRAY OF CHAR);
+
+BEGIN
+PutString(fontid); PutString(' sf'); Put(CR);
+(* Initialize some globals for first SetBitmapChar in this font.
+ This is not relevant when BeginBitmapFont is used before OutputPage.
+*)
+curh := MAX(INTEGER);
+curv := MAX(INTEGER);
+stringlen := 0;
+pendingch := '?';
+END BeginBitmapFont;
+
+(******************************************************************************)
+
+PROCEDURE SetBitmapChar (ch : CHAR; hpos, vpos, pwidth : INTEGER);
+
+BEGIN
+IF curv = vpos THEN (* don't update v position *)
+ IF curh <> hpos THEN (* update h position (kern or space) *)
+ stringlen := 0;
+ Put(')'); Put(pendingch); Put(CR);
+ PutInt(hpos-curh); Put('(');
+ pendingch := 'h';
+ END;
+ELSE (* update h and v position *)
+ IF stringlen > 0 THEN
+ stringlen := 0;
+ Put(')'); Put(pendingch); Put(CR);
+ END;
+ PutInt(hpos); Put(' '); PutInt(vpos); Put('(');
+ pendingch := 's';
+END;
+IF (ch >= ' ') AND (ch < DEL) THEN
+ IF (ch = '(') OR (ch = ')') OR (ch = '\') THEN (* prefix (,),\ with \ *)
+ Put('\'); Put(ch);
+ ELSE
+ Put(ch);
+ END;
+ELSE
+ Put('\');
+ (* and put out 3 octal digits representing ch *)
+ Put( CHR(ORD('0') + (ORD(ch) DIV 64)) );
+ Put( CHR(ORD('0') + ((ORD(ch) DIV 8) MOD 8)) );
+ Put( CHR(ORD('0') + (ORD(ch) MOD 8)) );
+END;
+(* update current page position and string length for next call *)
+curh := hpos + pwidth;
+curv := vpos;
+INC(stringlen);
+IF (stringlen MOD 72) = 0 THEN Put('\'); Put(CR) END;
+END SetBitmapChar;
+
+(******************************************************************************)
+
+PROCEDURE EndFont;
+
+(* Terminate the last "h v(..." or "dh(..." for the current font. *)
+
+BEGIN
+IF stringlen > 0 THEN
+ Put(')'); Put(pendingch); Put(CR);
+END;
+END EndFont;
+
+(******************************************************************************)
+
+PROCEDURE RestoreVM;
+
+BEGIN
+PutString('@restoreVM'); Put(CR);
+END RestoreVM;
+
+(******************************************************************************)
+
+PROCEDURE SetRule (wd, ht : CARDINAL; hpos, vpos : INTEGER);
+
+BEGIN
+PutCard(wd); Put(' '); PutCard(ht); Put(' ');
+PutInt(hpos); Put(' '); PutInt(vpos);
+PutString(' r'); Put(CR);
+END SetRule;
+
+(******************************************************************************)
+
+PROCEDURE EndPage (DVIpage : CARDINAL);
+
+BEGIN
+PutCard(DVIpage); PutString(' @eop'); Put(CR);
+END EndPage;
+
+(******************************************************************************)
+
+PROCEDURE CloseOutput;
+
+BEGIN
+PutString('@end'); Put(CR);
+Close(PSfile);
+END CloseOutput;
+
+(******************************************************************************)
+
+PROCEDURE Put (ch : CHAR);
+
+BEGIN
+WriteChar(PSfile,ch);
+END Put;
+
+(******************************************************************************)
+
+PROCEDURE PutString (s : ARRAY OF CHAR);
+
+VAR i : INTEGER;
+
+BEGIN
+(* SYSDEP: LEN assumes end of string is first NULL, or string is full *)
+FOR i := 0 TO LEN(s) - 1 DO
+ WriteChar(PSfile,s[i]);
+END;
+END PutString;
+
+(******************************************************************************)
+
+PROCEDURE PutInt (i : INTEGER);
+
+(* We call PutCard after writing any '-' sign. *)
+
+BEGIN
+IF i < 0 THEN
+ WriteChar(PSfile,'-');
+ i := ABS(i);
+END;
+PutCard(CARDINAL(i));
+END PutInt;
+
+(******************************************************************************)
+
+PROCEDURE PutCard (c : CARDINAL);
+
+(* Since the majority of given values will be < 10,000 we avoid
+ recursion until c >= 10,000.
+*)
+
+BEGIN
+IF c < 10 THEN
+ WriteChar(PSfile, CHR(ORD('0') + c) );
+ELSIF c < 100 THEN
+ WriteChar(PSfile, CHR(ORD('0') + (c DIV 10)) ); c := c MOD 10;
+ WriteChar(PSfile, CHR(ORD('0') + c) );
+ELSIF c < 1000 THEN
+ WriteChar(PSfile, CHR(ORD('0') + (c DIV 100)) ); c := c MOD 100;
+ WriteChar(PSfile, CHR(ORD('0') + (c DIV 10)) ); c := c MOD 10;
+ WriteChar(PSfile, CHR(ORD('0') + c) );
+ELSIF c < 10000 THEN
+ WriteChar(PSfile, CHR(ORD('0') + (c DIV 1000)) ); c := c MOD 1000;
+ WriteChar(PSfile, CHR(ORD('0') + (c DIV 100)) ); c := c MOD 100;
+ WriteChar(PSfile, CHR(ORD('0') + (c DIV 10)) ); c := c MOD 10;
+ WriteChar(PSfile, CHR(ORD('0') + c) );
+ELSE
+ PutCard(c DIV 10000); (* recursive if c >= 10000 *)
+ c := c MOD 10000;
+ WriteChar(PSfile, CHR(ORD('0') + (c DIV 1000)) ); c := c MOD 1000;
+ WriteChar(PSfile, CHR(ORD('0') + (c DIV 100)) ); c := c MOD 100;
+ WriteChar(PSfile, CHR(ORD('0') + (c DIV 10)) ); c := c MOD 10;
+ WriteChar(PSfile, CHR(ORD('0') + c) );
+END;
+END PutCard;
+
+(******************************************************************************)
+
+BEGIN
+END PSWriter.
diff --git a/dviware/psprint/vms/random.ps b/dviware/psprint/vms/random.ps
new file mode 100644
index 0000000000..3e69f4c16d
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/sysguide.tex b/dviware/psprint/vms/sysguide.tex
new file mode 100644
index 0000000000..f0ae07de6e
--- /dev/null
+++ b/dviware/psprint/vms/sysguide.tex
@@ -0,0 +1,563 @@
+% LaTeX source for PSPRINT System Guide.
+% Cross references are indicated by the string "XREF".
+
+\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
+\itemsep=0pt
+
+\def\DVItoVDU{DVIto\kern-.15em VDU}
+\def\Modula{\hbox{Modula-2}}
+\def\aligneddots{\leaders\hbox to .75em{\hss.\hss}\hfill}
+
+\begin{document}
+
+\vspace*{\fill}
+
+\begin{center}
+\Huge\bf PSPRINT System Guide\\ [3mm]
+\normalsize\bf Version 3.1 for VAX/VMS\\
+\bf Andrew Trevorrow, October 1989
+\end{center}
+
+\bigskip
+\bigskip
+
+This document explains how to install or modify PSPRINT, a PostScript
+driver that runs under VAX/VMS\@.
+Currently supported printers include the Apple LaserWriter,
+the Linotronic~300 and DEC's PrintServer~40.
+The PSPRINT command can be used to print a DVI file, a PostScript program,
+or an ordinary text file.
+The {\sl PSPRINT User Guide\/} has details on how to use the program.
+
+\bigskip
+\begin{center}
+\bf Contents
+\end{center}
+
+ % XREF: make sure page #s are up-to-date
+Overview \aligneddots\ 1\\
+Installing PSPRINT \aligneddots\ 2\\
+Testing PSPRINT \aligneddots\ 3\\
+Adding a New Device \aligneddots\ 4\\
+Existing Problems \aligneddots\ 5\\
+Changes to Version 1.1 \aligneddots\ 6\\
+Changes to Version 2.0 \aligneddots\ 7\\
+Changes to Version 3.0 \aligneddots\ 8
+
+\vspace*{\fill}
+
+\thispagestyle{empty}
+
+\newpage
+\setcounter{page}{1}
+
+\subsection*{Overview}
+
+PSPRINT is a mixture of \Modula, DCL and PostScript. All the necessary
+files, including documentation and source code, are kept in a directory
+referred to by the logical name \verb|tex_ps|. The file \verb|aaaread.me|
+gives a brief description of each file.
+
+The following sequence of events occurs when a user runs PSPRINT:
+\begin{enumerate}
+\item
+\verb|psprint.exe| is invoked. This \Modula\ program extracts the
+file parameter and qualifier values from the command line according
+to \verb|psprint.cld|.
+If everything seems okay then a device-specific command file is activated:
+ \begin{itemize}
+ \item [ ]
+ \verb|tex_ps:lw_print.com | --- if \verb|/device=LW|\\
+ \verb|tex_ps:lino_print.com| --- if \verb|/device=LINO|\\
+ \verb|tex_ps:ps40_print.com| --- if \verb|/device=PS40|
+ \end{itemize}
+The CLD file specifies the allowed \verb|/device| values and the default
+value (currently \verb|LW| for LaserWriter).
+
+\item
+These command files handle most of the messy system-dependent details.
+Each can process one of five file types:
+a DVI file, a PostScript program, or one of three text file types.
+(A DVI file is translated into a temporary PostScript file by
+PSDVI, another \Modula\ program.
+Each command file uses a different set of qualifiers to specify the
+printer's resolution, the location and format of bitmapped fonts,
+the order in which to translate pages, etc.)
+
+\item
+Each type of file is bracketed by device-specific header and trailer
+information before being sent to an appropriate print queue.
+\end{enumerate}
+Note that much of the behaviour of PSPRINT can be changed by simply
+editing command files and/or PostScript text files.
+Such flexibility is of particular benefit to sites without \Modula.
+You'll probably need the {\sl PostScript Language Reference Manual\/} by
+Adobe if you run into problems or wish to make substantial changes.
+
+\newpage
+
+\subsection*{Installing PSPRINT}
+
+Let's assume you've dumped all the necessary files into a suitable directory.
+Attach yourself to this directory and carry out the following steps:
+\begin{enumerate}
+\item
+Check \verb|psprint.cld| and \verb|psdvi.cld| for any site-dependent changes.
+Also check the \hbox{PSDVI} qualifiers in each of the \verb|*_print.com| files.
+
+\item
+Examine the file \verb|install.com| and make the necessary changes to suit
+your site. Running this command file will perform the following steps:
+\begin{itemize}
+ \item
+ Set terminal characteristics for a LaserWriter or Linotronic.
+ These printers are assumed to be connected to your VAX via a serial line.
+ The LaserWriter should have its mode switch set to 9600 baud.
+ The PrintServer~40 should be set up as described in the DEC documentation.
+ \item
+ Define the PostScript form type (used by LaserWriter and Linotronic).
+ \item
+ Initialize the print queue(s).
+ \item
+ Define \verb|tex_ps| to be a system logical name pointing to
+ the public-access directory.
+ \item
+ Install the PSPRINT and PSDVI commands.
+\end{itemize}
+Some of the above steps must be copied into appropriate
+system files if you want PSPRINT to work the next time you reboot.
+
+\item
+Start the appropriate print queue(s).
+Note that print jobs will disappear if the LaserWriter
+is switched off or its mode switch is incorrectly set.
+Similar warnings apply to the Linotronic~300.
+Both these devices use the standard VAX/VMS print symbiont.
+The symbiont for the PrintServer~40 is much more intelligent;
+it is able to interpret PostScript messages and can even send them
+back to the user's terminal (if \verb|/notify| is specified).
+
+\item
+Each PostScript printer has a system password that allows you to change
+persistent parameters.
+In an open-access environment it's probably a good idea to
+change the initial password.
+Make the appropriate changes to \verb|pass.ps| and then send it to the printer
+by typing `\verb|psprint pass.ps|' (with an appropriate \verb|/device| value).
+Then delete all reference to the new password!
+Note that the PrintServer~40 uses a string for the password;
+the other devices use an integer.
+
+\item
+\verb|psprint.hlp| is provided as a suitable source for on-line help.
+Feel free to make any changes to suit your site.
+Changes may also be needed in \verb|userguide.tex|; the likely locations
+are flagged by a ``\verb|SYSDEP|'' comment.
+
+\item
+Check the installation by logging out, then logging in as a normal user
+and trying PSPRINT on various DVI/PostScript/text files.
+
+\end{enumerate}
+
+\newpage
+
+\subsection*{Testing PSPRINT}
+
+There are a number of useful files in \verb|tex_ps| for testing PSPRINT:
+
+\begin{itemize}
+
+\item
+Type `\verb|psprint test|'.
+The top left corner of the first rule should appear
+1~inch in from the top and left paper edges.
+If not, then you'll need to modify \verb|tex.ps|.
+You should only need to carry out such changes for a LaserWriter.
+The last two integers of the \verb|setmatrix| array are pixel values that
+adjust the horizontal and vertical position of the origin.
+Also type `\verb|psprint test/land|' to test the positioning
+of landscaped output.
+(Note that the \verb|/hoffset| and \verb|/voffset| qualifiers allow
+users to shift the output as well.)
+
+\item
+Type `\verb|psprint lines.dat|' and `\verb|psprint lines.dat/land|'
+to check the output format of ordinary text files.
+
+\item
+Type `\verb|psprint clip.ps|' to produce some lines indicating
+the default clipping region; nothing can be printed outside this region.
+
+\item
+Type `\verb|psprint psfonts|' to test the use of resident PostScript fonts
+in a \TeX\ document (assuming you have the necessary TFM files).
+The fonts used in this test should be available in all PostScript printers.
+
+\item
+The file \verb|nasty.dvi| is also useful for testing rarely used code
+in PSDVI\@. Try some of these pages:
+ \begin{itemize}
+ \item [ ]
+ \verb|psprint nasty/page=1 | --- empty page\\
+ \verb|psprint nasty/page=3 | --- page with \verb|\special| commands\\
+ \verb|psprint nasty/page=10| --- tests long verbatim \verb|\tt| strings\\
+ \verb|psprint nasty/page=18| --- tests rules in math extension characters
+ \end{itemize}
+
+\end{itemize}
+
+\newpage
+
+\subsection*{Adding a New Device}
+
+Here are the steps required to support a new type of PostScript printer:
+\begin{enumerate}
+
+\item
+Create a new \verb|/device| value by adding a \verb|psprinter| keyword,
+say \verb|XXX|, at the bottom of \verb|psprint.cld|.
+
+\item
+Modify \verb|psprint.mod| to handle the new device value.
+Locate all occurrences of an existing device, say \verb|LW|, and duplicate
+the code. Type `\verb|@build|' to create a new version of PSPRINT\@.
+This assumes you have a Modula-2 compiler; if you don't then you could
+quite easily translate \verb|psprint.mod| into Pascal.
+It is a reasonably small and simple program.
+Note that no changes to PSDVI are needed.
+
+\item
+Create \verb|xxx_print.com| using one of the existing \verb|*_print.com|
+files as a starting point. This new command file will be activated when
+a user types `\verb|psprint/dev=xxx ...|'.
+
+\item
+Create \verb|xxx_header.ps|, \verb|xxx_trailer.ps| and \verb|xxx_fonts.ps|
+as required. Again, base these new files on the nearest equivalents for
+an existing device.
+
+\item
+Make any necessary changes to the job prologues:
+\verb|tex.ps|, \verb|ps.ps|, \verb|text.ps|, \verb|two.ps| and \verb|wide.ps|.
+Search these files for occurrences of \verb|dev|, \verb|res| and \verb|land|
+and add any code needed for the new device.
+Note that \verb|xxx_print.com| must make sure the definitions for these
+PostScript variables come {\em before\/} the prologue file.
+
+\item
+Connect the new printer to the VAX host and create a suitable queue.
+See \verb|install.com| for details.
+
+\item
+Type `\verb|set command psprint|' and
+test the new version of PSPRINT on a variety of files.
+% XREF
+The previous section describes some useful tests.
+
+\item
+Finally, update the user documentation in \verb|userguide.tex|
+and \verb|psprint.hlp|.
+If you plan to pass on your changes to other people
+it would be polite to update the system documentation as well
+(in \verb|sysguide.tex| and \verb|aaaread.me|).
+
+\end{enumerate}
+
+\newpage
+
+\subsection*{Existing Problems}
+
+\begin{itemize}
+
+\item
+PSPRINT is {\em not\/} a print symbiont.
+It cannot, for example, report any LaserWriter problems to an operator.
+Jobs will just disappear if the LaserWriter is turned off or
+its mode switch is on some setting other than 9600.
+The print queue should be started {\em after\/} turning on the LaserWriter
+and stopped {\em before\/} turning it off.
+
+\item
+Some DVI jobs may exceed PostScript's virtual memory, depending on the
+number and size of downloaded characters, and the amount of VM available.
+For reasons unknown, early versions of the LaserWriter can crash
+(and then restart by printing a test page) rather than show a ``VMerror''
+message. No banner page is printed.
+The ``\verb|VMERROR|'' code in \verb|tex.ps|
+attempts to overcome this problem by producing an error message if the
+VM usage reaches some threshold value.
+Enable this code if your LaserWriter suffers from such a problem.
+
+\item
+PSPRINT cannot handle FORTRAN carriage-control files nor RUNOFF output.
+
+\item
+PostScript printers can get occasional one-pixel rounding errors when
+drawing rules.
+The problem can sometimes be visible in a \TeX\ document, usually in large
+math extension characters containing one or more rules.
+The use of device-specific \verb|setmatrix| code in
+\verb|tex.ps| minimizes these errors.
+Some ``fine-tuning'' of the PostScript rule-drawing code may also be necessary.
+For example, in some versions of the LaserWriter I've had to
+add 1 to the vertical position of each rule.
+Page 18 of \verb|nasty.dvi| is a good test sheet; try printing it
+in both portrait and landscape orientation.
+
+\item
+To be able to use PostScript fonts with \TeX\ you must have the necessary
+TFM files. PSDVI requires that their names all begin with the
+\verb|/psprefix| value. The default prefix of ``\verb|ps-|''
+is set in \verb|psdvi.cld|. If you decide to use some other prefix then
+you'll need to edit \verb|*_fonts.ps| and update the user documentation.
+
+\item
+When using a PostScript text font, users need to be aware that
+the standard \TeX\ commands for accents and foreign letters must be redefined
+(and reinstated when switching back to a Computer Modern text font).
+See \verb|psfonts.tex| and \verb|pstext.tex| for one possible solution.
+
+\item
+If you are using any CM fonts with 256 characters then
+you'll have to change a few numbers appearing in the definition of
+\verb|@newfont| in \verb|tex.ps|.
+Change the two occurrences of 128 to 256 and the single 127 to 255.
+A warning: jobs that used to print okay may now exceed VM.
+
+\item
+The \verb|\special| facility provided by PSDVI (i.e., file inclusion with
+optional starting text) is quite primitive compared
+with other DVI-to-PostScript translators.
+The reason is that all \verb|\special| commands on a page are gathered
+together and sent all at once, as are all the fonts and rules.
+A significant advantage of this method is printing speed: by minimizing the
+number of font switches we keep character images in the font cache for as
+long as possible.
+
+\end{itemize}
+
+\newpage
+
+\subsection*{Changes to Version 1.1}
+
+\begin{itemize}
+
+\item
+These changes were made while I was working in the UK at The Open University.
+The current version of PSPRINT (and PSDVI) has leapt to 2.0 to coincide
+with the latest version of \DVItoVDU.
+
+\item
+PSPRINT now supports a variety of PostScript printers.
+The new \verb|/device| qualifier indicates which type of printer to use;
+a default device is specified in \verb|psprint.cld|.
+A separate command file exists for each device: see \verb|*_print.com|.
+Each device also requires slightly different PostScript code
+for each type of input file.
+The introduction of different devices has meant a major file-renaming exercise.
+
+\item
+PSPRINT has a number of new qualifiers --- \verb|/size|, \verb|/lowres| and
+\verb|/cutmarks| --- that only take effect if \verb|/device=LINO|.
+See the {\sl PSPRINT User Guide\/} for details.
+
+\item
+Temporary files are now created in \verb|sys$scratch|.
+This can easily be changed by editing the \verb|*_print.com| files.
+
+\item
+PSDVI can now handle resident PostScript fonts.
+Such fonts must have TFM file names beginning with ``\verb|ps-|''.
+The new \verb|/tfm_directory| qualifier specifies the default location of
+these TFM files. For each \verb|/device| value there exists a
+\verb|*_fonts.ps| file that maps the TFM names into the PostScript font names
+used in that type of printer.
+(Each PostScript printer has a different set of resident fonts.)
+
+\item
+PSDVI has a new \verb|/conserve_vm| qualifier. This can be used to conserve
+PostScript's virtual memory at the expense of downloading character bitmaps
+more often (resulting in a larger output file).
+PSPRINT makes \verb|/conserve_vm| the default for the Linotronic~300
+and \verb|/noconserve_vm| the default for the LaserWriter and PrintServer~40.
+
+\item
+PSDVI now creates an ordinary text file. Although slightly less efficient
+than creating a fixed-length-record file, the advantages of being able
+to easily edit/view/transmit a text file were considered more important.
+
+\end{itemize}
+
+\newpage
+
+\subsection*{Changes to Version 2.0}
+
+\begin{itemize}
+
+\item
+These changes were made while I was working at Aston University.
+The current version of PSPRINT (and PSDVI) is now 3.0.
+
+\item
+Added a number of new qualifiers to PSPRINT:
+\verb|/queue| allows users at sites with more than one printer of the
+same type to override the default queue;
+\verb|/output| copies the PostScript code generated by PSPRINT into a
+given file rather than sending it to a printer;
+\verb|/two| and \verb|/wide| are variants of \verb|/text| that print
+two ``pages'' (60 lines by 80/132 columns) on each sheet of paper;
+\verb|/nobanner| and \verb|/manualfeed| have been implemented for
+the LaserWriter;
+\verb|/reverse| and \verb|/noreverse| override the device-specific
+order in which pages are printed;
+\verb|/resolution|,
+\verb|/font_directory|,
+\verb|/dummy_font|,
+\verb|/tfm_directory|,
+\verb|/psprefix|,
+\verb|/xsize| and \verb|/ysize|
+can be used to override the device-specific default values used by PSDVI
+(although most users should never need to use them).
+
+\item
+Added \verb|/psprefix| qualifier to PSDVI so that sites can specify the
+TFM file name prefix used to indicate PostScript fonts.
+(The default prefix is ``\verb|ps-|''. If you decide to change this then
+you'll need to change the various \verb|*_fonts.ps| files; it's also
+mentioned in the user documentation.)
+
+\item
+Added \verb|/increment| qualifier to PSDVI and PSPRINT to simplify the
+printing of documents on both sides of the paper;
+see the {\sl User Guide\/} for details.
+
+\item
+Added \verb|/hoffset| and \verb|/voffset| qualifiers to PSDVI and PSPRINT
+to allow shifting of each page. This should be useful for sites with many
+printers of the same type, each with different margin settings.
+
+\item
+Reduced both the size and execution time of the PostScript code generated
+by PSDVI when setting resident PostScript fonts.
+
+\item
+Modified the \verb|BuildFontSpec| routine in PSDVI's \verb|FontReader| module
+to remove the limitation requiring all font files to contain a size substring
+of the same length. Sites that had to include a leading zero
+in some font names to overcome this limitation must now
+rename them (e.g., \verb|$rename *.0635pk *.635pk|).
+
+\item
+PSDVI's \verb|Terminal| module is now called \verb|TermOut| and no longer
+calls \verb|SYS$ASSIGN| to assign \verb|TT|.
+This change allows terminal output to be captured in a file ---
+very important when PSPRINT is used in a batch job!
+A side-effect is that page numbers now appear on separate lines.
+
+\item
+There is now a single prologue file for each type of job:
+\verb|tex.ps|, \verb|ps.ps|, \verb|text.ps|, \verb|two.ps| and \verb|wide.ps|.
+They rely on a few PostScript definitions created in \verb|*_print.com| to
+handle different devices, landscaping, etc.
+
+\item
+The \verb|*_print.com| files now put a single temporary file in the print
+queue. This simplifies the code required in \verb|text.ps| and
+overcomes problems caused by print symbionts adding unwanted characters
+(such as formfeeds/linefeeds) between files in a multi-file print job.
+A side-effect of this change is that the format characters in a
+FORTRAN carriage-control file are no longer obeyed
+(they will now be printed!).
+
+\item
+The CTRL-D sent at the start of each \verb|LW|/\verb|LINO| print job has
+been removed to avoid problems (involving the echoing of such characters)
+when a PostScript printer is connected to an X.25 pad.
+
+\end{itemize}
+
+\newpage
+
+\subsection*{Changes to Version 3.0}
+
+\begin{itemize}
+
+\item
+These changes were made while I was working at Aston University
+(for a second time).
+The current version of PSPRINT (and PSDVI) is now 3.1.
+
+\item
+Any \verb|\special|s on a page are now processed in the order they
+appear in the DVI file (instead of in reverse order).
+
+\item
+Fixed bug in \verb|FixToDVI| routine in \verb|FontReader.MOD| that
+prevented fonts being scaled to more than 128pt.
+Thanks to Niel Kempson for spotting this.
+
+\item
+Added code to \verb|PSWriter.MOD| to make sure that very long PostScript
+strings are correctly broken over multiple lines.
+This problem was spotted by Adrian Clark when using halftone fonts.
+
+\item
+Added support for Macintosh-generated PostScript files created
+by pressing Command-F after clicking OK in the Print dialogue.
+A new \verb|/prep=file| qualifier allows users to include a
+modified Laser Prep file at the end of the normal prologue.
+This is necessary when printing a DVI file that uses \verb|\special| to include
+a Command-F PostScript file.
+If only \verb|/prep| is given then a default file (specified in
+\verb|psprint.cld|) is included. The current default is
+\verb|tex_ps:laserprep70.ps| but other versions are provided in \verb|tex_ps|.
+These files contain comments describing how they were created.
+
+\item
+Allow \verb|/nobanner| on a Linotronic job.
+
+\item
+\verb|*_print.com| no longer append CTRL-D if \verb|/output| is used.
+
+\item
+Fixed \verb|*_print.com| so that CTRL-Y won't clobber a user's symbols.
+
+\item
+For a DVI job, if a file called \verb|global.ps| exists in the user's
+current directory then its contents will be included after the prologue.
+The example \verb|global.ps| file in \verb|tex_ps|
+shows how to get the word ``DRAFT'' printed in the background on every page.
+
+\item
+Added \verb|psnames.tex| and illustrated its use in \verb|psfonts.tex|.
+This might be a useful approach for people with access to more
+than one set of PostScript TFM files.
+
+\item
+\verb|/noreverse| is now the default for all devices.
+The default setting for this qualifier (and for \verb|/conserve_vm|)
+is now specified in \verb|*_print.com| rather than in \verb|psprint.mod|.
+
+\end{itemize}
+
+\end{document}
diff --git a/dviware/psprint/vms/termout.def b/dviware/psprint/vms/termout.def
new file mode 100644
index 0000000000..7528d5eb33
--- /dev/null
+++ b/dviware/psprint/vms/termout.def
@@ -0,0 +1,46 @@
+DEFINITION MODULE TermOut;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: August, 1986
+
+ Description:
+ These terminal output routines have been targeted at just one client: PSDVI.
+ NB:
+ - Halt will NOT display any message, unlike Hamburg's HALT.
+ It will also set the VMS $SEVERITY value:
+ Halt(0) exits and sets $SEVERITY to Warning.
+ Halt(1) exits and sets $SEVERITY to Success.
+ Halt(2) exits and sets $SEVERITY to Error.
+ - Output will only be updated after a WriteLn.
+
+ Revised:
+ June--August, 1988 (while at Aston University)
+ - No longer export WriteBuffer/StartLn.
+ - My Terminal module had to be renamed to TermOut to avoid collision with
+ standard library module.
+*)
+
+PROCEDURE Write (ch: CHAR);
+(* Write given character to output. *)
+
+PROCEDURE WriteString (s: ARRAY OF CHAR);
+(* Write given string of characters to output.
+ s is terminated by first NULL (unless full).
+*)
+
+PROCEDURE WriteInt (i : INTEGER);
+(* Write given integer to output. *)
+
+PROCEDURE WriteCard (c : CARDINAL);
+(* Write given cardinal to output. *)
+
+PROCEDURE WriteLn;
+(* Write end-of-line and update output. *)
+
+PROCEDURE Halt (status : CARDINAL);
+(* Terminate program with given status: 0 = warning, 1 = success, 2 = error.
+ No message is generated.
+*)
+
+END TermOut.
diff --git a/dviware/psprint/vms/termout.mod b/dviware/psprint/vms/termout.mod
new file mode 100644
index 0000000000..b352bcf094
--- /dev/null
+++ b/dviware/psprint/vms/termout.mod
@@ -0,0 +1,77 @@
+IMPLEMENTATION MODULE TermOut;
+
+(* Author: Andrew Trevorrow
+ Implementation: University of Hamburg Modula-2 under VAX/VMS version 4
+ Date Started: August, 1986
+
+ Description:
+ Implements terminal output routines used by PSDVI.
+
+ Revised:
+ June--August, 1988 (while at Aston University)
+ - No longer use buffering/SYS$ASSIGN/SYS$QIOW since it did not allow the
+ output to be captured in a file (which is pretty important if users want
+ to run PSPRINT in a batch job and still see any error messages!).
+*)
+
+FROM VMS IMPORT
+ SYS$EXIT;
+
+IMPORT InOut;
+
+(******************************************************************************)
+
+PROCEDURE Write (ch : CHAR);
+
+BEGIN
+InOut.Write(ch);
+END Write;
+
+(******************************************************************************)
+
+PROCEDURE WriteString (s: ARRAY OF CHAR);
+
+BEGIN
+InOut.WriteString(s);
+END WriteString;
+
+(******************************************************************************)
+
+PROCEDURE WriteInt (i : INTEGER);
+
+BEGIN
+InOut.WriteInt(i,1);
+END WriteInt;
+
+(******************************************************************************)
+
+PROCEDURE WriteCard (c : CARDINAL);
+
+BEGIN
+InOut.WriteCard(c,1);
+END WriteCard;
+
+(******************************************************************************)
+
+PROCEDURE WriteLn;
+
+BEGIN
+InOut.WriteLn;
+END WriteLn;
+
+(******************************************************************************)
+
+PROCEDURE Halt (status : CARDINAL);
+
+VAR result : CARDINAL;
+
+BEGIN
+(* SYSDEP: set high order bit so that no CLI message will be seen *)
+status := status + 10000000H;
+result := SYS$EXIT(status);
+END Halt;
+
+(******************************************************************************)
+
+BEGIN
+END TermOut.
diff --git a/dviware/psprint/vms/test.tex b/dviware/psprint/vms/test.tex
new file mode 100644
index 0000000000..2811adcdc9
--- /dev/null
+++ b/dviware/psprint/vms/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/vms/tex.ps b/dviware/psprint/vms/tex.ps
new file mode 100644
index 0000000000..36ac9cc08d
--- /dev/null
+++ b/dviware/psprint/vms/tex.ps
@@ -0,0 +1,236 @@
+% Prologue for a DVI job.
+% It assumes *_print.com 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 235 3100 ] 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/vms/text.ps b/dviware/psprint/vms/text.ps
new file mode 100644
index 0000000000..c331cef192
--- /dev/null
+++ b/dviware/psprint/vms/text.ps
@@ -0,0 +1,74 @@
+% Prologue for a /text job.
+% It assumes *_print.com 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
+
+/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 10 eq % or does thischar = linefeed?
+ { linefeed }
+ { thischar 12 eq % or does thischar = formfeed?
+ { formfeed }
+ { } % ignore any other control char
+ ifelse }
+ ifelse }
+ ifelse
+} bind def
+
+(%stdin) (r) file /infile exch def
+/currentchar 1 string def
+setlocation
+
+/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/vms/two.ps b/dviware/psprint/vms/two.ps
new file mode 100644
index 0000000000..e2c57cf397
--- /dev/null
+++ b/dviware/psprint/vms/two.ps
@@ -0,0 +1,111 @@
+% Prologue for a /two job.
+% It assumes *_print.com 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
+
+/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 10 eq % or does thischar = linefeed?
+ { linefeed }
+ { thischar 12 eq % or does thischar = formfeed?
+ { formfeed }
+ { % ignore any other control char
+ } 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/vms/userguide.tex b/dviware/psprint/vms/userguide.tex
new file mode 100644
index 0000000000..492f7ba132
--- /dev/null
+++ b/dviware/psprint/vms/userguide.tex
@@ -0,0 +1,648 @@
+% 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.1 for VAX/VMS\\
+\bf Andrew Trevorrow, October 1989
+\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
+Temporary Files \aligneddots\ 1\\
+\TeX\ Output \aligneddots\ 1\\
+PostScript Output \aligneddots\ 1\\
+Text Output \aligneddots\ 1\\
+Command Qualifiers \aligneddots\ 2\\
+Error Messages \aligneddots\ 5\\
+Including Global PostScript \aligneddots\ 6\\
+Using PostScript Fonts \aligneddots\ 6\\
+Using PostScript Graphics \aligneddots\ 7
+
+\vspace*{\fill}
+
+\thispagestyle{empty}
+
+\newpage
+\setcounter{page}{1}
+
+\subsection*{Temporary Files}
+
+For each type of input file, PSPRINT will create a temporary file
+in \verb|sys$scratch|. % SYSDEP
+This file has a \verb|.tmp| extension and
+contains the PostScript commands required to print your job.
+It is automatically deleted once printed;
+you will only need to delete it if you decide to delete your job
+from the print queue.
+
+\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| qualifier.
+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|/landscape| qualifier will
+rotate the paper so that you can have lines up to 132 characters long
+(but only 50 lines per page).
+The \verb|/two| and \verb|/wide| qualifiers are variants of \verb|/text|
+that use a smaller font to fit two logical pages on each sheet of
+paper.
+
+Type `\verb|psprint foo.ps /text|' if you want to print a PostScript file.
+
+\newpage
+
+\subsection*{Command Qualifiers}
+
+The PSPRINT command can be followed by a variety of qualifiers:
+\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}
+If you have access to more than one type of printer, it may be a good idea
+to define some symbols in your \verb|login.com| file:
+ \begin{itemize}
+ \item
+ \verb|$lw*print :== psprint/dev=LW ! for LaserWriter|\\
+ \verb|$lino*print :== psprint/dev=LINO ! for Linotronic 300|\\
+ \verb|$ps40*print :== psprint/dev=PS40 ! for PrintServer 40|
+ \end{itemize}
+\end{itemize}
+
+Some qualifiers only apply to certain devices:
+\begin{itemize}
+
+\item \verb|/nobanner| (only if \verb|/device=LW| or \verb|LINO|) ---
+prevents PSPRINT producing a banner page.
+
+\item \verb|/manualfeed| (only if \verb|/device=LW|) ---
+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 qualifiers 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|/landscape| 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 qualifiers 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 qualifiers can only be used with a DVI file:
+\begin{itemize}
+
+\item \verb|/pages=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|/pages|:
+ \begin{itemize}
+ \item
+ \verb|$ psprint foo /pages=2 | --- prints the 2nd DVI page
+ (\TeX\ page \verb|[1]|)\\
+ \verb|$ psprint foo /pages=:4 | --- prints the first four pages\\
+ \verb|$ psprint foo /pages=4: | --- prints the last two pages\\
+ \verb|$ psprint foo /pages=[2] | --- prints \verb|[2.1]| and \verb|[2.2]|\\
+ \verb|$ psprint foo /pages=1:[2] | --- prints the first four pages\\
+ \verb|$ psprint foo /pages=[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|.
+
+\item \verb|/increment=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|/pages| subrange) and $f+ni$ is less than or equal to
+the final DVI page selected.
+
+The primary use of \verb|/increment| 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 /inc=2 /nobanner /rev| --- 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 /inc=2 /pag=2: /norev| --- prints DVI pages 2, 4, 6, 8
+ \end{enumerate}
+Note that the use of \verb|/reverse| with \verb|/increment| has no effect on
+{\em which\/} pages are printed; it simply changes the {\em order\/} in
+which they are done.
+
+If you intend doing a lot of two-sided printing then it is a good idea to
+define some symbols in your \verb|login.com| file to avoid making mistakes:
+ \begin{itemize}
+ \item
+ \verb|$ oddpages :== psprint/pag=1:/inc=2/rev/nobanner|\\
+ \verb|$ evenpages :== psprint/pag=2:/inc=2/norev|
+ \end{itemize}
+
+\item \verb|/reverse| or \verb|/noreverse| ---
+forces PSPRINT to print pages in descending or ascending order respectively.
+By default PSPRINT prints DVI pages in ascending order.
+
+\item \verb|/magnification=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|/stats| ---
+shows statistics on the rules, fonts, characters and \verb|\special| commands
+used on each page.
+
+\item \verb|/conserve_vm| ---
+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_vm| is the default;
+if \verb|/device=LW| or \verb|PS40| then \verb|/noconserve_vm| is the default.
+
+\item \verb|/units=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|/hoffset=dimen| and \verb|/voffset=dimen| ---
+allow you to shift the printed location of each page.
+For example, \verb|/hoffset=-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|/units|).
+
+\end{itemize}
+
+The following qualifiers also apply to a DVI file, but are really for
+system wizards. Most users should never need to use them since their
+default values are normally defined once at installation time and
+are presumably correct:
+\begin{itemize}
+
+\item \verb|/resolution=n| ---
+specifies the resolution of your printer in pixels per inch;
+\verb|n| must be a positive integer.
+
+\item \verb|/xsize=dimen| and \verb|/ysize=dimen| ---
+specify the paper size.
+PSPRINT will check that each DVI page fits within the given dimensions.
+A \verb|dimen| is any positive integer or real number followed by a
+two-letter unit (the same as for \verb|/units|).
+
+\item \verb|/psprefix=string| ---
+defines the TFM file name prefix that PSPRINT uses to recognize a
+PostScript font.
+
+\item \verb|/tfm_directory=directory| ---
+specifies the location of TFM files for PostScript fonts.
+
+\item \verb|/font_directory=directory| ---
+specifies the default directory from which PSPRINT
+gets all its character bitmap information.
+This might come in handy if you are using Metafont
+to create your own fonts or modify existing ones.
+For example, the following commands
+tell PSPRINT to first search for fonts in the current directory (\verb|[]|)
+before looking in the default directory
+(assumed to be \verb|tex_disk:[tex.pk]|):
+ \begin{itemize}
+ \item
+ \verb|$ define dirlist [],tex_disk:[tex.pk]|\\
+ \verb|$ psprint foo.dvi /font="dirlist:"|
+ \end{itemize}
+Use \verb|/stats| to see the default font directory at your site.
+
+\item \verb|/dummy_font=file| ---
+indicates the naming convention and format of all font files.
+The given file must represent an unmagnified font.
+
+\end{itemize}
+
+\newpage
+
+The \verb|/prep| qualifier only applies to a DVI or PS file:
+\begin{itemize}
+
+\item \verb|/prep=file| ---
+specifies a file to be included at the end of the normal prologue.
+This file will normally be a modified version of Apple's Laser Prep.
+If no file is specified then a default file,
+\verb|tex_ps:laserprep70.ps|, is included.
+Such a file is needed to support PostScript files created by pressing Command-F
+after clicking OK in the Print dialogue of most Macintosh applications.
+The PostScript code generated by this method relies on the
+procedures defined in Laser Prep, so if you want to include such code
+(via a \verb|\special| command for instance) you need to use \verb|/prep| to
+make sure the appropriate Laser Prep code is loaded first.
+
+Command-F files contain comments at the top that indicate which version of
+Laser Prep they require. Try and choose the nearest matching Laser Prep file
+provided with PSPRINT; see \verb|tex_ps:laserprep*.ps|.
+These files contain comments describing how they were created, just in case
+you need to generate a new version.
+
+\end{itemize}
+
+The remaining qualifiers apply to all types of input files:
+\begin{itemize}
+
+\item \verb|/landscape| --- 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|/delete| --- deletes the input file after printing.
+
+\item \verb|/notify| --- notifies you when the print job has finished.
+On the PrintServer~40 you'll also see any PostScript messages,
+a particularly useful feature when debugging a PostScript program.
+
+\item \verb|/copies=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|/note=string| --- includes a note on your banner page.
+For example, to get your output put in box 99, just type
+`\verb|psprint/note="box 99" ...|'.
+
+\item \verb|/queue=string| --- overrides the default queue used by PSPRINT\@.
+(Some sites may have more than one printer of the same type).
+
+\item \verb|/output=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}
+
+\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 banner 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_vm|
+or print a few pages at a time.
+\item
+On a Linotronic, use \verb|/lowres|.
+(\verb|/conserve_vm| 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.
+If you are using a PrintServer~40 then specify \verb|/notify| to get all
+PostScript messages sent back to your terminal.
+
+\subsection*{Including Global PostScript}
+
+When printing a DVI file, PSPRINT looks in your current directory for
+a file called \verb|global.ps|.
+If it exists then its contents will be included after the normal prologue.
+The example \verb|global.ps| file supplied in \verb|tex_ps|
+shows how to get the word ``DRAFT'' printed in the background on every page.
+
+\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; determined by /psprefix value in psdvi.cld
+
+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 ---
+see \verb|tex_ps:*_fonts.ps|.
+
+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|'.
+
+There are some important differences between PostScript fonts and
+the Computer Modern fonts normally used with \TeX:
+\begin{enumerate}
+\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}
+
+\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 have a couple of choices:
+\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 another program to create the graphic image
+and then convert it into a corresponding PostScript file.
+The Macintosh is a particularly nice machine for this purpose.
+Many applications can either dump an EPS (Encapsulated PostScript) file,
+or you can use the Command-F method mentioned earlier in the discussion
+of PSPRINT's \verb|/prep| qualifier.
+\end{enumerate}
+
+\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{tex_ps:piechart.ps}
+ \special{tex_ps:greybox.ps}
+ \special{tex_ps:random.ps}
+\end{verbatim}
+at appropriate points in the source file.
+The directory location is given with each PostScript file
+so you can print a copy of the User Guide from any directory.
+If the \verb|\special| command is only given a file name then
+PSPRINT assumes the file is in your current directory.
+
+\begin{figure}[h] % produce figure here
+ \vspace{2.1in}
+ \special{tex_ps: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{tex_ps: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{tex_ps: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 200 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/vms/wide.ps b/dviware/psprint/vms/wide.ps
new file mode 100644
index 0000000000..4b7e97eb54
--- /dev/null
+++ b/dviware/psprint/vms/wide.ps
@@ -0,0 +1,109 @@
+% Prologue for a /wide job.
+% It assumes *_print.com 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
+
+/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 10 eq % or does thischar = linefeed?
+ { linefeed }
+ { thischar 12 eq % or does thischar = formfeed?
+ { formfeed }
+ { % ignore any other control char
+ } 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