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