2  INTRODUCTION  DVIDOC §1

1. Introduction. The utility program reads binary device-independent (“ ”) files that are produced by document compilers such as TEX, and approximates the intended document as a text file suitable for typing at a terminal or on a line printer.

This program is based on the program , which was written by Donald Knuth and David Fuchs. It contained a great deal of code checking for malformed files. Most of that code remains in , not because it is important (we trust TEX) to produce correct files), but because is was easier not to disturb the logic in modifying to produce .

The banner string defined here should be changed whenever gets modified. define banner ≡ ´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ´ { printed when the program starts }

2. This program is written in standard Pascal, except where it is necessary to use extensions; for example, must read files whose names are dynamically specified, and that would be impossible in pure Pascal. All places where nonstandard constructions are used have been listed in the index under “system dependencies.”

One of the extensions to standard Pascal that we shall deal with is the ability to move to a random place in a binary file.

Another extension is to use a default case as in , , etc. define othercases ≡ others : { default for cases not listed explicitly } define endcases ≡ end { follows the default case in an extended case statement } format othercases ≡ else format endcases ≡ end

3. The binary input comes from dvi file, and the symbolic output is written to stdout. The term print is used instead of write when this program writes on err file, so that all such output could easily be redirected if desired.

define print (#) ≡ write(err file, #) define print ln(#) ≡ write ln(err file, #) define error (#) ≡ print ln(#) define doc file ≡ output define eof (#) ≡ eof dvi file

program DVIDOC (input , output , dvi file, err file); label ⟨ Labels in the outer block 4 ⟩ const ⟨ Constants in the outer block 5 ⟩ type ⟨ Types in the outer block 9 ⟩ var ⟨ Globals in the outer block 11 ⟩

\underline{\overline{# ␣}} \{ declarations for external C procedures \} procedure initialize; { this procedure gets things started properly }

var i: integer ;

begin setpaths ; ⟨ Set initial values 12 ⟩

end;

4. If the program has to stop prematurely, it goes to the ‘final end ’. Another label, done, is used when stopping normally.

define final end = 9999 { label for the end of it all } define done = 30 { go here when finished with a subtask }

⟨ Labels in the outer block 4 ⟩ ≡

final end , done;

This code is used in 3.

§5  DVIDOC  INTRODUCTION 3

5. The following parameters can be changed at compile time to extend or reduce ’s capacity. ⟨ Constants in the outer block 5 ⟩ ≡

max fonts = 100; { maximum number of distinct fonts per file } max widths = 10000; { maximum number of different characters among all fonts } terminal line length = 150;

{ maximum number of characters input in a single line of input from the terminal } stack size = 100; { files shouldn’t push beyond this depth } name size = 1000; { total length of all font file names } name length = 100; { a file name shouldn’t be longer than this } page width max = 132; { maximum number of characters per line in the document } page length max = 88; { maximum number of lines per page in the document }

This code is used in 3.

6. Here are some macros for common programming idioms.

define incr (#) ≡ # ← # + 1 { increase a variable by unity } define decr (#) ≡ # ← # − 1 { decrease a variable by unity } define do nothing ≡ { empty statement }

7. If the  file is badly malformed, the whole process must be aborted;  will give up, after issuing

an error message about the symptoms that were noticed.

Such errors might be discovered inside of subroutines inside of subroutines, so a procedure called jump out has been introduced. This procedure, which simply transfers control to the label final end at the end of the program, contains the only non-local goto statement in .

define abort (#) ≡ begin message(´ ␣´ , #); jump out ; end

define bad dvi (#) ≡ abort (´ ␣ ␣ ␣´ , #, ´ ´ ) procedure jump out ;

begin goto final end ; end;

8. If the wrong options have been given to , we print a reminder message and exit.

define cannot start (#) ≡ begin message(#); goto done end

4  THE CHARACTER SET  DVIDOC §9
9. The character set. Like all programs written with the  system,  can be used with any

character set. But it uses ASCII code internally, because the programming for portable input-output is easier when a fixed internal code is used, and because files use ASCII code for file names and certain other strings.

The next few modules of have therefore been copied from the analogous ones in the system routines. They have been considerably simplified, since need not deal with the controversial ASCII codes less than ´ 40 . If such codes appear in the file, they will be printed as question marks. ⟨ Types in the outer block 9 ⟩ ≡

ASCII code = ␣ . . ; { a subrange of the integers }

1022.

This code is used in 3.

10. The original Pascal compiler was designed in the late 60s, when six-bit character sets were common, so it did not make provision for lower case letters. Nowadays, of course, we need to deal with both upper and lower case alphabets in a convenient way, especially in a program like . So we shall assume that the Pascal system being used for has a character set containing at least the standard visible characters of ASCII code ( through ).

Some Pascal compilers use the original name char for the data type associated with the characters in text files, while other Pascals consider char to be a 64-element subrange of a larger data type that has some other name. In order to accommodate this difference, we shall use the name text char to stand for the data type of the characters in the output file. We shall also assume that text char consists of the elements chr (first text char ) through chr (last text char ), inclusive. The following definitions should be adjusted if necessary.

define text char ≡ char { the data type of characters in text files }

define first text char = 0 { ordinal number of the smallest element of text char }

define last text char = 127 { ordinal number of the largest element of text char } ⟨ Types in the outer block 9 ⟩ +≡

text file = packed file of text char ;

11. The processor converts between ASCII code and the user’s external character set by means of arrays xord and xchr that are analogous to Pascal’s ord and chr functions. ⟨ Globals in the outer block 11 ⟩ ≡ xord : array [text char ] of ASCII code; { specifies conversion of input characters } xchr : array [0 . . 255] of text char ; { specifies conversion of output characters }

23, 27, 28, 32, 35, 41, 43, 44, 47, 49, 54, 61, 64, 70, 71, 76, 93, 97103.

This code is used in 3.

§12  DVIDOC  THE CHARACTER SET 5

12. Under our assumption that the visible characters of standard ASCII are all present, the following assignment statements initialize the xchr array properly, without needing any system-dependent changes. ⟨ Set initial values 12 ⟩ ≡

for i ← 0 to ´ 37 do xchr [i] ← ´ ´ ; xchr [´ 40 ] ← ´ ␣´ ; xchr [´ 41 ] ← ´ ´ ; xchr [´ 42 ] ← ´ ´ ; xchr [´ 43 ] ← ´ #´ ; xchr [´ 44 ] ← ´ $´ ; xchr [´ 45 ] ← ´ %´ ; xchr [´ 46 ] ← ´ ´ ; xchr [´ 47 ] ← ´ ´ ´ ´ ; xchr [´ 50 ] ← ´ ´ ; xchr [´ 51 ] ← ´ ´ ; xchr [´ 52 ] ← ´ ´ ; xchr [´ 53 ] ← ´ ´ ; xchr [´ 54 ] ← ´ ´ ; xchr [´ 55 ] ← ´ ´ ; xchr [´ 56 ] ← ´ ´ ; xchr [´ 57 ] ← ´ ´ ; xchr [´ 60 ] ← ´ ´ ; xchr [´ 61 ] ← ´ ´ ; xchr [´ 62 ] ← ´ ´ ; xchr [´ 63 ] ← ´ ´ ; xchr [´ 64 ] ← ´ ´ ; xchr [´ 65 ] ← ´ ´ ; xchr [´ 66 ] ← ´ ´ ; xchr [´ 67 ] ← ´ ´ ; xchr [´ 70 ] ← ´ ´ ; xchr [´ 71 ] ← ´ ´ ; xchr [´ 72 ] ← ´ ´ ; xchr [´ 73 ] ← ´ ´ ; xchr [´ 74 ] ← ´ ´ ; xchr [´ 75 ] ← ´ ´ ; xchr [´ 76 ] ← ´ ´ ; xchr [´ 77 ] ← ´ ´ ; xchr [´ 100 ] ← ´ ´ ; xchr [´ 101 ] ← ´ ´ ; xchr [´ 102 ] ← ´ ´ ; xchr [´ 103 ] ← ´ ´ ; xchr [´ 104 ] ← ´ ´ ; xchr [´ 105 ] ← ´ ´ ; xchr [´ 106 ] ← ´ ´ ; xchr [´ 107 ] ← ´ ´ ; xchr [´ 110 ] ← ´ ´ ; xchr [´ 111 ] ← ´ ´ ; xchr [´ 112 ] ← ´ ´ ; xchr [´ 113 ] ← ´ ´ ; xchr [´ 114 ] ← ´ ´ ; xchr [´ 115 ] ← ´ ´ ; xchr [´ 116 ] ← ´ ´ ; xchr [´ 117 ] ← ´ ´ ; xchr [´ 120 ] ← ´ ´ ; xchr [´ 121 ] ← ´ ´ ; xchr [´ 122 ] ← ´ ´ ; xchr [´ 123 ] ← ´ ´ ; xchr [´ 124 ] ← ´ ´ ; xchr [´ 125 ] ← ´ ´ ; xchr [´ 126 ] ← ´ ´ ; xchr [´ 127 ] ← ´ ´ ; xchr [´ 130 ] ← ´ ´ ; xchr [´ 131 ] ← ´ ´ ; xchr [´ 132 ] ← ´ ´ ; xchr [´ 133 ] ← ´ ´ ; xchr [´ 134 ] ← ´ ´ ; xchr [´ 135 ] ← ´ ´ ; xchr [´ 136 ] ← ´ ´ ; xchr [´ 137 ] ← ´ ´ ; xchr [´ 140 ] ← ´ ` ´ ; xchr [´ 141 ] ← ´ ´ ; xchr [´ 142 ] ← ´ ´ ; xchr [´ 143 ] ← ´ ´ ; xchr [´ 144 ] ← ´ ´ ; xchr [´ 145 ] ← ´ ´ ; xchr [´ 146 ] ← ´ ´ ; xchr [´ 147 ] ← ´ ´ ; xchr [´ 150 ] ← ´ ´ ; xchr [´ 151 ] ← ´ ´ ; xchr [´ 152 ] ← ´ ´ ; xchr [´ 153 ] ← ´ ´ ; xchr [´ 154 ] ← ´ ´ ; xchr [´ 155 ] ← ´ ´ ; xchr [´ 156 ] ← ´ ´ ; xchr [´ 157 ] ← ´ ´ ; xchr [´ 160 ] ← ´ ´ ; xchr [´ 161 ] ← ´ ´ ; xchr [´ 162 ] ← ´ ´ ; xchr [´ 163 ] ← ´ ´ ; xchr [´ 164 ] ← ´ ´ ; xchr [´ 165 ] ← ´ ´ ; xchr [´ 166 ] ← ´ ´ ; xchr [´ 167 ] ← ´ ´ ; xchr [´ 170 ] ← ´ ´ ; xchr [´ 171 ] ← ´ ´ ; xchr [´ 172 ] ← ´ ´ ; xchr [´ 173 ] ← ´ ´ ; xchr [´ 174 ] ← ´ ´ ; xchr [´ 175 ] ← ´ ´ ; xchr [´ 176 ] ← ´ ´ ; for i ← ´ 177 to 255 do xchr [i] ← ´ ´ ; 13, 33, 45, 55, 62, 7294.

This code is used in 3.

13. The following system-independent code makes the xord array contain a suitable inverse to the information in xchr . ⟨ Set initial values 12 ⟩ +≡

6  DEVICE-INDEPENDENT FILE FORMAT  DVIDOC §14

for i ← first text char to last text char do xord [chr (i)] ← ´ 40 ; for i ← ␣ to do xord [xchr [i]] ← i; 14. Device-independent file format. Before we get into the details of , we need to know exactly what files are. The form of such files was designed by David R. Fuchs in 1979. Almost any reasonable typesetting device can be driven by a program that takes files as input, and dozens of such -to-whatever programs have been written. Thus, it is possible to print the output of document compilers like TEX on many different kinds of equipment.

A file is a stream of 8-bit bytes, which may be regarded as a series of commands in a machine-like language. The first byte of each command is the operation code, and this code is followed by zero or more bytes that provide parameters to the command. The parameters themselves may consist of several consecutive bytes; for example, the ‘set rule’ command has two parameters, each of which is four bytes long. Parameters are usually regarded as nonnegative integers; but four-byte-long parameters, and shorter parameters that denote distances, can be either positive or negative. Such parameters are given in two’s complement notation. For example, a two-byte-long distance parameter has a value between −2^{15} and 2^{15} − 1.

A file consists of a “preamble,” followed by a sequence of one or more “pages,” followed by a “postamble.” The preamble is simply a pre command, with its parameters that define the dimensions used in the file; this must come first. Each “page” consists of a bop command, followed by any number of other commands that tell where characters are to be placed on a physical page, followed by an eop command. The pages appear in the order that they were generated, not in any particular numerical order. If we ignore nop commands and fnt def commands (which are allowed between any two commands in the file), each eop command is immediately followed by a bop command, or by a post command; in the latter case, there are no more pages in the file, and the remaining bytes form the postamble. Further details about the postamble will be explained later.

Some parameters in commands are “pointers.” These are four-byte quantities that give the location number of some other byte in the file; the first byte is number 0, then comes number 1, and so on. For example, one of the parameters of a bop command points to the previous bop; this makes it feasible to read the pages in backwards order, in case the results are being directed to a device that stacks its output face up. Suppose the preamble of a file occupies bytes 0 to 99. Now if the first page occupies bytes 100 to 999, say, and if the second page occupies bytes 1000 to 1999, then the bop that starts in byte 1000 points to 100 and the bop that starts in byte 2000 points to 1000. (The very first bop, i.e., the one that starts in byte 100, has a pointer of −1.)

15. The format is intended to be both compact and easily interpreted by a machine. Compactness is achieved by making most of the information implicit instead of explicit. When a -reading program reads the commands for a page, it keeps track of several quantities: (a) The current font f is an integer; this value is changed only by fnt and fnt num commands. (b) The current position on the page is given by two numbers called the horizontal and vertical coordinates, h and v. Both coordinates are zero at the upper left corner of the page; moving to the right corresponds to increasing the horizontal coordinate, and moving down corresponds to increasing the vertical coordinate. Thus, the coordinates are essentially Cartesian, except that vertical directions are flipped; the Cartesian version of (h, v) would be (h, −v). (c) The current spacing amounts are given by four numbers w, x, y, and z, where w and x are used for horizontal spacing and where y and z are used for vertical spacing. (d) There is a stack containing (h, v, w, x, y, z) values; the commands push and pop are used to change the current level of operation. Note that the current font f is not pushed and popped; the stack contains only information about positioning.

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

§16  DVIDOC  DEVICE-INDEPENDENT FILE FORMAT 7

16. Here is a list of all the commands that may appear in a file. Each command is specified by its symbolic name (e.g., bop), its opcode byte (e.g., 139), and its parameters (if any). The parameters are followed by a bracketed number telling how many bytes they occupy; for example, ‘p[4]’ means that parameter p is four bytes long.

set char 0 0. Typeset character number 0 from font f such that the reference point of the character is at (h, v). Then increase h by the width of that character. Note that a character may have zero or negative width, so one cannot be sure that h will advance after this command; but h usually does increase.

set char 1 through set char 127 (opcodes 1 to 127). Do the operations of set char 0 ; but use the character

whose number matches the opcode, instead of character 0. set1 128 c[1]. Same as set char 0 , except that character number c is typeset. TEX82 uses this command

for characters in the range 128 ≤ c < 256. set2 129 c[2]. Same as set1 , except that c is two bytes long, so it is in the range 0 ≤ c < 65536. TEX82

never uses this command, which is intended for processors that deal with oriental languages; but will allow character codes greater than 255, assuming that they all have the same width as the character whose code is c mod 256.

set3 130 c[3]. Same as set1 , except that c is three bytes long, so it can be as large as 2^{24} − 1. set4 131 c[4]. Same as set1 , except that c is four bytes long, possibly even negative. Imagine that. set rule 132 a[4] b[4]. Typeset a solid black rectangle of height a and width b, with its bottom left corner

at (h, v). Then set h ← h + b. If either a ≤ 0 or b ≤ 0, nothing should be typeset. Note that if b < 0, the value of h will decrease even though nothing else happens. Programs that typeset from files should be careful to make the rules line up carefully with digitized characters, as explained in connection with the rule pixels subroutine below.

put1 133 c[1]. Typeset character number c from font f such that the reference point of the character is at (h, v). (The ‘put’ commands are exactly like the ‘set’ commands, except that they simply put out a character or a rule without moving the reference point afterwards.)

put2 134 c[2]. Same as set2 , except that h is not changed. put3 135 c[3]. Same as set3 , except that h is not changed. put4 136 c[4]. Same as set4 , except that h is not changed. put rule 137 a[4] b[4]. Same as set rule, except that h is not changed. nop 138. No operation, do nothing. Any number of nop’s may occur between commands, but a nop

cannot be inserted between a command and its parameters or between two parameters. bop 139 c_{0}[4] c_{1}[4] … c_{9}[4] p[4]. Beginning of a page: Set (h, v, w, x, y, z) ← (0, 0, 0, 0, 0, 0) and set the

stack empty. Set the current font f to an undefined value. The ten c_{i} parameters can be used to identify pages, if a user wants to print only part of a file; TEX82 gives them the values of … at the time was invoked for this page. The parameter p points to the previous bop command in the file, where the first bop has p = −1.

eop 140. End of page: Print what you have read since the previous bop. At this point the stack should be empty. (The -reading programs that drive most output devices will have kept a buffer of the material that appears on the page that has just ended. This material is largely, but not entirely, in order by v coordinate and (for fixed v) by h coordinate; so it usually needs to be sorted into some order that is appropriate for the device in question. does not do such sorting.)

push 141. Push the current values of (h, v, w, x, y, z) onto the top of the stack; do not change any of these

values. Note that f is not pushed. pop 142. Pop the top six values off of the stack and assign them to (h, v, w, x, y, z). The number of pops

should never exceed the number of pushes, since it would be highly embarrassing if the stack were empty at the time of a pop command.

right1 143 b[1]. Set h ← h + b, i.e., move right b units. The parameter is a signed number in two’s complement notation, −128 ≤ b < 128; if b < 0, the reference point actually moves left.

8  DEVICE-INDEPENDENT FILE FORMAT  DVIDOC §16

right2 144 b[2]. Same as right1 , except that b is a two-byte quantity in the range −32768 ≤ b < 32768. right3 145 b[3]. Same as right1 , except that b is a three-byte quantity in the range −2^{23} ≤ b < 2^{23}. right4 146 b[4]. Same as right1 , except that b is a four-byte quantity in the range −2^{31} ≤ b < 2^{31}. w0 147. Set h ← h + w; i.e., move right w units. With luck, this parameterless command will usually

suffice, because the same kind of motion will occur several times in succession; the following commands explain how w gets particular values.

w1 148 b[1]. Set w ← b and h ← h + b. The value of b is a signed quantity in two’s complement notation,

−128 ≤ b < 128. This command changes the current w spacing and moves right by b. w2 149 b[2]. Same as w1 , but b is a two-byte-long parameter, −32768 ≤ b < 32768. w3 150 b[3]. Same as w1 , but b is a three-byte-long parameter, −2^{23} ≤ b < 2^{23}. w4 151 b[4]. Same as w1 , but b is a four-byte-long parameter, −2^{31} ≤ b < 2^{31}. x0 152. Set h ← h + x; i.e., move right x units. The ‘x’ commands are like the ‘w’ commands except that

they involve x instead of w. x1 153 b[1]. Set x ← b and h ← h + b. The value of b is a signed quantity in two’s complement notation,

−128 ≤ b < 128. This command changes the current x spacing and moves right by b. x2 154 b[2]. Same as x1 , but b is a two-byte-long parameter, −32768 ≤ b < 32768. x3 155 b[3]. Same as x1 , but b is a three-byte-long parameter, −2^{23} ≤ b < 2^{23}. x4 156 b[4]. Same as x1 , but b is a four-byte-long parameter, −2^{31} ≤ b < 2^{31}. down1 157 a[1]. Set v ← v + a, i.e., move down a units. The parameter is a signed number in two’s

complement notation, −128 ≤ a < 128; if a < 0, the reference point actually moves up. down2 158 a[2]. Same as down1 , except that a is a two-byte quantity in the range −32768 ≤ a < 32768. down3 159 a[3]. Same as down1 , except that a is a three-byte quantity in the range −2^{23} ≤ a < 2^{23}. down4 160 a[4]. Same as down1 , except that a is a four-byte quantity in the range −2^{31} ≤ a < 2^{31}. y0 161. Set v ← v + y; i.e., move down y units. With luck, this parameterless command will usually

suffice, because the same kind of motion will occur several times in succession; the following commands explain how y gets particular values.

y1 162 a[1]. Set y ← a and v ← v + a. The value of a is a signed quantity in two’s complement notation,

−128 ≤ a < 128. This command changes the current y spacing and moves down by a. y2 163 a[2]. Same as y1 , but a is a two-byte-long parameter, −32768 ≤ a < 32768. y3 164 a[3]. Same as y1 , but a is a three-byte-long parameter, −2^{23} ≤ a < 2^{23}. y4 165 a[4]. Same as y1 , but a is a four-byte-long parameter, −2^{31} ≤ a < 2^{31}. z0 166. Set v ← v + z; i.e., move down z units. The ‘z’ commands are like the ‘y’ commands except that

they involve z instead of y. z1 167 a[1]. Set z ← a and v ← v + a. The value of a is a signed quantity in two’s complement notation,

−128 ≤ a < 128. This command changes the current z spacing and moves down by a. z2 168 a[2]. Same as z1 , but a is a two-byte-long parameter, −32768 ≤ a < 32768. z3 169 a[3]. Same as z1 , but a is a three-byte-long parameter, −2^{23} ≤ a < 2^{23}. z4 170 a[4]. Same as z1 , but a is a four-byte-long parameter, −2^{31} ≤ a < 2^{31}. fnt num 0 171. Set f ← 0. Font 0 must previously have been defined by a fnt def instruction, as explained

below. fnt num 1 through fnt num 63 (opcodes 172 to 234). Set f ← 1, …, f ← 63, respectively. fnt1 235 k[1]. Set f ← k. TEX82 uses this command for font numbers in the range 64 ≤ k < 256. fnt2 236 k[2]. Same as fnt1 , except that k is two bytes long, so it is in the range 0 ≤ k < 65536. TEX82

never generates this command, but large font numbers may prove useful for specifications of color or texture, or they may be used for special fonts that have fixed numbers in some external coding scheme.

§16  DVIDOC  DEVICE-INDEPENDENT FILE FORMAT 9

fnt3 237 k[3]. Same as fnt1 , except that k is three bytes long, so it can be as large as 2^{24} − 1. fnt4 238 k[4]. Same as fnt1 , except that k is four bytes long; this is for the really big font numbers (and

for the negative ones). xxx1 239 k[1] x[k]. This command is undefined in general; it functions as a (k + 2)-byte nop unless special

-reading programs are being used. TEX82 generates xxx1 when a short enough appears, setting k to the number of bytes being sent. It is recommended that x be a string having the form of a keyword followed by possible parameters relevant to that keyword.

xxx2 240 k[2] x[k]. Like xxx1 , but 0 ≤ k < 65536. xxx3 241 k[3] x[k]. Like xxx1 , but 0 ≤ k < 2^{24}. xxx4 242 k[4] x[k]. Like xxx1 , but k can be ridiculously large. TEX82 uses xxx4 when xxx1 would be

incorrect. fnt def1 243 k[1] c[4] s[4] d[4] a[1] l[1] n[a + l]. Define font k, where 0 ≤ k < 256; font definitions will be

explained shortly. fnt def2 244 k[2] c[4] s[4] d[4] a[1] l[1] n[a + l]. Define font k, where 0 ≤ k < 65536. fnt def3 245 k[3] c[4] s[4] d[4] a[1] l[1] n[a + l]. Define font k, where 0 ≤ k < 2^{24}. fnt def4 246 k[4] c[4] s[4] d[4] a[1] l[1] n[a + l]. Define font k, where −2^{31} ≤ k < 2^{31}. pre 247 i[1] num[4] den[4] mag [4] k[1] x[k]. Beginning of the preamble; this must come at the very

beginning of the file. Parameters i, num, den, mag , k, and x are explained below. post 248. Beginning of the postamble, see below. post post 249. Ending of the postamble, see below.

Commands 250–255 are undefined at the present time.

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

18. The preamble contains basic information about the file as a whole. As stated above, there are six parameters:

i[1] num[4] den[4] mag [4] k[1] x[k].

The i byte identifies format; currently this byte is always set to 2. (Some day we will set i = 3, when format makes another incompatible change—perhaps in 1992.)

The next two parameters, num and den, are positive integers that define the units of measurement; they are the numerator and denominator of a fraction by which all dimensions in the file could be multiplied in order to get lengths in units of 10^{−7} meters. (For example, there are exactly 7227 TEX points in 254 centimeters, and TEX82 works with scaled points where there are 2^{16} sp in a point, so TEX82 sets num = 25400000 and den = 7227 · 2^{16} = 473628672.)

The mag parameter is what TEX82 calls , i.e., 1000 times the desired magnification. The actual fraction by which dimensions are multiplied is therefore mn/1000d. Note that if a TEX source document does not call for any ‘ ’ dimensions, and if you change it only by specifying a different setting, the file that TEX creates will be completely unchanged except for the value of mag in the preamble and postamble. (Fancy -reading programs allow users to override the mag setting when a file is being printed.)

Finally, k and x allow the writer to include a comment, which is not interpreted further. The length of comment x is k, where 0 ≤ k < 256.

define id byte = 2 { identifies the kind of files described here } 19. Font definitions for a given font number k contain further parameters

c[4] s[4] d[4] a[1] l[1] n[a + l].

The four-byte value c is the check sum that TEX (or whatever program generated the file) found in the file for this font; c should match the check sum of the font found by programs that read this file.

Parameter s contains a fixed-point scale factor that is applied to the character widths in font k; font dimensions in files and other font files are relative to this quantity, which is always positive and less than 2^{27}. It is given in the same units as the other dimensions of the file. Parameter d is similar to s; it is the “design size,” and it is given in units that have not been corrected for the magnification mag found in the preamble. Thus, font k is to be used at mag · s/1000d times its normal size.

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

Font definitions must appear before the first use of a particular font number. Once font k is defined, it must not be defined again; however, we shall see below that font definitions appear in the postamble as well as in the pages, so in this sense each font number is defined exactly twice, if at all. Like nop commands and xxx commands, font definitions can appear before the first bop, or between an eop and a bop.

20. The last page in a file is followed by ‘post ’; this command introduces the postamble, which summarizes important facts that TEX has accumulated about the file, making it possible to print subsets of the data with reasonable efficiency. The postamble has the form

post p[4] num[4] den[4] mag [4] l[4] u[4] s[2] t[2] ⟨ font definitions ⟩ post post q[4] i[1] 223’s[≥4]

Here p is a pointer to the final bop in the file. The next three parameters, num, den, and mag , are duplicates of the quantities that appeared in the preamble.

Parameters l and u give respectively the height-plus-depth of the tallest page and the width of the widest page, in the same units as other dimensions of the file. These numbers might be used by a -reading program to position individual “pages” on large sheets of film or paper; however, the standard convention for output on normal size paper is to position each page so that the upper left-hand corner is exactly one inch from the left and the top. Experience has shown that it is unwise to design -to-printer software that attempts cleverly to center the output; a fixed position of the upper left corner is easiest for users to understand and to work with. Therefore l and u are often ignored.

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

The postamble continues with font definitions, which are any number of fnt def commands as described above, possibly interspersed with nop commands. Each font number that is used in the file must be defined exactly twice: Once before it is first selected by a fnt command, and once in the postamble.

21. The last part of the postamble, following the post post byte that signifies the end of the font definitions, contains q, a pointer to the post command that started the postamble. An identification byte, i, comes next; this currently equals 2, as in the preamble.

The i byte is followed by four or more bytes that are all equal to the decimal number 223 (i.e., ´ 337 in octal). TEX puts out four to seven of these trailing bytes, until the total length of the file is a multiple of four bytes, since this works out best on machines that pack four bytes per word; but any number of 223’s is allowed, as long as there are at least four of them. In effect, 223 is a sort of signature that is added at the very end.

This curious way to finish off a file makes it feasible for -reading programs to find the postamble first, on most computers, even though TEX wants to write the postamble last. Most operating systems permit random access to individual words or bytes of a file, so the reader can start at the end and skip backwards over the 223’s until finding the identification byte. Then it can back up four bytes, read q, and move to byte q of the file. This byte should, of course, contain the value 248 (post ); now the postamble can be read, so the reader discovers all the information needed for typesetting the pages. Note that it is also possible to skip through the file at reasonably high speed to locate a particular page, if that proves desirable. This saves a lot of time, since files used in production jobs tend to be large.

When ”typesets” a character, it simply puts its ASCII code into the document file in the proper place according to the rounding of h and v to whole character positions. It may, of course, obliterate a character previously stored in the same position. Especially if a symbol font is being used, the ASCII code may print ultimately as an entirely different character than the one the document designer originally intended. For to produce more than a rough approximation to the intended document, fonts need to be chosen very carefully.

§22  DVIDOC  INPUT FROM BINARY FILES 13

22. Input from binary files. We have seen that a file is a sequence of 8-bit bytes. The bytes appear physically in what is called a ‘packed file of 0 . . 255’ in Pascal lingo.

Packing is system dependent, and many Pascal systems fail to implement such files in a sensible way (at least, from the viewpoint of producing good production software). For example, some systems treat all byte-oriented files as text, looking for end-of-line marks and such things. Therefore some system-dependent code is often needed to deal with binary files, even though most of the program in this section of is written in standard Pascal.

One common way to solve the problem is to consider files of integer numbers, and to convert an integer in the range −2^{31} ≤ x < 2^{31} to a sequence of four bytes (a, b, c, d) using the following code, which avoids the controversial integer division of negative numbers:

if x ≥ 0 then a ← x div ´ 100000000

else begin x ← (x + ´ 10000000000 ) + ´ 10000000000 ; a ← x div ´ 100000000 + 128;

end x ← x mod ´ 100000000 ; b ← x div ´ 200000 ; x ← x mod ´ 200000 ; c ← x div ´ 400 ; d ← x mod ´ 400 ;

The four bytes are then kept in a buffer and output one by one. (On 36-bit computers, an additional division by 16 is necessary at the beginning. Another way to separate an integer into four bytes is to use/abuse Pascal’s variant records, storing an integer and retrieving bytes that are packed in the same place; caveat implementor!) It is also desirable in some cases to read a hundred or so integers at a time, maintaining a larger buffer.

We shall stick to simple Pascal in this program, for reasons of clarity, even if such simplicity is sometimes unrealistic. ⟨ Types in the outer block 9 ⟩ +≡

eight bits = integer ; { unsigned one-byte quantity }

byte file = packed file of char ; { files that contain binary data }

23. The program deals with two binary file variables: dvi file is the main input file that we are translating into symbolic form, and tfm file is the current font metric file from which character-width information is being read. ⟨ Globals in the outer block 11 ⟩ +≡ dvi file: byte file; { the stuff we are typing } eof dvi file: boolean; { end of file on file } tfm file: byte file; { a font metric file }

24. To prepare these files for input, we reset them. An extension of Pascal is needed in the case of tfm file, since we want to associate it with external files whose names are specified dynamically (i.e., not known at compile time). The following code assumes that ‘reset (f, s)’ does this, when f is a file variable and s is a string variable that specifies the file name. If eof (f) is true immediately after reset (f, s) has acted, we assume that no file named s is accessible.

define read access mode = 4 { “read” mode for test access }

define write access mode = 2 { “write” mode for test access }

define no file path = 0 { no path searching should be done }

define font file path = 3 { path specifier for files }

14  INPUT FROM BINARY FILES  DVIDOC §25

25. We try to open the input file and append .dvi if it doesn’t have this extension already. ⟨ Open input file 25 ⟩ ≡

i ← 1;

while (i < name length) ∧ (base name[i] ≠ ´ ␣´ ) do incr (i);

if i < 5 then begin base name[i] ← ´ ´ ; base name[i + 1] ← ´ ´ ; base name[i + 2] ← ´ ´ ; base name[i + 3] ← ´ ´ ; base name[i + 4] ← ´ ␣´ ; end;

if (i ≥ 5) ∧ (i < name length − 4) ∧ ((base name[i − 4] ≠ ´ ´ ) ∨ (base name[i − 3] ≠

´´ ) ∨ (base name[i − 2] ≠ ´ ´ ) ∨ (base name[i − 1] ≠ ´ ´ )) then begin base name[i] ← ´ ´ ; base name[i + 1] ← ´ ´ ; base name[i + 2] ← ´ ´ ; base name[i + 3] ← ´ ´ ; base name[i + 4] ← ´ ␣´ ; end;

cur name ← base name;

if test access (read access mode, no file path) then begin open dvi file; if eof (dvi file) then cannot start (´ ␣ ␣ ␣ ´ ) end

else cannot start (´ ␣ ␣ ␣ ´ );

This code is used in 102.

26. Procedure to open TFM file. procedure open tfm file; { prepares to read packed bytes in tfm file }

begin if test access (read access mode, font file path) then reset (tfm file, real name of file)

else begin error (´ ␣ ␣ ␣ ´ ); goto done;

end; end;

27. If you looked carefully at the preceding code, you probably asked, “What are cur loc and cur name?” Good question. They’re global variables: cur loc is the number of the byte about to be read next from dvi file, and cur name is a string variable that will be set to the current font metric file name before open tfm file is called. ⟨ Globals in the outer block 11 ⟩ +≡ cur loc: integer ; { where we are about to look, in dvi file } base name, cur name, real name of file: packed array [1 . . name length] of char ;

{ external name, with no upper case letters }

28. It turns out to be convenient to read four bytes at a time, when we are inputting from files. The input goes into global variables b0 , b1 , b2 , and b3 , with b0 getting the first byte and b3 the fourth. ⟨ Globals in the outer block 11 ⟩ +≡ b0 , b1 , b2 , b3 : eight bits ; { four bytes input at once }

29. The read tfm word procedure sets b0 through b3 to the next four bytes in the current file.

define get tfm byte(#) ≡ read (tfm file, byte); # ← ord (byte);

if # < 0 then # ← # + 256;

procedure read tfm word ; var byte: char ; begin get tfm byte(b0 ); get tfm byte(b1 ); get tfm byte(b2 ); get tfm byte(b3 ); end; 30. Finally we come to the routines that are used for random reading. The driver program below needs two such routines: dvi length should compute the total number of bytes in dvi file, possibly also causing eof (dvi file) to be true; and move to byte(n) should position dvi file so that the next get byte will read byte n, starting with n = 0 for the first byte in the file.

Such routines are, of course, highly system dependent. They are implemented here in terms of two assumed system routines called set pos and cur pos . The call set pos (f, n) moves to item n in file f, unless n is negative or larger than the total number of items in f; in the latter case, set pos (f, n) moves to the end of file f. The call cur pos (f) gives the total number of items in f, if eof (f) is true; we use cur pos only in such a situation. function dvi length: integer ;

begin set pos (dvi file, −1); dvi length ← cur pos (dvi file);

end; procedure move to byte(n : integer );

begin set pos (dvi file, n); cur loc ← n;

16  READING THE FONT INFORMATION  DVIDOC §31

end; 31. Reading the font information. file format does not include information about character widths, since that would tend to make the files a lot longer. But a program that reads a file is supposed to know the widths of the characters that appear in set char commands. Therefore looks at the font metric ( ) files for the fonts that are involved.

The character-width data appears also in other files (e.g., in files that specify bit patterns for digitized characters); thus, it is usually possible for reading programs to get by with accessing only one file per font. has a comparatively easy task in this regard, since it needs only a few words of information from each font; other -to-printer programs may have to go to some pains to deal with complications that arise when a large number of large font files all need to be accessed simultaneously.

32. For purposes of this program, we need to know only two things about a given character c in a given font f: (1) Is c a legal character in f? (2) If so, what is the width of c? We also need to know the symbolic name of each font, so it can be printed out, and we need to know the approximate size of inter-word spaces in each font.

The answers to these questions appear implicitly in the following data structures. The current number of known fonts is nf . Each known font has an internal number f, where 0 ≤ f < nf ; the external number of this font, i.e., its font identification number in the file, is font num[f], and the external name of this font is the string that occupies positions font name[f] through font name[f + 1] − 1 of the array names . The latter array consists of ASCII code characters, and font name[nf ] is its first unoccupied position. A horizontal motion in the range −4 ∗ font space[f] < h < font space[f] will be treated as a ‘kern’ that is not indicated in the printouts that produces between brackets. The legal characters run from font bc[f] to font ec[f], inclusive; more precisely, a given character c is valid in font f if and only if font bc[f] ≤ c ≤ font ec[f] and char width(f)(c) ≠ invalid width. Finally, char width(f)(c) = width[width base[f] + c], and width ptr is the first unused position of the width array.

define char width end (#) ≡ # ]

define char width(#) ≡ width [ width base[#] + char width end

define invalid width ≡ ´ 17777777777 ⟨ Globals in the outer block 11 ⟩ +≡ font num: array [0 . . max fonts ] of integer ; { external font numbers } font name: array [0 . . max fonts ] of 0 . . name size; { starting positions of external font names } names : array [0 . . name size] of ASCII code; { characters of names } font check sum: array [0 . . max fonts ] of integer ; { check sums } font scaled size: array [0 . . max fonts ] of integer ; { scale factors } font design size: array [0 . . max fonts ] of integer ; { design sizes } font space: array [0 . . max fonts ] of integer ; { boundary between “small” and “large” spaces } font bc: array [0 . . max fonts ] of integer ; { beginning characters in fonts } font ec: array [0 . . max fonts ] of integer ; { ending characters in fonts } width base: array [0 . . max fonts ] of integer ; { index into width table } width: array [0 . . max widths ] of integer ; { character widths, in units } nf : 0 . . max fonts ; { the number of known fonts } width ptr : 0 . . max widths ; { the number of known character widths }

§34  DVIDOC  READING THE FONT INFORMATION 17

33. ⟨ Set initial values 12 ⟩ +≡ nf ← 0; width ptr ← 0; font name[0] ← 0; font space[0] ← 0; 34. It is, of course, a simple matter to print the name of a given font. procedure print font (f : integer ); { f is an internal font number }

var k: 0 . . name size; { index into names }

begin if f = nf then print (´ ´ )

else begin for k ← font name[f] to font name[f + 1] − 1 do print (xchr [names [k]]);

end; end;

35. An auxiliary array in width is used to hold the widths as they are input. The global variable tfm check sum is set to the check sum that appears in the current file. ⟨ Globals in the outer block 11 ⟩ +≡ in width: array [0 . . 255] of integer ; { width data in units } tfm check sum: integer ; { check sum found in tfm file }

36. Here is a procedure that absorbs the necessary information from a file, assuming that the file has just been successfully reset so that we are ready to read its first byte. (A complete description of file format appears in the documentation of and will not be repeated here.) The procedure does not

check the  file for validity, nor does it give explicit information about what is wrong with a  file that
proves to be invalid;  -reading programs need not do this, since  files are almost always valid, and
since the  utility program has been specifically designed to diagnose  errors. The procedure simply

returns false if it detects anything amiss in the data.

There is a parameter, z, which represents the scaling factor being used to compute the font dimensions; it must be in the range 0 < z < 2^{27}. function in TFM (z : integer ): boolean; { input data or return false }

label 9997, { go here when the format is bad } 9998, { go here when the information cannot be loaded } 9999; { go here to exit }

var k: integer ; { index for loops } lh: integer ; { length of the header data, in four-byte words } nw : integer ; { number of words in the width table } wp: 0 . . max widths ; { new value of width ptr after successful input } alpha, beta: integer ; { quantities used in the scaling computation }

begin ⟨ Read past the header data; goto 9997 if there is a problem 37 ⟩;

⟨ Store character-width indices at the end of the width table 38 ⟩;

⟨ Read and convert the width values, setting up the in width table 39 ⟩;

⟨ Move the widths from in width to width, and append pixel width values 42 ⟩;

width ptr ← wp; in TFM ← true; goto 9999; 9997: print ln(´ ␣ ␣ ␣ ␣ ␣ ´ ); 9998: in TFM ← false; 9999: end; 37. ⟨ Read past the header data; goto 9997 if there is a problem 37 ⟩ ≡

read tfm word ; lh ← b2 ∗ 256 + b3 ; read tfm word ; font bc[nf ] ← b0 ∗ 256 + b1 ; font ec[nf ] ← b2 ∗ 256 + b3 ; if font ec[nf ] < font bc[nf ] then font bc[nf ] ← font ec[nf ] + 1; if width ptr + font ec[nf ] − font bc[nf ] + 1 > max widths then

begin print ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); goto 9998; end;

wp ← width ptr + font ec[nf ] − font bc[nf ] + 1; read tfm word ; nw ← b0 ∗ 256 + b1 ; if (nw = 0) ∨ (nw > 256) then goto 9997; for k ← 1 to 3 + lh do

begin if eof (tfm file) then goto 9997;

read tfm word ;

if k = 4 then if b0 < 128 then tfm check sum ← ((b0 ∗ 256 + b1 ) ∗ 256 + b2 ) ∗ 256 + b3 else tfm check sum ← (((b0 − 256) ∗ 256 + b1 ) ∗ 256 + b2 ) ∗ 256 + b3 ;

end;

This code is used in 36.

38. ⟨ Store character-width indices at the end of the width table 38 ⟩ ≡

if wp > 0 then

for k ← width ptr to wp − 1 do begin read tfm word ; if b0 > nw then goto 9997; width[k] ← b0 ; end;

This code is used in 36.

39. The most important part of in TFM is the width computation, which involves multiplying the relative widths in the file by the scaling factor in the file. This fixed-point multiplication must be done with precisely the same accuracy by all -reading programs, in order to validate the assumptions made by -writing programs like TEX82.

Let us therefore summarize what needs to be done. Each width in a file appears as a four-byte quantity called a fix word . A fix word whose respective bytes are (a, b, c, d) represents the number

x = \begin{cases}b · 2^{−4} + c · 2^{−12} + d · 2^{−20}, & if a = 0; \\ −16 + b · 2^{−4} + c · 2^{−12} + d · 2^{−20}, & if a = 255. \end{cases}

(No other choices of a are allowed, since the magnitude of a dimension must be less than 16.) We want to multiply this quantity by the integer z, which is known to be less than 2^{27}. Let α = 16z. If z < 2^{23}, the individual multiplications b · z, c · z, d · z cannot overflow; otherwise we will divide z by 2, 4, 8, or 16, to obtain a multiplier less than 2^{23}, and we can compensate for this later. If z has thereby been replaced by z′ = z/2^{e}, let β = 2^{4−e}; we shall compute

⌊(b + c · 2^{−8} + d · 2^{−16}) z′/β⌋

if a = 0, or the same quantity minus α if a = 255. This calculation must be done exactly, for the reasons stated above; the following program does the job in a system-independent way, assuming that arithmetic is exact on numbers less than 2^{31} in magnitude. ⟨ Read and convert the width values, setting up the in width table 39 ⟩ ≡

⟨ Replace z by z′ and compute α, β 40 ⟩;

for k ← 0 to nw − 1 do begin read tfm word ; in width[k] ← (((((b3 ∗ z) div ´ 400 ) + (b2 ∗ z)) div ´ 400 ) + (b1 ∗ z)) div beta; if b0 > 0 then

if b0 < 255 then goto 9997

else in width[k] ← in width[k] − alpha; end

This code is used in 36.

40. ⟨ Replace z by z′ and compute α, β 40 ⟩ ≡ begin alpha ← 16 ∗ z; beta ← 16; while z ≥ ´ 40000000 do

begin z ← z div 2; beta ← beta div 2;

end; end

This code is used in 39.

41. A -reading program usually works with font files instead of  files, so  is atypical in that

respect. Font files should, however, contain exactly the same character width data that is found in the corresponding s; check sums are used to help ensure this. In addition, font files usually also contain the widths of characters in pixels, since the device-independent character widths of files are generally not perfect multiples of pixels.

The pixel width array contains this information; when width[k] is the device-independent width of some character in units, pixel width[k] is the corresponding width of that character in an actual font. The macro char pixel width is set up to be analogous to char width.

define char pixel width(#) ≡ pixel width [ width base[#] + char width end ⟨ Globals in the outer block 11 ⟩ +≡ pixel width: array [0 . . max widths ] of integer ; { actual character widths, in pixels } horiz conv : real ; { converts units to horizontal pixels } vert conv : real ; { converts units to vertical pixels } true horiz conv : real ; { converts unmagnified units to pixels } true vert conv : real ; { converts unmagnified units to pixels } numerator , denominator : integer ; { stated conversion ratio } mag : integer ; { magnification factor times 1000 }

42. The following code computes pixel widths by simply rounding the widths to the nearest integer number of pixels, based on the conversion factor horiz conv that converts units to pixels. However, such a simple formula will not be valid for all fonts, and it will often give results that are off by ±1 when a lowresolution font has been carefully hand-fitted. For example, a font designer often wants to make the letter ‘m’ a pixel wider or narrower in order to make the font appear more consistent. -to-printer programs should therefore input the correct pixel width information from font files whenever there is a chance that it may differ. A warning message may also be desirable in the case that at least one character is found whose pixel width differs from conv ∗ width by more than a full pixel.

define horiz pixel round (#) ≡ round (horiz conv ∗ (#))

define vert pixel round (#) ≡ round (vert conv ∗ (#)) ⟨ Move the widths from in width to width, and append pixel width values 42 ⟩ ≡

width base[nf ] ← width ptr − font bc[nf ];

if wp > 0 then

for k ← width ptr to wp − 1 do begin width[k] ← in width[width[k]]; pixel width[k] ← horiz pixel round (width[k]); end

This code is used in 36.

§43  DVIDOC  OPTIONAL MODES OF OUTPUT 21

43. Optional modes of output. output will vary depending on some options that the user must specify: The typeout can be confined to a restricted subset of the pages by specifying the desired starting page and the maximum number of pages.

The starting page is specified by giving a sequence of 1 to 10 numbers or asterisks separated by dots. For example, the specification ‘ ’ can be used to refer to a page output by TEX when = 1 and = −5. (Recall that bop commands in a file are followed by ten ‘count’ values.) An asterisk matches any number, so the ‘ ’ in ‘ ’ means that is ignored when specifying the first page. If several pages match the given specification, will begin with the earliest such page in the file. The default specification ‘ ’ (which matches all pages) therefore denotes the page at the beginning of the file. ⟨ Globals in the outer block 11 ⟩ +≡ max pages : integer ; { at most this many bop . . eop pages will be printed } horiz resolution: real ; { pixels per inch } vert resolution: real ; { pixels per inch } new mag : integer ; { if positive, overrides the postamble’s magnification }

44. The starting page specification is recorded in two global arrays called start count and start there. For example, ‘ ’ is represented by start there[0] = true, start count [0] = 1, start there[1] = false, start there[2] = true, start count [2] = −5. We also set start vals = 2, to indicate that count 2 was the last one mentioned. The other values of start count and start there are not important, in this example. ⟨ Globals in the outer block 11 ⟩ +≡ start count : array [0 . . 9] of integer ; { count values to select starting page } start there: array [0 . . 9] of boolean; { is the start count value relevant? } start vals : 0 . . 9; { the last count considered significant } count : array [0 . . 9] of integer ; { the count values on the current page }

45. ⟨ Set initial values 12 ⟩ +≡ max pages ← 1000000; start vals ← 0; start there[0] ← false;

46. Here is a simple subroutine that tests if the current page might be the starting page. function start match: boolean; { does count match the starting spec? }

var k: 0 . . 9; { loop index }

match: boolean; { does everything match so far? } begin match ← true; for k ← 0 to start vals do

if start there[k] ∧ (start count [k] ≠ count [k]) then match ← false; start match ← match; end;

47. The copy ln copies characters from the command line argument in cur name. ⟨ Globals in the outer block 11 ⟩ +≡ buffer : array [0 . . terminal line length] of ASCII code;

48. The count starts at 2 to skip the -x flag characters. We subtract 3 because buffer starts at 0. procedure copy ln; { copies a line from the terminal }

var k: 0 . . terminal line length;

begin k ← 2;

while (k < name length) ∧ (cur name[k] ≠ ´ ␣´ ) do begin buffer [k − 3] ← xord [cur name[k]]; incr (k) end;

buffer [k − 3] ← xord [´ ␣´ ];

end;

22  OPTIONAL MODES OF OUTPUT  DVIDOC §49

49. The global variable buf ptr is used while scanning each line of input; it points to the first unread character in buffer . ⟨ Globals in the outer block 11 ⟩ +≡ buf ptr : 0 . . terminal line length; { the number of characters read }

50. Here is a routine that scans a (possibly signed) integer and computes the decimal value. If no decimal integer starts at buf ptr , the value 0 is returned. The integer should be less than 2^{31} in absolute value. function get integer : integer ;

var x: integer ; { accumulates the value }

negative: boolean; { should the value be negated? } begin if buffer [buf ptr ] = then

begin negative ← true; incr (buf ptr );

end else negative ← false; x ← 0; while (buffer [buf ptr ] ≥ ) ∧ (buffer [buf ptr ] ≤ ) do

begin x ← 10 ∗ x + buffer [buf ptr ] − ; incr (buf ptr ); end;

if negative then get integer ← −x else get integer ← x; end;

51. The selected options are put into global variables by the options procedure, which is called just as begins. procedure options ;

var j, k: integer ; { loop variable } begin log errors ← false; start vals ← 0; start there[0] ← false; max pages ← 1000000; horiz resolution ← 13.76582; { cmtt10 chars per inch } vert resolution ← 6.0225; { 72.27pt/12pt } new mag ← 0; base name[1] ← ´ ␣´ ; j ← 1; while j < argc do

begin argv (j, cur name);

if cur name[1] = ´ ´ then begin if cur name[2] = ´ ´ then log errors ← true else if cur name[2] = ´ ´ then

begin ⟨ Determine the desired start count values 52 ⟩

end else if cur name[2] = ´ ´ then

begin ⟨ Determine the desired max pages 53 ⟩ end

else cannot start (´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ´ ) end

else if base name[1] = ´ ␣´ then argv (j, base name)

else cannot start (´ ␣ ␣ ␣ ␣ ´ ); incr (j) end;

if base name[1] = ´ ␣´ then cannot start (´ ␣ ␣ ␣ ´ ); end; 52. ⟨ Determine the desired start count values 52 ⟩ ≡

copy ln; buf ptr ← 0; k ← 0; if buffer [0] ≠ ␣ then

repeat if buffer [buf ptr ] = then begin start there[k] ← false; incr (buf ptr ); end

else begin start there[k] ← true; start count [k] ← get integer ;

end; if (k < 9) ∧ (buffer [buf ptr ] = ) then

begin incr (k); incr (buf ptr ); end

else if buffer [buf ptr ] = ␣ then start vals ← k

else cannot start (´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ) until start vals = k

This code is used in 51.

53. ⟨ Determine the desired max pages 53 ⟩ ≡ copy ln; buf ptr ← 0; if buffer [0] ≠ ␣ then

begin max pages ← get integer ; if max pages ≤ 0 then cannot start (´ ␣ ␣ ␣ ␣ ␣ ´ ) end

This code is used in 51.

24  DEFINING FONTS  DVIDOC §54

54. Defining fonts. reads the postamble first and loads all of the fonts defined there; then it processes the pages. In this case, a fnt def command should match a previous definition if and only if the fnt def being processed is not in the postamble.

A global variable in postamble is provided to tell whether we are processing the postamble or not. ⟨ Globals in the outer block 11 ⟩ +≡ in postamble: boolean; { are we reading the postamble? }

55. ⟨ Set initial values 12 ⟩ +≡ in postamble ← false;

56. The following subroutine does the necessary things when a fnt def command is being processed. procedure define font (e : integer ); { e is an external font number }

var f: 0 . . max fonts ; p: integer ; { length of the area/directory spec } n: integer ; { length of the font name proper } c, q, d: integer ; { check sum, scaled size, and design size } r: 0 . . name length; { index into cur name } j, k: 0 . . name size; { indices into names } mismatch: boolean; { do names disagree? }

begin if nf = max fonts then abort (´ ␣ ␣ ␣ ␣ ´ , max fonts : 1, ´ ´ ); font num[nf ] ← e; f ← 0; while font num[f] ≠ e do incr (f); ⟨ Read the font parameters into position for font nf , and print the font name 58 ⟩;

if in postamble then

begin if f < nf then print ln(´ ␣ ␣ ␣ ␣ ´ ); end

else begin if f = nf then print ln(´ ␣ ␣ ´ ´ ␣ ␣ ´ );

end; if f = nf then ⟨ Load the new font, unless there are problems 59 ⟩ else ⟨ Check that the current font definition matches the old one 57 ⟩; end;

57. ⟨ Check that the current font definition matches the old one 57 ⟩ ≡

begin if font check sum[f] ≠ c then

print ln(´ ␣ ␣ ´ ´ ␣ ␣ ␣ ´ ); if font scaled size[f] ≠ q then print ln(´ ␣ ␣ ´ ´ ␣ ␣ ␣ ´ ); if font design size[f] ≠ d then print ln(´ ␣ ␣ ´ ´ ␣ ␣ ␣ ´ ); j ← font name[f]; k ← font name[nf ]; mismatch ← false; while j < font name[f + 1] do

begin if names [j] ≠ names [k] then mismatch ← true;

incr (j); incr (k);

end; if k ≠ font name[nf + 1] then mismatch ← true; if mismatch then print ln(´ ␣ ␣ ´ ´ ␣ ␣ ␣ ´ ); print ln(´ ␣´ ) end

This code is used in 56.

§58  DVIDOC  DEFINING FONTS 25

58. ⟨ Read the font parameters into position for font nf , and print the font name 58 ⟩ ≡ c ← signed quad ; font check sum[nf ] ← c; q ← signed quad ; font scaled size[nf ] ← q; d ← signed quad ; font design size[nf ] ← d; p ← get byte; n ← get byte; if font name[nf ] + n + p > name size then

abort (´ ␣ ␣ ␣ ␣ ´ , name size : 1, ´ ´ ); font name[nf + 1] ← font name[nf ] + n + p; print (´ ␣´ , e : 1, ´ ␣´ ); if n + p = 0 then print (´ ␣ ␣ ´ ) else for k ← font name[nf ] to font name[nf + 1] − 1 do names [k] ← get byte; incr (nf ); print font (nf − 1); decr (nf )

This code is used in 56.

59. ⟨ Load the new font, unless there are problems 59 ⟩ ≡ begin ⟨ Move font name into the cur name string 63 ⟩; open tfm file; if eof (tfm file) then print (´ ␣ ␣ ␣ ␣ ´ ´ ␣ ␣ ´ ) else begin if (q ≤ 0) ∨ (q ≥ ´ 1000000000 ) then print (´ ␣ ␣ ␣ ␣ ´ , q : 1, ´ ´ )

else if (d ≤ 0) ∨ (d ≥ ´ 1000000000 ) then print (´ ␣ ␣ ␣ ␣ ␣ ´ , d : 1, ´ ´ )

else if in TFM (q) then ⟨ Finish loading the new font info 60 ⟩; end;

print ln(´ ␣´ ); end

This code is used in 56.

60. ⟨ Finish loading the new font info 60 ⟩ ≡ begin font space[nf ] ← q div 6; { this is a 3-unit “thin space” } if (c ≠ 0) ∧ (tfm check sum ≠ 0) ∧ (c ≠ tfm check sum) then

begin print ln(´ ␣ ␣ ␣ ␣ ␣ ´ );

print ln(´ ␣␣␣ ´ , c : 1, ´ ␣ ␣´ , tfm check sum : 1, ´ ´ ); print (´ ␣␣␣´ );

end; print (´ ␣ ␣ ␣´ , q : 1, ´ ␣ ␣ ´ ); d ← round ((100.0 ∗ horiz conv ∗ q)/(true horiz conv ∗ d)); if d ≠ 100 then

begin print ln(´ ␣´ ); print (´ ␣ ␣ ␣ ␣ ␣´ , d : 1, ´ % ´ );

end; incr (nf ); { now the new font is officially present } font space[nf ] ← 0; { for out space and out vmove } end

This code is used in 59.

61. If p = 0, i.e., if no font directory has been specified, is supposed to use the default font directory, which is a system-dependent place where the standard fonts are kept. The string variable default directory contains the name of this area.

define default directory name ≡ ´ ´ { change this to the correct name } define default directory name length = 9 { change this to the correct length }

⟨ Globals in the outer block 11 ⟩ +≡ default directory : packed array [1 . . default directory name length] of char ;

62. ⟨ Set initial values 12 ⟩ +≡ default directory ← default directory name; 63. The string cur name is supposed to be set to the external name of the file for the current font. This usually means that we need to, at most sites, append the suffix “.tfm”. ⟨ Move font name into the cur name string 63 ⟩ ≡

for k ← 1 to name length do cur name[k] ← ´ ␣´ ; r ← 0; for k ← font name[nf ] to font name[nf + 1] − 1 do

begin incr (r);

if r + 4 > name length then

abort (´ ␣ ␣ ␣ ␣ ␣ ␣ ´ , name length : 1, ´ ´ ); cur name[r] ← xchr [names [k]]; end;

cur name[r + 1] ← ´ ´ ; cur name[r + 2] ← ´ ´ ; cur name[r + 3] ← ´ ´ ; cur name[r + 4] ← ´ ´

This code is used in 59.

§64  DVIDOC  LOW LEVEL OUTPUT ROUTINES 27

64. Low level output routines. Characters set by the file are placed in page buffer , a two dimensional array of characters with one element for each print position on the page. The page buffer is cleared at the beginning of each page and printed at the end of each page. doc file, the file to which the document is destined, is an ordinary text file.

To optimize the initialization and printing of page buffer , a high water mark line number, page hwm, is kept to indicate the last line that contains any printable characters, and for each line a high water mark character number, line hwm, is kept to indicate the location of the last printable character in the line. ⟨ Globals in the outer block 11 ⟩ +≡ i: 1 . . name length; log errors : boolean; err file: text file; page buffer : packed array [1 . . page width max , 1 . . page length max ] of ASCII code;

{ storage for a document page }

line hwm: array [1 . . page length max ] of 0 . . page width max ; { high water marks for each line } page hwm: 0 . . page length max ; { high water mark for page }

65. err file needs to be opened. Create err file with a suffix of .err. ⟨ Create error message file 65 ⟩ ≡

if log errors then

begin cur name ← base name; i ← 1;

while (i ≤ name length) ∧ (cur name[i] ≠ ´ ␣´ ) do incr (i);

cur name[i − 3] ← ´ ´ ; cur name[i − 2] ← ´ ´ ; cur name[i − 1] ← ´ ´ ; if test access (write access mode, no file path) then rewrite(err file, cur name) else cannot start (´ ␣ ␣ ␣ ´ ) end

else begin cur name ← ´ ´ ; if test access (write access mode, no file path) then rewrite(err file, cur name) else cannot start (´ ␣ ␣ ´ ) end;

This code is used in 102.

66. The flush page procedure will print the page buffer . procedure flush page;

var i: 0 . . page width max ; j: 0 . . page length max ;

begin for j ← 1 to page hwm do begin for i ← 1 to line hwm[j] do write(doc file, xchr [page buffer [i, j]]); write ln(doc file) end;

write(doc file, chr (12)) { end the page with a form feed }

end;

67. The empty page procedure will empty the page buffer data structure. procedure empty page;

begin page hwm ← 0

end;

28  LOW LEVEL OUTPUT ROUTINES  DVIDOC §68

68. And the out char procedure puts something into it. The usual printable ASCII characters will be put into the buffer as is. Non-printable characters, including the blank, will be put into the buffer as question mark chracters. procedure out char (p, hh, vv : integer );

var i: 1 . . page width max ; j: 1 . . page length max ;

{ hh and vv range from zero up while i and j range from one up. } k: integer ; c: ASCII code;

begin if (p > ␣ ) ∧ (p ≤ ) then c ← p else c ← xord [´ ´ ]; if (hh > page width max − 1) ∨ (vv > page length max − 1) then

begin print ln(´ ␣´ ); print (´ ␣ ´ , xchr [c], ´ ␣ ␣ ␣ ␣´ , hh + 1 : 1); print ln(´ ␣ ␣ ␣´ , vv + 1 : 1, ´ ´ ); print (´ ␣ ␣ ␣ ␣ ␣ ´ ); print (page width max : 1, ´ ´ , page length max : 1, ´ ´ ); print ln(´ ␣´ ) end

else begin i ← hh + 1; j ← vv + 1;

if j > page hwm then begin { initialize any as yet untouched lines } for k ← page hwm + 1 to j do line hwm[k] ← 0; page hwm ← j end;

if i > line hwm[j] then begin { initialize any as yet untouched characters } for k ← line hwm[j] + 1 to i do page buffer [k, j] ← xord [´ ␣´ ]; line hwm[j] ← i end;

page buffer [i, j] ← c { put the character in its place } end

§69  DVIDOC  TRANSLATION TO SYMBOLIC FORM 29

end; 69. Translation to symbolic form. The main work of is accomplished by the do page procedure, which produces the output for an entire page, assuming that the bop command for that page has already been processed. This procedure is essentially an interpretive routine that reads and acts on the commands.

70. The definition of  files refers to six registers, (h, v, w, x, y, z), which hold integer values in  units.

In practice, we also need registers hh and vv , the pixel analogs of h and v, since it is not always true that hh = horiz pixel round (h) or vv = vert pixel round (v).

The stack of (h, v, w, x, y, z) values is represented by eight arrays called hstack , …, zstack , hhstack , and vvstack . ⟨ Globals in the outer block 11 ⟩ +≡ h, v, w, x, y, z, hh, vv : integer ; { current state values } hstack , vstack , wstack , xstack , ystack , zstack : array [0 . . stack size] of integer ;

{ pushed down values in units }

hhstack , vvstack : array [0 . . stack size] of integer ; { pushed down values in pixels }

71. Three characteristics of the pages (their max v , max h, and max s ) are specified in the postamble, and a warning message is printed if these limits are exceeded. Actually max v is set to the maximum height plus depth of a page, and max h to the maximum width, for purposes of page layout. Since characters can legally be set outside of the page boundaries, it is not an error when max v or max h is exceeded. But max s should not be exceeded.

The postamble also specifies the total number of pages; checks to see if this total is accurate. ⟨ Globals in the outer block 11 ⟩ +≡ max v : integer ; { the value of abs (v) should probably not exceed this } max h: integer ; { the value of abs (h) should probably not exceed this } max s : integer ; { the stack depth should not exceed this } max v so far , max h so far , max s so far : integer ; { the record high levels } total pages : integer ; { the stated total number of pages } page count : integer ; { the total number of pages seen so far }

30  TRANSLATION TO SYMBOLIC FORM  DVIDOC §73

72. ⟨ Set initial values 12 ⟩ +≡ max v ← ´ 17777777777 − 99; max h ← ´ 17777777777 − 99; max s ← stack size + 1; max v so far ← 0; max h so far ← 0; max s so far ← 0; page count ← 0; 73. Before we get into the details of do page, it is convenient to consider a simpler routine that computes the first parameter of each opcode.

define four cases (#) ≡ #, # + 1, # + 2, # + 3 define eight cases (#) ≡ four cases (#), four cases (# + 4) define sixteen cases (#) ≡ eight cases (#), eight cases (# + 8) define thirty two cases (#) ≡ sixteen cases (#), sixteen cases (# + 16) define sixty four cases (#) ≡ thirty two cases (#), thirty two cases (# + 32)

function first par (o : eight bits ): integer ;

begin case o of

sixty four cases (set char 0 ), sixty four cases (set char 0 + 64): first par ← o − set char 0 ; set1 , put1 , fnt1 , xxx1 , fnt def1 : first par ← get byte; set1 + 1, put1 + 1, fnt1 + 1, xxx1 + 1, fnt def1 + 1: first par ← get two bytes ; set1 + 2, put1 + 2, fnt1 + 2, xxx1 + 2, fnt def1 + 2: first par ← get three bytes ; right1 , w1 , x1 , down1 , y1 , z1 : first par ← signed byte; right1 + 1, w1 + 1, x1 + 1, down1 + 1, y1 + 1, z1 + 1: first par ← signed pair ; right1 + 2, w1 + 2, x1 + 2, down1 + 2, y1 + 2, z1 + 2: first par ← signed trio; set1 + 3, set rule, put1 + 3, put rule, right1 + 3, w1 + 3, x1 + 3, down1 + 3, y1 + 3, z1 + 3, fnt1 + 3,

xxx1 + 3, fnt def1 + 3: first par ← signed quad ; nop, bop, eop, push, pop, pre, post , post post , undefined commands : first par ← 0; w0 : first par ← w; x0 : first par ← x; y0 : first par ← y; z0 : first par ← z; sixty four cases (fnt num 0 ): first par ← o − fnt num 0 ; end; end;

74. Here are two other subroutines that we need: They compute the number of pixels in the height or width of a rule. Characters and rules will line up properly if the sizes are computed precisely as specified here. (Since horiz conv and vert conv are computed with some floating-point roundoff error, in a machinedependent way, format designers who are tailoring something for a particular resolution should not plan their measurements to come out to an exact integer number of pixels; they should compute things so that the rule dimensions are a little less than an integer number of pixels, e.g., 4.99 instead of 5.00.) function horiz rule pixels (x : integer ): integer ; { computes ⌈horiz conv · x⌉ }

var n: integer ; begin n ← trunc(horiz conv ∗ x); if n < horiz conv ∗ x then horiz rule pixels ← n + 1 else horiz rule pixels ← n; end;

function vert rule pixels (x : integer ): integer ; { computes ⌈vert conv · x⌉ } var n: integer ; begin n ← trunc(vert conv ∗ x); if n < vert conv ∗ x then vert rule pixels ← n + 1 else vert rule pixels ← n; end; 75. Strictly speaking, the do page procedure is really a function with side effects, not a ‘procedure’ ; it returns the value false if should be aborted because of some unusual happening. The subroutine is organized as a typical interpreter, with a multiway branch on the command code followed by goto statements leading to routines that finish up the activities common to different commands. We will use the following labels:

define fin set = 41 { label for commands that set or put a character }

define fin rule = 42 { label for commands that set or put a rule }

define move right = 43 { label for commands that change h }

define move down = 44 { label for commands that change v }

define show state = 45 { label for commands that change s }

define change font = 46 { label for commands that change cur font }

76. Some Pascal compilers severely restrict the length of procedure bodies, so we shall split do page into two parts, one of which is called special cases . The different parts communicate with each other via the global variables mentioned above, together with the following ones: ⟨ Globals in the outer block 11 ⟩ +≡ s: integer ; { current stack size } ss : integer ; { stack size to print } cur font : integer ; { current internal font number }

77. Here is the overall setup. ⟨ Declare the function called special cases 80 ⟩ function do page: boolean;

label fin set , fin rule, move right , show state, done, 9998, 9999;

var o: eight bits ; { operation code of the current command } p, q: integer ; { parameters of the current command } a: integer ; { byte number of the current command } i, j: integer ; { for loop indices for setting rules } hhh: integer ; { h, rounded to the nearest pixel }

begin empty page; cur font ← nf ; { set current font undefined }

s ← 0; h ← 0; v ← 0; w ← 0; x ← 0; y ← 0; z ← 0; hh ← 0; vv ← 0; { initialize the state variables } while true do ⟨ Translate the next command in the file; goto 9999 with do page = true if it was

eop; goto 9998 if premature termination is needed 78 ⟩;

9998: print ln(´ ´ ); do page ← false; 9999: end;

78. ⟨ Translate the next command in the file; goto 9999 with do page = true if it was eop; goto 9998 if

premature termination is needed 78 ⟩ ≡ begin a ← cur loc; o ← get byte; p ← first par (o); if eof (dvi file) then bad dvi (´ ␣ ␣ ␣ ´ ); ⟨ Start translation of command o and goto the appropriate label to finish the job 79 ⟩;

fin set : ⟨ Finish a command that either sets or puts a character, then goto move right or done 87 ⟩; fin rule: ⟨ Finish a command that either sets or puts a rule, then goto move right or done 88 ⟩; move right : ⟨ Finish a command that sets h ← h + q, then goto done 89 ⟩; show state: ; done: ;

end

This code is used in 77.

79. The multiway switch in first par , above, was organized by the length of each command; the one in do page is organized by the semantics. ⟨ Start translation of command o and goto the appropriate label to finish the job 79 ⟩ ≡

if o < set char 0 + 128 then ⟨ Translate a set char command 86 ⟩

else case o of

four cases (set1 ): begin out char (p, hh, vv ); goto fin set ;

end; set rule: begin goto fin rule;

end; put rule: begin goto fin rule;

end; ⟨ Cases for commands nop, bop, …, pop 81 ⟩ ⟨ Cases for horizontal motion 82 ⟩ othercases if special cases (o, p, a) then goto done else goto 9998 endcases

This code is used in 78.

80. ⟨ Declare the function called special cases 80 ⟩ ≡ function special cases (o : eight bits ; p, a : integer ): boolean;

label change font , move down, done, 9998; var q: integer ; { parameter of the current command }

k: integer ; { loop index }

bad char : boolean; { has a non-ASCII character code appeared in this xxx ? } pure: boolean; { is the command error-free? } vvv : integer ; { v, rounded to the nearest pixel }

begin pure ← true;

case o of

four cases (put1 ): begin goto done;

end; ⟨ Cases for vertical motion 83 ⟩ ⟨ Cases for fonts 84 ⟩ four cases (xxx1 ): ⟨ Translate an xxx command and goto done 85 ⟩; pre: begin error (´ ␣ ␣ ␣ ␣ ´ ); goto 9998;

end; post , post post : begin error (´ ␣ ␣ ␣ ␣ ´ ); goto 9998;

end; othercases begin error (´ ␣ ␣´ , o : 1, ´ ´ ); goto done;

end endcases;

move down: ⟨ Finish a command that sets v ← v + p, then goto done 90 ⟩; change font : ⟨ Finish a command that changes the current font, then goto done 91 ⟩; 9998: pure ← false; done: special cases ← pure;

end;

This code is used in 77.

81. ⟨ Cases for commands nop, bop, …, pop 81 ⟩ ≡ nop: begin goto done;

end; bop: begin error (´ ␣ ␣ ␣ ´ ); goto 9998;

end; eop: begin if s ≠ 0 then error (´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣´ , s : 1, ´ ´ );

do page ← true; flush page; goto 9999; end;

push: begin if s = max s so far then begin max s so far ← s + 1; if s = max s then error (´ ␣ ␣ ␣ ␣ ´ ); if s = stack size then

begin error (´ ␣ ␣ ␣ ␣ ´ , stack size : 1, ´ ´ ); goto 9998; end;

end; hstack [s] ← h; vstack [s] ← v; wstack [s] ← w; xstack [s] ← x; ystack [s] ← y; zstack [s] ← z; hhstack [s] ← hh; vvstack [s] ← vv ; incr (s); ss ← s − 1; goto show state; end;

pop: begin if s = 0 then error (´ ␣ ␣ ␣ ␣ ´ )

else begin decr (s); hh ← hhstack [s]; vv ← vvstack [s]; h ← hstack [s]; v ← vstack [s]; w ← wstack [s]; x ← xstack [s]; y ← ystack [s]; z ← zstack [s]; end;

ss ← s; goto show state; end;

This code is used in 79.

82. Rounding to the nearest pixel is best done in the manner shown here, so as to be inoffensive to the eye: When the horizontal motion is small, like a kern, hh changes by rounding the kern; but when the motion is large, hh changes by rounding the true position h so that accumulated rounding errors disappear.

define out space ≡

if abs (p) ≥ font space[cur font ] then begin hh ← horiz pixel round (h + p); end

else hh ← hh + horiz pixel round (p); q ← p; goto move right

⟨ Cases for horizontal motion 82 ⟩ ≡ four cases (right1 ): begin out space;

end; w0 , four cases (w1 ): begin w ← p; out space;

end; x0 , four cases (x1 ): begin x ← p; out space;

end;

This code is used in 79.

83. Vertical motion is done similarly, but with the threshold between “small” and “large” increased by a factor of five. The idea is to make fractions like “\frac{1}{2}” round consistently, but to absorb accumulated rounding errors in the baseline-skip moves.

define out vmove ≡ if abs (p) ≥ 5 ∗ font space[cur font ] then vv ← vert pixel round (v + p) else vv ← vv + vert pixel round (p);

goto move down

⟨ Cases for vertical motion 83 ⟩ ≡ four cases (down1 ): begin out vmove;

end; y0 , four cases (y1 ): begin y ← p; out vmove;

end; z0 , four cases (z1 ): begin z ← p; out vmove;

end;

This code is used in 80.

84. ⟨ Cases for fonts 84 ⟩ ≡ sixty four cases (fnt num 0 ): begin goto change font ;

end; four cases (fnt1 ): begin goto change font ;

end; four cases (fnt def1 ): begin define font (p); goto done;

end;

This code is used in 80.

85. ⟨ Translate an xxx command and goto done 85 ⟩ ≡ begin print (´ ´ ´ ´ ); bad char ← false; for k ← 1 to p do

begin q ← get byte;

if (q < ␣ ) ∨ (q > ) then bad char ← true; print (xchr [q]); end;

print (´ ´ ´ ´ ); if bad char then error (´ ␣ ␣ ␣ ␣ ´ ); goto done; end

This code is used in 80.

86. ⟨ Translate a set char command 86 ⟩ ≡ begin out char (p, hh, vv ) end

This code is used in 79.

87. ⟨ Finish a command that either sets or puts a character, then goto move right or done 87 ⟩ ≡ if p < 0 then p ← 255 − ((−1 − p) mod 256) else if p ≥ 256 then p ← p mod 256; { width computation for oriental fonts } if (p < font bc[cur font ]) ∨ (p > font ec[cur font ]) then q ← invalid width else q ← char width(cur font )(p); if q = invalid width then

begin error (´ ␣´ , p : 1, ´ ␣ ␣ ␣ ␣´ ); print font (cur font ); if cur font ≠ nf then print (´ ´ ); { font nf has ‘ ’ in its name } end;

if o ≥ put1 then goto done; if q = invalid width then q ← 0 else hh ← hh + char pixel width(cur font )(p);

goto move right

This code is used in 78.

88. ⟨ Finish a command that either sets or puts a rule, then goto move right or done 88 ⟩ ≡ q ← signed quad ; if (p > 0) ∧ (q > 0) then

for i ← hh to hh + horiz rule pixels (q) − 1 do

for j ← vv downto vv − vert rule pixels (p) + 1 do out char (xord [´ ´ ], i, j); if o = put rule then goto done; hh ← hh + horiz rule pixels (q); goto move right

This code is used in 78.

89. Since is intended to diagnose strange errors, it checks carefully to make sure that h and v do not get out of range. Normal -reading programs need not do this.

define infinity ≡ ´ 17777777777 { ∞ (approximately) } define max drift = 2 { we insist that abs(hh − pixel round (h)) ≤ max drift }

⟨ Finish a command that sets h ← h + q, then goto done 89 ⟩ ≡

if (h > 0) ∧ (q > 0) then

if h > infinity − q then begin error (´ ␣ ␣ ␣ ␣ ␣´ , q : 1, ´ ␣ ␣´ , infinity − h : 1); q ← infinity − h; end;

if (h < 0) ∧ (q < 0) then

if −h > q + infinity then begin error (´ ␣ ␣ ␣ ␣ ␣´ , q : 1, ´ ␣ ␣´ , (−h)−infinity : 1); q ← (−h) − infinity ; end;

hhh ← horiz pixel round (h + q); if abs (hhh − hh) > max drift then

if hhh > hh then hh ← hhh − max drift else hh ← hhh + max drift ;

h ← h + q; if abs (h) > max h so far then

begin if abs (h) > max h + 99 then begin error (´ ␣ ´ , max h : 1, ´ ´ ); max h ← abs (h); end;

max h so far ← abs (h);

end;

goto done

This code is used in 78.

90. ⟨ Finish a command that sets v ← v + p, then goto done 90 ⟩ ≡

if (v > 0) ∧ (p > 0) then

if v > infinity − p then begin error (´ ␣ ␣ ␣ ␣ ␣´ , p : 1, ´ ␣ ␣´ , infinity − v : 1); p ← infinity − v; end;

if (v < 0) ∧ (p < 0) then

if −v > p + infinity then begin error (´ ␣ ␣ ␣ ␣ ␣´ , p : 1, ´ ␣ ␣´ , (−v)−infinity : 1); p ← (−v) − infinity ; end;

vvv ← vert pixel round (v + p); if abs (vvv − vv ) > max drift then

if vvv > vv then vv ← vvv − max drift else vv ← vvv + max drift ;

v ← v + p; if abs (v) > max v so far then

begin if abs (v) > max v + 99 then begin error (´ ␣ ´ , max v : 1, ´ ´ ); max v ← abs (v); end;

max v so far ← abs (v);

end;

goto done

This code is used in 80.

91. ⟨ Finish a command that changes the current font, then goto done 91 ⟩ ≡ font num[nf ] ← p; cur font ← 0; while font num[cur font ] ≠ p do incr (cur font );

goto done

This code is used in 80.

38  SKIPPING PAGES  DVIDOC §92

92. Skipping pages.

93. Global variables called old backpointer and new backpointer are used to check whether the back pointers are properly set up. Another one tells whether we have already found the starting page. ⟨ Globals in the outer block 11 ⟩ +≡ old backpointer : integer ; { the previous bop command location } new backpointer : integer ; { the current bop command location } started : boolean; { has the starting page been found? }

94. ⟨ Set initial values 12 ⟩ +≡ old backpointer ← −1; started ← false;

95. ⟨ Pass a bop command, setting up the count array 95 ⟩ ≡ new backpointer ← cur loc − 1; incr (page count ); for k ← 0 to 9 do count [k] ← signed quad ; if signed quad ≠ old backpointer then

print ln(´ ␣ ␣ ␣´ , cur loc − 4 : 1, ´ ␣ ␣ ␣´ , old backpointer : 1, ´ ´ ); old backpointer ← new backpointer

This code is used in 106.

§96  DVIDOC  USING THE BACKPOINTERS 39

96. Using the backpointers. First comes a routine that illustrates how to find the postamble quickly. ⟨ Find the postamble, working back from the end 96 ⟩ ≡

n ← dvi length; if n < 53 then bad dvi (´ ␣´ , n : 1, ´ ␣ ␣ ´ ); m ← n − 4; repeat if m = 0 then bad dvi (´ ␣ ´ );

move to byte(m); k ← get byte; decr (m); until k ≠ 223; if k ≠ id byte then bad dvi (´ ␣ ␣ ␣´ , k : 1); move to byte(m − 3); q ← signed quad ; if (q < 0) ∨ (q > m − 33) then bad dvi (´ ␣ ␣´ , q : 1, ´ ␣ ␣ ␣´ , m − 3 : 1); move to byte(q); k ← get byte; if k ≠ post then bad dvi (´ ␣´ , q : 1, ´ ␣ ␣ ␣ ´ ); post loc ← q; first backpointer ← signed quad

This code is used in 102.

97. Note that the last steps of the above code save the locations of the the post byte and the final bop. We had better declare these global variables, together with another one that we will need shortly. ⟨ Globals in the outer block 11 ⟩ +≡ post loc: integer ; { byte location where the postamble begins } first backpointer : integer ; { the pointer following post } start loc: integer ; { byte location of the first page to process }

98. The next little routine shows how the backpointers can be followed to move through a file in reverse order. Ordinarily a -reading program would do this only if it wants to print the pages backwards or if it wants to find a specified starting page that is not necessarily the first page in the file; otherwise it would of course be simpler and faster just to read the whole file from the beginning. ⟨ Count the pages and move to the starting page 98 ⟩ ≡

q ← post loc; p ← first backpointer ; start loc ← −1; if p ≥ 0 then

repeat { now q points to a post or bop command; p ≥ 0 is prev pointer } if p > q − 46 then bad dvi (´ ␣ ␣´ , p : 1, ´ ␣ ␣ ␣´ , q : 1); q ← p; move to byte(q); k ← get byte; if k = bop then incr (page count ) else bad dvi (´ ␣´ , q : 1, ´ ␣ ␣ ␣ ´ ); for k ← 0 to 9 do count [k] ← signed quad ; if start match then start loc ← q; p ← signed quad ;

until p < 0; if start loc < 0 then abort (´ ␣ ␣ ␣ ␣ ␣ ␣ ´ ); move to byte(start loc + 1); old backpointer ← start loc; for k ← 0 to 9 do count [k] ← signed quad ; p ← signed quad ; started ← true

This code is used in 102.

40  READING THE POSTAMBLE  DVIDOC §99

99. Reading the postamble. Now imagine that we are reading the file and positioned just four bytes after the post command. That, in fact, is the situation, when the following part of is called upon to read, translate, and check the rest of the postamble. procedure read postamble;

var k: integer ; { loop index }

p, q, m: integer ; { general purpose registers } begin post loc ← cur loc − 5; if signed quad ≠ numerator then print ln(´ ␣ ´ ´ ␣ ␣ ␣ ´ ); if signed quad ≠ denominator then print ln(´ ␣ ´ ´ ␣ ␣ ␣ ´ ); if signed quad ≠ mag then

if new mag = 0 then print ln(´ ␣ ´ ´ ␣ ␣ ␣ ´ ); max v ← signed quad ; max h ← signed quad ; max s ← get two bytes ; total pages ← get two bytes ; ⟨ Process the font definitions of the postamble 101 ⟩; ⟨ Make sure that the end of the file is well-formed 100 ⟩; end;

100. When we get to the present code, the post post command has just been read. ⟨ Make sure that the end of the file is well-formed 100 ⟩ ≡

q ← signed quad ; if q ≠ post loc then print ln(´ ␣ ␣ ␣ ␣ ␣´ , cur loc − 4 : 1, ´ ´ ); m ← get byte; if m ≠ id byte then

print ln(´ ␣ ␣ ␣´ , cur loc − 1 : 1, ´ ␣ ␣ ␣´ , id byte : 1, ´ ´ ); k ← cur loc; m ← 223; while (m = 223) ∧ ¬eof (dvi file) do m ← get byte; if ¬eof (dvi file) then bad dvi (´ ␣ ␣ ␣´ , cur loc − 1 : 1, ´ ␣ ␣ ␣ ´ ) else if cur loc < k + 4 then

print ln(´ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ␣ ´ , cur loc − k : 1, ´ ´ );

This code is used in 99.

101. ⟨ Process the font definitions of the postamble 101 ⟩ ≡

repeat k ← get byte;

if (k ≥ fnt def1 ) ∧ (k < fnt def1 + 4) then begin p ← first par (k); define font (p); print ln(´ ␣´ ); k ← nop; end;

until k ≠ nop; if k ≠ post post then print ln(´ ␣´ , cur loc − 1 : 1, ´ ␣ ␣ ␣ ´ )

This code is used in 99.

§102  DVIDOC  THE MAIN PROGRAM 41

102. The main program. Now we are ready to put it all together. This is where starts, and where it ends. We use the UNIX facilty to pass in command line arguments here.

begin initialize; { get all variables initialized } options ; { set up all the options } ⟨ Open input file 25 ⟩⟨ Create error message file 65 ⟩⟨ Process the preamble 104 ⟩; ⟨ Find the postamble, working back from the end 96 ⟩; in postamble ← true; read postamble; in postamble ← false; ⟨ Count the pages and move to the starting page 98 ⟩; if ¬in postamble then ⟨ Translate up to max pages pages 106 ⟩;

final end : end.

103. The main program needs a few global variables in order to do its work. ⟨ Globals in the outer block 11 ⟩ +≡ k, m, n, p, q: integer ; { general purpose registers }

104. A -reading program that reads the postamble first need not look at the preamble; but looks at the preamble in order to do error checking, and to display the introductory comment. ⟨ Process the preamble 104 ⟩ ≡

p ← get byte; { fetch the first byte } if p ≠ pre then bad dvi (´ ␣ ␣ ´ ´ ␣ ␣ ␣ ´ ); p ← get byte; { fetch the identification byte } if p ≠ id byte then print ln(´ ␣ ␣ ␣ ␣ ␣ ␣´ , id byte : 1, ´ ´ ); ⟨ Compute the conversion factor 105 ⟩; p ← get byte; { fetch the length of the introductory comment } print (´ ´ ´ ´ ); while p > 0 do

begin decr (p); print (xchr [get byte]); end;

print ln(´ ´ ´ ´ )

This code is used in 102.

105. The conversion factors horiz conv and vert conv are figured as follows: There are exactly n/d units per decimicron, and 254000 decimicrons per inch, and horiz resolution or vert resolution characters per inch. Then we have to adjust this by the stated amount of magnification. ⟨ Compute the conversion factor 105 ⟩ ≡

numerator ← signed quad ; denominator ← signed quad ; if numerator ≤ 0 then bad dvi (´ ␣ ␣´ , numerator : 1); if denominator ≤ 0 then bad dvi (´ ␣ ␣´ , denominator : 1); horiz conv ← (numerator /254000.0) ∗ (horiz resolution/denominator ); vert conv ← (numerator /254000.0) ∗ (vert resolution/denominator ); mag ← signed quad ; if new mag > 0 then mag ← new mag else if mag ≤ 0 then bad dvi (´ ␣ ␣´ , mag : 1); true horiz conv ← horiz conv ; horiz conv ← true horiz conv ∗ (mag /1000.0); true vert conv ← vert conv ; vert conv ← true vert conv ∗ (mag /1000.0);

This code is used in 104.

42  THE MAIN PROGRAM  DVIDOC §106

106. The code shown here uses a convention that has proved to be useful: If the starting page was specified as, e.g., ‘ ’, then all page numbers in the file are displayed by showing the values of counts 0, 1, and 2, separated by dots. Such numbers can, for example, be displayed on the console of a printer when it is working on that page. ⟨ Translate up to max pages pages 106 ⟩ ≡

begin while max pages > 0 do begin decr (max pages ); print (´ ␣´ ); for k ← 0 to start vals do

begin print (count [k] : 1);

if k < start vals then print (´ ´ )

else print ln(´ ␣´ );

end; if ¬do page then bad dvi (´ ␣ ␣ ´ ); repeat k ← get byte;

if (k ≥ fnt def1 ) ∧ (k < fnt def1 + 4) then begin p ← first par (k); define font (p); k ← nop; end;

until k ≠ nop; if k = post then

begin in postamble ← true; goto done; end;

if k ≠ bop then bad dvi (´ ␣´ , cur loc − 1 : 1, ´ ␣ ␣ ␣ ´ ); ⟨ Pass a bop command, setting up the count array 95 ⟩; end;

done: end

This code is used in 102.

§107  DVIDOC  SYSTEM-DEPENDENT CHANGES 43

107. System-dependent changes. This section should be replaced, if necessary, by changes to the program that are necessary to make work at a particular installation. It is usually best to design your change file so that all changes to previous sections preserve the section numbering; then everybody’s version will be consistent with the printed program. More extensive changes, which introduce new sections, can be inserted here; then only the index itself will get a new section number.

44  INDEX  DVIDOC §108

108. Index. Pointers to error messages appear here together with the section numbers where each identifier is used.

a: \underline{77}, \underline{80}. abort : \underline{7}, 56, 58, 63, 98. abs : 71, 82, 83, 89, 90. : 96. alpha: \underline{36}, 39, 40. argc: 51. argv : 51. : 89, 90. ASCII code: \underline{9}, 11, 32, 47, 64, 68. : 95. : 59. : 7. : 100. : 59. bad char : \underline{80}, 85. bad dvi : \underline{7}, 78, 96, 98, 100, 104, 105, 106. banner : \underline{1}. base name: 25, \underline{27}, 51, 65. beta: \underline{36}, 39, 40. : 60. boolean: 23, 36, 44, 46, 50, 54, 56, 64, 77, 80, 93. bop: 14, 16, \underline{17}, 19, 20, 43, 69, 73, 81, 93,

97, 98, 106. : 81. buf ptr : \underline{49}, 50, 52, 53. buffer : \underline{47}, 48, 49, 50, 52, 53. byte: \underline{29}. : 98, 106. : 96. : 101. byte file: \underline{22}, 23. b0 : \underline{28}, 29, 37, 38, 39. b1 : \underline{28}, 29, 37, 39. b2 : \underline{28}, 29, 37, 39. b3 : \underline{28}, 29, 37, 39. c: \underline{56}. cannot start : \underline{8}, 25, 51, 52, 53, 65. change font : \underline{75}, 80, 84. char : 10, 22, 27, 29, 61. char pixel width: \underline{41}, 87. char width: \underline{32}, 41, 87. char width end : \underline{32}, 41. c : 87. check sum: 19. : 57. : 60. Chinese characters: 16, 87. chr : 10, 11, 13, 66. conv : 42. copy ln: 47, \underline{48}, 52, 53. count : \underline{44}, 46, 95, 98, 106. cur font : 75, \underline{76}, 77, 82, 83, 87, 91. cur loc: \underline{27}, 30, 78, 95, 99, 100, 101, 106. cur name: 25, 27, 47, 48, 51, 56, 63, 65. cur pos : 30. d: \underline{56}. decr : \underline{6}, 58, 81, 96, 104, 106. : 81. default directory : \underline{61}, 62. default directory name: \underline{61}, 62. default directory name length: \underline{61}. define font : \underline{56}, 84, 101, 106. den: 16, \underline{18}, 20. denominator : \underline{41}, 99, 105. : 99. : 105. : 57. do nothing : \underline{6}. do page: 69, 73, 75, 76, \underline{77}, 79, 81, 106. doc file: \underline{3}, 64, 66. done: \underline{4}, 8, 26, 77, 78, 79, 80, 81, 84, 85, 87,

88, 89, 90, 91, 106. down1 : 16, \underline{17}, 73, 83. down2 : 16. down3 : 16. down4 : 16. files : 14. dvi file: \underline{3}, \underline{23}, 25, 27, 30, 78, 100. dvi length: \underline{30}, 96. DVIDOC : \underline{3}. : 56, 58, 63. : 37. e: \underline{56}. eight bits : \underline{22}, 28, 73, 77, 80. eight cases : \underline{73}. else: 2. empty page: \underline{67}, 77. end: 2. endcases: \underline{2}. eof : \underline{3}, 24, 25, 30, 37, 59, 78, 100. eof dvi file: 3, \underline{23}. eop: 14, 16, \underline{17}, 19, 43, 73, 81. err file: \underline{3}, \underline{64}, 65. error : \underline{3}, 26, 80, 81, 85, 87, 89, 90. f: \underline{34}, \underline{56}. false: 36, 44, 45, 46, 50, 51, 52, 55, 57, 75, 77,

80, 85, 94, 102. fin rule: \underline{75}, 77, 78, 79.

fin set : \underline{75}, 77, 78, 79.
final end : \underline{4}, 7, 102.

§108  DVIDOC  INDEX 45

: 104. first backpointer : 96, \underline{97}, 98. first par : \underline{73}, 78, 79, 101, 106. first text char : \underline{10}, 13. fix word : 39. flush page: \underline{66}, 81. fnt def1 : 16, \underline{17}, 73, 84, 101, 106. fnt def2 : 16. fnt def3 : 16. fnt def4 : 16. fnt num 0 : 16, \underline{17}, 73, 84. fnt num 1 : 16. fnt num 63 : 16. fnt1 : 16, \underline{17}, 73, 84. fnt2 : 16. fnt3 : 16. fnt4 : 16. : 57. font bc: \underline{32}, 37, 42, 87. font check sum: \underline{32}, 57, 58. font design size: \underline{32}, 57, 58. font ec: \underline{32}, 37, 87. font file path: \underline{24}, 26. font name: \underline{32}, 33, 34, 57, 58, 63. font num: \underline{32}, 56, 91. font scaled size: \underline{32}, 57, 58. font space: \underline{32}, 33, 60, 82, 83. four cases : \underline{73}, 79, 80, 82, 83, 84. Fuchs, David Raymond: 14, 21. get byte: 30, 58, 73, 78, 85, 96, 98, 100, 101,

104, 106. get integer : \underline{50}, 52, 53. get tfm byte: \underline{29}. get three bytes : 73. get two bytes : 73, 99. h: \underline{70}. hh: 68, \underline{70}, 77, 79, 81, 82, 86, 87, 88, 89. hhh: \underline{77}, 89. hhstack : \underline{70}, 81. horiz conv : \underline{41}, 42, 60, 74, 105. horiz pixel round : \underline{42}, 70, 82, 89. horiz resolution: \underline{43}, 51, 105. horiz rule pixels : \underline{74}, 88. hstack : \underline{70}, 81. i: \underline{3}, \underline{18}, \underline{64}, \underline{66}, \underline{68}. : 96. id byte: \underline{18}, 96, 100, 104. : 100, 104. in postamble: \underline{54}, 55, 56, 102, 106. in TFM : \underline{36}, 39, 59. in width: \underline{35}, 39, 42.

incr : \underline{6}, 25, 48, 50, 51, 52, 56, 57, 58, 60, 63,

65, 81, 91, 95, 98. infinity : \underline{89}, 90. initialize: \underline{3}, 102. input : 3. integer : 3, 22, 27, 30, 32, 34, 35, 36, 41, 43, 44, 50, 51, 56, 68, 70, 71, 73, 74, 76, 77, 80, 93, 97, 99, 103.

invalid width: \underline{32}, 87.

j: \underline{51}, \underline{56}.

Japanese characters: 16, 87.

jump out : \underline{7}.

k: \underline{18}, \underline{34}, \underline{36}, \underline{46}, \underline{48}, \underline{56}, \underline{80}, \underline{99}, \underline{103}.

last text char : \underline{10}, 13.

lh: \underline{36}, 37.

line hwm: \underline{64}, 66, 68. log errors : 51, \underline{64}, 65. m: \underline{99}, \underline{103}. mag : 16, \underline{18}, 19, 20, \underline{41}, 99, 105. : 99. : 105. match: \underline{46}. max drift : \underline{89}, 90. max fonts : \underline{5}, 32, 56. max h: \underline{71}, 72, 89, 99. max h so far : \underline{71}, 72, 89. max pages : \underline{43}, 45, 51, 53, 106. max s : \underline{71}, 72, 81, 99. max s so far : \underline{71}, 72, 81. max v : \underline{71}, 72, 90, 99. max v so far : \underline{71}, 72, 90. max widths : \underline{5}, 32, 36, 37, 41. message: 7, 8. mismatch: \underline{56}, 57. move down: \underline{75}, 80, 83. move right : \underline{75}, 77, 78, 82, 87, 88. move to byte: \underline{30}, 96, 98. n: \underline{56}, \underline{74}, \underline{103}. name length: \underline{5}, 25, 27, 48, 56, 63, 64, 65. name size: \underline{5}, 32, 34, 56, 58. names : \underline{32}, 34, 56, 57, 58, 63. negative: \underline{50}. new backpointer : \underline{93}, 95. new mag : \underline{43}, 51, 99, 105. nf : \underline{32}, 33, 34, 37, 42, 56, 57, 58, 60, 63, 77, 87, 91. no file path: \underline{24}, 25, 65. : 85. nop: 14, 16, \underline{17}, 19, 20, 73, 81, 101, 106. : 100. : 58. num: 16, \underline{18}, 20. numerator : \underline{41}, 99, 105.

: 99. : 105. nw : \underline{36}, 37, 38, 39. o: \underline{77}, \underline{80}. old backpointer : \underline{93}, 94, 95, 98. : 96. open dvi file: 25. open tfm file: \underline{26}, 27, 59. options : \underline{51}, 102. ord : 11, 29. oriental characters: 16, 87. othercases: \underline{2}. others : 2. out char : \underline{68}, 79, 86, 88. out space: 60, \underline{82}. out vmove: 60, \underline{83}. output : 3. : 68. p: \underline{56}, \underline{77}, \underline{80}, \underline{99}, \underline{103}. : 106. : 98. page buffer : \underline{64}, 66, 67, 68. page count : \underline{71}, 72, 95, 98. page hwm: \underline{64}, 66, 67, 68. page length max : \underline{5}, 64, 66, 68. page width max : \underline{5}, 64, 66, 68. pixel round : 89. pixel width: \underline{41}, 42. pop: 15, 16, \underline{17}, 20, 73, 81. post : 14, 16, \underline{17}, 20, 21, 73, 80, 96, 97, 98, 99, 106. : 96. post loc: 96, \underline{97}, 98, 99, 100. post post : 16, \underline{17}, 20, 21, 73, 80, 100, 101. : 80. : 99. pre: 14, 16, \underline{17}, 73, 80, 104. : 80. print : \underline{3}, 34, 58, 59, 60, 68, 85, 87, 104, 106. print font : \underline{34}, 58, 87. print ln: \underline{3}, 36, 37, 56, 57, 59, 60, 68, 77, 95,

99, 100, 101, 104, 106. pure: \underline{80}. push: 5, 15, 16, \underline{17}, 20, 73, 81. : 81. put rule: 16, \underline{17}, 73, 79, 88. put1 : 16, \underline{17}, 73, 80, 87. put2 : 16. put3 : 16. put4 : 16. q: \underline{56}, \underline{77}, \underline{80}, \underline{99}, \underline{103}. r: \underline{56}. read : 29. read access mode: \underline{24}, 25, 26. read postamble: \underline{99}, 102. read tfm word : \underline{29}, 37, 38, 39. real : 41, 43. real name of file: 26, 27. reset : 24, 26. rewrite: 65. right1 : 16, \underline{17}, 73, 82. right2 : 16. right3 : 16. right4 : 16. round : 42, 60. rule pixels : 16. s: \underline{76}. : 57. set char 0 : 16, \underline{17}, 73, 79. set char 1 : 16. set char 127 : 16. set pos : 30. set rule: 14, 16, \underline{17}, 73, 79. setpaths : 3. set1 : 16, \underline{17}, 73, 79. set2 : 16. set3 : 16. set4 : 16. show state: \underline{75}, 77, 78, 81. : 100. signed byte: 73. signed pair : 73. signed quad : 58, 73, 88, 95, 96, 98, 99, 100, 105. signed trio: 73. sixteen cases : \underline{73}. sixty four cases : \underline{73}, 84. sp: 18. special cases : 76, 79, \underline{80}. ss : \underline{76}, 81. : 81. stack size: \underline{5}, 70, 72, 81. start count : \underline{44}, 46, 52. start loc: \underline{97}, 98. start match: \underline{46}, 98. start there: \underline{44}, 45, 46, 51, 52. start vals : \underline{44}, 45, 46, 51, 52, 106. started : \underline{93}, 94, 98. system dependencies: \underline{2}, 7, 8, 10, 22, 24, 25, 29, 30, 42, 47, 48, 51, 61, 63, 102, 107.

terminal line length: \underline{5}, 47, 48, 49.

test access : 24, 25, 26, 65.

text char : \underline{10}, 11. text file: \underline{10}, 64. files : 31. ´ : 59.

: 36. tfm check sum: \underline{35}, 37, 60. tfm file: \underline{23}, 24, 26, 29, 35, 37, 59. : 78. thirty two cases : \underline{73}. : 60. : 56. : 56. total pages : \underline{71}, 99. true: 36, 44, 46, 50, 51, 52, 57, 77, 80, 81, 85,

98, 102, 106. true horiz conv : \underline{41}, 60, 105. true vert conv : \underline{41}, 105. trunc: 74. : 34. : 80. undefined commands : \underline{17}, 73. v: \underline{70}. vert conv : \underline{41}, 42, 74, 105. vert pixel round : \underline{42}, 70, 83, 90. vert resolution: \underline{43}, 51, 105. vert rule pixels : \underline{74}, 88. vstack : \underline{70}, 81. vv : 68, \underline{70}, 77, 79, 81, 83, 86, 88, 90. vvstack : \underline{70}, 81. vvv : \underline{80}, 90. w: \underline{70}. : 89. : 90. width: \underline{32}, 38, 41, 42. width base: \underline{32}, 41, 42. width ptr : \underline{32}, 33, 36, 37, 38, 42. wp: \underline{36}, 37, 38, 42. write: 3, 66. write access mode: \underline{24}, 65. write ln: 3, 66. wstack : \underline{70}, 81. w0 : 16, \underline{17}, 73, 82. w1 : 16, \underline{17}, 73, 82. w2 : 16. w3 : 16. w4 : 16. x: \underline{18}, \underline{50}, \underline{70}. xchr : \underline{11}, 12, 13, 34, 63, 66, 68, 85, 104. xord : \underline{11}, 13, 48, 68, 88. xstack : \underline{70}, 81. xxx1 : 16, \underline{17}, 73, 80. xxx2 : 16. xxx3 : 16. xxx4 : 16, \underline{17}. x0 : 16, \underline{17}, 73, 82. x1 : 16, \underline{17}, 73, 82. x2 : 16. x3 : 16. x4 : 16. y: \underline{70}. ystack : \underline{70}, 81. y0 : 16, \underline{17}, 73, 83. y1 : 16, \underline{17}, 73, 83. y2 : 16. y3 : 16. y4 : 16. z: \underline{36}, \underline{70}. zstack : \underline{70}, 81. z0 : 16, \underline{17}, 73, 83. z1 : 16, \underline{17}, 73, 83. z2 : 16. z3 : 16. z4 : 16.

48  NAMES OF THE SECTIONS  DVIDOC §108

⟨ Cases for commands nop, bop, …, pop 81 ⟩ Used in 79. ⟨ Cases for fonts 84 ⟩ Used in 80. ⟨ Cases for horizontal motion 82 ⟩ Used in 79. ⟨ Cases for vertical motion 83 ⟩ Used in 80. ⟨ Check that the current font definition matches the old one 57 ⟩ Used in 56. ⟨ Compute the conversion factor 105 ⟩ Used in 104. ⟨ Constants in the outer block 5 ⟩ Used in 3. ⟨ Count the pages and move to the starting page 98 ⟩ Used in 102. ⟨ Create error message file 65 ⟩ Used in 102. ⟨ Declare the function called special cases 80 ⟩ Used in 77. ⟨ Determine the desired max pages 53 ⟩ Used in 51. ⟨ Determine the desired start count values 52 ⟩ Used in 51. ⟨ Find the postamble, working back from the end 96 ⟩ Used in 102. ⟨ Finish a command that changes the current font, then goto done 91 ⟩ Used in 80. ⟨ Finish a command that either sets or puts a character, then goto move right or done 87 ⟩ Used in 78. ⟨ Finish a command that either sets or puts a rule, then goto move right or done 88 ⟩ Used in 78. ⟨ Finish a command that sets h ← h + q, then goto done 89 ⟩ Used in 78. ⟨ Finish a command that sets v ← v + p, then goto done 90 ⟩ Used in 80. ⟨ Finish loading the new font info 60 ⟩ Used in 59.

⟨ Globals in the outer block 11, 23, 27, 28, 32, 35, 41, 43, 44, 47, 49, 54, 61, 64, 70, 71, 76, 93, 97, 103 ⟩ Used in 3.

⟨ Labels in the outer block 4 ⟩ Used in 3. ⟨ Load the new font, unless there are problems 59 ⟩ Used in 56. ⟨ Make sure that the end of the file is well-formed 100 ⟩ Used in 99. ⟨ Move font name into the cur name string 63 ⟩ Used in 59. ⟨ Move the widths from in width to width, and append pixel width values 42 ⟩ Used in 36. ⟨ Open input file 25 ⟩ Used in 102. ⟨ Pass a bop command, setting up the count array 95 ⟩ Used in 106. ⟨ Process the font definitions of the postamble 101 ⟩ Used in 99. ⟨ Process the preamble 104 ⟩ Used in 102. ⟨ Read and convert the width values, setting up the in width table 39 ⟩ Used in 36. ⟨ Read past the header data; goto 9997 if there is a problem 37 ⟩ Used in 36. ⟨ Read the font parameters into position for font nf , and print the font name 58 ⟩ Used in 56. ⟨ Replace z by z′ and compute α, β 40 ⟩ Used in 39.

⟨ Set initial values 12, 13, 33, 45, 55, 62, 72, 94 ⟩ Used in 3.

⟨ Start translation of command o and goto the appropriate label to finish the job 79 ⟩ Used in 78. ⟨ Store character-width indices at the end of the width table 38 ⟩ Used in 36. ⟨ Translate a set char command 86 ⟩ Used in 79. ⟨ Translate an xxx command and goto done 85 ⟩ Used in 80. ⟨ Translate the next command in the file; goto 9999 with do page = true if it was eop; goto 9998 if

premature termination is needed 78 ⟩ Used in 77. ⟨ Translate up to max pages pages 106 ⟩ Used in 102. ⟨ Types in the outer block 9, 10, 22 ⟩ Used in 3.

The DVIDOC processor

(Version 2, July 1987)

Section Page

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 The character set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 4 Device-independent file format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 6 Input from binary files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 13 Reading the font information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 16 Optional modes of output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 21 Defining fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 24 Low level output routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 27 Translation to symbolic form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 29 Skipping pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 38 Using the backpointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 39 Reading the postamble . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 40 The main program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 41 System-dependent changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 43 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 44

‘TEX’ is a trademark of the American Mathematical Society.