modernc.org/knuth@v0.0.4/web/testdata/ctan.org/tex-archive/systems/knuth/dist/texware/dvitype.web (about) 1 % This program by D. E. Knuth is not copyrighted and can be used freely. 2 % Version 1 was completed in September, 1982. 3 % Slight changes were made in October, 1982, for version 0.7 of TeX. 4 % Version 1.1 corrected minor bugs (May, 1983). 5 % Version 2 was released with version 0.999 of TeX (July, 1983). 6 % Version 2.1 corrected a bug when no fonts are present (September, 1983). 7 % Version 2.2 corrected bugs in max_*_so_far and put1 (October, 1983). 8 % Version 2.3 corrected spacing of accents (March, 1984). 9 % Version 2.4 fixed rounding, changed oriental font conventions (April, 1984). 10 % Version 2.5 improved the case of zero pages (May, 1984). 11 % Version 2.6 introduced max_drift (June, 1984). 12 % Version 2.7 had minor editorial changes (August, 1984). 13 % Version 2.8 made default resolution 300/1 (April, 1985). 14 % Version 2.9 changed negative scaling as in TeX version 2.7 (November, 1987). 15 % Version 3 introduced an intermediate level of verbosity (October,1989). 16 % Version 3.1 gave magnification info in final font list (November, 1989). 17 % Version 3.2 doublechecked design size of each font (January, 1990). 18 % Version 3.3 had more robust for loops in print_font, define_font (May, 1990). 19 % Version 3.4 more robustness in presence of bad fonts (September, 1990). 20 % Version 3.5 checked skipped material more strictly (March, 1995). 21 % Version 3.6 gives a better help message (December, 1995). 22 23 % Here is TeX material that gets inserted after \input webmac 24 \def\hang{\hangindent 3em\indent\ignorespaces} 25 \font\ninerm=cmr9 26 \let\mc=\ninerm % medium caps for names like SAIL 27 \def\PASCAL{Pascal} 28 29 \def\(#1){} % this is used to make section names sort themselves better 30 \def\9#1{} % this is used for sort keys in the index 31 32 \def\title{DVI$\,$\lowercase{type}} 33 \def\contentspagenumber{401} 34 \def\topofcontents{\null 35 \titlefalse % include headline on the contents page 36 \def\rheader{\mainfont\hfil \contentspagenumber} 37 \vfill 38 \centerline{\titlefont The {\ttitlefont DVItype} processor} 39 \vskip 15pt 40 \centerline{(Version 3.6, December 1995)} 41 \vfill} 42 \def\botofcontents{\vfill 43 \centerline{\hsize 5in\baselineskip9pt 44 \vbox{\ninerm\noindent 45 The preparation of this report 46 was supported in part by the National Science 47 Foundation under grants IST-8201926 and MCS-8300984, 48 and by the System Development Foundation. `\TeX' is a 49 trademark of the American Mathematical Society.}}} 50 \pageno=\contentspagenumber \advance\pageno by 1 51 52 @* Introduction. 53 The \.{DVItype} utility program reads binary device-independent (``\.{DVI}'') 54 files that are produced by document compilers such as \TeX, and converts them 55 into symbolic form. This program has two chief purposes: (1)~It can be used to 56 determine whether a \.{DVI} file is valid or invalid, when diagnosing 57 compiler errors; and (2)~it serves as an example of a program that reads 58 \.{DVI} files correctly, for system programmers who are developing 59 \.{DVI}-related software. 60 61 Goal number (2) needs perhaps a bit more explanation. Programs for 62 typesetting need to be especially careful about how they do arithmetic; if 63 rounding errors accumulate, margins won't be straight, vertical rules 64 won't line up, and so on. But if rounding is done everywhere, even in the 65 midst of words, there will be uneven spacing between the letters, and that 66 looks bad. Human eyes notice differences of a thousandth of an inch in the 67 positioning of lines that are close together; on low resolution devices, 68 where rounding produces effects four times as great as this, the problem 69 is especially critical. Experience has shown that unusual care is needed 70 even on high-resolution equipment; for example, a mistake in the sixth 71 significant hexadecimal place of a constant once led to a difficult-to-find 72 bug in some software for the Alphatype CRS, which has a resolution of 5333 73 pixels per inch (make that 5333.33333333 pixels per inch). The document 74 compilers that generate \.{DVI} files make certain assumptions about the 75 arithmetic that will be used by \.{DVI}-reading software, and if these 76 assumptions are violated the results will be of inferior quality. 77 Therefore the present program is intended as a guide to proper procedure 78 in the critical places where a bit of subtlety is involved. 79 80 The first \.{DVItype} program was designed by David Fuchs in 1979, and it 81 @^Fuchs, David Raymond@> 82 went through several versions on different computers as the format of 83 \.{DVI} files was evolving to its present form. Peter Breitenlohner 84 helped with the latest revisions. 85 @^Breitenlohner, Peter@> 86 87 The |banner| string defined here should be changed whenever \.{DVItype} 88 gets modified. 89 90 @d banner=='This is DVItype, Version 3.6' {printed when the program starts} 91 92 @ This program is written in standard \PASCAL, except where it is necessary 93 to use extensions; for example, \.{DVItype} must read files whose names 94 are dynamically specified, and that would be impossible in pure \PASCAL. 95 All places where nonstandard constructions are used have been listed in 96 the index under ``system dependencies.'' 97 @!@^system dependencies@> 98 99 One of the extensions to standard \PASCAL\ that we shall deal with is the 100 ability to move to a random place in a binary file; another is to 101 determine the length of a binary file. Such extensions are not necessary 102 for reading \.{DVI} files, and they are not important for efficiency 103 reasons either---an infrequently used program like \.{DVItype} does not 104 have to be efficient. But they are included there because of \.{DVItype}'s 105 r\^^Dole as a model of a \.{DVI} reading routine, since other \.{DVI} 106 processors ought to be highly efficient. If \.{DVItype} is being used with 107 \PASCAL s for which random file positioning is not efficiently available, 108 the following definition should be changed from |true| to |false|; in such 109 cases, \.{DVItype} will not include the optional feature that reads the 110 postamble first. 111 112 Another extension is to use a default |case| as in \.{TANGLE}, \.{WEAVE}, 113 etc. 114 115 @d random_reading==true {should we skip around in the file?} 116 @d othercases == others: {default for cases not listed explicitly} 117 @d endcases == @+end {follows the default case in an extended |case| statement} 118 @f othercases == else 119 @f endcases == end 120 121 @ The binary input comes from |dvi_file|, and the symbolic output is written 122 on \PASCAL's standard |output| file. The term |print| is used instead of 123 |write| when this program writes on |output|, so that all such output 124 could easily be redirected if desired. 125 126 @d print(#)==write(#) 127 @d print_ln(#)==write_ln(#) 128 129 @p program DVI_type(@!dvi_file,@!output); 130 label @<Labels in the outer block@>@/ 131 const @<Constants in the outer block@>@/ 132 type @<Types in the outer block@>@/ 133 var @<Globals in the outer block@>@/ 134 procedure initialize; {this procedure gets things started properly} 135 var i:integer; {loop index for initializations} 136 begin print_ln(banner);@/ 137 @<Set initial values@>@/ 138 end; 139 140 @ If the program has to stop prematurely, it goes to the 141 `|final_end|'. Another label, |done|, is used when stopping normally. 142 143 @d final_end=9999 {label for the end of it all} 144 @d done=30 {go here when finished with a subtask} 145 146 @<Labels...@>=final_end,done; 147 148 @ The following parameters can be changed at compile time to extend or 149 reduce \.{DVItype}'s capacity. 150 151 @<Constants...@>= 152 @!max_fonts=100; {maximum number of distinct fonts per \.{DVI} file} 153 @!max_widths=10000; {maximum number of different characters among all fonts} 154 @!line_length=79; {bracketed lines of output will be at most this long} 155 @!terminal_line_length=150; {maximum number of characters input in a single 156 line of input from the terminal} 157 @!stack_size=100; {\.{DVI} files shouldn't |push| beyond this depth} 158 @!name_size=1000; {total length of all font file names} 159 @!name_length=50; {a file name shouldn't be longer than this} 160 161 @ Here are some macros for common programming idioms. 162 163 @d incr(#) == #:=#+1 {increase a variable by unity} 164 @d decr(#) == #:=#-1 {decrease a variable by unity} 165 @d do_nothing == {empty statement} 166 167 @ If the \.{DVI} file is badly malformed, the whole process must be aborted; 168 \.{DVItype} will give up, after issuing an error message about the symptoms 169 that were noticed. 170 171 Such errors might be discovered inside of subroutines inside of subroutines, 172 so a procedure called |jump_out| has been introduced. This procedure, which 173 simply transfers control to the label |final_end| at the end of the program, 174 contains the only non-local |goto| statement in \.{DVItype}. 175 @^system dependencies@> 176 177 @d abort(#)==begin print(' ',#); jump_out; 178 end 179 @d bad_dvi(#)==abort('Bad DVI file: ',#,'!') 180 @.Bad DVI file@> 181 182 @p procedure jump_out; 183 begin goto final_end; 184 end; 185 186 @* The character set. 187 Like all programs written with the \.{WEB} system, \.{DVItype} can be 188 used with any character set. But it uses ASCII code internally, because 189 the programming for portable input-output is easier when a fixed internal 190 code is used, and because \.{DVI} files use ASCII code for file names 191 and certain other strings. 192 193 The next few sections of \.{DVItype} have therefore been copied from the 194 analogous ones in the \.{WEB} system routines. They have been considerably 195 simplified, since \.{DVItype} need not deal with the controversial 196 ASCII codes less than @'40 or greater than @'176. 197 If such codes appear in the \.{DVI} file, 198 they will be printed as question marks. 199 200 @<Types...@>= 201 @!ASCII_code=" ".."~"; {a subrange of the integers} 202 203 @ The original \PASCAL\ compiler was designed in the late 60s, when six-bit 204 character sets were common, so it did not make provision for lower case 205 letters. Nowadays, of course, we need to deal with both upper and lower case 206 alphabets in a convenient way, especially in a program like \.{DVItype}. 207 So we shall assume that the \PASCAL\ system being used for \.{DVItype} 208 has a character set containing at least the standard visible characters 209 of ASCII code (|"!"| through |"~"|). 210 211 Some \PASCAL\ compilers use the original name |char| for the data type 212 associated with the characters in text files, while other \PASCAL s 213 consider |char| to be a 64-element subrange of a larger data type that has 214 some other name. In order to accommodate this difference, we shall use 215 the name |text_char| to stand for the data type of the characters in the 216 output file. We shall also assume that |text_char| consists of 217 the elements |chr(first_text_char)| through |chr(last_text_char)|, 218 inclusive. The following definitions should be adjusted if necessary. 219 @^system dependencies@> 220 221 @d text_char == char {the data type of characters in text files} 222 @d first_text_char=0 {ordinal number of the smallest element of |text_char|} 223 @d last_text_char=127 {ordinal number of the largest element of |text_char|} 224 225 @<Types...@>= 226 @!text_file=packed file of text_char; 227 228 @ The \.{DVItype} processor converts between ASCII code and 229 the user's external character set by means of arrays |xord| and |xchr| 230 that are analogous to \PASCAL's |ord| and |chr| functions. 231 232 @<Globals...@>= 233 @!xord: array [text_char] of ASCII_code; 234 {specifies conversion of input characters} 235 @!xchr: array [0..255] of text_char; 236 {specifies conversion of output characters} 237 238 @ Under our assumption that the visible characters of standard ASCII are 239 all present, the following assignment statements initialize the 240 |xchr| array properly, without needing any system-dependent changes. 241 242 @<Set init...@>= 243 for i:=0 to @'37 do xchr[i]:='?'; 244 xchr[@'40]:=' '; 245 xchr[@'41]:='!'; 246 xchr[@'42]:='"'; 247 xchr[@'43]:='#'; 248 xchr[@'44]:='$'; 249 xchr[@'45]:='%'; 250 xchr[@'46]:='&'; 251 xchr[@'47]:='''';@/ 252 xchr[@'50]:='('; 253 xchr[@'51]:=')'; 254 xchr[@'52]:='*'; 255 xchr[@'53]:='+'; 256 xchr[@'54]:=','; 257 xchr[@'55]:='-'; 258 xchr[@'56]:='.'; 259 xchr[@'57]:='/';@/ 260 xchr[@'60]:='0'; 261 xchr[@'61]:='1'; 262 xchr[@'62]:='2'; 263 xchr[@'63]:='3'; 264 xchr[@'64]:='4'; 265 xchr[@'65]:='5'; 266 xchr[@'66]:='6'; 267 xchr[@'67]:='7';@/ 268 xchr[@'70]:='8'; 269 xchr[@'71]:='9'; 270 xchr[@'72]:=':'; 271 xchr[@'73]:=';'; 272 xchr[@'74]:='<'; 273 xchr[@'75]:='='; 274 xchr[@'76]:='>'; 275 xchr[@'77]:='?';@/ 276 xchr[@'100]:='@@'; 277 xchr[@'101]:='A'; 278 xchr[@'102]:='B'; 279 xchr[@'103]:='C'; 280 xchr[@'104]:='D'; 281 xchr[@'105]:='E'; 282 xchr[@'106]:='F'; 283 xchr[@'107]:='G';@/ 284 xchr[@'110]:='H'; 285 xchr[@'111]:='I'; 286 xchr[@'112]:='J'; 287 xchr[@'113]:='K'; 288 xchr[@'114]:='L'; 289 xchr[@'115]:='M'; 290 xchr[@'116]:='N'; 291 xchr[@'117]:='O';@/ 292 xchr[@'120]:='P'; 293 xchr[@'121]:='Q'; 294 xchr[@'122]:='R'; 295 xchr[@'123]:='S'; 296 xchr[@'124]:='T'; 297 xchr[@'125]:='U'; 298 xchr[@'126]:='V'; 299 xchr[@'127]:='W';@/ 300 xchr[@'130]:='X'; 301 xchr[@'131]:='Y'; 302 xchr[@'132]:='Z'; 303 xchr[@'133]:='['; 304 xchr[@'134]:='\'; 305 xchr[@'135]:=']'; 306 xchr[@'136]:='^'; 307 xchr[@'137]:='_';@/ 308 xchr[@'140]:='`'; 309 xchr[@'141]:='a'; 310 xchr[@'142]:='b'; 311 xchr[@'143]:='c'; 312 xchr[@'144]:='d'; 313 xchr[@'145]:='e'; 314 xchr[@'146]:='f'; 315 xchr[@'147]:='g';@/ 316 xchr[@'150]:='h'; 317 xchr[@'151]:='i'; 318 xchr[@'152]:='j'; 319 xchr[@'153]:='k'; 320 xchr[@'154]:='l'; 321 xchr[@'155]:='m'; 322 xchr[@'156]:='n'; 323 xchr[@'157]:='o';@/ 324 xchr[@'160]:='p'; 325 xchr[@'161]:='q'; 326 xchr[@'162]:='r'; 327 xchr[@'163]:='s'; 328 xchr[@'164]:='t'; 329 xchr[@'165]:='u'; 330 xchr[@'166]:='v'; 331 xchr[@'167]:='w';@/ 332 xchr[@'170]:='x'; 333 xchr[@'171]:='y'; 334 xchr[@'172]:='z'; 335 xchr[@'173]:='{'; 336 xchr[@'174]:='|'; 337 xchr[@'175]:='}'; 338 xchr[@'176]:='~'; 339 for i:=@'177 to 255 do xchr[i]:='?'; 340 341 @ The following system-independent code makes the |xord| array contain a 342 suitable inverse to the information in |xchr|. 343 344 @<Set init...@>= 345 for i:=first_text_char to last_text_char do xord[chr(i)]:=@'40; 346 for i:=" " to "~" do xord[xchr[i]]:=i; 347 348 @* Device-independent file format. 349 Before we get into the details of \.{DVItype}, we need to know exactly 350 what \.{DVI} files are. The form of such files was designed by David R. 351 @^Fuchs, David Raymond@> 352 Fuchs in 1979. Almost any reasonable typesetting device can be driven by 353 a program that takes \.{DVI} files as input, and dozens of such 354 \.{DVI}-to-whatever programs have been written. Thus, it is possible to 355 print the output of document compilers like \TeX\ on many different kinds 356 of equipment. 357 358 A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a 359 series of commands in a machine-like language. The first byte of each command 360 is the operation code, and this code is followed by zero or more bytes 361 that provide parameters to the command. The parameters themselves may consist 362 of several consecutive bytes; for example, the `|set_rule|' command has two 363 parameters, each of which is four bytes long. Parameters are usually 364 regarded as nonnegative integers; but four-byte-long parameters, 365 and shorter parameters that denote distances, can be 366 either positive or negative. Such parameters are given in two's complement 367 notation. For example, a two-byte-long distance parameter has a value between 368 $-2^{15}$ and $2^{15}-1$. 369 @.DVI {\rm files}@> 370 371 A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one 372 or more ``pages,'' followed by a ``postamble.'' The preamble is simply a 373 |pre| command, with its parameters that define the dimensions used in the 374 file; this must come first. Each ``page'' consists of a |bop| command, 375 followed by any number of other commands that tell where characters are to 376 be placed on a physical page, followed by an |eop| command. The pages 377 appear in the order that they were generated, not in any particular 378 numerical order. If we ignore |nop| commands and \\{fnt\_def} commands 379 (which are allowed between any two commands in the file), each |eop| 380 command is immediately followed by a |bop| command, or by a |post| 381 command; in the latter case, there are no more pages in the file, and the 382 remaining bytes form the postamble. Further details about the postamble 383 will be explained later. 384 385 Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte 386 quantities that give the location number of some other byte in the file; 387 the first byte is number~0, then comes number~1, and so on. For example, 388 one of the parameters of a |bop| command points to the previous |bop|; 389 this makes it feasible to read the pages in backwards order, in case the 390 results are being directed to a device that stacks its output face up. 391 Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the 392 first page occupies bytes 100 to 999, say, and if the second 393 page occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000 394 points to 100 and the |bop| that starts in byte 2000 points to 1000. (The 395 very first |bop|, i.e., the one that starts in byte 100, has a pointer of $-1$.) 396 397 @ The \.{DVI} format is intended to be both compact and easily interpreted 398 by a machine. Compactness is achieved by making most of the information 399 implicit instead of explicit. When a \.{DVI}-reading program reads the 400 commands for a page, it keeps track of several quantities: (a)~The current 401 font |f| is an integer; this value is changed only 402 by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page 403 is given by two numbers called the horizontal and vertical coordinates, 404 |h| and |v|. Both coordinates are zero at the upper left corner of the page; 405 moving to the right corresponds to increasing the horizontal coordinate, and 406 moving down corresponds to increasing the vertical coordinate. Thus, the 407 coordinates are essentially Cartesian, except that vertical directions are 408 flipped; the Cartesian version of |(h,v)| would be |(h,-v)|. (c)~The 409 current spacing amounts are given by four numbers |w|, |x|, |y|, and |z|, 410 where |w| and~|x| are used for horizontal spacing and where |y| and~|z| 411 are used for vertical spacing. (d)~There is a stack containing 412 |(h,v,w,x,y,z)| values; the \.{DVI} commands |push| and |pop| are used to 413 change the current level of operation. Note that the current font~|f| is 414 not pushed and popped; the stack contains only information about 415 positioning. 416 417 The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up 418 to 32 bits, including the sign. Since they represent physical distances, 419 there is a small unit of measurement such that increasing |h| by~1 means 420 moving a certain tiny distance to the right. The actual unit of 421 measurement is variable, as explained below. 422 423 @ Here is a list of all the commands that may appear in a \.{DVI} file. Each 424 command is specified by its symbolic name (e.g., |bop|), its opcode byte 425 (e.g., 139), and its parameters (if any). The parameters are followed 426 by a bracketed number telling how many bytes they occupy; for example, 427 `|p[4]|' means that parameter |p| is four bytes long. 428 429 \yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f| 430 such that the reference point of the character is at |(h,v)|. Then 431 increase |h| by the width of that character. Note that a character may 432 have zero or negative width, so one cannot be sure that |h| will advance 433 after this command; but |h| usually does increase. 434 435 \yskip\hang|set_char_1| through |set_char_127| (opcodes 1 to 127). 436 Do the operations of |set_char_0|; but use the character whose number 437 matches the opcode, instead of character~0. 438 439 \yskip\hang|set1| 128 |c[1]|. Same as |set_char_0|, except that character 440 number~|c| is typeset. \TeX82 uses this command for characters in the 441 range |128<=c<256|. 442 443 \yskip\hang|set2| 129 |c[2]|. Same as |set1|, except that |c|~is two 444 bytes long, so it is in the range |0<=c<65536|. \TeX82 never uses this 445 command, which is intended for processors that deal with oriental languages; 446 but \.{DVItype} will allow character codes greater than 255, assuming that 447 they all have the same width as the character whose code is $c \bmod 256$. 448 @^oriental characters@>@^Chinese characters@>@^Japanese characters@> 449 450 \yskip\hang|set3| 130 |c[3]|. Same as |set1|, except that |c|~is three 451 bytes long, so it can be as large as $2^{24}-1$. 452 453 \yskip\hang|set4| 131 |c[4]|. Same as |set1|, except that |c|~is four 454 bytes long, possibly even negative. Imagine that. 455 456 \yskip\hang|set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle 457 of height |a| and width |b|, with its bottom left corner at |(h,v)|. Then 458 set |h:=h+b|. If either |a<=0| or |b<=0|, nothing should be typeset. Note 459 that if |b<0|, the value of |h| will decrease even though nothing else happens. 460 Programs that typeset from \.{DVI} files should be careful to make the rules 461 line up carefully with digitized characters, as explained in connection with 462 the |rule_pixels| subroutine below. 463 464 \yskip\hang|put1| 133 |c[1]|. Typeset character number~|c| from font~|f| 465 such that the reference point of the character is at |(h,v)|. (The `put' 466 commands are exactly like the `set' commands, except that they simply put out a 467 character or a rule without moving the reference point afterwards.) 468 469 \yskip\hang|put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed. 470 471 \yskip\hang|put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed. 472 473 \yskip\hang|put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed. 474 475 \yskip\hang|put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that 476 |h| is not changed. 477 478 \yskip\hang|nop| 138. No operation, do nothing. Any number of |nop|'s 479 may occur between \.{DVI} commands, but a |nop| cannot be inserted between 480 a command and its parameters or between two parameters. 481 482 \yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning 483 of a page: Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set 484 the current font |f| to an undefined value. The ten $c_i$ parameters can 485 be used to identify pages, if a user wants to print only part of a \.{DVI} 486 file; \TeX82 gives them the values of \.{\\count0} $\ldots$ \.{\\count9} 487 at the time \.{\\shipout} was invoked for this page. The parameter |p| 488 points to the previous |bop| command in the file, where the first |bop| 489 has $p=-1$. 490 491 \yskip\hang|eop| 140. End of page: Print what you have read since the 492 previous |bop|. At this point the stack should be empty. (The \.{DVI}-reading 493 programs that drive most output devices will have kept a buffer of the 494 material that appears on the page that has just ended. This material is 495 largely, but not entirely, in order by |v| coordinate and (for fixed |v|) by 496 |h|~coordinate; so it usually needs to be sorted into some order that is 497 appropriate for the device in question. \.{DVItype} does not do such sorting.) 498 499 \yskip\hang|push| 141. Push the current values of |(h,v,w,x,y,z)| onto the 500 top of the stack; do not change any of these values. Note that |f| is 501 not pushed. 502 503 \yskip\hang|pop| 142. Pop the top six values off of the stack and assign 504 them to |(h,v,w,x,y,z)|. The number of pops should never exceed the number 505 of pushes, since it would be highly embarrassing if the stack were empty 506 at the time of a |pop| command. 507 508 \yskip\hang|right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units. 509 The parameter is a signed number in two's complement notation, |-128<=b<128|; 510 if |b<0|, the reference point actually moves left. 511 512 \yskip\hang|right2| 144 |b[2]|. Same as |right1|, except that |b| is a 513 two-byte quantity in the range |-32768<=b<32768|. 514 515 \yskip\hang|right3| 145 |b[3]|. Same as |right1|, except that |b| is a 516 three-byte quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|. 517 518 \yskip\hang|right4| 146 |b[4]|. Same as |right1|, except that |b| is a 519 four-byte quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|. 520 521 \yskip\hang|w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck, 522 this parameterless command will usually suffice, because the same kind of motion 523 will occur several times in succession; the following commands explain how 524 |w| gets particular values. 525 526 \yskip\hang|w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a 527 signed quantity in two's complement notation, |-128<=b<128|. This command 528 changes the current |w|~spacing and moves right by |b|. 529 530 \yskip\hang|w2| 149 |b[2]|. Same as |w1|, but |b| is a two-byte-long 531 parameter, |-32768<=b<32768|. 532 533 \yskip\hang|w3| 150 |b[3]|. Same as |w1|, but |b| is a three-byte-long 534 parameter, |@t$-2^{23}$@><=b<@t$2^{23}$@>|. 535 536 \yskip\hang|w4| 151 |b[4]|. Same as |w1|, but |b| is a four-byte-long 537 parameter, |@t$-2^{31}$@><=b<@t$2^{31}$@>|. 538 539 \yskip\hang|x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|' 540 commands are like the `|w|' commands except that they involve |x| instead 541 of |w|. 542 543 \yskip\hang|x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a 544 signed quantity in two's complement notation, |-128<=b<128|. This command 545 changes the current |x|~spacing and moves right by |b|. 546 547 \yskip\hang|x2| 154 |b[2]|. Same as |x1|, but |b| is a two-byte-long 548 parameter, |-32768<=b<32768|. 549 550 \yskip\hang|x3| 155 |b[3]|. Same as |x1|, but |b| is a three-byte-long 551 parameter, |@t$-2^{23}$@><=b<@t$2^{23}$@>|. 552 553 \yskip\hang|x4| 156 |b[4]|. Same as |x1|, but |b| is a four-byte-long 554 parameter, |@t$-2^{31}$@><=b<@t$2^{31}$@>|. 555 556 \yskip\hang|down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units. 557 The parameter is a signed number in two's complement notation, |-128<=a<128|; 558 if |a<0|, the reference point actually moves up. 559 560 \yskip\hang|down2| 158 |a[2]|. Same as |down1|, except that |a| is a 561 two-byte quantity in the range |-32768<=a<32768|. 562 563 \yskip\hang|down3| 159 |a[3]|. Same as |down1|, except that |a| is a 564 three-byte quantity in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|. 565 566 \yskip\hang|down4| 160 |a[4]|. Same as |down1|, except that |a| is a 567 four-byte quantity in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|. 568 569 \yskip\hang|y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck, 570 this parameterless command will usually suffice, because the same kind of motion 571 will occur several times in succession; the following commands explain how 572 |y| gets particular values. 573 574 \yskip\hang|y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a 575 signed quantity in two's complement notation, |-128<=a<128|. This command 576 changes the current |y|~spacing and moves down by |a|. 577 578 \yskip\hang|y2| 163 |a[2]|. Same as |y1|, but |a| is a two-byte-long 579 parameter, |-32768<=a<32768|. 580 581 \yskip\hang|y3| 164 |a[3]|. Same as |y1|, but |a| is a three-byte-long 582 parameter, |@t$-2^{23}$@><=a<@t$2^{23}$@>|. 583 584 \yskip\hang|y4| 165 |a[4]|. Same as |y1|, but |a| is a four-byte-long 585 parameter, |@t$-2^{31}$@><=a<@t$2^{31}$@>|. 586 587 \yskip\hang|z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands 588 are like the `|y|' commands except that they involve |z| instead of |y|. 589 590 \yskip\hang|z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a 591 signed quantity in two's complement notation, |-128<=a<128|. This command 592 changes the current |z|~spacing and moves down by |a|. 593 594 \yskip\hang|z2| 168 |a[2]|. Same as |z1|, but |a| is a two-byte-long 595 parameter, |-32768<=a<32768|. 596 597 \yskip\hang|z3| 169 |a[3]|. Same as |z1|, but |a| is a three-byte-long 598 parameter, |@t$-2^{23}$@><=a<@t$2^{23}$@>|. 599 600 \yskip\hang|z4| 170 |a[4]|. Same as |z1|, but |a| is a four-byte-long 601 parameter, |@t$-2^{31}$@><=a<@t$2^{31}$@>|. 602 603 \yskip\hang|fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been 604 defined by a \\{fnt\_def} instruction, as explained below. 605 606 \yskip\hang|fnt_num_1| through |fnt_num_63| (opcodes 172 to 234). Set 607 |f:=1|, \dots, |f:=63|, respectively. 608 609 \yskip\hang|fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font 610 numbers in the range |64<=k<256|. 611 612 \yskip\hang|fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two 613 bytes long, so it is in the range |0<=k<65536|. \TeX82 never generates this 614 command, but large font numbers may prove useful for specifications of 615 color or texture, or they may be used for special fonts that have fixed 616 numbers in some external coding scheme. 617 618 \yskip\hang|fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three 619 bytes long, so it can be as large as $2^{24}-1$. 620 621 \yskip\hang|fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four 622 bytes long; this is for the really big font numbers (and for the negative ones). 623 624 \yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in 625 general; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading 626 programs are being used. \TeX82 generates |xxx1| when a short enough 627 \.{\\special} appears, setting |k| to the number of bytes being sent. It 628 is recommended that |x| be a string having the form of a keyword followed 629 by possible parameters relevant to that keyword. 630 631 \yskip\hang|xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|. 632 633 \yskip\hang|xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|. 634 635 \yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously 636 large. \TeX82 uses |xxx4| when |xxx1| would be incorrect. 637 638 \yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. 639 Define font |k|, where |0<=k<256|; font definitions will be explained shortly. 640 641 \yskip\hang|fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. 642 Define font |k|, where |0<=k<65536|. 643 644 \yskip\hang|fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. 645 Define font |k|, where |0<=k<@t$2^{24}$@>|. 646 647 \yskip\hang|fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. 648 Define font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|. 649 650 \yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|. 651 Beginning of the preamble; this must come at the very beginning of the 652 file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below. 653 654 \yskip\hang|post| 248. Beginning of the postamble, see below. 655 656 \yskip\hang|post_post| 249. Ending of the postamble, see below. 657 658 \yskip\noindent Commands 250--255 are undefined at the present time. 659 660 @ @d set_char_0=0 {typeset character 0 and move right} 661 @d set1=128 {typeset a character and move right} 662 @d set_rule=132 {typeset a rule and move right} 663 @d put1=133 {typeset a character} 664 @d put_rule=137 {typeset a rule} 665 @d nop=138 {no operation} 666 @d bop=139 {beginning of page} 667 @d eop=140 {ending of page} 668 @d push=141 {save the current positions} 669 @d pop=142 {restore previous positions} 670 @d right1=143 {move right} 671 @d w0=147 {move right by |w|} 672 @d w1=148 {move right and set |w|} 673 @d x0=152 {move right by |x|} 674 @d x1=153 {move right and set |x|} 675 @d down1=157 {move down} 676 @d y0=161 {move down by |y|} 677 @d y1=162 {move down and set |y|} 678 @d z0=166 {move down by |z|} 679 @d z1=167 {move down and set |z|} 680 @d fnt_num_0=171 {set current font to 0} 681 @d fnt1=235 {set current font} 682 @d xxx1=239 {extension to \.{DVI} primitives} 683 @d xxx4=242 {potentially long extension to \.{DVI} primitives} 684 @d fnt_def1=243 {define the meaning of a font number} 685 @d pre=247 {preamble} 686 @d post=248 {postamble beginning} 687 @d post_post=249 {postamble ending} 688 @d undefined_commands==250,251,252,253,254,255 689 690 @ The preamble contains basic information about the file as a whole. As 691 stated above, there are six parameters: 692 $$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$ 693 The |i| byte identifies \.{DVI} format; currently this byte is always set 694 to~2. (The value |i=3| is currently used for an extended format that 695 allows a mixture of right-to-left and left-to-right typesetting. 696 Some day we will set |i=4|, when \.{DVI} format makes another 697 incompatible change---perhaps in the year 2048.) 698 699 The next two parameters, |num| and |den|, are positive integers that define 700 the units of measurement; they are the numerator and denominator of a 701 fraction by which all dimensions in the \.{DVI} file could be multiplied 702 in order to get lengths in units of $10^{-7}$ meters. (For example, there are 703 exactly 7227 \TeX\ points in 254 centimeters, and \TeX82 works with scaled 704 points where there are $2^{16}$ sp in a point, so \TeX82 sets |num=25400000| 705 and $|den|=7227\cdot2^{16}=473628672$.) 706 @^sp@> 707 708 The |mag| parameter is what \TeX82 calls \.{\\mag}, i.e., 1000 times the 709 desired magnification. The actual fraction by which dimensions are 710 multiplied is therefore $mn/1000d$. Note that if a \TeX\ source document 711 does not call for any `\.{true}' dimensions, and if you change it only by 712 specifying a different \.{\\mag} setting, the \.{DVI} file that \TeX\ 713 creates will be completely unchanged except for the value of |mag| in the 714 preamble and postamble. (Fancy \.{DVI}-reading programs allow users to 715 override the |mag|~setting when a \.{DVI} file is being printed.) 716 717 Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not 718 interpreted further. The length of comment |x| is |k|, where |0<=k<256|. 719 720 @d id_byte=2 {identifies the kind of \.{DVI} files described here} 721 722 @ Font definitions for a given font number |k| contain further parameters 723 $$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$ 724 The four-byte value |c| is the check sum that \TeX\ (or whatever program 725 generated the \.{DVI} file) found in the \.{TFM} file for this font; 726 |c| should match the check sum of the font found by programs that read 727 this \.{DVI} file. 728 @^check sum@> 729 730 Parameter |s| contains a fixed-point scale factor that is applied to the 731 character widths in font |k|; font dimensions in \.{TFM} files and other 732 font files are relative to this quantity, which is always positive and 733 less than $2^{27}$. It is given in the same units as the other dimensions 734 of the \.{DVI} file. Parameter |d| is similar to |s|; it is the ``design 735 size,'' and (like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be 736 used at $|mag|\cdot s/1000d$ times its normal size. 737 738 The remaining part of a font definition gives the external name of the font, 739 which is an ASCII string of length |a+l|. The number |a| is the length 740 of the ``area'' or directory, and |l| is the length of the font name itself; 741 the standard local system font area is supposed to be used when |a=0|. 742 The |n| field contains the area in its first |a| bytes. 743 744 Font definitions must appear before the first use of a particular font number. 745 Once font |k| is defined, it must not be defined again; however, we 746 shall see below that font definitions appear in the postamble as well as 747 in the pages, so in this sense each font number is defined exactly twice, 748 if at all. Like |nop| commands, font definitions can 749 appear before the first |bop|, or between an |eop| and a |bop|. 750 751 @ The last page in a \.{DVI} file is followed by `|post|'; this command 752 introduces the postamble, which summarizes important facts that \TeX\ has 753 accumulated about the file, making it possible to print subsets of the data 754 with reasonable efficiency. The postamble has the form 755 $$\vbox{\halign{\hbox{#\hfil}\cr 756 |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr 757 $\langle\,$font definitions$\,\rangle$\cr 758 |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$ 759 Here |p| is a pointer to the final |bop| in the file. The next three 760 parameters, |num|, |den|, and |mag|, are duplicates of the quantities that 761 appeared in the preamble. 762 763 Parameters |l| and |u| give respectively the height-plus-depth of the tallest 764 page and the width of the widest page, in the same units as other dimensions 765 of the file. These numbers might be used by a \.{DVI}-reading program to 766 position individual ``pages'' on large sheets of film or paper; however, 767 the standard convention for output on normal size paper is to position each 768 page so that the upper left-hand corner is exactly one inch from the left 769 and the top. Experience has shown that it is unwise to design \.{DVI}-to-printer 770 software that attempts cleverly to center the output; a fixed position of 771 the upper left corner is easiest for users to understand and to work with. 772 Therefore |l| and~|u| are often ignored. 773 774 Parameter |s| is the maximum stack depth (i.e., the largest excess of 775 |push| commands over |pop| commands) needed to process this file. Then 776 comes |t|, the total number of pages (|bop| commands) present. 777 778 The postamble continues with font definitions, which are any number of 779 \\{fnt\_def} commands as described above, possibly interspersed with |nop| 780 commands. Each font number that is used in the \.{DVI} file must be defined 781 exactly twice: Once before it is first selected by a \\{fnt} command, and once 782 in the postamble. 783 784 @ The last part of the postamble, following the |post_post| byte that 785 signifies the end of the font definitions, contains |q|, a pointer to the 786 |post| command that started the postamble. An identification byte, |i|, 787 comes next; this currently equals~2, as in the preamble. 788 789 The |i| byte is followed by four or more bytes that are all equal to 790 the decimal number 223 (i.e., @'337 in octal). \TeX\ puts out four to seven of 791 these trailing bytes, until the total length of the file is a multiple of 792 four bytes, since this works out best on machines that pack four bytes per 793 word; but any number of 223's is allowed, as long as there are at least four 794 of them. In effect, 223 is a sort of signature that is added at the very end. 795 @^Fuchs, David Raymond@> 796 797 This curious way to finish off a \.{DVI} file makes it feasible for 798 \.{DVI}-reading programs to find the postamble first, on most computers, 799 even though \TeX\ wants to write the postamble last. Most operating 800 systems permit random access to individual words or bytes of a file, so 801 the \.{DVI} reader can start at the end and skip backwards over the 223's 802 until finding the identification byte. Then it can back up four bytes, read 803 |q|, and move to byte |q| of the file. This byte should, of course, 804 contain the value 248 (|post|); now the postamble can be read, so the 805 \.{DVI} reader discovers all the information needed for typesetting the 806 pages. Note that it is also possible to skip through the \.{DVI} file at 807 reasonably high speed to locate a particular page, if that proves 808 desirable. This saves a lot of time, since \.{DVI} files used in production 809 jobs tend to be large. 810 811 Unfortunately, however, standard \PASCAL\ does not include the ability to 812 @^system dependencies@> 813 access a random position in a file, or even to determine the length of a file. 814 Almost all systems nowadays provide the necessary capabilities, so \.{DVI} 815 format has been designed to work most efficiently with modern operating systems. 816 As noted above, \.{DVItype} will limit itself to the restrictions of standard 817 \PASCAL\ if |random_reading| is defined to be |false|. 818 819 @* Input from binary files. 820 We have seen that a \.{DVI} file is a sequence of 8-bit bytes. The bytes 821 appear physically in what is called a `|packed file of 0..255|' 822 in \PASCAL\ lingo. 823 824 Packing is system dependent, and many \PASCAL\ systems fail to implement 825 such files in a sensible way (at least, from the viewpoint of producing 826 good production software). For example, some systems treat all 827 byte-oriented files as text, looking for end-of-line marks and such 828 things. Therefore some system-dependent code is often needed to deal with 829 binary files, even though most of the program in this section of 830 \.{DVItype} is written in standard \PASCAL. 831 @^system dependencies@> 832 833 One common way to solve the problem is to consider files of |integer| 834 numbers, and to convert an integer in the range $-2^{31}\L x<2^{31}$ to 835 a sequence of four bytes $(a,b,c,d)$ using the following code, which 836 avoids the controversial integer division of negative numbers: 837 $$\vbox{\halign{#\hfil\cr 838 |if x>=0 then a:=x div @'100000000|\cr 839 |else begin x:=(x+@'10000000000)+@'10000000000; a:=x div @'100000000+128;|\cr 840 \quad|end|\cr 841 |x:=x mod @'100000000;|\cr 842 |b:=x div @'200000; x:=x mod @'200000;|\cr 843 |c:=x div @'400; d:=x mod @'400;|\cr}}$$ 844 The four bytes are then kept in a buffer and output one by one. (On 36-bit 845 computers, an additional division by 16 is necessary at the beginning. 846 Another way to separate an integer into four bytes is to use/abuse 847 \PASCAL's variant records, storing an integer and retrieving bytes that are 848 packed in the same place; {\sl caveat implementor!\/}) It is also desirable 849 in some cases to read a hundred or so integers at a time, maintaining a 850 larger buffer. 851 852 We shall stick to simple \PASCAL\ in this program, for reasons of clarity, 853 even if such simplicity is sometimes unrealistic. 854 855 @<Types...@>= 856 @!eight_bits=0..255; {unsigned one-byte quantity} 857 @!byte_file=packed file of eight_bits; {files that contain binary data} 858 859 @ The program deals with two binary file variables: |dvi_file| is the main 860 input file that we are translating into symbolic form, and |tfm_file| is 861 the current font metric file from which character-width information is 862 being read. 863 864 @<Glob...@>= 865 @!dvi_file:byte_file; {the stuff we are \.{DVI}typing} 866 @!tfm_file:byte_file; {a font metric file} 867 868 @ To prepare these files for input, we |reset| them. An extension of 869 \PASCAL\ is needed in the case of |tfm_file|, since we want to associate 870 it with external files whose names are specified dynamically (i.e., not 871 known at compile time). The following code assumes that `|reset(f,s)|' 872 does this, when |f| is a file variable and |s| is a string variable that 873 specifies the file name. If |eof(f)| is true immediately after 874 |reset(f,s)| has acted, we assume that no file named |s| is accessible. 875 @^system dependencies@> 876 877 @p procedure open_dvi_file; {prepares to read packed bytes in |dvi_file|} 878 begin reset(dvi_file); 879 cur_loc:=0; 880 end; 881 @# 882 procedure open_tfm_file; {prepares to read packed bytes in |tfm_file|} 883 begin reset(tfm_file,cur_name); 884 end; 885 886 @ If you looked carefully at the preceding code, you probably asked, 887 ``What are |cur_loc| and |cur_name|?'' Good question. They're global 888 variables: |cur_loc| is the number of the byte about to be read next from 889 |dvi_file|, and |cur_name| is a string variable that will be set to the 890 current font metric file name before |open_tfm_file| is called. 891 892 @<Glob...@>= 893 @!cur_loc:integer; {where we are about to look, in |dvi_file|} 894 @!cur_name:packed array[1..name_length] of char; {external name, 895 with no lower case letters} 896 897 @ It turns out to be convenient to read four bytes at a time, when we are 898 inputting from \.{TFM} files. The input goes into global variables 899 |b0|, |b1|, |b2|, and |b3|, with |b0| getting the first byte and |b3| 900 the fourth. 901 902 @<Glob...@>= 903 @!b0,@!b1,@!b2,@!b3: eight_bits; {four bytes input at once} 904 905 @ The |read_tfm_word| procedure sets |b0| through |b3| to the next 906 four bytes in the current \.{TFM} file. 907 @^system dependencies@> 908 909 @p procedure read_tfm_word; 910 begin read(tfm_file,b0); read(tfm_file,b1); 911 read(tfm_file,b2); read(tfm_file,b3); 912 end; 913 914 @ We shall use another set of simple functions to read the next byte or 915 bytes from |dvi_file|. There are seven possibilities, each of which is 916 treated as a separate function in order to minimize the overhead for 917 subroutine calls. 918 @^system dependencies@> 919 920 @p function get_byte:integer; {returns the next byte, unsigned} 921 var b:eight_bits; 922 begin if eof(dvi_file) then get_byte:=0 923 else begin read(dvi_file,b); incr(cur_loc); get_byte:=b; 924 end; 925 end; 926 @# 927 function signed_byte:integer; {returns the next byte, signed} 928 var b:eight_bits; 929 begin read(dvi_file,b); incr(cur_loc); 930 if b<128 then signed_byte:=b @+ else signed_byte:=b-256; 931 end; 932 @# 933 function get_two_bytes:integer; {returns the next two bytes, unsigned} 934 var a,@!b:eight_bits; 935 begin read(dvi_file,a); read(dvi_file,b); 936 cur_loc:=cur_loc+2; 937 get_two_bytes:=a*256+b; 938 end; 939 @# 940 function signed_pair:integer; {returns the next two bytes, signed} 941 var a,@!b:eight_bits; 942 begin read(dvi_file,a); read(dvi_file,b); 943 cur_loc:=cur_loc+2; 944 if a<128 then signed_pair:=a*256+b 945 else signed_pair:=(a-256)*256+b; 946 end; 947 @# 948 function get_three_bytes:integer; {returns the next three bytes, unsigned} 949 var a,@!b,@!c:eight_bits; 950 begin read(dvi_file,a); read(dvi_file,b); read(dvi_file,c); 951 cur_loc:=cur_loc+3; 952 get_three_bytes:=(a*256+b)*256+c; 953 end; 954 @# 955 function signed_trio:integer; {returns the next three bytes, signed} 956 var a,@!b,@!c:eight_bits; 957 begin read(dvi_file,a); read(dvi_file,b); read(dvi_file,c); 958 cur_loc:=cur_loc+3; 959 if a<128 then signed_trio:=(a*256+b)*256+c 960 else signed_trio:=((a-256)*256+b)*256+c; 961 end; 962 @# 963 function signed_quad:integer; {returns the next four bytes, signed} 964 var a,@!b,@!c,@!d:eight_bits; 965 begin read(dvi_file,a); read(dvi_file,b); read(dvi_file,c); read(dvi_file,d); 966 cur_loc:=cur_loc+4; 967 if a<128 then signed_quad:=((a*256+b)*256+c)*256+d 968 else signed_quad:=(((a-256)*256+b)*256+c)*256+d; 969 end; 970 971 @ Finally we come to the routines that are used only if |random_reading| is 972 |true|. The driver program below needs two such routines: |dvi_length| should 973 compute the total number of bytes in |dvi_file|, possibly also 974 causing |eof(dvi_file)| to be true; and |move_to_byte(n)| 975 should position |dvi_file| so that the next |get_byte| will read byte |n|, 976 starting with |n=0| for the first byte in the file. 977 @^system dependencies@> 978 979 Such routines are, of course, highly system dependent. They are implemented 980 here in terms of two assumed system routines called |set_pos| and |cur_pos|. 981 The call |set_pos(f,n)| moves to item |n| in file |f|, unless |n| is 982 negative or larger than the total number of items in |f|; in the latter 983 case, |set_pos(f,n)| moves to the end of file |f|. 984 The call |cur_pos(f)| gives the total number of items in |f|, if 985 |eof(f)| is true; we use |cur_pos| only in such a situation. 986 987 @p function dvi_length:integer; 988 begin set_pos(dvi_file,-1); dvi_length:=cur_pos(dvi_file); 989 end; 990 @# 991 procedure move_to_byte(n:integer); 992 begin set_pos(dvi_file,n); cur_loc:=n; 993 end; 994 995 @* Reading the font information. 996 \.{DVI} file format does not include information about character widths, since 997 that would tend to make the files a lot longer. But a program that reads 998 a \.{DVI} file is supposed to know the widths of the characters that appear 999 in \\{set\_char} commands. Therefore \.{DVItype} looks at the font metric 1000 (\.{TFM}) files for the fonts that are involved. 1001 @.TFM {\rm files}@> 1002 1003 The character-width data appears also in other files (e.g., in \.{GF} files 1004 that specify bit patterns for digitized characters); 1005 thus, it is usually possible for \.{DVI} reading programs to get by with 1006 accessing only one file per font. \.{DVItype} has a comparatively easy 1007 task in this regard, since it needs only a few words of information from 1008 each font; other \.{DVI}-to-printer programs may have to go to some pains to 1009 deal with complications that arise when a large number of large font files 1010 all need to be accessed simultaneously. 1011 1012 @ For purposes of this program, we need to know only two things about a 1013 given character |c| in a given font |f|: (1)~Is |c| a legal character 1014 in~|f|? (2)~If so, what is the width of |c|? We also need to know the 1015 symbolic name of each font, so it can be printed out, and we need to know 1016 the approximate size of inter-word spaces in each font. 1017 1018 The answers to these questions appear implicitly in the following data 1019 structures. The current number of known fonts is |nf|. Each known font has 1020 an internal number |f|, where |0<=f<nf|; the external number of this font, 1021 i.e., its font identification number in the \.{DVI} file, is 1022 |font_num[f]|, and the external name of this font is the string that 1023 occupies positions |font_name[f]| through |font_name[f+1]-1| of the array 1024 |names|. The latter array consists of |ASCII_code| characters, and 1025 |font_name[nf]| is its first unoccupied position. A horizontal motion 1026 in the range |-4*font_space[f]<h<font_space[f]| 1027 will be treated as a `kern' that is not 1028 indicated in the printouts that \.{DVItype} produces between brackets. The 1029 legal characters run from |font_bc[f]| to |font_ec[f]|, inclusive; more 1030 precisely, a given character |c| is valid in font |f| if and only if 1031 |font_bc[f]<=c<=font_ec[f]| and |char_width(f)(c)<>invalid_width|. 1032 Finally, |char_width(f)(c)=width[width_base[f]+c]|, and |width_ptr| is the 1033 first unused position of the |width| array. 1034 1035 @d char_width_end(#)==#] 1036 @d char_width(#)==width[width_base[#]+char_width_end 1037 @d invalid_width==@'17777777777 1038 @d invalid_font==max_fonts 1039 1040 @<Glob...@>= 1041 @!font_num:array [0..max_fonts] of integer; {external font numbers} 1042 @!font_name:array [0..max_fonts] of 1..name_size; {starting positions 1043 of external font names} 1044 @!names:array [1..name_size] of ASCII_code; {characters of names} 1045 @!font_check_sum:array [0..max_fonts] of integer; {check sums} 1046 @!font_scaled_size:array [0..max_fonts] of integer; {scale factors} 1047 @!font_design_size:array [0..max_fonts] of integer; {design sizes} 1048 @!font_space:array [0..max_fonts] of integer; {boundary between ``small'' 1049 and ``large'' spaces} 1050 @!font_bc:array [0..max_fonts] of integer; {beginning characters in fonts} 1051 @!font_ec:array [0..max_fonts] of integer; {ending characters in fonts} 1052 @!width_base:array [0..max_fonts] of integer; {index into |width| table} 1053 @!width:array [0..max_widths] of integer; {character widths, in \.{DVI} units} 1054 @!nf:0..max_fonts; {the number of known fonts} 1055 @!width_ptr:0..max_widths; {the number of known character widths} 1056 1057 @ @<Set init...@>= 1058 nf:=0; width_ptr:=0; font_name[0]:=1;@/ 1059 font_space[invalid_font]:=0; {for |out_space| and |out_vmove|} 1060 font_bc[invalid_font]:=1; font_ec[invalid_font]:=0; 1061 1062 @ It is, of course, a simple matter to print the name of a given font. 1063 1064 @p procedure print_font(@!f:integer); {|f| is an internal font number} 1065 var k:0..name_size; {index into |names|} 1066 begin if f=invalid_font then print('UNDEFINED!') 1067 @.UNDEFINED@> 1068 else begin for k:=font_name[f] to font_name[f+1]-1 do 1069 print(xchr[names[k]]); 1070 end; 1071 end; 1072 1073 @ An auxiliary array |in_width| is used to hold the widths as they are 1074 input. The global variables |tfm_check_sum| and |tfm_design_size| are 1075 set to the check sum and design size that 1076 appear in the current \.{TFM} file. 1077 1078 @<Glob...@>= 1079 @!in_width:array[0..255] of integer; {\.{TFM} width data in \.{DVI} units} 1080 @!tfm_check_sum:integer; {check sum found in |tfm_file|} 1081 @!tfm_design_size:integer; {design size found in |tfm_file|, in \.{DVI} units} 1082 @!tfm_conv:real; {\.{DVI} units per absolute \.{TFM} unit} 1083 1084 @ Here is a procedure that absorbs the necessary information from a 1085 \.{TFM} file, assuming that the file has just been successfully reset 1086 so that we are ready to read its first byte. (A complete description of 1087 \.{TFM} file format appears in the documentation of \.{TFtoPL} and will 1088 not be repeated here.) The procedure does not check the \.{TFM} file 1089 for validity, nor does it give explicit information about what is 1090 wrong with a \.{TFM} file that proves to be invalid; \.{DVI}-reading 1091 programs need not do this, since \.{TFM} files are almost always valid, 1092 and since the \.{TFtoPL} utility program has been specifically designed 1093 to diagnose \.{TFM} errors. The procedure simply returns |false| if it 1094 detects anything amiss in the \.{TFM} data. 1095 1096 There is a parameter, |z|, which represents the scaling factor being 1097 used to compute the font dimensions; it must be in the range $0<z<2^{27}$. 1098 1099 @p function in_TFM(@!z:integer):boolean; {input \.{TFM} data or return |false|} 1100 label 9997, {go here when the format is bad} 1101 9998, {go here when the information cannot be loaded} 1102 9999; {go here to exit} 1103 var k:integer; {index for loops} 1104 @!lh:integer; {length of the header data, in four-byte words} 1105 @!nw:integer; {number of words in the width table} 1106 @!wp:0..max_widths; {new value of |width_ptr| after successful input} 1107 @!alpha,@!beta:integer; {quantities used in the scaling computation} 1108 begin @<Read past the header data; |goto 9997| if there is a problem@>; 1109 @<Store character-width indices at the end of the |width| table@>; 1110 @<Read and convert the width values, setting up the |in_width| table@>; 1111 @<Move the widths from |in_width| to |width|, and append |pixel_width| values@>; 1112 width_ptr:=wp; in_TFM:=true; goto 9999; 1113 9997: print_ln('---not loaded, TFM file is bad'); 1114 @.TFM file is bad@> 1115 9998: in_TFM:=false; 1116 9999: end; 1117 1118 @ @<Read past the header...@>= 1119 read_tfm_word; lh:=b2*256+b3; 1120 read_tfm_word; font_bc[nf]:=b0*256+b1; font_ec[nf]:=b2*256+b3; 1121 if font_ec[nf]<font_bc[nf] then font_bc[nf]:=font_ec[nf]+1; 1122 if width_ptr+font_ec[nf]-font_bc[nf]+1>max_widths then 1123 begin print_ln('---not loaded, DVItype needs larger width table'); 1124 @.DVItype needs larger...@> 1125 goto 9998; 1126 end; 1127 wp:=width_ptr+font_ec[nf]-font_bc[nf]+1; 1128 read_tfm_word; nw:=b0*256+b1; 1129 if (nw=0)or(nw>256) then goto 9997; 1130 for k:=1 to 3+lh do 1131 begin if eof(tfm_file) then goto 9997; 1132 read_tfm_word; 1133 if k=4 then 1134 if b0<128 then tfm_check_sum:=((b0*256+b1)*256+b2)*256+b3 1135 else tfm_check_sum:=(((b0-256)*256+b1)*256+b2)*256+b3 1136 else if k=5 then 1137 if b0<128 then 1138 tfm_design_size:=round(tfm_conv*(((b0*256+b1)*256+b2)*256+b3)) 1139 else goto 9997; 1140 end; 1141 1142 @ @<Store character-width indices...@>= 1143 if wp>0 then for k:=width_ptr to wp-1 do 1144 begin read_tfm_word; 1145 if b0>nw then goto 9997; 1146 width[k]:=b0; 1147 end; 1148 1149 @ The most important part of |in_TFM| is the width computation, which 1150 involves multiplying the relative widths in the \.{TFM} file by the 1151 scaling factor in the \.{DVI} file. This fixed-point multiplication 1152 must be done with precisely the same accuracy by all \.{DVI}-reading programs, 1153 in order to validate the assumptions made by \.{DVI}-writing programs 1154 like \TeX82. 1155 1156 Let us therefore summarize what needs to be done. Each width in a \.{TFM} 1157 file appears as a four-byte quantity called a |fix_word|. A |fix_word| 1158 whose respective bytes are $(a,b,c,d)$ represents the number 1159 $$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr 1160 b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr 1161 -16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$ 1162 (No other choices of $a$ are allowed, since the magnitude of a \.{TFM} 1163 dimension must be less than 16.) We want to multiply this quantity by the 1164 integer~|z|, which is known to be less than $2^{27}$. 1165 If $|z|<2^{23}$, the individual multiplications $b\cdot z$, $c\cdot z$, 1166 $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2, 4, 8, or 1167 16, to obtain a multiplier less than $2^{23}$, and we can compensate for 1168 this later. If |z| has thereby been replaced by $|z|^\prime=|z|/2^e$, let 1169 $\beta=2^{4-e}$; we shall compute 1170 $$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$ if $a=0$, 1171 or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$. 1172 This calculation must be 1173 done exactly, for the reasons stated above; the following program does the 1174 job in a system-independent way, assuming that arithmetic is exact on 1175 numbers less than $2^{31}$ in magnitude. 1176 1177 @<Read and convert the width values...@>= 1178 @<Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$@>; 1179 for k:=0 to nw-1 do 1180 begin read_tfm_word; 1181 in_width[k]:=(((((b3*z)div@'400)+(b2*z))div@'400)+(b1*z))div beta; 1182 if b0>0 then if b0<255 then goto 9997 1183 else in_width[k]:=in_width[k]-alpha; 1184 end 1185 1186 @ @<Replace |z|...@>= 1187 begin alpha:=16; 1188 while z>=@'40000000 do 1189 begin z:=z div 2; alpha:=alpha+alpha; 1190 end; 1191 beta:=256 div alpha; alpha:=alpha*z; 1192 end 1193 1194 @ A \.{DVI}-reading program usually works with font files instead of 1195 \.{TFM} files, so \.{DVItype} is atypical in that respect. Font files 1196 should, however, contain exactly the same character width data that is 1197 found in the corresponding \.{TFM}s; check sums are used to help 1198 ensure this. In addition, font files usually also contain the widths of 1199 characters in pixels, since the device-independent character widths of 1200 \.{TFM} files are generally not perfect multiples of pixels. 1201 1202 The |pixel_width| array contains this information; when |width[k]| is the 1203 device-independent width of some character in \.{DVI} units, |pixel_width[k]| 1204 is the corresponding width of that character in an actual font. 1205 The macro |char_pixel_width| is set up to be analogous to |char_width|. 1206 1207 @d char_pixel_width(#)==pixel_width[width_base[#]+char_width_end 1208 1209 @<Glob...@>= 1210 @!pixel_width:array[0..max_widths] of integer; {actual character widths, 1211 in pixels} 1212 @!conv:real; {converts \.{DVI} units to pixels} 1213 @!true_conv:real; {converts unmagnified \.{DVI} units to pixels} 1214 @!numerator,@!denominator:integer; {stated conversion ratio} 1215 @!mag:integer; {magnification factor times 1000} 1216 1217 @ The following code computes pixel widths by simply rounding the \.{TFM} 1218 widths to the nearest integer number of pixels, based on the conversion factor 1219 |conv| that converts \.{DVI} units to pixels. However, such a simple 1220 formula will not be valid for all fonts, and it will often give results that 1221 are off by $\pm1$ when a low-resolution font has been carefully 1222 hand-fitted. For example, a font designer often wants to make the letter `m' 1223 a pixel wider or narrower in order to make the font appear more consistent. 1224 \.{DVI}-to-printer programs should therefore input the correct pixel width 1225 information from font files whenever there is a chance that it may differ. 1226 A warning message may also be desirable in the case that at least one character 1227 is found whose pixel width differs from |conv*width| by more than a full pixel. 1228 @^system dependencies@> 1229 1230 @d pixel_round(#)==round(conv*(#)) 1231 1232 @<Move the widths from |in_width| to |width|, and append |pixel_width| values@>= 1233 if in_width[0]<>0 then goto 9997; {the first width should be zero} 1234 width_base[nf]:=width_ptr-font_bc[nf]; 1235 if wp>0 then for k:=width_ptr to wp-1 do 1236 if width[k]=0 then 1237 begin width[k]:=invalid_width; pixel_width[k]:=0; 1238 end 1239 else begin width[k]:=in_width[width[k]]; 1240 pixel_width[k]:=pixel_round(width[k]); 1241 end 1242 1243 @* Optional modes of output. 1244 \.{DVItype} will print different quantities of information based on some 1245 options that the user must specify: The |out_mode| level is set to one of 1246 five values (|errors_only|, |terse|, |mnemonics_only|, 1247 |verbose|, |the_works|), giving 1248 different degrees of output; and the listing can be confined to a 1249 restricted subset of the pages by specifying the desired starting page and 1250 the maximum number of pages. Furthermore there is an option to specify the 1251 resolution of an assumed discrete output device, so that pixel-oriented 1252 calculations will be shown; and there is an option to override the 1253 magnification factor that is stated in the \.{DVI} file. 1254 1255 The starting page is specified by giving a sequence of 1 to 10 numbers or 1256 asterisks separated by dots. For example, the specification `\.{1.*.-5}' 1257 can be used to refer to a page output by \TeX\ when $\.{\\count0}=1$ 1258 and $\.{\\count2}=-5$. (Recall that |bop| commands in a \.{DVI} file 1259 are followed by ten `count' values.) An asterisk matches any number, 1260 so the `\.*' in `\.{1.*.-5}' means that \.{\\count1} is ignored when 1261 specifying the first page. If several pages match the given specification, 1262 \.{DVItype} will begin with the earliest such page in the file. The 1263 default specification `\.*' (which matches all pages) therefore denotes 1264 the page at the beginning of the file. 1265 1266 When \.{DVItype} begins, it engages the user in a brief dialog so that the 1267 options will be specified. This part of \.{DVItype} requires nonstandard 1268 \PASCAL\ constructions to handle the online interaction; so it may be 1269 preferable in some cases to omit the dialog and simply to stick to the 1270 default options (|out_mode=the_works|, starting page `\.*', 1271 |max_pages=1000000|, |resolution=300.0|, |new_mag=0|). On other hand, the 1272 system-dependent routines that are needed are not complicated, so it will 1273 not be terribly difficult to introduce them. 1274 @^system dependencies@> 1275 1276 @d errors_only=0 {value of |out_mode| when minimal printing occurs} 1277 @d terse=1 {value of |out_mode| for abbreviated output} 1278 @d mnemonics_only=2 {value of |out_mode| for medium-quantity output} 1279 @d verbose=3 {value of |out_mode| for detailed tracing} 1280 @d the_works=4 {|verbose|, plus check of postamble if |random_reading|} 1281 1282 @<Glob...@>= 1283 @!out_mode:errors_only..the_works; {controls the amount of output} 1284 @!max_pages:integer; {at most this many |bop..eop| pages will be printed} 1285 @!resolution:real; {pixels per inch} 1286 @!new_mag:integer; {if positive, overrides the postamble's magnification} 1287 1288 @ The starting page specification is recorded in two global arrays called 1289 |start_count| and |start_there|. For example, `\.{1.*.-5}' is represented 1290 by |start_there[0]=true|, |start_count[0]=1|, |start_there[1]=false|, 1291 |start_there[2]=true|, |start_count[2]=-5|. 1292 We also set |start_vals=2|, to indicate that count 2 was the last one 1293 mentioned. The other values of |start_count| and |start_there| are not 1294 important, in this example. 1295 1296 @<Glob...@>= 1297 @!start_count:array[0..9] of integer; {count values to select starting page} 1298 @!start_there:array[0..9] of boolean; {is the |start_count| value relevant?} 1299 @!start_vals:0..9; {the last count considered significant} 1300 @!count:array[0..9] of integer; {the count values on the current page} 1301 1302 @ @<Set init...@>= 1303 out_mode:=the_works; max_pages:=1000000; start_vals:=0; start_there[0]:=false; 1304 1305 @ Here is a simple subroutine that tests if the current page might be the 1306 starting page. 1307 1308 @p function start_match:boolean; {does |count| match the starting spec?} 1309 var k:0..9; {loop index} 1310 @!match:boolean; {does everything match so far?} 1311 begin match:=true; 1312 for k:=0 to start_vals do 1313 if start_there[k]and(start_count[k]<>count[k]) then match:=false; 1314 start_match:=match; 1315 end; 1316 1317 @ The |input_ln| routine waits for the user to type a line at his or her 1318 terminal; then it puts ASCII-code equivalents for the characters on that line 1319 into the |buffer| array. The |term_in| file is used for terminal input, 1320 and |term_out| for terminal output. 1321 @^system dependencies@> 1322 1323 @<Glob...@>= 1324 @!buffer:array[0..terminal_line_length] of ASCII_code; 1325 @!term_in:text_file; {the terminal, considered as an input file} 1326 @!term_out:text_file; {the terminal, considered as an output file} 1327 1328 @ Since the terminal is being used for both input and output, some systems 1329 need a special routine to make sure that the user can see a prompt message 1330 before waiting for input based on that message. (Otherwise the message 1331 may just be sitting in a hidden buffer somewhere, and the user will have 1332 no idea what the program is waiting for.) We shall invoke a system-dependent 1333 subroutine |update_terminal| in order to avoid this problem. 1334 @^system dependencies@> 1335 1336 @d update_terminal == break(term_out) {empty the terminal output buffer} 1337 1338 @ During the dialog, \.{DVItype} will treat the first blank space in a 1339 line as the end of that line. Therefore |input_ln| makes sure that there 1340 is always at least one blank space in |buffer|. 1341 @^system dependencies@> 1342 1343 @p procedure input_ln; {inputs a line from the terminal} 1344 var k:0..terminal_line_length; 1345 begin update_terminal; reset(term_in); 1346 if eoln(term_in) then read_ln(term_in); 1347 k:=0; 1348 while (k<terminal_line_length)and not eoln(term_in) do 1349 begin buffer[k]:=xord[term_in^]; incr(k); get(term_in); 1350 end; 1351 buffer[k]:=" "; 1352 end; 1353 1354 @ The global variable |buf_ptr| is used while scanning each line of input; 1355 it points to the first unread character in |buffer|. 1356 1357 @<Glob...@>= 1358 @!buf_ptr:0..terminal_line_length; {the number of characters read} 1359 1360 @ Here is a routine that scans a (possibly signed) integer and computes 1361 the decimal value. If no decimal integer starts at |buf_ptr|, the 1362 value 0 is returned. The integer should be less than $2^{31}$ in 1363 absolute value. 1364 1365 @p function get_integer:integer; 1366 var x:integer; {accumulates the value} 1367 @!negative:boolean; {should the value be negated?} 1368 begin if buffer[buf_ptr]="-" then 1369 begin negative:=true; incr(buf_ptr); 1370 end 1371 else negative:=false; 1372 x:=0; 1373 while (buffer[buf_ptr]>="0")and(buffer[buf_ptr]<="9") do 1374 begin x:=10*x+buffer[buf_ptr]-"0"; incr(buf_ptr); 1375 end; 1376 if negative then get_integer:=-x @+ else get_integer:=x; 1377 end; 1378 1379 @ The selected options are put into global variables by the |dialog| 1380 procedure, which is called just as \.{DVItype} begins. 1381 @^system dependencies@> 1382 1383 @p procedure dialog; 1384 label 1,2,3,4,5; 1385 var k:integer; {loop variable} 1386 begin rewrite(term_out); {prepare the terminal for output} 1387 write_ln(term_out,banner); 1388 @<Determine the desired |out_mode|@>; 1389 @<Determine the desired |start_count| values@>; 1390 @<Determine the desired |max_pages|@>; 1391 @<Determine the desired |resolution|@>; 1392 @<Determine the desired |new_mag|@>; 1393 @<Print all the selected options@>; 1394 end; 1395 1396 @ @<Determine the desired |out_mode|@>= 1397 1: write(term_out,'Output level (default=4, ? for help): '); 1398 out_mode:=the_works; input_ln; 1399 if buffer[0]<>" " then 1400 if (buffer[0]>="0")and(buffer[0]<="4") then out_mode:=buffer[0]-"0" 1401 else begin write(term_out,'Type 4 for complete listing,'); 1402 write(term_out,' 0 for errors and fonts only,'); 1403 write_ln(term_out,' 1 or 2 or 3 for something in between.'); 1404 goto 1; 1405 end 1406 1407 @ @<Determine the desired |start...@>= 1408 2: write(term_out,'Starting page (default=*): '); 1409 start_vals:=0; start_there[0]:=false; 1410 input_ln; buf_ptr:=0; k:=0; 1411 if buffer[0]<>" " then 1412 repeat if buffer[buf_ptr]="*" then 1413 begin start_there[k]:=false; incr(buf_ptr); 1414 end 1415 else begin start_there[k]:=true; start_count[k]:=get_integer; 1416 end; 1417 if (k<9)and(buffer[buf_ptr]=".") then 1418 begin incr(k); incr(buf_ptr); 1419 end 1420 else if buffer[buf_ptr]=" " then start_vals:=k 1421 else begin write(term_out,'Type, e.g., 1.*.-5 to specify the '); 1422 write_ln(term_out,'first page with \count0=1, \count2=-5.'); 1423 goto 2; 1424 end; 1425 until start_vals=k 1426 1427 @ @<Determine the desired |max_pages|@>= 1428 3: write(term_out,'Maximum number of pages (default=1000000): '); 1429 max_pages:=1000000; input_ln; buf_ptr:=0; 1430 if buffer[0]<>" " then 1431 begin max_pages:=get_integer; 1432 if max_pages<=0 then 1433 begin write_ln(term_out,'Please type a positive number.'); 1434 goto 3; 1435 end; 1436 end 1437 1438 @ @<Determine the desired |resolution|@>= 1439 4: write(term_out,'Assumed device resolution'); 1440 write(term_out,' in pixels per inch (default=300/1): '); 1441 resolution:=300.0; input_ln; buf_ptr:=0; 1442 if buffer[0]<>" " then 1443 begin k:=get_integer; 1444 if (k>0)and(buffer[buf_ptr]="/")and 1445 (buffer[buf_ptr+1]>"0")and(buffer[buf_ptr+1]<="9") then 1446 begin incr(buf_ptr); resolution:=k/get_integer; 1447 end 1448 else begin write(term_out,'Type a ratio of positive integers;'); 1449 write_ln(term_out,' (1 pixel per mm would be 254/10).'); 1450 goto 4; 1451 end; 1452 end 1453 1454 @ @<Determine the desired |new_mag|@>= 1455 5: write(term_out,'New magnification (default=0 to keep the old one): '); 1456 new_mag:=0; input_ln; buf_ptr:=0; 1457 if buffer[0]<>" " then 1458 if (buffer[0]>="0")and(buffer[0]<="9") then new_mag:=get_integer 1459 else begin write(term_out,'Type a positive integer to override '); 1460 write_ln(term_out,'the magnification in the DVI file.'); 1461 goto 5; 1462 end 1463 1464 @ After the dialog is over, we print the options so that the user 1465 can see what \.{DVItype} thought was specified. 1466 1467 @<Print all the selected options@>= 1468 print_ln('Options selected:'); 1469 @.Options selected@> 1470 print(' Starting page = '); 1471 for k:=0 to start_vals do 1472 begin if start_there[k] then print(start_count[k]:1) 1473 else print('*'); 1474 if k<start_vals then print('.') 1475 else print_ln(' '); 1476 end; 1477 print_ln(' Maximum number of pages = ',max_pages:1); 1478 print(' Output level = ',out_mode:1); 1479 case out_mode of 1480 errors_only: print_ln(' (showing bops, fonts, and error messages only)'); 1481 terse: print_ln(' (terse)'); 1482 mnemonics_only: print_ln(' (mnemonics)'); 1483 verbose: print_ln(' (verbose)'); 1484 the_works: if random_reading then print_ln(' (the works)') 1485 else begin out_mode:=verbose; 1486 print_ln(' (the works: same as level 3 in this DVItype)'); 1487 end; 1488 end;@/ 1489 print_ln(' Resolution = ',resolution:12:8,' pixels per inch'); 1490 if new_mag>0 then print_ln(' New magnification factor = ',new_mag/1000:8:3) 1491 1492 @* Defining fonts. 1493 When |out_mode=the_works|, \.{DVItype} reads the postamble first and loads 1494 all of the fonts defined there; then it processes the pages. In this 1495 case, a \\{fnt\_def} command should match a previous definition if and only 1496 if the \\{fnt\_def} being processed is not in the postamble. But if 1497 |out_mode<the_works|, \.{DVItype} reads the pages first and the postamble 1498 last, so the conventions are reversed: a \\{fnt\_def} should match a previous 1499 \\{fnt\_def} if and only if the current one is a part of the postamble. 1500 1501 A global variable |in_postamble| is provided to tell whether we are 1502 processing the postamble or not. 1503 1504 @<Glob...@>= 1505 @!in_postamble:boolean; {are we reading the postamble?} 1506 1507 @ @<Set init...@>= 1508 in_postamble:=false; 1509 1510 @ The following subroutine does the necessary things when a \\{fnt\_def} 1511 command is being processed. 1512 1513 @p procedure define_font(@!e:integer); {|e| is an external font number} 1514 var f:0..max_fonts; 1515 @!p:integer; {length of the area/directory spec} 1516 @!n:integer; {length of the font name proper} 1517 @!c,@!q,@!d,@!m:integer; {check sum, scaled size, design size, magnification} 1518 @!r:0..name_length; {index into |cur_name|} 1519 @!j,@!k:0..name_size; {indices into |names|} 1520 @!mismatch:boolean; {do names disagree?} 1521 begin if nf=max_fonts then abort('DVItype capacity exceeded (max fonts=', 1522 max_fonts:1,')!'); 1523 @.DVItype capacity exceeded...@> 1524 font_num[nf]:=e; f:=0; 1525 while font_num[f]<>e do incr(f); 1526 @<Read the font parameters into position for font |nf|, and 1527 print the font name@>; 1528 if ((out_mode=the_works)and in_postamble)or@| 1529 ((out_mode<the_works)and not in_postamble) then 1530 begin if f<nf then print_ln('---this font was already defined!'); 1531 @.this font was already defined@> 1532 end 1533 else begin if f=nf then print_ln('---this font wasn''t loaded before!'); 1534 @.this font wasn't loaded before@> 1535 end; 1536 if f=nf then @<Load the new font, unless there are problems@> 1537 else @<Check that the current font definition matches the old one@>; 1538 end; 1539 1540 @ @<Check that the current...@>= 1541 begin if font_check_sum[f]<>c then 1542 print_ln('---check sum doesn''t match previous definition!'); 1543 @.check sum doesn't match@> 1544 if font_scaled_size[f]<>q then 1545 print_ln('---scaled size doesn''t match previous definition!'); 1546 @.scaled size doesn't match@> 1547 if font_design_size[f]<>d then 1548 print_ln('---design size doesn''t match previous definition!'); 1549 @.design size doesn't match@> 1550 j:=font_name[f]; k:=font_name[nf]; 1551 if font_name[f+1]-j<>font_name[nf+1]-k then mismatch:=true 1552 else begin mismatch:=false; 1553 while j<font_name[f+1] do 1554 begin if names[j]<>names[k] then mismatch:=true; 1555 incr(j); incr(k); 1556 end; 1557 end; 1558 if mismatch then print_ln('---font name doesn''t match previous definition!'); 1559 @.font name doesn't match@> 1560 end 1561 1562 @ @<Read the font parameters into position for font |nf|...@>= 1563 c:=signed_quad; font_check_sum[nf]:=c;@/ 1564 q:=signed_quad; font_scaled_size[nf]:=q;@/ 1565 d:=signed_quad; font_design_size[nf]:=d;@/ 1566 if (q<=0) or (d<=0) then m:=1000 1567 else m:=round((1000.0*conv*q)/(true_conv*d)); 1568 p:=get_byte; n:=get_byte; 1569 if font_name[nf]+n+p>name_size then 1570 abort('DVItype capacity exceeded (name size=',name_size:1,')!'); 1571 @.DVItype capacity exceeded...@> 1572 font_name[nf+1]:=font_name[nf]+n+p; 1573 if showing then print(': ') 1574 {when |showing| is true, the font number has already been printed} 1575 else print('Font ',e:1,': '); 1576 if n+p=0 then print('null font name!') 1577 @.null font name@> 1578 else for k:=font_name[nf] to font_name[nf+1]-1 do names[k]:=get_byte; 1579 print_font(nf); 1580 if not showing then if m<>1000 then print(' scaled ',m:1) 1581 @.scaled@> 1582 1583 @ @<Load the new font, unless there are problems@>= 1584 begin @<Move font name into the |cur_name| string@>; 1585 open_tfm_file; 1586 if eof(tfm_file) then 1587 print('---not loaded, TFM file can''t be opened!') 1588 @.TFM file can\'t be opened@> 1589 else begin if (q<=0)or(q>=@'1000000000) then 1590 print('---not loaded, bad scale (',q:1,')!') 1591 @.bad scale@> 1592 else if (d<=0)or(d>=@'1000000000) then 1593 print('---not loaded, bad design size (',d:1,')!') 1594 @.bad design size@> 1595 else if in_TFM(q) then @<Finish loading the new font info@>; 1596 end; 1597 if out_mode=errors_only then print_ln(' '); 1598 end 1599 1600 @ @<Finish loading...@>= 1601 begin font_space[nf]:=q div 6; {this is a 3-unit ``thin space''} 1602 if (c<>0)and(tfm_check_sum<>0)and(c<>tfm_check_sum) then 1603 begin print_ln('---beware: check sums do not agree!'); 1604 @.beware: check sums do not agree@> 1605 @.check sums do not agree@> 1606 print_ln(' (',c:1,' vs. ',tfm_check_sum:1,')'); 1607 print(' '); 1608 end; 1609 if abs(tfm_design_size-d)>2 then 1610 begin print_ln('---beware: design sizes do not agree!'); 1611 @.beware: design sizes do not agree@> 1612 @.design sizes do not agree@> 1613 print_ln(' (',d:1,' vs. ',tfm_design_size:1,')'); 1614 print(' '); 1615 end; 1616 print('---loaded at size ',q:1,' DVI units'); 1617 d:=round((100.0*conv*q)/(true_conv*d)); 1618 if d<>100 then 1619 begin print_ln(' '); print(' (this font is magnified ',d:1,'%)'); 1620 end; 1621 @.this font is magnified@> 1622 incr(nf); {now the new font is officially present} 1623 end 1624 1625 @ If |p=0|, i.e., if no font directory has been specified, \.{DVItype} 1626 is supposed to use the default font directory, which is a 1627 system-dependent place where the standard fonts are kept. 1628 The string variable |default_directory| contains the name of this area. 1629 @^system dependencies@> 1630 1631 @d default_directory_name=='TeXfonts:' {change this to the correct name} 1632 @d default_directory_name_length=9 {change this to the correct length} 1633 1634 @<Glob...@>= 1635 @!default_directory:packed array[1..default_directory_name_length] of char; 1636 1637 @ @<Set init...@>= 1638 default_directory:=default_directory_name; 1639 1640 @ The string |cur_name| is supposed to be set to the external name of the 1641 \.{TFM} file for the current font. This usually means that we need to 1642 prepend the name of the default directory, and 1643 to append the suffix `\.{.TFM}'. Furthermore, we change lower case letters 1644 to upper case, since |cur_name| is a \PASCAL\ string. 1645 @^system dependencies@> 1646 1647 @<Move font name into the |cur_name| string@>= 1648 for k:=1 to name_length do cur_name[k]:=' '; 1649 if p=0 then 1650 begin for k:=1 to default_directory_name_length do 1651 cur_name[k]:=default_directory[k]; 1652 r:=default_directory_name_length; 1653 end 1654 else r:=0; 1655 for k:=font_name[nf] to font_name[nf+1]-1 do 1656 begin incr(r); 1657 if r+4>name_length then 1658 abort('DVItype capacity exceeded (max font name length=', 1659 name_length:1,')!'); 1660 @.DVItype capacity exceeded...@> 1661 if (names[k]>="a")and(names[k]<="z") then 1662 cur_name[r]:=xchr[names[k]-@'40] 1663 else cur_name[r]:=xchr[names[k]]; 1664 end; 1665 cur_name[r+1]:='.'; cur_name[r+2]:='T'; cur_name[r+3]:='F'; cur_name[r+4]:='M' 1666 1667 @* Low level output routines. 1668 Simple text in the \.{DVI} file is saved in a buffer until |line_length-2| 1669 characters have accumulated, or until some non-simple \.{DVI} operation 1670 occurs. Then the accumulated text is printed on a line, surrounded by 1671 brackets. The global variable |text_ptr| keeps track of the number of 1672 characters currently in the buffer. 1673 1674 @<Glob...@>= 1675 @!text_ptr:0..line_length; {the number of characters in |text_buf|} 1676 @!text_buf:array[1..line_length] of ASCII_code; {saved characters} 1677 1678 @ @<Set init...@>= 1679 text_ptr:=0; 1680 1681 @ The |flush_text| procedure will empty the buffer if there is something in it. 1682 1683 @p procedure flush_text; 1684 var k:0..line_length; {index into |text_buf|} 1685 begin if text_ptr>0 then 1686 begin if out_mode>errors_only then 1687 begin print('['); 1688 for k:=1 to text_ptr do print(xchr[text_buf[k]]); 1689 print_ln(']'); 1690 end; 1691 text_ptr:=0; 1692 end; 1693 end; 1694 1695 @ And the |out_text| procedure puts something in it. 1696 1697 @p procedure out_text(c:ASCII_code); 1698 begin if text_ptr=line_length-2 then flush_text; 1699 incr(text_ptr); text_buf[text_ptr]:=c; 1700 end; 1701 1702 @* Translation to symbolic form. 1703 The main work of \.{DVItype} is accomplished by the |do_page| procedure, 1704 which produces the output for an entire page, assuming that the |bop| 1705 command for that page has already been processed. This procedure is 1706 essentially an interpretive routine that reads and acts on the \.{DVI} 1707 commands. 1708 1709 @ The definition of \.{DVI} files refers to six registers, 1710 $(h,v,w,x,y,z)$, which hold integer values in \.{DVI} units. In practice, 1711 we also need registers |hh| and |vv|, the pixel analogs of $h$ and $v$, 1712 since it is not always true that |hh=pixel_round(h)| or 1713 |vv=pixel_round(v)|. 1714 1715 The stack of $(h,v,w,x,y,z)$ values is represented by eight arrays 1716 called |hstack|, \dots, |zstack|, |hhstack|, and |vvstack|. 1717 1718 @<Glob...@>= 1719 @!h,@!v,@!w,@!x,@!y,@!z,@!hh,@!vv:integer; {current state values} 1720 @!hstack,@!vstack,@!wstack,@!xstack,@!ystack,@!zstack: 1721 array [0..stack_size] of integer; {pushed down values in \.{DVI} units} 1722 @!hhstack,@!vvstack: 1723 array [0..stack_size] of integer; {pushed down values in pixels} 1724 1725 @ Three characteristics of the pages (their |max_v|, |max_h|, and 1726 |max_s|) are specified in the postamble, and a warning message 1727 is printed if these limits are exceeded. Actually |max_v| is set to 1728 the maximum height plus depth of a page, and |max_h| to the maximum width, 1729 for purposes of page layout. Since characters can legally be set outside 1730 of the page boundaries, it is not an error when |max_v| or |max_h| is 1731 exceeded. But |max_s| should not be exceeded. 1732 1733 The postamble also specifies the total number of pages; \.{DVItype} 1734 checks to see if this total is accurate. 1735 1736 @<Glob...@>= 1737 @!max_v:integer; {the value of |abs(v)| should probably not exceed this} 1738 @!max_h:integer; {the value of |abs(h)| should probably not exceed this} 1739 @!max_s:integer; {the stack depth should not exceed this} 1740 @!max_v_so_far,@!max_h_so_far,@!max_s_so_far:integer; {the record high levels} 1741 @!total_pages:integer; {the stated total number of pages} 1742 @!page_count:integer; {the total number of pages seen so far} 1743 1744 @ @<Set init...@>= 1745 max_v:=@'17777777777-99; max_h:=@'17777777777-99; max_s:=stack_size+1;@/ 1746 max_v_so_far:=0; max_h_so_far:=0; max_s_so_far:=0; page_count:=0; 1747 1748 @ Before we get into the details of |do_page|, it is convenient to 1749 consider a simpler routine that computes the first parameter of each 1750 opcode. 1751 1752 @d four_cases(#)==#,#+1,#+2,#+3 1753 @d eight_cases(#)==four_cases(#),four_cases(#+4) 1754 @d sixteen_cases(#)==eight_cases(#),eight_cases(#+8) 1755 @d thirty_two_cases(#)==sixteen_cases(#),sixteen_cases(#+16) 1756 @d sixty_four_cases(#)==thirty_two_cases(#),thirty_two_cases(#+32) 1757 1758 @p function first_par(o:eight_bits):integer; 1759 begin case o of 1760 sixty_four_cases(set_char_0),sixty_four_cases(set_char_0+64): 1761 first_par:=o-set_char_0; 1762 set1,put1,fnt1,xxx1,fnt_def1: first_par:=get_byte; 1763 set1+1,put1+1,fnt1+1,xxx1+1,fnt_def1+1: first_par:=get_two_bytes; 1764 set1+2,put1+2,fnt1+2,xxx1+2,fnt_def1+2: first_par:=get_three_bytes; 1765 right1,w1,x1,down1,y1,z1: first_par:=signed_byte; 1766 right1+1,w1+1,x1+1,down1+1,y1+1,z1+1: first_par:=signed_pair; 1767 right1+2,w1+2,x1+2,down1+2,y1+2,z1+2: first_par:=signed_trio; 1768 set1+3,set_rule,put1+3,put_rule,right1+3,w1+3,x1+3,down1+3,y1+3,z1+3, 1769 fnt1+3,xxx1+3,fnt_def1+3: first_par:=signed_quad; 1770 nop,bop,eop,push,pop,pre,post,post_post,undefined_commands: first_par:=0; 1771 w0: first_par:=w; 1772 x0: first_par:=x; 1773 y0: first_par:=y; 1774 z0: first_par:=z; 1775 sixty_four_cases(fnt_num_0): first_par:=o-fnt_num_0; 1776 end; 1777 end; 1778 1779 @ Here is another subroutine that we need: It computes the number of 1780 pixels in the height or width of a rule. Characters and rules will line up 1781 properly if the sizes are computed precisely as specified here. (Since 1782 |conv| is computed with some floating-point roundoff error, in a 1783 machine-dependent way, format designers who are tailoring something for a 1784 particular resolution should not plan their measurements to come out to an 1785 exact integer number of pixels; they should compute things so that the 1786 rule dimensions are a little less than an integer number of pixels, e.g., 1787 4.99 instead of 5.00.) 1788 1789 @p function rule_pixels(x:integer):integer; 1790 {computes $\lceil|conv|\cdot x\rceil$} 1791 var n:integer; 1792 begin n:=trunc(conv*x); 1793 if n<conv*x then rule_pixels:=n+1 @+ else rule_pixels:=n; 1794 end; 1795 1796 @ Strictly speaking, the |do_page| procedure is really a function with 1797 side effects, not a `\&{procedure}'\thinspace; it returns the value |false| 1798 if \.{DVItype} should be aborted because of some unusual happening. The 1799 subroutine is organized as a typical interpreter, with a multiway branch 1800 on the command code followed by |goto| statements leading to routines that 1801 finish up the activities common to different commands. We will use the 1802 following labels: 1803 1804 @d fin_set=41 {label for commands that set or put a character} 1805 @d fin_rule=42 {label for commands that set or put a rule} 1806 @d move_right=43 {label for commands that change |h|} 1807 @d move_down=44 {label for commands that change |v|} 1808 @d show_state=45 {label for commands that change |s|} 1809 @d change_font=46 {label for commands that change |cur_font|} 1810 1811 @ Some \PASCAL\ compilers severely restrict the length of procedure bodies, 1812 so we shall split |do_page| into two parts, one of which is 1813 called |special_cases|. The different parts communicate with each other 1814 via the global variables mentioned above, together with the following ones: 1815 1816 @<Glob...@>= 1817 @!s:integer; {current stack size} 1818 @!ss:integer; {stack size to print} 1819 @!cur_font:integer; {current internal font number} 1820 @!showing:boolean; {is the current command being translated in full?} 1821 1822 @ Here is the overall setup. 1823 1824 @p @t\4@>@<Declare the function called |special_cases|@>@; 1825 function do_page:boolean; 1826 label fin_set,fin_rule,move_right,show_state,done,9998,9999; 1827 var o:eight_bits; {operation code of the current command} 1828 @!p,@!q:integer; {parameters of the current command} 1829 @!a:integer; {byte number of the current command} 1830 @!hhh:integer; {|h|, rounded to the nearest pixel} 1831 begin cur_font:=invalid_font; {set current font undefined} 1832 s:=0; h:=0; v:=0; w:=0; x:=0; y:=0; z:=0; hh:=0; vv:=0; 1833 {initialize the state variables} 1834 while true do @<Translate the next command in the \.{DVI} file; 1835 |goto 9999| with |do_page=true| if it was |eop|; 1836 |goto 9998| if premature termination is needed@>; 1837 9998: print_ln('!'); do_page:=false; 1838 9999: end; 1839 1840 @ Commands are broken down into ``major'' and ``minor'' categories: 1841 A major command is always shown in full, while a minor one is 1842 put into the buffer in abbreviated form. Minor commands, which 1843 account for the bulk of most \.{DVI} files, involve horizontal spacing 1844 and the typesetting of characters in a line; these are shown in full 1845 only if |out_mode>=verbose|. 1846 1847 @d show(#)==begin flush_text; showing:=true; print(a:1,': ',#); 1848 end 1849 @d major(#)==if out_mode>errors_only then show(#) 1850 @d minor(#)==if out_mode>terse then 1851 begin showing:=true; print(a:1,': ',#); 1852 end 1853 @d error(#)==if not showing then show(#) else print(' ',#) 1854 1855 @<Translate the next command...@>= 1856 begin a:=cur_loc; showing:=false; 1857 o:=get_byte; p:=first_par(o); 1858 if eof(dvi_file) then bad_dvi('the file ended prematurely'); 1859 @.the file ended prematurely@> 1860 @<Start translation of command |o| and |goto| the appropriate label to 1861 finish the job@>; 1862 fin_set: @<Finish a command that either sets or puts a character, then 1863 |goto move_right| or |done|@>; 1864 fin_rule: @<Finish a command that either sets or puts a rule, then 1865 |goto move_right| or |done|@>; 1866 move_right: @<Finish a command that sets |h:=h+q|, then |goto done|@>; 1867 show_state: @<Show the values of |ss|, |h|, |v|, |w|, |x|, |y|, |z|, 1868 |hh|, and |vv|; then |goto done|@>; 1869 done: if showing then print_ln(' '); 1870 end 1871 1872 @ The multiway switch in |first_par|, above, was organized by the length 1873 of each command; the one in |do_page| is organized by the semantics. 1874 1875 @<Start translation...@>= 1876 if o<set_char_0+128 then @<Translate a |set_char| command@> 1877 else case o of 1878 four_cases(set1): begin major('set',o-set1+1:1,' ',p:1); goto fin_set; 1879 end; 1880 four_cases(put1): begin major('put',o-put1+1:1,' ',p:1); goto fin_set; 1881 end; 1882 set_rule: begin major('setrule'); goto fin_rule; 1883 end; 1884 put_rule: begin major('putrule'); goto fin_rule; 1885 end; 1886 @t\4@>@<Cases for commands |nop|, |bop|, \dots, |pop|@>@; 1887 @t\4@>@<Cases for horizontal motion@>@; 1888 othercases if special_cases(o,p,a) then goto done@+else goto 9998 1889 endcases 1890 1891 @ @<Declare the function called |special_cases|@>= 1892 function special_cases(@!o:eight_bits;@!p,@!a:integer):boolean; 1893 label change_font,move_down,done,9998; 1894 var q:integer; {parameter of the current command} 1895 @!k:integer; {loop index} 1896 @!bad_char:boolean; {has a non-ASCII character code appeared in this \\{xxx}?} 1897 @!pure:boolean; {is the command error-free?} 1898 @!vvv:integer; {|v|, rounded to the nearest pixel} 1899 begin pure:=true; 1900 case o of 1901 @t\4@>@<Cases for vertical motion@>@; 1902 @t\4@>@<Cases for fonts@>@; 1903 four_cases(xxx1): @<Translate an |xxx| command and |goto done|@>; 1904 pre: begin error('preamble command within a page!'); goto 9998; 1905 end; 1906 @.preamble command within a page@> 1907 post,post_post: begin error('postamble command within a page!'); goto 9998; 1908 @.postamble command within a page@> 1909 end; 1910 othercases begin error('undefined command ',o:1,'!'); 1911 goto done; 1912 @.undefined command@> 1913 end 1914 endcases; 1915 move_down: @<Finish a command that sets |v:=v+p|, then |goto done|@>; 1916 change_font: @<Finish a command that changes the current font, 1917 then |goto done|@>; 1918 9998: pure:=false; 1919 done: special_cases:=pure; 1920 end; 1921 1922 @ @<Cases for commands |nop|, |bop|, \dots, |pop|@>= 1923 nop: begin minor('nop'); goto done; 1924 end; 1925 bop: begin error('bop occurred before eop!'); goto 9998; 1926 @.bop occurred before eop@> 1927 end; 1928 eop: begin major('eop'); 1929 if s<>0 then error('stack not empty at end of page (level ', 1930 s:1,')!'); 1931 @.stack not empty...@> 1932 do_page:=true; print_ln(' '); goto 9999; 1933 end; 1934 push: begin major('push'); 1935 if s=max_s_so_far then 1936 begin max_s_so_far:=s+1; 1937 if s=max_s then error('deeper than claimed in postamble!'); 1938 @.deeper than claimed...@> 1939 @.push deeper than claimed...@> 1940 if s=stack_size then 1941 begin error('DVItype capacity exceeded (stack size=', 1942 stack_size:1,')'); goto 9998; 1943 end; 1944 end; 1945 hstack[s]:=h; vstack[s]:=v; wstack[s]:=w; 1946 xstack[s]:=x; ystack[s]:=y; zstack[s]:=z; 1947 hhstack[s]:=hh; vvstack[s]:=vv; incr(s); ss:=s-1; goto show_state; 1948 end; 1949 pop: begin major('pop'); 1950 if s=0 then error('(illegal at level zero)!') 1951 else begin decr(s); hh:=hhstack[s]; vv:=vvstack[s]; 1952 h:=hstack[s]; v:=vstack[s]; w:=wstack[s]; 1953 x:=xstack[s]; y:=ystack[s]; z:=zstack[s]; 1954 end; 1955 ss:=s; goto show_state; 1956 end; 1957 1958 @ Rounding to the nearest pixel is best done in the manner shown here, so as 1959 to be inoffensive to the eye: When the horizontal motion is small, like a 1960 kern, |hh| changes by rounding the kern; but when the motion is large, |hh| 1961 changes by rounding the true position |h| so that accumulated rounding errors 1962 disappear. We allow a larger space in the negative direction than in 1963 the positive one, because \TeX\ makes comparatively 1964 large backspaces when it positions accents. 1965 1966 @d out_space(#)==if (p>=font_space[cur_font])or(p<=-4*font_space[cur_font]) then 1967 begin out_text(" "); hh:=pixel_round(h+p); 1968 end 1969 else hh:=hh+pixel_round(p); 1970 minor(#,' ',p:1); q:=p; goto move_right 1971 1972 @<Cases for horizontal motion@>= 1973 four_cases(right1):begin out_space('right',o-right1+1:1); 1974 end; 1975 w0,four_cases(w1):begin w:=p; out_space('w',o-w0:1); 1976 end; 1977 x0,four_cases(x1):begin x:=p; out_space('x',o-x0:1); 1978 end; 1979 1980 @ Vertical motion is done similarly, but with the threshold between 1981 ``small'' and ``large'' increased by a factor of five. The idea is to make 1982 fractions like ``$1\over2$'' round consistently, but to absorb accumulated 1983 rounding errors in the baseline-skip moves. 1984 1985 @d out_vmove(#)==if abs(p)>=5*font_space[cur_font] then vv:=pixel_round(v+p) 1986 else vv:=vv+pixel_round(p); 1987 major(#,' ',p:1); goto move_down 1988 1989 @<Cases for vertical motion@>= 1990 four_cases(down1):begin out_vmove('down',o-down1+1:1); 1991 end; 1992 y0,four_cases(y1):begin y:=p; out_vmove('y',o-y0:1); 1993 end; 1994 z0,four_cases(z1):begin z:=p; out_vmove('z',o-z0:1); 1995 end; 1996 1997 @ @<Cases for fonts@>= 1998 sixty_four_cases(fnt_num_0): begin major('fntnum',p:1); 1999 goto change_font; 2000 end; 2001 four_cases(fnt1): begin major('fnt',o-fnt1+1:1,' ',p:1); 2002 goto change_font; 2003 end; 2004 four_cases(fnt_def1): begin major('fntdef',o-fnt_def1+1:1,' ',p:1); 2005 define_font(p); goto done; 2006 end; 2007 2008 @ @<Translate an |xxx| command and |goto done|@>= 2009 begin major('xxx '''); bad_char:=false; 2010 if p<0 then error('string of negative length!'); 2011 @.string of negative length@> 2012 for k:=1 to p do 2013 begin q:=get_byte; 2014 if (q<" ")or(q>"~") then bad_char:=true; 2015 if showing then print(xchr[q]); 2016 end; 2017 if showing then print(''''); 2018 if bad_char then error('non-ASCII character in xxx command!'); 2019 @.non-ASCII character...@> 2020 goto done; 2021 end 2022 2023 @ @<Translate a |set_char|...@>= 2024 begin if (o>" ")and(o<="~") then 2025 begin out_text(p); minor('setchar',p:1); 2026 end 2027 else major('setchar',p:1); 2028 goto fin_set; 2029 end 2030 2031 @ @<Finish a command that either sets or puts a character...@>= 2032 if p<0 then p:=255-((-1-p) mod 256) 2033 else if p>=256 then p:=p mod 256; {width computation for oriental fonts} 2034 @^oriental characters@>@^Chinese characters@>@^Japanese characters@> 2035 if (p<font_bc[cur_font])or(p>font_ec[cur_font]) then q:=invalid_width 2036 else q:=char_width(cur_font)(p); 2037 if q=invalid_width then 2038 begin error('character ',p:1,' invalid in font '); 2039 @.character $c$ invalid...@> 2040 print_font(cur_font); 2041 if cur_font<>invalid_font then 2042 print('!'); {the invalid font has `\.!' in its name} 2043 end; 2044 if o>=put1 then goto done; 2045 if q=invalid_width then q:=0 2046 else hh:=hh+char_pixel_width(cur_font)(p); 2047 goto move_right 2048 2049 @ @<Finish a command that either sets or puts a rule...@>= 2050 q:=signed_quad; 2051 if showing then 2052 begin print(' height ',p:1,', width ',q:1); 2053 if out_mode>mnemonics_only then 2054 if (p<=0)or(q<=0) then print(' (invisible)') 2055 else print(' (',rule_pixels(p):1,'x',rule_pixels(q):1,' pixels)'); 2056 end; 2057 if o=put_rule then goto done; 2058 if showing then if out_mode>mnemonics_only then print_ln(' '); 2059 hh:=hh+rule_pixels(q); goto move_right 2060 2061 @ A sequence of consecutive rules, or consecutive characters in a fixed-width 2062 font whose width is not an integer number of pixels, can cause |hh| to drift 2063 far away from a correctly rounded value. \.{DVItype} ensures that the 2064 amount of drift will never exceed |max_drift| pixels. 2065 2066 Since \.{DVItype} is intended to diagnose strange errors, it checks 2067 carefully to make sure that |h| and |v| do not get out of range. 2068 Normal \.{DVI}-reading programs need not do this. 2069 2070 @d infinity==@'17777777777 {$\infty$ (approximately)} 2071 @d max_drift=2 {we insist that abs|(hh-pixel_round(h))<=max_drift|} 2072 2073 @<Finish a command that sets |h:=h+q|, then |goto done|@>= 2074 if (h>0)and(q>0) then if h>infinity-q then 2075 begin error('arithmetic overflow! parameter changed from ', 2076 @.arithmetic overflow...@> 2077 q:1,' to ',infinity-h:1); 2078 q:=infinity-h; 2079 end; 2080 if (h<0)and(q<0) then if -h>q+infinity then 2081 begin error('arithmetic overflow! parameter changed from ', 2082 q:1, ' to ',(-h)-infinity:1); 2083 q:=(-h)-infinity; 2084 end; 2085 hhh:=pixel_round(h+q); 2086 if abs(hhh-hh)>max_drift then 2087 if hhh>hh then hh:=hhh-max_drift 2088 else hh:=hhh+max_drift; 2089 if showing then if out_mode>mnemonics_only then 2090 begin print(' h:=',h:1); 2091 if q>=0 then print('+'); 2092 print(q:1,'=',h+q:1,', hh:=',hh:1); 2093 end; 2094 h:=h+q; 2095 if abs(h)>max_h_so_far then 2096 begin if abs(h)>max_h+99 then 2097 begin error('warning: |h|>',max_h:1,'!'); 2098 @.warning: |h|...@> 2099 max_h:=abs(h); 2100 end; 2101 max_h_so_far:=abs(h); 2102 end; 2103 goto done 2104 2105 @ @<Finish a command that sets |v:=v+p|, then |goto done|@>= 2106 if (v>0)and(p>0) then if v>infinity-p then 2107 begin error('arithmetic overflow! parameter changed from ', 2108 @.arithmetic overflow...@> 2109 p:1,' to ',infinity-v:1); 2110 p:=infinity-v; 2111 end; 2112 if (v<0)and(p<0) then if -v>p+infinity then 2113 begin error('arithmetic overflow! parameter changed from ', 2114 p:1, ' to ',(-v)-infinity:1); 2115 p:=(-v)-infinity; 2116 end; 2117 vvv:=pixel_round(v+p); 2118 if abs(vvv-vv)>max_drift then 2119 if vvv>vv then vv:=vvv-max_drift 2120 else vv:=vvv+max_drift; 2121 if showing then if out_mode>mnemonics_only then 2122 begin print(' v:=',v:1); 2123 if p>=0 then print('+'); 2124 print(p:1,'=',v+p:1,', vv:=',vv:1); 2125 end; 2126 v:=v+p; 2127 if abs(v)>max_v_so_far then 2128 begin if abs(v)>max_v+99 then 2129 begin error('warning: |v|>',max_v:1,'!'); 2130 @.warning: |v|...@> 2131 max_v:=abs(v); 2132 end; 2133 max_v_so_far:=abs(v); 2134 end; 2135 goto done 2136 2137 @ @<Show the values of |ss|, |h|, |v|, |w|, |x|, |y|, |z|...@>= 2138 if showing then if out_mode>mnemonics_only then 2139 begin print_ln(' '); 2140 print('level ',ss:1,':(h=',h:1,',v=',v:1, 2141 ',w=',w:1,',x=',x:1,',y=',y:1,',z=',z:1, 2142 ',hh=',hh:1,',vv=',vv:1,')'); 2143 end; 2144 goto done 2145 2146 @ @<Finish a command that changes the current font...@>= 2147 font_num[nf]:=p; cur_font:=0; 2148 while font_num[cur_font]<>p do incr(cur_font); 2149 if cur_font=nf then 2150 begin cur_font:=invalid_font; 2151 error('invalid font selection: font ',p:1,' was never defined!'); 2152 end; 2153 if showing then if out_mode>mnemonics_only then 2154 begin print(' current font is '); print_font(cur_font); 2155 end; 2156 goto done 2157 2158 @* Skipping pages. 2159 A routine that's much simpler than |do_page| is used to pass over 2160 pages that are not being translated. The |skip_pages| subroutine 2161 is assumed to begin just after the preamble has been read, or just 2162 after a |bop| has been processed. It continues until either finding a 2163 |bop| that matches the desired starting page specifications, or until 2164 running into the postamble. 2165 2166 @p @t\4@>@<Declare the procedure called |scan_bop|@>@; 2167 procedure skip_pages(@!bop_seen:boolean); 2168 label 9999; {end of this subroutine} 2169 var p:integer; {a parameter} 2170 @!k:0..255; {command code} 2171 @!down_the_drain:integer; {garbage} 2172 begin showing:=false; 2173 while true do 2174 begin if not bop_seen then 2175 begin scan_bop; 2176 if in_postamble then goto 9999; 2177 if not started then if start_match then 2178 begin started:=true; goto 9999; 2179 end; 2180 end; 2181 @<Skip until finding |eop|@>; 2182 bop_seen:=false; 2183 end; 2184 9999:end; 2185 2186 @ @<Skip until finding |eop|@>= 2187 repeat if eof(dvi_file) then bad_dvi('the file ended prematurely'); 2188 @.the file ended prematurely@> 2189 k:=get_byte; 2190 p:=first_par(k); 2191 case k of 2192 set_rule,put_rule: down_the_drain:=signed_quad; 2193 four_cases(fnt_def1): begin define_font(p); 2194 print_ln(' '); 2195 end; 2196 four_cases(xxx1): while p>0 do 2197 begin down_the_drain:=get_byte; decr(p); 2198 end; 2199 bop,pre,post,post_post,undefined_commands: 2200 bad_dvi('illegal command at byte ',cur_loc-1:1); 2201 @.illegal command at byte n@> 2202 othercases do_nothing 2203 endcases; 2204 until k=eop; 2205 2206 @ Global variables called |old_backpointer| and |new_backpointer| 2207 are used to check whether the back pointers are properly set up. 2208 Another one tells whether we have already found the starting page. 2209 2210 @<Glob...@>= 2211 @!old_backpointer:integer; {the previous |bop| command location} 2212 @!new_backpointer:integer; {the current |bop| command location} 2213 @!started:boolean; {has the starting page been found?} 2214 2215 @ @<Set init...@>= 2216 old_backpointer:=-1; started:=false; 2217 2218 @ The |scan_bop| procedure reads \.{DVI} commands following the preamble 2219 or following |eop|, until finding either |bop| or the postamble. 2220 2221 @<Declare the procedure called |scan_bop|@>= 2222 procedure scan_bop; 2223 var k:0..255; {command code} 2224 begin repeat if eof(dvi_file) then bad_dvi('the file ended prematurely'); 2225 @.the file ended prematurely@> 2226 k:=get_byte; 2227 if (k>=fnt_def1)and(k<fnt_def1+4) then 2228 begin define_font(first_par(k)); k:=nop; 2229 end; 2230 until k<>nop; 2231 if k=post then in_postamble:=true 2232 else begin if k<>bop then bad_dvi('byte ',cur_loc-1:1,' is not bop'); 2233 @.byte n is not bop@> 2234 new_backpointer:=cur_loc-1; incr(page_count); 2235 for k:=0 to 9 do count[k]:=signed_quad; 2236 if signed_quad<>old_backpointer 2237 then print_ln('backpointer in byte ',cur_loc-4:1, 2238 ' should be ',old_backpointer:1,'!'); 2239 @.backpointer...should be p@> 2240 old_backpointer:=new_backpointer; 2241 end; 2242 end; 2243 2244 @* Using the backpointers. 2245 The routines in this section of the program are brought into play only 2246 if |random_reading| is |true| (and only if |out_mode=the_works|). 2247 First comes a routine that illustrates how to find the postamble quickly. 2248 2249 @<Find the postamble, working back from the end@>= 2250 n:=dvi_length; 2251 if n<53 then bad_dvi('only ',n:1,' bytes long'); 2252 @.only n bytes long@> 2253 m:=n-4; 2254 repeat if m=0 then bad_dvi('all 223s'); 2255 @.all 223s@> 2256 move_to_byte(m); k:=get_byte; decr(m); 2257 until k<>223; 2258 if k<>id_byte then bad_dvi('ID byte is ',k:1); 2259 @.ID byte is wrong@> 2260 move_to_byte(m-3); q:=signed_quad; 2261 if (q<0)or(q>m-33) then bad_dvi('post pointer ',q:1,' at byte ',m-3:1); 2262 @.post pointer is wrong@> 2263 move_to_byte(q); k:=get_byte; 2264 if k<>post then bad_dvi('byte ',q:1,' is not post'); 2265 @.byte n is not post@> 2266 post_loc:=q; first_backpointer:=signed_quad 2267 2268 @ Note that the last steps of the above code save the locations of the 2269 |post| byte and the final |bop|. We had better declare these global 2270 variables, together with two more that we will need shortly. 2271 2272 @<Glob...@>= 2273 @!post_loc:integer; {byte location where the postamble begins} 2274 @!first_backpointer:integer; {the pointer following |post|} 2275 @!start_loc:integer; {byte location of the first page to process} 2276 @!after_pre:integer; {byte location immediately following the preamble} 2277 2278 @ The next little routine shows how the backpointers can be followed 2279 to move through a \.{DVI} file in reverse order. Ordinarily a \.{DVI}-reading 2280 program would do this only if it wants to print the pages backwards or 2281 if it wants to find a specified starting page that is not necessarily the 2282 first page in the file; otherwise it would of course be simpler and faster 2283 just to read the whole file from the beginning. 2284 2285 @<Count the pages and move to the starting page@>= 2286 q:=post_loc; p:=first_backpointer; start_loc:=-1; 2287 if p<0 then in_postamble:=true 2288 else begin repeat 2289 {now |q| points to a |post| or |bop| command; |p>=0| is prev pointer} 2290 if p>q-46 then 2291 bad_dvi('page link ',p:1,' after byte ',q:1); 2292 @.page link wrong...@> 2293 q:=p; move_to_byte(q); k:=get_byte; 2294 if k=bop then incr(page_count) 2295 else bad_dvi('byte ',q:1,' is not bop'); 2296 @.byte n is not bop@> 2297 for k:=0 to 9 do count[k]:=signed_quad; 2298 p:=signed_quad; 2299 if start_match then 2300 begin start_loc:=q; old_backpointer:=p; 2301 end; 2302 until p<0; 2303 if start_loc<0 then abort('starting page number could not be found!'); 2304 @.starting page number...@> 2305 if old_backpointer<0 then start_loc:=after_pre; {we want to check everything} 2306 move_to_byte(start_loc); 2307 end; 2308 if page_count<>total_pages then 2309 print_ln('there are really ',page_count:1,' pages, not ',total_pages:1,'!') 2310 @.there are really n pages@> 2311 2312 @* Reading the postamble. 2313 Now imagine that we are reading the \.{DVI} file and positioned just 2314 four bytes after the |post| command. That, in fact, is the situation, 2315 when the following part of \.{DVItype} is called upon to read, translate, 2316 and check the rest of the postamble. 2317 2318 @p procedure read_postamble; 2319 var k:integer; {loop index} 2320 @!p,@!q,@!m:integer; {general purpose registers} 2321 begin showing:=false; post_loc:=cur_loc-5; 2322 print_ln('Postamble starts at byte ',post_loc:1,'.'); 2323 @.Postamble starts at byte n@> 2324 if signed_quad<>numerator then 2325 print_ln('numerator doesn''t match the preamble!'); 2326 @.numerator doesn't match@> 2327 if signed_quad<>denominator then 2328 print_ln('denominator doesn''t match the preamble!'); 2329 @.denominator doesn't match@> 2330 if signed_quad<>mag then if new_mag=0 then 2331 print_ln('magnification doesn''t match the preamble!'); 2332 @.magnification doesn't match@> 2333 max_v:=signed_quad; max_h:=signed_quad;@/ 2334 print('maxv=',max_v:1,', maxh=',max_h:1);@/ 2335 max_s:=get_two_bytes; total_pages:=get_two_bytes;@/ 2336 print_ln(', maxstackdepth=',max_s:1,', totalpages=',total_pages:1); 2337 if out_mode<the_works then 2338 @<Compare the \\{lust} parameters with the accumulated facts@>; 2339 @<Process the font definitions of the postamble@>; 2340 @<Make sure that the end of the file is well-formed@>; 2341 end; 2342 2343 @ No warning is given when |max_h_so_far| exceeds |max_h| by less than~100, 2344 since 100 units is invisibly small; it's approximately the wavelength of 2345 visible light, in the case of \TeX\ output. Rounding errors can be expected 2346 to make |h| and |v| slightly more than |max_h| and |max_v|, every once in 2347 a~while; hence small discrepancies are not cause for alarm. 2348 2349 @<Compare the \\{lust}...@>= 2350 begin if max_v+99<max_v_so_far then 2351 print_ln('warning: observed maxv was ',max_v_so_far:1); 2352 @.warning: observed maxv...@> 2353 @.observed maxv was x@> 2354 if max_h+99<max_h_so_far then 2355 print_ln('warning: observed maxh was ',max_h_so_far:1); 2356 @.warning: observed maxh...@> 2357 @.observed maxh was x@> 2358 if max_s<max_s_so_far then 2359 print_ln('warning: observed maxstackdepth was ',max_s_so_far:1); 2360 @.warning: observed maxstack...@> 2361 @.observed maxstackdepth was x@> 2362 if page_count<>total_pages then 2363 print_ln('there are really ',page_count:1,' pages, not ',total_pages:1,'!'); 2364 end 2365 @.there are really n pages@> 2366 2367 @ When we get to the present code, the |post_post| command has 2368 just been read. 2369 2370 @<Make sure that the end of the file is well-formed@>= 2371 q:=signed_quad; 2372 if q<>post_loc then 2373 print_ln('bad postamble pointer in byte ',cur_loc-4:1,'!'); 2374 @.bad postamble pointer@> 2375 m:=get_byte; 2376 if m<>id_byte then print_ln('identification in byte ',cur_loc-1:1, 2377 @.identification...should be n@> 2378 ' should be ',id_byte:1,'!'); 2379 k:=cur_loc; m:=223; 2380 while (m=223)and not eof(dvi_file) do m:=get_byte; 2381 if not eof(dvi_file) then bad_dvi('signature in byte ',cur_loc-1:1, 2382 @.signature...should be...@> 2383 ' should be 223') 2384 else if cur_loc<k+4 then 2385 print_ln('not enough signature bytes at end of file (', 2386 @.not enough signature bytes...@> 2387 cur_loc-k:1,')'); 2388 2389 @ @<Process the font definitions...@>= 2390 repeat k:=get_byte; 2391 if (k>=fnt_def1)and(k<fnt_def1+4) then 2392 begin p:=first_par(k); define_font(p); print_ln(' '); k:=nop; 2393 end; 2394 until k<>nop; 2395 if k<>post_post then 2396 print_ln('byte ',cur_loc-1:1,' is not postpost!') 2397 @.byte n is not postpost@> 2398 2399 @* The main program. 2400 Now we are ready to put it all together. This is where \.{DVItype} starts, 2401 and where it ends. 2402 2403 @p begin initialize; {get all variables initialized} 2404 dialog; {set up all the options} 2405 @<Process the preamble@>; 2406 if out_mode=the_works then {|random_reading=true|} 2407 begin @<Find the postamble, working back from the end@>; 2408 in_postamble:=true; read_postamble; in_postamble:=false; 2409 @<Count the pages and move to the starting page@>; 2410 end; 2411 skip_pages(false); 2412 if not in_postamble then @<Translate up to |max_pages| pages@>; 2413 if out_mode<the_works then 2414 begin if not in_postamble then skip_pages(true); 2415 if signed_quad<>old_backpointer then 2416 print_ln('backpointer in byte ',cur_loc-4:1, 2417 ' should be ',old_backpointer:1,'!'); 2418 @.backpointer...should be p@> 2419 read_postamble; 2420 end; 2421 final_end:end. 2422 2423 @ The main program needs a few global variables in order to do its work. 2424 2425 @<Glob...@>= 2426 @!k,@!m,@!n,@!p,@!q:integer; {general purpose registers} 2427 2428 @ A \.{DVI}-reading program that reads the postamble first need not look at the 2429 preamble; but \.{DVItype} looks at the preamble in order to do error 2430 checking, and to display the introductory comment. 2431 2432 @<Process the preamble@>= 2433 open_dvi_file; 2434 p:=get_byte; {fetch the first byte} 2435 if p<>pre then bad_dvi('First byte isn''t start of preamble!'); 2436 @.First byte isn't...@> 2437 p:=get_byte; {fetch the identification byte} 2438 if p<>id_byte then 2439 print_ln('identification in byte 1 should be ',id_byte:1,'!'); 2440 @.identification...should be n@> 2441 @<Compute the conversion factors@>; 2442 p:=get_byte; {fetch the length of the introductory comment} 2443 print(''''); 2444 while p>0 do 2445 begin decr(p); print(xchr[get_byte]); 2446 end; 2447 print_ln(''''); 2448 after_pre:=cur_loc 2449 2450 @ The conversion factor |conv| is figured as follows: There are exactly 2451 |n/d| decimicrons per \.{DVI} unit, and 254000 decimicrons per inch, 2452 and |resolution| pixels per inch. Then we have to adjust this 2453 by the stated amount of magnification. 2454 2455 @<Compute the conversion factors@>= 2456 numerator:=signed_quad; denominator:=signed_quad; 2457 if numerator<=0 then bad_dvi('numerator is ',numerator:1); 2458 @.numerator is wrong@> 2459 if denominator<=0 then bad_dvi('denominator is ',denominator:1); 2460 @.denominator is wrong@> 2461 print_ln('numerator/denominator=',numerator:1,'/',denominator:1); 2462 tfm_conv:=(25400000.0/numerator)*(denominator/473628672)/16.0; 2463 conv:=(numerator/254000.0)*(resolution/denominator); 2464 mag:=signed_quad; 2465 if new_mag>0 then mag:=new_mag 2466 else if mag<=0 then bad_dvi('magnification is ',mag:1); 2467 @.magnification is wrong@> 2468 true_conv:=conv; conv:=true_conv*(mag/1000.0); 2469 print_ln('magnification=',mag:1,'; ',conv:16:8,' pixels per DVI unit') 2470 2471 @ The code shown here uses a convention that has proved to be useful: 2472 If the starting page was specified as, e.g., `\.{1.*.-5}', then 2473 all page numbers in the file are displayed by showing the values of 2474 counts 0, 1, and~2, separated by dots. Such numbers can, for example, 2475 be displayed on the console of a printer when it is working on that 2476 page. 2477 2478 @<Translate up to...@>= 2479 begin while max_pages>0 do 2480 begin decr(max_pages); 2481 print_ln(' '); print(cur_loc-45:1,': beginning of page '); 2482 for k:=0 to start_vals do 2483 begin print(count[k]:1); 2484 if k<start_vals then print('.') 2485 else print_ln(' '); 2486 end; 2487 if not do_page then bad_dvi('page ended unexpectedly'); 2488 @.page ended unexpectedly@> 2489 scan_bop; 2490 if in_postamble then goto done; 2491 end; 2492 done:end 2493 2494 @* System-dependent changes. 2495 This section should be replaced, if necessary, by changes to the program 2496 that are necessary to make \.{DVItype} work at a particular installation. 2497 It is usually best to design your change file so that all changes to 2498 previous sections preserve the section numbering; then everybody's version 2499 will be consistent with the printed program. More extensive changes, 2500 which introduce new sections, can be inserted here; then only the index 2501 itself will get a new section number. 2502 @^system dependencies@> 2503 2504 @* Index. 2505 Pointers to error messages appear here together with the section numbers 2506 where each ident\-i\-fier is used.