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.