summaryrefslogtreecommitdiff
path: root/dviware/psprint/vms
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/psprint/vms')
-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
59 files changed, 12335 insertions, 0 deletions
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