[mod.sources] v06i013: TeX DVI driver for LaserJet+

sources-request@mirror.UUCP (06/22/86)

Submitted by: Tor Lillqvist <talcott!seismo!mcvax!santra!tml>
Mod.sources: Volume 6, Issue 13
Archive-name: texdvi2lj/Part1

[ I have split this submission into three pieces named LJ.1.3,
  LJ.2.3, and LJ.2.3.  Unpack each piece and do
	  "cat LJ.[123].3 >dvi2lj.web"
  This is not great, but is the best way I could think of to
  distribute a large single-file source; if you have a better
  way, please let me know.  --r$]

Here is a DVI (TeX output) driver for the HP LaserJet+.  This version
is for the Pascal/1000 compiler on HP1000 machines running RTE-A (and
my TeX implementation), but it should be fairly easy to convert to
other TeX implementations, compilers and operating systems.

DVIplus is based on the DVItype program. It downloads only those
characters actually used. Pages are printed in reverse.

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# Contents:  LJ.1.3
 
echo x - LJ.1.3
sed 's/^XX//' > "LJ.1.3" <<'@//E*O*F LJ.1.3//'
XX% DVIPLUS.WEB
XX%
XX% This program is not copyrighted and may be used freely.
XX%
XX% Written by Tor Lillqvist
XX%            Technical Research Centre of Finland
XX%            Lehtisaarentie 2 A
XX%            SF-00340  HELSINKI
XX%            FINLAND
XX%
XX% E-mail: tml@fingate.bitnet, tml@santra.uucp, ...!mcvax!santra!tml
XX% Phone: +358 0 4566132
XX% Telex: 122972 vttha sf
XX  
XX% Here is TeX material that gets inserted after \input webmac
XX  
XX\def\hang{\hangindent 3em\indent\ignorespaces}
XX\font\ninerm=cmr9
XX\let\mc=\ninerm % medium caps for names like SAIL
XX\def\PASCAL{Pascal}
XX  
XX\def\(#1){} % this is used to make section names sort themselves better
XX\def\9#1{} % this is used for sort keys in the index
XX  
XX\def\title{DVI$\,$\lowercase{plus}}
XX\def\contentspagenumber{1}
XX\def\topofcontents{\null
XX  \def\titlepage{F} % include headline on the contents page
XX  \def\rheader{\mainfont\hfil \contentspagenumber}
XX  \vfill
XX  \centerline{\titlefont The {\ttitlefont DVIplus} processor}
XX  \vskip 10pt
XX  \centerline{\titlefont for HP LaserJet+}
XX  \vskip 15pt
XX  \centerline{(Version 1.2, April 1986)}
XX  \vfill}
XX\def\botofcontents{\vfill
XX  \centerline{\baselineskip9pt
XX    \vbox{\ninerm\noindent
XX    `\TeX' is a
XX    trademark of the American Mathematical Society.}}}
XX\pageno=\contentspagenumber \advance\pageno by 1
XX  
XX@* Introduction.
XXThe \.{DVIplus} program reads binary device-independent (``\.{DVI}'')
XXfiles that are produced by document compilers such as \TeX,
XXand translates them for printing on a HP LaserJet+
XXpage printer.
XXThis program is written by Tor Lillqvist,
XXbased on the DVItype program by Donald E.~Knuth.
XX  
XXThis version is for the \PASCAL/1000 compiler on the RTE--A operating
XXsystem running on the HP1000 A--Series computers.
XX  
XXPrograms for
XXtypesetting need to be especially careful about how they do arithmetic; if
XXrounding errors accumulate, margins won't be straight, vertical rules
XXwon't line up, and so on. But if rounding is done everywhere, even in the
XXmidst of words, there will be uneven spacing between the letters, and that
XXlooks bad. Human eyes notice differences of a thousandth of an inch in the
XXpositioning of lines that are close together; on low resolution devices,
XXwhere rounding produces effects four times as great as this, the problem
XXis especially critical. Experience has shown that unusual care is needed
XXeven on high-resolution equipment; for example, a mistake in the sixth
XXsignificant hexadecimal place of a constant once led to a difficult-to-find
XXbug in some software for the Alphatype CRS, which has a resolution of 5333
XXpixels per inch (make that 5333.33333333 pixels per inch).  The document
XXcompilers that generate \.{DVI} files make certain assumptions about the
XXarithmetic that will be used by \.{DVI}-reading software, and if these
XXassumptions are violated the results will be of inferior quality.
XXTherefore the present program is intended as a guide to proper procedure
XXin the critical places where a bit of subtlety is involved.
XX  
XXThe |banner| string defined here should be changed whenever \.{DVIplus}
XXgets modified.
XXThe editor of RTE--A automagically updates this timestamp when
XXthe file is written.
XX  
XX@d banner=='This is DVIplus, RTE-A Version 1.2 <860605.2059>'
XX  
XX@ This program is not written in standard \PASCAL, but
XXthe \PASCAL/1000 dialect used on HP1000 A--series computers
XXrunning the RTE--A operating system;
XXit should be easy to convert to other reasonable \PASCAL\
XXdialects.
XX  
XXPlaces where pecliarities depndent on the RTE--A implmentation have
XXbeen used are listed in the index under ``system dependencies''.
XX@!@^system dependencies@>
XX  
XXOne of the extensions to standard \PASCAL\ that we shall deal with is the
XXability to move to a random place in a binary file; another is to
XXdetermine the length of a binary file.
XXIn fact, in RTE--A we cannot determine the logical length of a binary file,
XXso another approach is used: The first doubleword in \.{PXL} and \.{DVI}
XXfiles contains the size of the file (in doublewords = integers).
XXThe records are numbered sequentially starting from 1. The internal pointers
XXin \.{DVI} and \.{PXL} files start the (byte) numbering from 0, so an offset
XXis added in the |seek| calls.
XX 
XX\PASCAL/1000 allows writing nonprinting characters to |text| files
XXusing a notation with a number sign followed by the decimal
XXordinal number of the character. For example, |write(f, #27'E')| writes
XXan escape followed by a capital `E'.
XX  
XXIn \PASCAL/1000, output to |text| files is line buffered, and we cannot
XXkeep |write|ing without using |writeln| every now and then.
XXThis terminates the record, which
XXnormally causes a newline, but the terminal drivers in RTE--A
XXleave the newline out if the last byte of a write request is underscore.
XXThis is handled by the |write_lj| macro.
XX  
XXAnother extension is to use a default |case| as in \.{TANGLE}, \.{WEAVE},
XXetc.
XX  
XX@d othercases == otherwise {default for cases not listed explicitly}
XX@d endcases == @+end {follows the default case in an extended |case| statement}
XX@f othercases == else
XX@f endcases == end
XX  
XX@ Before the program heading we have some compiler options.
XXThese specify that code should be generated for the `CDS' mode,
XXi.e. Code-and-Data-Separation.
XX  
XXThe binary input comes from |dvi_file| and the |pxl_file|s.
XX@^system dependencies@>
XX  
XX@p
XX@=$Standard_Level 'HP1000', CDS On, Debug, Range Off$@>@/
XXprogram DVIplus;
XXtype @<Types in the outer block@>@/
XXvar @<Globals in the outer block@>@/
XX@<External routine declarations@>@/
XXprocedure initialize; {this procedure gets things started properly}
XXvar i:0..255;
XXbegin
XX  @<Set initial values@>@/
XXend;
XX  
XX@ Here are some macros for common programming idioms.
XX  
XX@d do_nothing == {empty statement}
XX@d incr(#) == #:=#+1 {increase a variable by unity}
XX@d decr(#) == #:=#-1 {decrease a variable by unity}
XX  
XX@ We do our own error handling.
XX@^system dependencies@>
XX  
XX@d catch_errors==error_status:=true
XX@d dont_catch_errors==error_status:=false
XX  
XX@<Types...@>=
XX@!error_type=(err_run,err_ema,err_io,err_fmp,err_seg,err_wrn);
XX@!error_file_name=packed array [1..150] of char;
XX  
XX@ The |error_status| flag is set |true| when errors are to be catched.
XXIf a file system related error occurs, |error_status| is set false.
XX  
XX@<Glob...@>=
XX@!error_status:boolean;
XX  
XX@ If an error that we are not prepared to catch occurs, we call
XXthe standard error printing routine, and |halt|.
XX  
XX@p procedure errorprinter @=$Alias 'Pas.ErrorPrinter'$@>
XX(err_type: error_type; err_number, err_line: short;
XXvar err_file: error_file_name; err_flen: short);
XX  external;@t\2@>@/
XX@#
XXprocedure errorcatcher @=$Alias 'Pas.ErrorCatcher'$@>
XX(err_type: error_type; err_number, err_line: short;
XXvar err_file: error_file_name; err_flen: short);
XXbegin
XX  if err_type=err_wrn then
XX     do_nothing
XX  else if error_status and (err_type=err_fmp) then
XX    error_status := false
XX  else begin
XX    errorprinter(err_type,err_number,err_line,err_file,err_flen);
XX    halt(1); {an error we weren't prepared to catch}
XX  end;
XXend;
XX  
XX@ External routines are declared here.
XX|parameters| retrieves a runstring parameter.
XX|LURQ| is used to lock the output device.
XX|dcb_address| returns a pointer to the DCB (a sort of file control
XXblock for an open file.
XX|fmp_interactive| tells if a DCB corresponds to an interactive device,
XXand |fmp_lu| returns the `logical unit' number of a device.
XX@^system dependencies@>
XX  
XX@<External routine...@>=
XXfunction parameters @=$Alias 'Pas.Parameters'$@>
XX  (pos:short; var par:file_name; len:short):short; external; @t\2@>@#
XX  
XXprocedure LURQ(option:short; var lu:short; num: short; var key:short);
XX  external; @t\2@>@#
XX  
XXprocedure dcb_address @=$Alias 'Pas.DcbAddress1'$@>
XX  (var p:dcb_ptr; var f:text_file); external; @t\2@>@#
XX  
XXfunction fmp_interactive @=$Alias 'FmpInteractive'$@>
XX  (var d:dcb):short; external; @t\2@>@#
XX  
XXfunction fmp_lu @=$Alias 'FmpLU'$@> (var d:dcb):short; external; @t\2@>@#
XX  
XX@ Types related to system routines.
XX  
XX@d name_length=64 {a file name shouldn't be longer than this}
XX  
XX@<Types...@>=
XX@!short=-32768..32767;
XX@!file_name=packed array [1..name_length] of char;
XX@!dcb=array [1..144] of short;
XX@!dcb_ptr=^dcb;
XX  
XX@ @<Globals...@>=
XX@!laser_dcb:dcb_ptr;
XX@!lu,@!key:short;
XX  
XX@ We lock the printer after opening it if it is a device.
XXThis prevents intermixed output.
XXThe default output file name is given here.
XX@^system dependencies@>
XX  
XX@d default_out=='61'
XX  
XX@<Open and lock |laser_file|@>=
XXif parameters(arg_index,cur_name,name_length) <= 0 then
XX  cur_name:=default_out;
XXrewrite(laser_file,cur_name,'NOCCTL,SHARED');
XXdcb_address(laser_dcb,laser_file);
XXif fmp_interactive(laser_dcb^) <> 0 then begin
XX  lu:=fmp_lu(laser_dcb^);
XX  LURQ(1,lu,1,key);
XXend
XX  
XX@ Labels (global and local).
XX  
XX@d done=30 {go here when finished with a subtask}
XX@d exit=999 {go here to leave a procedure}
XX@d return==goto exit
XX  
XX@ The following parameters can be changed to extend or
XXreduce \.{DVIplus}'s capacity.
XX  
XX@d max_fonts=75 {maximum number of distinct fonts per \.{DVI} file}
XX@d max_printer_fonts=20 {maximum number of fonts kept in printer}
XX@d max_fonts_on_page=16 {maximum number of fonts per page}
XX@d max_widths=9601 {|max_fonts * 128 + 1|}
XX  {maximum number of different characters among all fonts}
XX@d line_length=79 {bracketed lines of output will be at most this long}
XX@d terminal_line_length=128 {maximum number of characters input in a single
XX  line of input from the terminal}
XX@d stack_size=100 {\.{DVI} files shouldn't |push| beyond this depth}
XX@d name_size=1000 {total length of all font file names}
XX@d max_bops=1000 {maximum number of pages printed}
XX  
XX@ If the \.{DVI} file is badly malformed, the whole process must be aborted;
XX\.{DVIplus} will give up, after issuing an error message about the symptoms
XXthat were noticed.
XX  
XXSuch errors might be discovered inside of subroutines inside of subroutines,
XXso a procedure called |jump_out| has been introduced. This procedure simply
XXhalts the program using the \PASCAL/1000 procedure |halt|.
XX@^system dependencies@>
XX  
XX@d print(#)==write(term_out,#)
XX@d print_ln(#)==write_ln(term_out,#)
XX@d print_nl==write_ln(term_out)
XX@d abort(#)==begin print('? ',#); jump_out;
XX    end
XX@d bad_dvi(#)==abort('Bad DVI file: ',#,'!')
XX@.Bad DVI file@>
XX@d bad_pxl(#)==begin print_nl; abort('Bad PXL file: ',#,'!'); end
XX@.Bad PXL file@>
XX  
XX@p procedure jump_out;
XXbegin halt(1)
XXend;
XX  
XX@ We fill output lines to |laser_file|, breaking the line when
XX|lj_threshold| characters have been written. An underscore character
XXis appended to the line before the newline (record boundary).
XXThis prevents the RTE--A terminal driver from writing a {\tt CR~LF}
XXpair at the end of the line.
XX@^system dependencies@>
XX  
XXAll output to |laser_file| goes through the macros |write_lj| or
XX|write_lj_f|. The latter doesn't test for line break before writing.
XX 
XX@d lj_threshold=70
XX  
XX@d write_lj(#)==begin if linepos(laser_file)>lj_threshold then
XX    write_ln(laser_file,'_');
XX  write(laser_file,#)
XXend
XX@d write_lj_f(#)==write(laser_file,#)
XX  
XX@* The character set.
XXLike all programs written with the  \.{WEB} system, \.{DVIplus} can be
XXused with any character set. But it uses ASCII code internally, because
XXthe programming for portable input-output is easier when a fixed internal
XXcode is used, and because \.{DVI} files use ASCII code for file names
XXand certain other strings.
XX  
XXThe next few sections of \.{DVIplus} have therefore been copied from the
XXanalogous ones in the \.{WEB} system routines. They have been considerably
XXsimplified, since \.{DVIplus} need not deal with the controversial
XXASCII codes less than @'40. If such codes appear in the \.{DVI} file,
XXthey will be printed as question marks.
XX  
XX@<Types...@>=
XX@!ASCII_code=" ".."~"; {a subrange of the integers}
XX  
XX@ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
XXcharacter sets were common, so it did not make provision for lower case
XXletters. Nowadays, of course, we need to deal with both upper and lower case
XXalphabets in a convenient way, especially in a program like \.{DVIplus}.
XXSo we shall assume that the \PASCAL\ system being used for \.{DVIplus}
XXhas a character set containing at least the standard visible characters
XXof ASCII code (|"!"| through |"~"|).
XX  
XXSome \PASCAL\ compilers use the original name |char| for the data type
XXassociated with the characters in text files, while other \PASCAL s
XXconsider |char| to be a 64-element subrange of a larger data type that has
XXsome other name.  In order to accommodate this difference, we shall use
XXthe name |text_char| to stand for the data type of the characters in the
XXoutput file.  We shall also assume that |text_char| consists of
XXthe elements |chr(first_text_char)| through |chr(last_text_char)|,
XXinclusive. The following definitions should be adjusted if necessary.
XX@^system dependencies@>
XX  
XX@d text_char == char {the data type of characters in text files}
XX@d first_text_char=0 {ordinal number of the smallest element of |text_char|}
XX@d last_text_char=255 {ordinal number of the largest element of |text_char|}

XX@<Types...@>=
XX@!text_file=text_;

XX@ The \.{DVIplus} processor converts between ASCII code and
XXthe user's external character set by means of arrays |xord| and |xchr|
XXthat are analogous to \PASCAL's |ord| and |chr| functions.

XX@<Globals...@>=
XX@!xord: array [text_char] of ASCII_code;
XX  {specifies conversion of input characters}
XX@!xchr: array [0..255] of text_char;
XX  {specifies conversion of output characters}

XX@ Under our assumption that the visible characters of standard ASCII are
XXall present, the following assignment statements initialize the
XX|xchr| array properly, without needing any system-dependent changes.

XX@<Set init...@>=
XXfor i:=0 to @'37 do xchr[i]:='?';
XXxchr[@'40]:=' ';
XXxchr[@'41]:='!';
XXxchr[@'42]:='"';
XXxchr[@'43]:='#';
XXxchr[@'44]:='$';
XXxchr[@'45]:='%';
XXxchr[@'46]:='&';
XXxchr[@'47]:='''';@/
XXxchr[@'50]:='(';
XXxchr[@'51]:=')';
XXxchr[@'52]:='*';
XXxchr[@'53]:='+';
XXxchr[@'54]:=',';
XXxchr[@'55]:='-';
XXxchr[@'56]:='.';
XXxchr[@'57]:='/';@/
XXxchr[@'60]:='0';
XXxchr[@'61]:='1';
XXxchr[@'62]:='2';
XXxchr[@'63]:='3';
XXxchr[@'64]:='4';
XXxchr[@'65]:='5';
XXxchr[@'66]:='6';
XXxchr[@'67]:='7';@/
XXxchr[@'70]:='8';
XXxchr[@'71]:='9';
XXxchr[@'72]:=':';
XXxchr[@'73]:=';';
XXxchr[@'74]:='<';
XXxchr[@'75]:='=';
XXxchr[@'76]:='>';
XXxchr[@'77]:='?';@/
XXxchr[@'100]:='@@';
XXxchr[@'101]:='A';
XXxchr[@'102]:='B';
XXxchr[@'103]:='C';
XXxchr[@'104]:='D';
XXxchr[@'105]:='E';
XXxchr[@'106]:='F';
XXxchr[@'107]:='G';@/
XXxchr[@'110]:='H';
XXxchr[@'111]:='I';
XXxchr[@'112]:='J';
XXxchr[@'113]:='K';
XXxchr[@'114]:='L';
XXxchr[@'115]:='M';
XXxchr[@'116]:='N';
XXxchr[@'117]:='O';@/
XXxchr[@'120]:='P';
XXxchr[@'121]:='Q';
XXxchr[@'122]:='R';
XXxchr[@'123]:='S';
XXxchr[@'124]:='T';
XXxchr[@'125]:='U';
XXxchr[@'126]:='V';
XXxchr[@'127]:='W';@/
XXxchr[@'130]:='X';
XXxchr[@'131]:='Y';
XXxchr[@'132]:='Z';
XXxchr[@'133]:='[';
XXxchr[@'134]:='\';
XXxchr[@'135]:=']';
XXxchr[@'136]:='^';
XXxchr[@'137]:='_';@/
XXxchr[@'140]:='`';
XXxchr[@'141]:='a';
XXxchr[@'142]:='b';
XXxchr[@'143]:='c';
XXxchr[@'144]:='d';
XXxchr[@'145]:='e';
XXxchr[@'146]:='f';
XXxchr[@'147]:='g';@/
XXxchr[@'150]:='h';
XXxchr[@'151]:='i';
XXxchr[@'152]:='j';
XXxchr[@'153]:='k';
XXxchr[@'154]:='l';
XXxchr[@'155]:='m';
XXxchr[@'156]:='n';
XXxchr[@'157]:='o';@/
XXxchr[@'160]:='p';
XXxchr[@'161]:='q';
XXxchr[@'162]:='r';
XXxchr[@'163]:='s';
XXxchr[@'164]:='t';
XXxchr[@'165]:='u';
XXxchr[@'166]:='v';
XXxchr[@'167]:='w';@/
XXxchr[@'170]:='x';
XXxchr[@'171]:='y';
XXxchr[@'172]:='z';
XXxchr[@'173]:='{';
XXxchr[@'174]:='|';
XXxchr[@'175]:='}';
XXxchr[@'176]:='~';
XXfor i:=@'177 to 255 do xchr[i]:='?';
XX  
XX@ The following system-independent code makes the |xord| array contain a
XXsuitable inverse to the information in |xchr|.
XX  
XX@<Set init...@>=
XXfor i:=first_text_char to last_text_char do xord[chr(i)]:=@'40;
XXfor i:=" " to "~" do xord[xchr[i]]:=i;
XX  
XX@ The LaserJet refuses to print other that `visible characters', that is
XXcharacters in the range @'41--@'177 or @'240--@'377.
XX  
XX@p function vis_chr(p : integer):char;
XXbegin
XX  if p < @'41 then
XX    p:=p+@'240;
XX  vis_chr:=chr(p);
XXend;
XX  
XX@* Device-independent file format.
XXBefore we get into the details of \.{DVIplus}, we need to know exactly
XXwhat \.{DVI} files are. The form of such files was designed by David R.
XX@^Fuchs, David Raymond@>
XXFuchs in 1979. Almost any reasonable typesetting device can be driven by
XXa program that takes \.{DVI} files as input, and dozens of such
XX\.{DVI}-to-whatever programs have been written. Thus, it is possible to
XXprint the output of document compilers like \TeX\ on many different kinds
XXof equipment.
XX  
XXA \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a
XXseries of commands in a machine-like language. The first byte of each command
XXis the operation code, and this code is followed by zero or more bytes
XXthat provide parameters to the command. The parameters themselves may consist
XXof several consecutive bytes; for example, the `|set_rule|' command has two
XXparameters, each of which is four bytes long. Parameters are usually
XXregarded as nonnegative integers; but four-byte-long parameters,
XXand shorter parameters that denote distances, can be
XXeither positive or negative. Such parameters are given in two's complement
XXnotation. For example, a two-byte-long distance parameter has a value between
XX$-2^{15}$ and $2^{15}-1$.
XX@.DVI {\rm files}@>

XXA \.{DVI} file consists of a ``preamble,'' followed by a sequence of one
XXor more ``pages,'' followed by a ``postamble.'' The preamble is simply a
XX|pre| command, with its parameters that define the dimensions used in the
XXfile; this must come first.  Each ``page'' consists of a |bop| command,
XXfollowed by any number of other commands that tell where characters are to
XXbe placed on a physical page, followed by an |eop| command. The pages
XXappear in the order that they were generated, not in any particular
XXnumerical order. If we ignore |nop| commands and \\{fnt\_def} commands
XX(which are allowed between any two commands in the file), each |eop|
XXcommand is immediately followed by a |bop| command, or by a |post|
XXcommand; in the latter case, there are no more pages in the file, and the
XXremaining bytes form the postamble.  Further details about the postamble
XXwill be explained later.

XXSome parameters in \.{DVI} commands are ``pointers.'' These are four-byte
XXquantities that give the location number of some other byte in the file;
XXthe first byte is number~0, then comes number~1, and so on. For example,
XXone of the parameters of a |bop| command points to the previous |bop|;
XXthis makes it feasible to read the pages in backwards order, in case the
XXresults are being directed to a device that stacks its output face up.
XXSuppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the
XXfirst page occupies bytes 100 to 999, say, and if the second
XXpage occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000
XXpoints to 100 and the |bop| that starts in byte 2000 points to 1000. (The
XXvery first |bop|, i.e., the one that starts in byte 100, has a pointer of $-1$.)

XX@ The \.{DVI} format is intended to be both compact and easily interpreted
XXby a machine. Compactness is achieved by making most of the information
XXimplicit instead of explicit. When a \.{DVI}-reading program reads the
XXcommands for a page, it keeps track of several quantities: (a)~The current
XXfont |f| is an integer; this value is changed only
XXby \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page
XXis given by two numbers called the horizontal and vertical coordinates,
XX|h| and |v|. Both coordinates are zero at the upper left corner of the page;
XXmoving to the right corresponds to increasing the horizontal coordinate, and
XXmoving down corresponds to increasing the vertical coordinate. Thus, the
XXcoordinates are essentially Cartesian, except that vertical directions are
XXflipped; the Cartesian version of |(h,v)| would be |(h,-v)|.  (c)~The
XXcurrent spacing amounts are given by four numbers |w|, |x|, |y|, and |z|,
XXwhere |w| and~|x| are used for horizontal spacing and where |y| and~|z|
XXare used for vertical spacing. (d)~There is a stack containing
XX|(h,v,w,x,y,z)| values; the \.{DVI} commands |push| and |pop| are used to
XXchange the current level of operation. Note that the current font~|f| is
XXnot pushed and popped; the stack contains only information about
XXpositioning.

XXThe values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up
XXto 32 bits, including the sign. Since they represent physical distances,
XXthere is a small unit of measurement such that increasing |h| by~1 means
XXmoving a certain tiny distance to the right. The actual unit of
XXmeasurement is variable, as explained below.

XX@ Here is a list of all the commands that may appear in a \.{DVI} file. Each
XXcommand is specified by its symbolic name (e.g., |bop|), its opcode byte
XX(e.g., 139), and its parameters (if any). The parameters are followed
XXby a bracketed number telling how many bytes they occupy; for example,
XX`|p[4]|' means that parameter |p| is four bytes long.

XX\yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f|
XXsuch that the reference point of the character is at |(h,v)|. Then
XXincrease |h| by the width of that character. Note that a character may
XXhave zero or negative width, so one cannot be sure that |h| will advance
XXafter this command; but |h| usually does increase.

XX\yskip\hang|set_char_1| through |set_char_127| (opcodes 1 to 127).
XXDo the operations of |set_char_0|; but use the character whose number
XXmatches the opcode, instead of character~0.

XX\yskip\hang|set1| 128 |c[1]|. Same as |set_char_0|, except that character
XXnumber~|c| is typeset. \TeX82 uses this command for characters in the
XXrange |128<=c<256|.

XX\yskip\hang|set2| 129 |c[2]|. Same as |set1|, except that |c|~is two
XXbytes long, so it is in the range |0<=c<65536|. \TeX82 never uses this
XXcommand, which is intended for processors that deal with oriental languages;
XXbut \.{DVIplus} will allow character codes greater than 255, assuming that
XXthey all have the same width as the character whose code is $c \bmod 256$.
XX@^oriental characters@>@^Chinese characters@>@^Japanese characters@>

XX\yskip\hang|set3| 130 |c[3]|. Same as |set1|, except that |c|~is three
XXbytes long, so it can be as large as $2^{24}-1$.

XX\yskip\hang|set4| 131 |c[4]|. Same as |set1|, except that |c|~is four
XXbytes long, possibly even negative. Imagine that.

XX\yskip\hang|set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle
XXof height |a| and width |b|, with its bottom left corner at |(h,v)|. Then
XXset |h:=h+b|. If either |a<=0| or |b<=0|, nothing should be typeset. Note
XXthat if |b<0|, the value of |h| will decrease even though nothing else happens.
XXPrograms that typeset from \.{DVI} files should be careful to make the rules
XXline up carefully with digitized characters, as explained in connection with
XXthe |rule_pixels| subroutine below.

XX\yskip\hang|put1| 133 |c[1]|. Typeset character number~|c| from font~|f|
XXsuch that the reference point of the character is at |(h,v)|. (The `put'
XXcommands are exactly like the `set' commands, except that they simply put out a
XXcharacter or a rule without moving the reference point afterwards.)

XX\yskip\hang|put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.

XX\yskip\hang|put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.

XX\yskip\hang|put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.

XX\yskip\hang|put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that
XX|h| is not changed.

XX\yskip\hang|nop| 138. No operation, do nothing. Any number of |nop|'s
XXmay occur between \.{DVI} commands, but a |nop| cannot be inserted between
XXa command and its parameters or between two parameters.

XX\yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning
XXof a page: Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set
XXthe current font |f| to an undefined value.  The ten $c_i$ parameters can
XXbe used to identify pages, if a user wants to print only part of a \.{DVI}
XXfile; \TeX82 gives them the values of \.{\\count0} $\ldots$ \.{\\count9}
XXat the time \.{\\shipout} was invoked for this page.  The parameter |p|
XXpoints to the previous |bop| command in the file, where the first |bop|
XXhas $p=-1$.

XX\yskip\hang|eop| 140.  End of page: Print what you have read since the
XXprevious |bop|. At this point the stack should be empty. (The \.{DVI}-reading
XXprograms that drive most output devices will have kept a buffer of the
XXmaterial that appears on the page that has just ended. This material is
XXlargely, but not entirely, in order by |v| coordinate and (for fixed |v|) by
XX|h|~coordinate; so it usually needs to be sorted into some order that is
XXappropriate for the device in question. \.{DVIplus} does not do such sorting.)

XX\yskip\hang|push| 141. Push the current values of |(h,v,w,x,y,z)| onto the
XXtop of the stack; do not change any of these values. Note that |f| is
XXnot pushed.

XX\yskip\hang|pop| 142. Pop the top six values off of the stack and assign
XXthem to |(h,v,w,x,y,z)|. The number of pops should never exceed the number
XXof pushes, since it would be highly embarrassing if the stack were empty
XXat the time of a |pop| command.

XX\yskip\hang|right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units.
XXThe parameter is a signed number in two's complement notation, |-128<=b<128|;
XXif |b<0|, the reference point actually moves left.

XX\yskip\hang|right2| 144 |b[2]|. Same as |right1|, except that |b| is a
XXtwo-byte quantity in the range |-32768<=b<32768|.

XX\yskip\hang|right3| 145 |b[3]|. Same as |right1|, except that |b| is a
XXthree-byte quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|.

XX\yskip\hang|right4| 146 |b[4]|. Same as |right1|, except that |b| is a
XXfour-byte quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|.

XX\yskip\hang|w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck,
XXthis parameterless command will usually suffice, because the same kind of motion
XXwill occur several times in succession; the following commands explain how
XX|w| gets particular values.

XX\yskip\hang|w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a
XXsigned quantity in two's complement notation, |-128<=b<128|. This command
XXchanges the current |w|~spacing and moves right by |b|.

XX\yskip\hang|w2| 149 |b[2]|. Same as |w1|, but |b| is a two-byte-long
XXparameter, |-32768<=b<32768|.

XX\yskip\hang|w3| 150 |b[3]|. Same as |w1|, but |b| is a three-byte-long
XXparameter, |@t$-2^{23}$@><=b<@t$2^{23}$@>|.

XX\yskip\hang|w4| 151 |b[4]|. Same as |w1|, but |b| is a four-byte-long
XXparameter, |@t$-2^{31}$@><=b<@t$2^{31}$@>|.

XX\yskip\hang|x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|'
XXcommands are like the `|w|' commands except that they involve |x| instead
XXof |w|.

XX\yskip\hang|x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a
XXsigned quantity in two's complement notation, |-128<=b<128|. This command
XXchanges the current |x|~spacing and moves right by |b|.

XX\yskip\hang|x2| 154 |b[2]|. Same as |x1|, but |b| is a two-byte-long
XXparameter, |-32768<=b<32768|.

XX\yskip\hang|x3| 155 |b[3]|. Same as |x1|, but |b| is a three-byte-long
XXparameter, |@t$-2^{23}$@><=b<@t$2^{23}$@>|.

XX\yskip\hang|x4| 156 |b[4]|. Same as |x1|, but |b| is a four-byte-long
XXparameter, |@t$-2^{31}$@><=b<@t$2^{31}$@>|.

XX\yskip\hang|down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units.
XXThe parameter is a signed number in two's complement notation, |-128<=a<128|;
XXif |a<0|, the reference point actually moves up.

XX\yskip\hang|down2| 158 |a[2]|. Same as |down1|, except that |a| is a
XXtwo-byte quantity in the range |-32768<=a<32768|.

XX\yskip\hang|down3| 159 |a[3]|. Same as |down1|, except that |a| is a
XXthree-byte quantity in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|.

XX\yskip\hang|down4| 160 |a[4]|. Same as |down1|, except that |a| is a
XXfour-byte quantity in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|.

XX\yskip\hang|y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck,
XXthis parameterless command will usually suffice, because the same kind of motion
XXwill occur several times in succession; the following commands explain how
XX|y| gets particular values.

XX\yskip\hang|y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a
XXsigned quantity in two's complement notation, |-128<=a<128|. This command
XXchanges the current |y|~spacing and moves down by |a|.

XX\yskip\hang|y2| 163 |a[2]|. Same as |y1|, but |a| is a two-byte-long
XXparameter, |-32768<=a<32768|.

XX\yskip\hang|y3| 164 |a[3]|. Same as |y1|, but |a| is a three-byte-long
XXparameter, |@t$-2^{23}$@><=a<@t$2^{23}$@>|.

XX\yskip\hang|y4| 165 |a[4]|. Same as |y1|, but |a| is a four-byte-long
XXparameter, |@t$-2^{31}$@><=a<@t$2^{31}$@>|.

XX\yskip\hang|z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands
XXare like the `|y|' commands except that they involve |z| instead of |y|.

XX\yskip\hang|z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a
XXsigned quantity in two's complement notation, |-128<=a<128|. This command
XXchanges the current |z|~spacing and moves down by |a|.

XX\yskip\hang|z2| 168 |a[2]|. Same as |z1|, but |a| is a two-byte-long
XXparameter, |-32768<=a<32768|.

XX\yskip\hang|z3| 169 |a[3]|. Same as |z1|, but |a| is a three-byte-long
XXparameter, |@t$-2^{23}$@><=a<@t$2^{23}$@>|.

XX\yskip\hang|z4| 170 |a[4]|. Same as |z1|, but |a| is a four-byte-long
XXparameter, |@t$-2^{31}$@><=a<@t$2^{31}$@>|.

XX\yskip\hang|fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been
XXdefined by a \\{fnt\_def} instruction, as explained below.

XX\yskip\hang|fnt_num_1| through |fnt_num_63| (opcodes 172 to 234). Set
XX|f:=1|, \dots, |f:=63|, respectively.

XX\yskip\hang|fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font
XXnumbers in the range |64<=k<256|.

XX\yskip\hang|fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two
XXbytes long, so it is in the range |0<=k<65536|. \TeX82 never generates this
XXcommand, but large font numbers may prove useful for specifications of
XXcolor or texture, or they may be used for special fonts that have fixed
XXnumbers in some external coding scheme.

XX\yskip\hang|fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three
XXbytes long, so it can be as large as $2^{24}-1$.

XX\yskip\hang|fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four
XXbytes long; this is for the really big font numbers (and for the negative ones).

XX\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
XXgeneral; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading
XXprograms are being used. \TeX82 generates |xxx1| when a short enough
XX\.{\\special} appears, setting |k| to the number of bytes being sent. It
XXis recommended that |x| be a string having the form of a keyword followed
XXby possible parameters relevant to that keyword.

XX\yskip\hang|xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.

XX\yskip\hang|xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.

XX\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously
XXlarge. \TeX82 uses |xxx4| when |xxx1| would be incorrect.

XX\yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
XXDefine font |k|, where |0<=k<256|; font definitions will be explained shortly.

XX\yskip\hang|fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
XXDefine font |k|, where |0<=k<65536|.

XX\yskip\hang|fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
XXDefine font |k|, where |0<=k<@t$2^{24}$@>|.

XX\yskip\hang|fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
XXDefine font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|.

XX\yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
XXBeginning of the preamble; this must come at the very beginning of the
XXfile. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.

XX\yskip\hang|post| 248. Beginning of the postamble, see below.

XX\yskip\hang|post_post| 249. Ending of the postamble, see below.

XX\yskip\noindent Commands 250--255 are undefined at the present time.

XX@ @d set_char_0=0 {typeset character 0 and move right}
XX@d set1=128 {typeset a character and move right}
XX@d set_rule=132 {typeset a rule and move right}
XX@d put1=133 {typeset a character}
XX@d put_rule=137 {typeset a rule}
XX@d nop=138 {no operation}
XX@d bop=139 {beginning of page}
XX@d eop=140 {ending of page}
XX@d push=141 {save the current positions}
XX@d pop=142 {restore previous positions}
XX@d right1=143 {move right}
XX@d w0=147 {move right by |w|}
XX@d w1=148 {move right and set |w|}
XX@d x0=152 {move right by |x|}
XX@d x1=153 {move right and set |x|}
XX@d down1=157 {move down}
XX@d y0=161 {move down by |y|}
XX@d y1=162 {move down and set |y|}
XX@d z0=166 {move down by |z|}
XX@d z1=167 {move down and set |z|}
XX@d fnt_num_0=171 {set current font to 0}
XX@d fnt1=235 {set current font}
XX@d xxx1=239 {extension to \.{DVI} primitives}
XX@d xxx4=242 {potentially long extension to \.{DVI} primitives}
XX@d fnt_def1=243 {define the meaning of a font number}
XX@d pre=247 {preamble}
XX@d post=248 {postamble beginning}
XX@d post_post=249 {postamble ending}
XX@d undefined_commands==250,251,252,253,254,255

XX@ The preamble contains basic information about the file as a whole. As
XXstated above, there are six parameters:
XX$$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
XXThe |i| byte identifies \.{DVI} format; currently this byte is always set
XXto~2. (Some day we will set |i=3|, when \.{DVI} format makes another
XXincompatible change---perhaps in 1992.)

XXThe next two parameters, |num| and |den|, are positive integers that define
XXthe units of measurement; they are the numerator and denominator of a
XXfraction by which all dimensions in the \.{DVI} file could be multiplied
XXin order to get lengths in units of $10^{-7}$ meters. (For example, there are
XXexactly 7227 \TeX\ points in 254 centimeters, and \TeX82 works with scaled
XXpoints where there are $2^{16}$ sp in a point, so \TeX82 sets |num=25400000|
XXand $|den|=7227\cdot2^{16}=473628672$.)
XX@^sp@>

XXThe |mag| parameter is what \TeX82 calls \.{\\mag}, i.e., 1000 times the
XXdesired magnification. The actual fraction by which dimensions are
XXmultiplied is therefore $mn/1000d$. Note that if a \TeX\ source document
XXdoes not call for any `\.{true}' dimensions, and if you change it only by
XXspecifying a different \.{\\mag} setting, the \.{DVI} file that \TeX\
XXcreates will be completely unchanged except for the value of |mag| in the
XXpreamble and postamble. (Fancy \.{DVI}-reading programs allow users to
XXoverride the |mag|~setting when a \.{DVI} file is being printed.)

XXFinally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
XXinterpreted further. The length of comment |x| is |k|, where |0<=k<256|.

XX@d dvi_id=2 {identifies the kind of \.{DVI} files described here}

XX@ Font definitions for a given font number |k| contain further parameters
XX$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$
XXThe four-byte value |c| is the check sum that \TeX\ (or whatever program
XXgenerated the \.{DVI} file) found in the \.{TFM} file for this font;
XX|c| should match the check sum of the font found by programs that read
XXthis \.{DVI} file.
XX@^check sum@>

XXParameter |s| contains a fixed-point scale factor that is applied to the
XXcharacter widths in font |k|; font dimensions in \.{TFM} files and other
XXfont files are relative to this quantity, which is always positive and
XXless than $2^{27}$. It is given in the same units as the other dimensions
XXof the \.{DVI} file.  Parameter |d| is similar to |s|; it is the ``design
XXsize,'' and it is given in \.{DVI} units that have not been corrected for
XXthe magnification~|mag| found in the preamble.  Thus, font |k| is to be
XXused at $|mag|\cdot s/1000d$ times its normal size.

XXThe remaining part of a font definition gives the external name of the font,
XXwhich is an ASCII string of length |a+l|. The number |a| is the length
XXof the ``area'' or directory, and |l| is the length of the font name itself;
XXthe standard local system font area is supposed to be used when |a=0|.
XXThe |n| field contains the area in its first |a| bytes.

XXFont definitions must appear before the first use of a particular font number.
XXOnce font |k| is defined, it must not be defined again; however, we
XXshall see below that font definitions appear in the postamble as well as
XXin the pages, so in this sense each font number is defined exactly twice,
XXif at all. Like |nop| commands and \\{xxx} commands, font definitions can
XXappear before the first |bop|, or between an |eop| and a |bop|.

XX@ The last page in a \.{DVI} file is followed by `|post|'; this command
XXintroduces the postamble, which summarizes important facts that \TeX\ has
XXaccumulated about the file, making it possible to print subsets of the data
XXwith reasonable efficiency. The postamble has the form
XX$$\vbox{\halign{\hbox{#\hfil}\cr
XX  |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
XX  $\langle\,$font definitions$\,\rangle$\cr
XX  |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
XXHere |p| is a pointer to the final |bop| in the file. The next three
XXparameters, |num|, |den|, and |mag|, are duplicates of the quantities that
XXappeared in the preamble.

XXParameters |l| and |u| give respectively the height-plus-depth of the tallest
XXpage and the width of the widest page, in the same units as other dimensions
XXof the file. These numbers might be used by a \.{DVI}-reading program to
XXposition individual ``pages'' on large sheets of film or paper.

XXParameter |s| is the maximum stack depth (i.e., the largest excess of
XX|push| commands over |pop| commands) needed to process this file. Then
XXcomes |t|, the total number of pages (|bop| commands) present.

XXThe postamble continues with font definitions, which are any number of
XX\\{fnt\_def} commands as described above, possibly interspersed with |nop|
XXcommands. Each font number that is used in the \.{DVI} file must be defined
XXexactly twice: Once before it is first selected by a \\{fnt} command, and once
XXin the postamble.

XX@ The last part of the postamble, following the |post_post| byte that
XXsignifies the end of the font definitions, contains |q|, a pointer to the
XX|post| command that started the postamble.  An identification byte, |i|,
XXcomes next; this currently equals~2, as in the preamble.

XXThe |i| byte is followed by four or more bytes that are all equal to
XXthe decimal number 223 (i.e., @'337 in octal). \TeX\ puts out four to seven of
XXthese trailing bytes, until the total length of the file is a multiple of
XXfour bytes, since this works out best on machines that pack four bytes per
XXword; but any number of 223's is allowed, as long as there are at least four
XXof them. In effect, 223 is a sort of signature that is added at the very end.
XX@^Fuchs, David Raymond@>

XXThis curious way to finish off a \.{DVI} file makes it feasible for
XX\.{DVI}-reading programs to find the postamble first, on most computers,
XXeven though \TeX\ wants to write the postamble last. Most operating
XXsystems permit random access to individual words or bytes of a file, so
XXthe \.{DVI} reader can start at the end and skip backwards over the 223's
XXuntil finding the identification byte. Then it can back up four bytes, read
XX|q|, and move to byte |q| of the file. This byte should, of course,
XXcontain the value 248 (|post|); now the postamble can be read, so the
XX\.{DVI} reader discovers all the information needed for typesetting the
XXpages. Note that it is also possible to skip through the \.{DVI} file at
XXreasonably high speed to locate a particular page, if that proves
XXdesirable. This saves a lot of time, since \.{DVI} files used in production
XXjobs tend to be large.
XX  
XX@* Input from binary files.
XXWe have seen that a \.{DVI} file is a sequence of 8-bit bytes. The bytes
XXappear physically in what is called a `|packed file of 0..255|'
XXin \PASCAL\ lingo.
XX  
XXPacking is system dependent, and many \PASCAL\ systems fail to implement
XXsuch files in a sensible way (at least, from the viewpoint of producing
XXgood production software).  For example, some systems treat all
XXbyte-oriented files as text, looking for end-of-line marks and such
XXthings. Therefore some system-dependent code is often needed to deal with
XXbinary files.
XX@^system dependencies@>
XX  
XXIn the RTE--A implementation, \.{DVI} and \.{PXL} files are files of
XX|integer|s,
XXwith the first |integer| containing the number of |integer|s to follow.
XX(It is impossible to know the logical size of a random-access file).
XXThe bytes of the file are accessed through a variant record.
XX  
XX@d pxl_id=1001 {identifies the kind of \.{PXL} files handled}
XX  
XX@<Types...@>=
XX@!eight_bits=0..255; {unsigned one-byte quantity}
XXfour=0..3;
XX@!i2c=packed record case four of 0: (i:integer);@/
XX1:(i0,i1:short);@/
XX2:(b:packed array[0..3] of eight_bits);
XX3:(c:packed array[0..3] of char) end;
XX@!int_file=file of integer;
XX@!byte_file=record {files that contain binary data}
XXx:i2c;i:0..3;m,s:integer;
XXf:int_file;
XXend;
XX  
XX@ The program deals with the binary file variables |dvi_file| which is the
XXmain input file that we are printing, and |pxl_file| is an array of
XXfont image files from which character images is downloaded
XXto the printer.
XX  
XX@<Glob...@>=
XX@!laser_file:text_file;
XX@!dvi_file:byte_file; {the stuff we are \.{DVI}typing}
XX@!pxl_file:array[0..max_fonts] of file of i2c; {font image files}
XX@!s_pxl_file:integer; {size of |pxl_file|}
XX  
XX@ To prepare these files for input, we |reset| them. An extension of
XX\PASCAL\ is needed in the case of |pxl_file|, since we want to associate
XXit with external files whose names are specified dynamically (i.e., not
XXknown at compile time). The following code assumes that `|reset(f,s)|'
XXdoes this, when |f| is a file variable and |s| is a string variable that
XXspecifies the file name.
XXThe function result is false if the file couldn't be opened.
XX@^system dependencies@>
XX  
XX@p function open_dvi_file:boolean;
XXvar i,j:short;
XXbegin
XXi:=parameters(arg_index,cur_name,name_length);
XXincr(arg_index);
XXj:=1;
XXwhile (j<=i)and(cur_name[j]<>'.') do incr(j);
XXif j>i then begin
XX  cur_name[j]:='.'; incr(j);
XX  cur_name[j]:='d'; incr(j);
XX  cur_name[j]:='v'; incr(j);
XX  cur_name[j]:='i'; incr(j);
XXend;
XXcatch_errors;
XXreset(dvi_file.f,cur_name,'SHARED');
XXopen_dvi_file:=error_status;
XXif error_status then begin
XX  dont_catch_errors;
XX  close(dvi_file.f);
XX  open(dvi_file.f,cur_name,'SHARED');
XX  get(dvi_file.f);
XX  dvi_file.s:=dvi_file.f^;
XX  get(dvi_file.f);
XX  dvi_file.x.i:=dvi_file.f^;
XX  dvi_file.i:=0;
XXend;
XXcur_loc:=0;
XXend;
XX@#
XXfunction open_pxl_file(i:short):boolean;
XXbegin
XXcatch_errors;
XXreset(pxl_file[i],cur_name,'SHARED');
XXopen_pxl_file:=error_status;
XXif error_status then begin
XX  dont_catch_errors;
XX  close(pxl_file[i]);
XX  open(pxl_file[i],cur_name,'SHARED');
XX  get(pxl_file[i]);
XX  s_pxl_file:=pxl_file[i]^.i;
XX  get(pxl_file[i]);
XX  if pxl_file[i]^.i <> pxl_id then
XX    bad_pxl('bad header id');
XXend;
XXend;
XX  
XX@ If you looked carefully at the preceding code, you probably asked,
XX``What are |cur_loc| and |cur_name|?'' Good question. They're global
XXvariables: |cur_loc| is the number of the byte about to be read next from
XX|dvi_file|, and |cur_name| is a string variable that will be set to the
XXcurrent pixel image file name before |open_pxl_file| is called.
XX  
XX@<Glob...@>=
XX@!cur_loc:integer; {where we are about to look, in |dvi_file|}
XX@!cur_name:file_name; {external name,
XX  with no lower case letters}
XX  
XX@ It turns out to be convenient to read four bytes at a time, when we are
XXinputting from \.{PXL} files. The input goes into global variables
XX|b0|, |b1|, |b2|, and |b3|, with |b0| getting the first byte and |b3|
XXthe fourth.
XX  
XX@<Glob...@>=
XX@!b0,@!b1,@!b2,@!b3: integer; {four bytes input at once}
XX  
XX@ The |read_pxl_word| procedure sets |b0| through |b3| to the next
XXfour bytes in the current \.{TFM} file.
XX@^system dependencies@>
XX  
XX@p procedure read_pxl_word(i:short);
XXbegin
XXb0:=pxl_file[i]^.b[0];b1:=pxl_file[i]^.b[1];
XXb2:=pxl_file[i]^.b[2];b3:=pxl_file[i]^.b[3];
XXget(pxl_file[i]);
XXend;
XX  
XX@ We shall use another set of simple functions to read the next byte or
XXbytes from |dvi_file|. There are seven possibilities, each of which is
XXtreated as a separate function in order to minimize the overhead for
XXsubroutine calls.
XX@^system dependencies@>
XX  
XXThis is the best way to check ``eof'' in RTE--A, as the logical length of
XXthe file is unknown (except from the first word).
XX  
XX@d eof_dvi_file==(cur_loc>dvi_file.s*4)
XX  
XX@p function get_byte:integer; {returns the next byte, unsigned}
XXvar b:eight_bits;
XXbegin if eof_dvi_file then get_byte:=0
XXelse  begin
XX    get_byte:=dvi_file.x.b[dvi_file.i];
XX    if dvi_file.i=3 then begin
XX        get(dvi_file.f);
XX        dvi_file.x.i:=dvi_file.f^;
XX        dvi_file.i:=0; end
XX    else
XX        incr(dvi_file.i);
XX  end;
XX  incr(cur_loc);
XXend;
XX@#
XXfunction signed_byte:integer; {returns the next byte, signed}
XXvar b:eight_bits;
XXbegin b:=get_byte;
XXif b<128 then signed_byte:=b @+ else signed_byte:=b-256;
XXend;
XX@#
XXfunction get_two_bytes:integer; {returns the next two bytes, unsigned}
XXvar a,@!b:integer;
XXbegin a:=get_byte; b:=get_byte;
XXget_two_bytes:=a*256+b;
XXend;
XX@#
XXfunction signed_pair:integer; {returns the next two bytes, signed}
XXvar a,@!b:integer;
XXbegin a:=get_byte; b:=get_byte;
XXif a<128 then signed_pair:=a*256+b
XXelse signed_pair:=(a-256)*256+b;
XXend;
XX@#
XXfunction get_three_bytes:integer; {returns the next three bytes, unsigned}
XXvar a,@!b,@!c:eight_bits;
XXbegin a:=get_byte; b:=get_byte; c:=get_byte;
XXget_three_bytes:=(a*256+b)*256+c;
XXend;
XX@#
XXfunction signed_trio:integer; {returns the next three bytes, signed}
XXvar a,@!b,@!c:integer;
XXbegin a:=get_byte; b:=get_byte; c:=get_byte;
XXif a<128 then signed_trio:=(a*256+b)*256+c
XXelse signed_trio:=((a-256)*256+b)*256+c;
XXend;
XX@#
XXfunction signed_quad:integer; {returns the next four bytes, signed}
XXvar a,@!b,@!c,@!d:integer;
XXbegin a:=get_byte; b:=get_byte; c:=get_byte; d:=get_byte;
XXif a<128 then signed_quad:=((a*256+b)*256+c)*256+d
XXelse signed_quad:=(((a-256)*256+b)*256+c)*256+d;
XXend;
XX  
XX@ Finally we come to the routines that are used to acces the |dvi_file|
XXrandomly. The driver program below needs two such routines: |dvi_length|
XXshould compute the total number of bytes in |dvi_file|, possibly also
XXcausing |eof_dvi_file| to be true; and |move_to_byte(n)|
XXshould position |dvi_file| so that the next |get_byte| will read byte |n|,
XXstarting with |n=0| for the first byte in the file.
XX@^system dependencies@>
XXSuch routines are, of course, highly system dependent.
XX  
XX@d dvi_length==(dvi_file.s*4)
XX@#
XX@d move_to_byte(#)==begin seek(dvi_file.f,((#) div 4)+2); get(dvi_file.f);
XXdvi_file.x.i:=dvi_file.f^; dvi_file.i:=(#) mod 4; cur_loc:=#; end
XX  
XX@
XXFont files
XXshould contain exactly the same character width data that is
XXfound in the corresponding \.{TFM}s; check sums are used to help
XXensure this. In addition, font files also contain the widths of
XXcharacters in pixels, since the device-independent character widths of
XX\.{TFM} files are generally not perfect multiples of pixels.
XX  
XXThe |pixel_width| array contains this information; when |width[k]| is the
XXdevice-independent width of some character in \.{DVI} units, |pixel_width[k]|
XXis the corresponding width of that character in an actual font.
XXThe macro |char_pixel_width| is set up to be analogous to |char_width|.
XX  
XXThe |status| array tells if a charater has been downloaded to the
XXlaser printer, or if it is too large, and must be transferred as raster
XXgraphics. It might also contain a positive value that indicates a shift
XXup of the reference point (because the ``baseline'' of the characters
XXis set at |baseline| pixels from the bottom, characters can't be deeper than
XX|baseline| pixels).
XX 
XXThe large arrays are located in
XXEMA (Extended Memory Area) (outside the 32 page range addressable
XXwith one-word addresses).
XXThe \.{Ema\_Var} compiler options specify which variables are in EMA.
XX@^system dependencies@>
XX 
XX@d char_end_width(#)==#]
XX@d char_pixel_width(#)==pixel_width[width_base[#]+char_end_width
XX@d char_status(#)==status[width_base[#]+char_end_width
XX@d not_loaded=0
XX@d too_large=-1
XX@d loaded_ok=-2
XX@d baseline=55
XX  
XX@<Glob...@>=
XX@=$Ema_Var On$@>
XX@!pixel_width:array[0..max_widths] of short; {actual character widths,
XX  in pixels}
XX@!status:array[0..max_widths] of short; {character statuses}
XX@=$Ema_Var Off$@>
XX@!conv:real; {converts \.{DVI} units to pixels}
XX@!true_conv:real; {converts unmagnified \.{DVI} units to pixels}
XX@!numerator,@!denominator:integer; {stated conversion ratio}
XX@!mag:integer; {magnification factor times 1000}
XX@!desired_mag:integer;
XX@!best_mag:integer;
@//E*O*F LJ.1.3//
chmod u=rw,g=rw,o=rw LJ.1.3
 
exit 0