summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/gftodvi.web
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
committerKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
commitad547a6b5986815fda458221149728d9d9ab1d87 (patch)
tree16296910eb3eca724371474ea9aea3994dc69614 /Build/source/texk/web2c/gftodvi.web
parent947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff)
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/gftodvi.web')
-rw-r--r--Build/source/texk/web2c/gftodvi.web4393
1 files changed, 4393 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/gftodvi.web b/Build/source/texk/web2c/gftodvi.web
new file mode 100644
index 00000000000..9fb263a7e35
--- /dev/null
+++ b/Build/source/texk/web2c/gftodvi.web
@@ -0,0 +1,4393 @@
+% This program by D. E. Knuth is not copyrighted and can be used freely.
+% Version 0 was completed on April 23, 1984.
+% Version 0.1 added char_code output (May 4).
+% Version 0.2 included rules and dots in the boundary calculations (May 25).
+% Version 0.3 added label type "/" (May 27).
+% Version 0.4 (by Arthur Samuel) improved the dot labeling routine (July 23).
+% Version 0.5 added the slant font for rules (September 2).
+% Version 0.6 changed label types and allowed invisible dots (September 28).
+% Version 1.0 switched to new GF format (December 8).
+% Version 1.1 switched to newer GF format (February 2, 1985).
+% Version 1.2 added the offset operations of MF version 0.8 (April 1, 1985).
+% Version 1.3 allowed online entry of gray font, etc. (April 22, 1985).
+% Version 1.4 allowed "almost" horizontal or vertical rules (May 20, 1985).
+% Version 1.5 corrected a bug in the diagonal slant routine (June 18, 1985).
+% Version 1.6 corrected a bug if labels exist but no dots (September 13, 1985).
+% Version 1.7 changed from am to cm fonts; fam became ext (October 5, 1985).
+% Version 2.0 was tuned up for the METAFONTware report (April, 1989).
+% Version 3.0 uses 8-bit codes and extended ligatures (October, 1989).
+
+% Here is TeX material that gets inserted after \input webmac
+\def\hang{\hangindent 3em\indent\ignorespaces}
+\font\ninerm=cmr9
+\let\mc=\ninerm % medium caps for names like SAIL
+\def\PASCAL{Pascal}
+\font\logo=manfnt % font used for the METAFONT logo
+\def\MF{{\logo META}\-{\logo FONT}}
+\let\swap=\leftrightarrow
+
+\def\(#1){} % this is used to make section names sort themselves better
+\def\9#1{} % this is used for sort keys in the index
+
+\def\title{GF$\,$\lowercase{to}$\,$DVI}
+\def\contentspagenumber{301}
+\def\topofcontents{\null
+ \titlefalse % include headline on the contents page
+ \def\rheader{\mainfont\hfil \contentspagenumber}
+ \vfill
+ \centerline{\titlefont The {\ttitlefont GFtoDVI} processor}
+ \vskip 15pt
+ \centerline{(Version 3.0, October 1989)}
+ \vfill}
+\def\botofcontents{\vfill
+ \centerline{\hsize 5in\baselineskip9pt
+ \vbox{\ninerm\noindent
+ The preparation of this report
+ was supported in part by the National Science
+ Foundation under grants IST-8201926, MCS-8300984, and
+ CCR-8610181,
+ and by the System Development Foundation. `\TeX' is a
+ trademark of the American Mathematical Society.
+ `{\logo hijklmnj}\kern1pt' is a trademark of Addison-Wesley
+ Publishing Company.}}}
+\pageno=\contentspagenumber \advance\pageno by 1
+
+@* Introduction.
+The \.{GFtoDVI} utility program reads binary generic font (``\.{GF}'')
+files that are produced by font compilers such as \MF, and converts them
+into device-independent (``\.{DVI}'') files that can be printed to give
+annotated hardcopy proofs of the character shapes. The annotations are
+specified by the comparatively simple conventions of plain \MF; i.e.,
+there are mechanisms for labeling chosen points and for superimposing
+horizontal or vertical rules on the enlarged character shapes.
+
+The purpose of \.{GFtoDVI} is simply to make proof copies; it does not
+exhaustively test the validity of a \.{GF} file, nor do its algorithms
+much resemble the algorithms that are typically used to prepare font
+descriptions for commercial typesetting equipment. Another program,
+\.{GFtype}, is available for validity checking; \.{GFtype} also serves
+as a model of programs that convert fonts from \.{GF} format to some
+other coding scheme.
+
+The |banner| string defined here should be changed whenever \.{GFtoDVI}
+gets modified.
+
+@d banner=='This is GFtoDVI, Version 3.0' {printed when the program starts}
+
+@ This program is written in standard \PASCAL, except where it is necessary
+to use extensions; for example, \.{GFtoDVI} must read files whose names
+are dynamically specified, and such a task would be impossible in pure \PASCAL.
+All places where nonstandard constructions are used have been listed in
+the index under ``system dependencies.''
+@!@^system dependencies@>
+
+Another exception to standard \PASCAL\ occurs in the
+use of default branches in |case| statements; the conventions
+of \.{TANGLE}, \.{WEAVE}, etc., have been followed.
+
+@d othercases == others: {default for cases not listed explicitly}
+@d endcases == @+end {follows the default case in an extended |case| statement}
+@f othercases == else
+@f endcases == end
+
+@ The main input and output files are not mentioned in the program header,
+because their external names
+will be determined at run time (e.g., by interpreting the
+command line that invokes this program). Error messages and other remarks
+are written on the |output| file, which the user may
+choose to assign to the terminal if the system permits it.
+@^system dependencies@>
+
+The term |print| is used instead of |write| when this program writes on
+the |output| file, so that all such output can be easily deflected.
+
+@d print(#)==write(#)
+@d print_ln(#)==write_ln(#)
+@d print_nl(#)==@+begin write_ln; write(#);@+end
+
+@p program GF_to_DVI(@!output);
+label @<Labels in the outer block@>@/
+const @<Constants in the outer block@>@/
+type @<Types in the outer block@>@/
+var @<Globals in the outer block@>@/
+procedure initialize; {this procedure gets things started properly}
+ var @!i,@!j,@!m,@!n:integer; {loop indices for initializations}
+ begin print_ln(banner);@/
+ @<Set initial values@>@/
+ end;
+
+@ If the program has to stop prematurely, it goes to the
+`|final_end|'.
+
+@d final_end=9999 {label for the end of it all}
+
+@<Labels...@>=final_end;
+
+@ The following parameters can be changed at compile time to extend or
+reduce \.{GFtoDVI}'s capacity.
+
+@<Constants...@>=
+@!max_labels=2000; {maximum number of labels and dots and rules per character}
+@!pool_size=10000; {maximum total length of labels and other strings}
+@!max_strings=1100; {maximum number of labels and other strings}
+@!terminal_line_length=150; {maximum number of characters input in a single
+ line of input from the terminal}
+@!file_name_size=50; {a file name shouldn't be longer than this}
+@!font_mem_size=2000; {space for font metric data}
+@!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8}
+@!widest_row=8192; {maximum number of pixels per row}
+@!lig_lookahead=20; {size of stack used when inserting ligature characters}
+
+@ Labels are given symbolic names by the following definitions, so that
+occasional |goto| statements will be meaningful. We insert the label
+`|exit|:' just before the `\ignorespaces|end|\unskip' of a procedure in
+which we have used the `|return|' statement defined below; the label
+`|reswitch|' is occasionally used just prior to a |case|
+statement in which some cases change the conditions and we wish to branch
+to the newly applicable case. Loops that are set up with the |loop|
+construction defined below are commonly exited by going to `|done|' or to
+`|found|' or to `|not_found|', and they are sometimes repeated by going to
+`|continue|'.
+
+Incidentally, this program never declares a label that isn't actually used,
+because some fussy \PASCAL\ compilers will complain about redundant labels.
+
+@d exit=10 {go here to leave a procedure}
+@d reswitch=21 {go here to start a case statement again}
+@d continue=22 {go here to resume a loop}
+@d done=30 {go here to exit a loop}
+@d done1=31 {like |done|, when there is more than one loop}
+@d found=40 {go here when you've found it}
+@d not_found=45 {go here when you've found nothing}
+
+@ Here are some macros for common programming idioms.
+
+@d incr(#) == #:=#+1 {increase a variable by unity}
+@d decr(#) == #:=#-1 {decrease a variable by unity}
+@d loop == @+ while true do@+ {repeat over and over until a |goto| happens}
+@f loop == xclause
+ {\.{WEB}'s |xclause| acts like `\ignorespaces|while true do|\unskip'}
+@d do_nothing == {empty statement}
+@d return == goto exit {terminate a procedure call}
+@f return == nil {\.{WEB} will henceforth say |return| instead of \\{return}}
+
+@ If the \.{GF} file is badly malformed, the whole process must be aborted;
+\.{GFtoDVI} will give up, after issuing an error message about the symptoms
+that were noticed.
+
+Such errors might be discovered inside of subroutines inside of subroutines,
+so a procedure called |jump_out| has been introduced. This procedure, which
+simply transfers control to the label |final_end| at the end of the program,
+contains the only non-local |goto| statement in \.{GFtoDVI}.
+@^system dependencies@>
+
+@d abort(#)==@+begin print(' ',#); jump_out;@+end
+@d bad_gf(#)==abort('Bad GF file: ',#,'! (at byte ',cur_loc-1:1,')')
+@.Bad GF file@>
+
+@p procedure jump_out;
+begin goto final_end;
+end;
+
+@ As in \TeX\ and \MF, this program deals with numeric quantities that
+are integer multiples of~$2^{16}$, and calls them |scaled|.
+
+@d unity==@'200000 {|scaled| representation of 1.0}
+
+@<Types ...@>=
+@!scaled=integer; {fixed-point numbers}
+
+@* The character set.
+Like all programs written with the \.{WEB} system, \.{GFtoDVI} can be
+used with any character set. But it uses ASCII code internally, because
+the programming for portable input-output is easier when a fixed internal
+code is used. Furthermore, both \.{GF} and \.{DVI} files use ASCII code
+for file names and certain other strings.
+The next few sections of \.{GFtoDVI} have therefore been copied from the
+analogous ones in the \.{WEB} system routines.
+
+@<Types ...@>=
+@!ASCII_code=0..255; {eight-bit numbers, a subrange of the integers}
+
+@ The original \PASCAL\ compiler was designed in the late 60s, when
+six-bit character sets were common, so it did not make provision for lowercase
+letters. Nowadays, of course, we need to deal with both capital and
+small letters in a convenient way. So we shall assume that the
+\PASCAL\ system being used for \.{GFtoDVI} has a character set containing
+at least the standard visible ASCII characters (|"!"| through |"~"|). If
+additional characters are present, \.{GFtoDVI} can be configured to
+work with them too.
+
+Some \PASCAL\ compilers use the original name |char| for the data type
+associated with the characters in text files, while other \PASCAL s
+consider |char| to be a 64-element subrange of a larger data type that has
+some other name. In order to accommodate this difference, we shall use
+the name |text_char| to stand for the data type of the characters in the
+output file. We shall also assume that |text_char| consists of
+the elements |chr(first_text_char)| through |chr(last_text_char)|,
+inclusive. The following definitions should be adjusted if necessary.
+@^system dependencies@>
+
+@d text_char == char {the data type of characters in text files}
+@d first_text_char=0 {ordinal number of the smallest element of |text_char|}
+@d last_text_char=255 {ordinal number of the largest element of |text_char|}
+
+@<Types ...@>=
+@!text_file=packed file of text_char;
+
+@ The \.{GFtoDVI} processor converts between ASCII code and
+the user's external character set by means of arrays |xord| and |xchr|
+that are analogous to \PASCAL's |ord| and |chr| functions.
+
+@<Globals...@>=
+@!xord: array [text_char] of ASCII_code;
+ {specifies conversion of input characters}
+@!xchr: array [ASCII_code] of text_char;
+ {specifies conversion of output characters}
+
+@ Under our assumption that the visible characters of standard ASCII are
+all present, the following assignment statements initialize the
+|xchr| array properly, without needing any system-dependent changes.
+
+@<Set init...@>=
+xchr[@'40]:=' ';
+xchr[@'41]:='!';
+xchr[@'42]:='"';
+xchr[@'43]:='#';
+xchr[@'44]:='$';
+xchr[@'45]:='%';
+xchr[@'46]:='&';
+xchr[@'47]:='''';@/
+xchr[@'50]:='(';
+xchr[@'51]:=')';
+xchr[@'52]:='*';
+xchr[@'53]:='+';
+xchr[@'54]:=',';
+xchr[@'55]:='-';
+xchr[@'56]:='.';
+xchr[@'57]:='/';@/
+xchr[@'60]:='0';
+xchr[@'61]:='1';
+xchr[@'62]:='2';
+xchr[@'63]:='3';
+xchr[@'64]:='4';
+xchr[@'65]:='5';
+xchr[@'66]:='6';
+xchr[@'67]:='7';@/
+xchr[@'70]:='8';
+xchr[@'71]:='9';
+xchr[@'72]:=':';
+xchr[@'73]:=';';
+xchr[@'74]:='<';
+xchr[@'75]:='=';
+xchr[@'76]:='>';
+xchr[@'77]:='?';@/
+xchr[@'100]:='@@';
+xchr[@'101]:='A';
+xchr[@'102]:='B';
+xchr[@'103]:='C';
+xchr[@'104]:='D';
+xchr[@'105]:='E';
+xchr[@'106]:='F';
+xchr[@'107]:='G';@/
+xchr[@'110]:='H';
+xchr[@'111]:='I';
+xchr[@'112]:='J';
+xchr[@'113]:='K';
+xchr[@'114]:='L';
+xchr[@'115]:='M';
+xchr[@'116]:='N';
+xchr[@'117]:='O';@/
+xchr[@'120]:='P';
+xchr[@'121]:='Q';
+xchr[@'122]:='R';
+xchr[@'123]:='S';
+xchr[@'124]:='T';
+xchr[@'125]:='U';
+xchr[@'126]:='V';
+xchr[@'127]:='W';@/
+xchr[@'130]:='X';
+xchr[@'131]:='Y';
+xchr[@'132]:='Z';
+xchr[@'133]:='[';
+xchr[@'134]:='\';
+xchr[@'135]:=']';
+xchr[@'136]:='^';
+xchr[@'137]:='_';@/
+xchr[@'140]:='`';
+xchr[@'141]:='a';
+xchr[@'142]:='b';
+xchr[@'143]:='c';
+xchr[@'144]:='d';
+xchr[@'145]:='e';
+xchr[@'146]:='f';
+xchr[@'147]:='g';@/
+xchr[@'150]:='h';
+xchr[@'151]:='i';
+xchr[@'152]:='j';
+xchr[@'153]:='k';
+xchr[@'154]:='l';
+xchr[@'155]:='m';
+xchr[@'156]:='n';
+xchr[@'157]:='o';@/
+xchr[@'160]:='p';
+xchr[@'161]:='q';
+xchr[@'162]:='r';
+xchr[@'163]:='s';
+xchr[@'164]:='t';
+xchr[@'165]:='u';
+xchr[@'166]:='v';
+xchr[@'167]:='w';@/
+xchr[@'170]:='x';
+xchr[@'171]:='y';
+xchr[@'172]:='z';
+xchr[@'173]:='{';
+xchr[@'174]:='|';
+xchr[@'175]:='}';
+xchr[@'176]:='~';
+
+@ Here now is the system-dependent part of the character set.
+If \.{GFtoDVI} is being implemented on a garden-variety \PASCAL\ for which
+only standard ASCII codes will appear in the input and output files, you
+don't need to make any changes here. But if you have, for example, an extended
+character set like the one in Appendix~C of {\sl The \TeX book}, the first
+line of code in this module should be changed to
+$$\hbox{|for i:=0 to @'37 do xchr[i]:=chr(i);|}$$
+\.{WEB}'s character set is essentially identical to \TeX's.
+@^system dependencies@>
+
+@<Set init...@>=
+for i:=0 to @'37 do xchr[i]:='?';
+for i:=@'177 to @'377 do xchr[i]:='?';
+
+@ The following system-independent code makes the |xord| array contain a
+suitable inverse to the information in |xchr|.
+
+@<Set init...@>=
+for i:=first_text_char to last_text_char do xord[chr(i)]:=" ";
+for i:=1 to @'377 do xord[xchr[i]]:=i;
+xord['?']:="?";
+
+@ The |input_ln| routine waits for the user to type a line at his or her
+terminal; then it puts ASCII-code equivalents for the characters on that line
+into the |buffer| array. The |term_in| file is used for terminal input.
+@^system dependencies@>
+
+Since the terminal is being used for both input and output, some systems
+need a special routine to make sure that the user can see a prompt message
+before waiting for input based on that message. (Otherwise the message
+may just be sitting in a hidden buffer somewhere, and the user will have
+no idea what the program is waiting for.) We shall call a system-dependent
+subroutine |update_terminal| in order to avoid this problem.
+
+@d update_terminal == break(output) {empty the terminal output buffer}
+
+@<Glob...@>=
+@!buffer:array[0..terminal_line_length] of 0..255;
+@!term_in:text_file; {the terminal, considered as an input file}
+
+@ A global variable |line_length| records the first buffer position after
+the line just read.
+@^system dependencies@>
+
+@p procedure input_ln; {inputs a line from the terminal}
+begin update_terminal; reset(term_in);
+if eoln(term_in) then read_ln(term_in);
+line_length:=0;
+while (line_length<terminal_line_length)and not eoln(term_in) do
+ begin buffer[line_length]:=xord[term_in^]; incr(line_length); get(term_in);
+ end;
+end;
+
+@ The global variable |buf_ptr| is used while scanning each line of input;
+it points to the first unread character in |buffer|.
+
+@<Glob...@>=
+@!buf_ptr:0..terminal_line_length; {the number of characters read}
+@!line_length:0..terminal_line_length; {end of line read by |input_ln|}
+
+@* Device-independent file format.
+Before we get into the details of \.{GFtoDVI}, we need to know exactly
+what \.{DVI} files are. The form of such files was designed by David R.
+@^Fuchs, David Raymond@>
+Fuchs in 1979. Almost any reasonable typesetting device can be driven by
+a program that takes \.{DVI} files as input, and dozens of such
+\.{DVI}-to-whatever programs have been written. Thus, it is possible to
+print the output of document compilers like \TeX\ on many different kinds
+of equipment. (The following material has been copied almost verbatim from the
+program for \TeX.)
+
+A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a
+series of commands in a machine-like language. The first byte of each command
+is the operation code, and this code is followed by zero or more bytes
+that provide parameters to the command. The parameters themselves may consist
+of several consecutive bytes; for example, the `|set_rule|' command has two
+parameters, each of which is four bytes long. Parameters are usually
+regarded as nonnegative integers; but four-byte-long parameters,
+and shorter parameters that denote distances, can be
+either positive or negative. Such parameters are given in two's complement
+notation. For example, a two-byte-long distance parameter has a value between
+$-2^{15}$ and $2^{15}-1$.
+@.DVI {\rm files}@>
+
+Incidentally, when two or more 8-bit bytes are combined to form an integer of
+16 or more bits, the most significant bytes appear first in the file.
+This is called BigEndian order.
+@^BigEndian order@>
+
+A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one
+or more ``pages,'' followed by a ``postamble.'' The preamble is simply a
+|pre| command, with its parameters that define the dimensions used in the
+file; this must come first. Each ``page'' consists of a |bop| command,
+followed by any number of other commands that tell where characters are to
+be placed on a physical page, followed by an |eop| command. The pages
+appear in the order that they were generated, not in any particular
+numerical order. If we ignore |nop| commands and \\{fnt\_def} commands
+(which are allowed between any two commands in the file), each |eop|
+command is immediately followed by a |bop| command, or by a |post|
+command; in the latter case, there are no more pages in the file, and the
+remaining bytes form the postamble. Further details about the postamble
+will be explained later.
+
+Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
+quantities that give the location number of some other byte in the file;
+the first byte is number~0, then comes number~1, and so on. For example,
+one of the parameters of a |bop| command points to the previous |bop|;
+this makes it feasible to read the pages in backwards order, in case the
+results are being directed to a device that stacks its output face up.
+Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the
+first page occupies bytes 100 to 999, say, and if the second
+page occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000
+points to 100 and the |bop| that starts in byte 2000 points to 1000. (The
+very first |bop|, i.e., the one that starts in byte 100, has a pointer of $-1$.)
+
+@ The \.{DVI} format is intended to be both compact and easily interpreted
+by a machine. Compactness is achieved by making most of the information
+implicit instead of explicit. When a \.{DVI}-reading program reads the
+commands for a page, it keeps track of several quantities: (a)~The current
+font |f| is an integer; this value is changed only
+by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page
+is given by two numbers called the horizontal and vertical coordinates,
+|h| and |v|. Both coordinates are zero at the upper left corner of the page;
+moving to the right corresponds to increasing the horizontal coordinate, and
+moving down corresponds to increasing the vertical coordinate. Thus, the
+coordinates are essentially Cartesian, except that vertical directions are
+flipped; the Cartesian version of |(h,v)| would be |(h,-v)|. (c)~The
+current spacing amounts are given by four numbers |w|, |x|, |y|, and |z|,
+where |w| and~|x| are used for horizontal spacing and where |y| and~|z|
+are used for vertical spacing. (d)~There is a stack containing
+|(h,v,w,x,y,z)| values; the \.{DVI} commands |push| and |pop| are used to
+change the current level of operation. Note that the current font~|f| is
+not pushed and popped; the stack contains only information about
+positioning.
+
+The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up
+to 32 bits, including the sign. Since they represent physical distances,
+there is a small unit of measurement such that increasing |h| by~1 means
+moving a certain tiny distance to the right. The actual unit of
+measurement is variable, as explained below.
+
+@ Here is a list of all the commands that may appear in a \.{DVI} file. Each
+command is specified by its symbolic name (e.g., |bop|), its opcode byte
+(e.g., 139), and its parameters (if any). The parameters are followed
+by a bracketed number telling how many bytes they occupy; for example,
+`|p[4]|' means that parameter |p| is four bytes long.
+
+\yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f|
+such that the reference point of the character is at |(h,v)|. Then
+increase |h| by the width of that character. Note that a character may
+have zero or negative width, so one cannot be sure that |h| will advance
+after this command; but |h| usually does increase.
+
+\yskip\hang|set_char_1| through |set_char_127| (opcodes 1 to 127).
+Do the operations of |set_char_0|; but use the character whose number
+matches the opcode, instead of character~0.
+
+\yskip\hang|set1| 128 |c[1]|. Same as |set_char_0|, except that character
+number~|c| is typeset. \TeX82 uses this command for characters in the
+range |128<=c<256|.
+
+\yskip\hang|set2| 129 |c[2]|. Same as |set1|, except that |c|~is two
+bytes long, so it is in the range |0<=c<65536|.
+
+\yskip\hang|set3| 130 |c[3]|. Same as |set1|, except that |c|~is three
+bytes long, so it can be as large as $2^{24}-1$. Not even the Chinese
+language has this many characters, but this command might prove useful
+in some yet unforeseen way.
+
+\yskip\hang|set4| 131 |c[4]|. Same as |set1|, except that |c|~is four
+bytes long, possibly even negative. Imagine that.
+
+\yskip\hang|set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle
+of height |a| and width |b|, with its bottom left corner at |(h,v)|. Then
+set |h:=h+b|. If either |a<=0| or |b<=0|, nothing should be typeset. Note
+that if |b<0|, the value of |h| will decrease even though nothing else happens.
+
+\yskip\hang|put1| 133 |c[1]|. Typeset character number~|c| from font~|f|
+such that the reference point of the character is at |(h,v)|. (The `put'
+commands are exactly like the `set' commands, except that they simply put out a
+character or a rule without moving the reference point afterwards.)
+
+\yskip\hang|put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.
+
+\yskip\hang|put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.
+
+\yskip\hang|put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.
+
+\yskip\hang|put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that
+|h| is not changed.
+
+\yskip\hang|nop| 138. No operation, do nothing. Any number of |nop|'s
+may occur between \.{DVI} commands, but a |nop| cannot be inserted between
+a command and its parameters or between two parameters.
+
+\yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning
+of a page: Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set
+the current font |f| to an undefined value. The ten $c_i$ parameters can
+be used to identify pages, if a user wants to print only part of a \.{DVI}
+file; \TeX82 gives them the values of \.{\\count0} $\ldots$ \.{\\count9}
+at the time \.{\\shipout} was invoked for this page. The parameter |p|
+points to the previous |bop| command in the file, where the first |bop|
+has $p=-1$.
+
+\yskip\hang|eop| 140. End of page: Print what you have read since the
+previous |bop|. At this point the stack should be empty. (The \.{DVI}-reading
+programs that drive most output devices will have kept a buffer of the
+material that appears on the page that has just ended. This material is
+largely, but not entirely, in order by |v| coordinate and (for fixed |v|) by
+|h|~coordinate; so it usually needs to be sorted into some order that is
+appropriate for the device in question. \.{GFtoDVI} does not do such sorting.)
+
+\yskip\hang|push| 141. Push the current values of |(h,v,w,x,y,z)| onto the
+top of the stack; do not change any of these values. Note that |f| is
+not pushed.
+
+\yskip\hang|pop| 142. Pop the top six values off of the stack and assign
+them to |(h,v,w,x,y,z)|. The number of pops should never exceed the number
+of pushes, since it would be highly embarrassing if the stack were empty
+at the time of a |pop| command.
+
+\yskip\hang|right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units.
+The parameter is a signed number in two's complement notation, |-128<=b<128|;
+if |b<0|, the reference point actually moves left.
+
+\yskip\hang|right2| 144 |b[2]|. Same as |right1|, except that |b| is a
+two-byte quantity in the range |-32768<=b<32768|.
+
+\yskip\hang|right3| 145 |b[3]|. Same as |right1|, except that |b| is a
+three-byte quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+
+\yskip\hang|right4| 146 |b[4]|. Same as |right1|, except that |b| is a
+four-byte quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+
+\yskip\hang|w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck,
+this parameterless command will usually suffice, because the same kind of motion
+will occur several times in succession; the following commands explain how
+|w| gets particular values.
+
+\yskip\hang|w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a
+signed quantity in two's complement notation, |-128<=b<128|. This command
+changes the current |w|~spacing and moves right by |b|.
+
+\yskip\hang|w2| 149 |b[2]|. Same as |w1|, but |b| is a two-byte-long
+parameter, |-32768<=b<32768|.
+
+\yskip\hang|w3| 150 |b[3]|. Same as |w1|, but |b| is a three-byte-long
+parameter, |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+
+\yskip\hang|w4| 151 |b[4]|. Same as |w1|, but |b| is a four-byte-long
+parameter, |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+
+\yskip\hang|x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|'
+commands are like the `|w|' commands except that they involve |x| instead
+of |w|.
+
+\yskip\hang|x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a
+signed quantity in two's complement notation, |-128<=b<128|. This command
+changes the current |x|~spacing and moves right by |b|.
+
+\yskip\hang|x2| 154 |b[2]|. Same as |x1|, but |b| is a two-byte-long
+parameter, |-32768<=b<32768|.
+
+\yskip\hang|x3| 155 |b[3]|. Same as |x1|, but |b| is a three-byte-long
+parameter, |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+
+\yskip\hang|x4| 156 |b[4]|. Same as |x1|, but |b| is a four-byte-long
+parameter, |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+
+\yskip\hang|down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units.
+The parameter is a signed number in two's complement notation, |-128<=a<128|;
+if |a<0|, the reference point actually moves up.
+
+\yskip\hang|down2| 158 |a[2]|. Same as |down1|, except that |a| is a
+two-byte quantity in the range |-32768<=a<32768|.
+
+\yskip\hang|down3| 159 |a[3]|. Same as |down1|, except that |a| is a
+three-byte quantity in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+
+\yskip\hang|down4| 160 |a[4]|. Same as |down1|, except that |a| is a
+four-byte quantity in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+
+\yskip\hang|y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck,
+this parameterless command will usually suffice, because the same kind of motion
+will occur several times in succession; the following commands explain how
+|y| gets particular values.
+
+\yskip\hang|y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a
+signed quantity in two's complement notation, |-128<=a<128|. This command
+changes the current |y|~spacing and moves down by |a|.
+
+\yskip\hang|y2| 163 |a[2]|. Same as |y1|, but |a| is a two-byte-long
+parameter, |-32768<=a<32768|.
+
+\yskip\hang|y3| 164 |a[3]|. Same as |y1|, but |a| is a three-byte-long
+parameter, |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+
+\yskip\hang|y4| 165 |a[4]|. Same as |y1|, but |a| is a four-byte-long
+parameter, |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+
+\yskip\hang|z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands
+are like the `|y|' commands except that they involve |z| instead of |y|.
+
+\yskip\hang|z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a
+signed quantity in two's complement notation, |-128<=a<128|. This command
+changes the current |z|~spacing and moves down by |a|.
+
+\yskip\hang|z2| 168 |a[2]|. Same as |z1|, but |a| is a two-byte-long
+parameter, |-32768<=a<32768|.
+
+\yskip\hang|z3| 169 |a[3]|. Same as |z1|, but |a| is a three-byte-long
+parameter, |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+
+\yskip\hang|z4| 170 |a[4]|. Same as |z1|, but |a| is a four-byte-long
+parameter, |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+
+\yskip\hang|fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been
+defined by a \\{fnt\_def} instruction, as explained below.
+
+\yskip\hang|fnt_num_1| through |fnt_num_63| (opcodes 172 to 234). Set
+|f:=1|, \dots, |f:=63|, respectively.
+
+\yskip\hang|fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font
+numbers in the range |64<=k<256|.
+
+\yskip\hang|fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two
+bytes long, so it is in the range |0<=k<65536|. \TeX82 never generates this
+command, but large font numbers may prove useful for specifications of
+color or texture, or they may be used for special fonts that have fixed
+numbers in some external coding scheme.
+
+\yskip\hang|fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three
+bytes long, so it can be as large as $2^{24}-1$.
+
+\yskip\hang|fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four
+bytes long; this is for the really big font numbers (and for the negative ones).
+
+\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
+general; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading
+programs are being used. \TeX82 generates |xxx1| when a short enough
+\.{\\special} appears, setting |k| to the number of bytes being sent. It
+is recommended that |x| be a string having the form of a keyword followed
+by possible parameters relevant to that keyword.
+
+\yskip\hang|xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
+
+\yskip\hang|xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
+
+\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously
+large. \TeX82 uses |xxx4| when |xxx1| would be incorrect.
+
+\yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0<=k<256|; font definitions will be explained shortly.
+
+\yskip\hang|fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0<=k<65536|.
+
+\yskip\hang|fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |0<=k<@t$2^{24}$@>|.
+
+\yskip\hang|fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
+Define font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|.
+
+\yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
+Beginning of the preamble; this must come at the very beginning of the
+file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.
+
+\yskip\hang|post| 248. Beginning of the postamble, see below.
+
+\yskip\hang|post_post| 249. Ending of the postamble, see below.
+
+\yskip\noindent Commands 250--255 are undefined at the present time.
+
+@ Only a few of the operation codes above are actually needed by \.{GFtoDVI}.
+
+@d set1=128 {typeset a character and move right}
+@d put_rule=137 {typeset a rule}
+@d bop=139 {beginning of page}
+@d eop=140 {ending of page}
+@d push=141 {save the current positions}
+@d pop=142 {restore previous positions}
+@d right4=146 {move right}
+@d down4=160 {move down}
+@d z0=166 {move down |z|}
+@d z4=170 {move down and set |z|}
+@d fnt_num_0=171 {set current font to 0}
+@d fnt_def1=243 {define the meaning of a font number}
+@d pre=247 {preamble}
+@d post=248 {postamble beginning}
+@d post_post=249 {postamble ending}
+
+@ The preamble contains basic information about the file as a whole. As
+stated above, there are six parameters:
+$$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
+The |i| byte identifies \.{DVI} format; currently this byte is always set
+to~2. (The value |i=3| is currently used for an extended format that
+allows a mixture of right-to-left and left-to-right typesetting.
+Some day we will set |i=4|, when \.{DVI} format makes another
+incompatible change---perhaps in the year 2048.)
+
+The next two parameters, |num| and |den|, are positive integers that define
+the units of measurement; they are the numerator and denominator of a
+fraction by which all dimensions in the \.{DVI} file could be multiplied
+in order to get lengths in units of $10^{-7}$ meters. (For example, there are
+exactly 7227 \TeX\ points in 254 centimeters, and \TeX82 works with scaled
+points where there are $2^{16}$ sp in a point, so \TeX82 sets |num=25400000|
+and $|den|=7227\cdot2^{16}=473628672$.)
+@^sp@>
+
+The |mag| parameter is what \TeX82 calls \.{\\mag}, i.e., 1000 times the
+desired magnification. The actual fraction by which dimensions are
+multiplied is therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\
+source document does not call for any `\.{true}' dimensions, and if you
+change it only by specifying a different \.{\\mag} setting, the \.{DVI}
+file that \TeX\ creates will be completely unchanged except for the value
+of |mag| in the preamble and postamble. (Fancy \.{DVI}-reading programs allow
+users to override the |mag|~setting when a \.{DVI} file is being printed.)
+
+Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
+interpreted further. The length of comment |x| is |k|, where |0<=k<256|.
+
+@d dvi_id_byte=2 {identifies the kind of \.{DVI} files described here}
+
+@ Font definitions for a given font number |k| contain further parameters
+$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$
+The four-byte value |c| is the check sum that \TeX\ (or whatever program
+generated the \.{DVI} file) found in the \.{TFM} file for this font;
+|c| should match the check sum of the font found by programs that read
+this \.{DVI} file.
+@^check sum@>
+
+Parameter |s| contains a fixed-point scale factor that is applied to the
+character widths in font |k|; font dimensions in \.{TFM} files and other
+font files are relative to this quantity, which is always positive and
+less than $2^{27}$. It is given in the same units as the other dimensions
+of the \.{DVI} file. Parameter |d| is similar to |s|; it is the ``design
+size,'' and (like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be
+used at $|mag|\cdot s/1000d$ times its normal size.
+
+The remaining part of a font definition gives the external name of the font,
+which is an ASCII string of length |a+l|. The number |a| is the length
+of the ``area'' or directory, and |l| is the length of the font name itself;
+the standard local system font area is supposed to be used when |a=0|.
+The |n| field contains the area in its first |a| bytes.
+
+Font definitions must appear before the first use of a particular font number.
+Once font |k| is defined, it must not be defined again; however, we
+shall see below that font definitions appear in the postamble as well as
+in the pages, so in this sense each font number is defined exactly twice,
+if at all. Like |nop| commands, font definitions can
+appear before the first |bop|, or between an |eop| and a |bop|.
+
+@ The last page in a \.{DVI} file is followed by `|post|'; this command
+introduces the postamble, which summarizes important facts that \TeX\ has
+accumulated about the file, making it possible to print subsets of the data
+with reasonable efficiency. The postamble has the form
+$$\vbox{\halign{\hbox{#\hfil}\cr
+ |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
+ $\langle\,$font definitions$\,\rangle$\cr
+ |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
+Here |p| is a pointer to the final |bop| in the file. The next three
+parameters, |num|, |den|, and |mag|, are duplicates of the quantities that
+appeared in the preamble.
+
+Parameters |l| and |u| give respectively the height-plus-depth of the tallest
+page and the width of the widest page, in the same units as other dimensions
+of the file. These numbers might be used by a \.{DVI}-reading program to
+position individual ``pages'' on large sheets of film or paper; however,
+the standard convention for output on normal size paper is to position each
+page so that the upper left-hand corner is exactly one inch from the left
+and the top. Experience has shown that it is unwise to design \.{DVI}-to-printer
+software that attempts cleverly to center the output; a fixed position of
+the upper left corner is easiest for users to understand and to work with.
+Therefore |l| and~|u| are often ignored.
+
+Parameter |s| is the maximum stack depth (i.e., the largest excess of
+|push| commands over |pop| commands) needed to process this file. Then
+comes |t|, the total number of pages (|bop| commands) present.
+
+The postamble continues with font definitions, which are any number of
+\\{fnt\_def} commands as described above, possibly interspersed with |nop|
+commands. Each font number that is used in the \.{DVI} file must be defined
+exactly twice: Once before it is first selected by a \\{fnt} command, and once
+in the postamble.
+
+@ The last part of the postamble, following the |post_post| byte that
+signifies the end of the font definitions, contains |q|, a pointer to the
+|post| command that started the postamble. An identification byte, |i|,
+comes next; this currently equals~2, as in the preamble.
+
+The |i| byte is followed by four or more bytes that are all equal to
+the decimal number 223 (i.e., @'337 in octal). \TeX\ puts out four to seven of
+these trailing bytes, until the total length of the file is a multiple of
+four bytes, since this works out best on machines that pack four bytes per
+word; but any number of 223's is allowed, as long as there are at least four
+of them. In effect, 223 is a sort of signature that is added at the very end.
+@^Fuchs, David Raymond@>
+
+This curious way to finish off a \.{DVI} file makes it feasible for
+\.{DVI}-reading programs to find the postamble first, on most computers,
+even though \TeX\ wants to write the postamble last. Most operating
+systems permit random access to individual words or bytes of a file, so
+the \.{DVI} reader can start at the end and skip backwards over the 223's
+until finding the identification byte. Then it can back up four bytes, read
+|q|, and move to byte |q| of the file. This byte should, of course,
+contain the value 248 (|post|); now the postamble can be read, so the
+\.{DVI} reader can discover all the information needed for typesetting the
+pages. Note that it is also possible to skip through the \.{DVI} file at
+reasonably high speed to locate a particular page, if that proves
+desirable. This saves a lot of time, since \.{DVI} files used in production
+jobs tend to be large.
+
+Unfortunately, however, standard \PASCAL\ does not include the ability to
+@^system dependencies@>
+access a random position in a file, or even to determine the length of a file.
+Almost all systems nowadays provide the necessary capabilities, so \.{DVI}
+format has been designed to work most efficiently with modern operating systems.
+
+@* Generic font file format.
+The ``generic font'' (\.{GF}) input files that \.{GFtoDVI} must deal with
+have a structure that was inspired by \.{DVI} format, although the
+operation codes are quite different in most cases. The term {\sl
+generic\/} indicates that this file format doesn't match the conventions
+of any name-brand manufacturer; but it is easy to convert \.{GF} files to
+the special format required by almost all digital phototypesetting
+equipment. There's a strong analogy between the \.{DVI} files written by
+\TeX\ and the \.{GF} files written by \MF; and, in fact, the reader will
+notice that many of the paragraphs below are identical to their
+counterparts in the description of \.{DVI} already given. The following
+description has been lifted almost verbatim from the program for \MF.
+
+A \.{GF} file is a stream of 8-bit bytes that may be
+regarded as a series of commands in a machine-like language. The first
+byte of each command is the operation code, and this code is followed by
+zero or more bytes that provide parameters to the command. The parameters
+themselves may consist of several consecutive bytes; for example, the
+`|boc|' (beginning of character) command has six parameters, each of
+which is four bytes long. Parameters are usually regarded as nonnegative
+integers; but four-byte-long parameters can be either positive or
+negative, hence they range in value from $-2^{31}$ to $2^{31}-1$.
+As in \.{DVI} files, numbers that occupy
+more than one byte position appear in BigEndian order,
+and negative numbers appear in two's complement notation.
+
+A \.{GF} file consists of a ``preamble,'' followed by a sequence of one or
+more ``characters,'' followed by a ``postamble.'' The preamble is simply a
+|pre| command, with its parameters that introduce the file; this must come
+first. Each ``character'' consists of a |boc| command, followed by any
+number of other commands that specify ``black'' pixels,
+followed by an |eoc| command. The characters appear in the order that \MF\
+generated them. If we ignore no-op commands (which are allowed between any
+two commands in the file), each |eoc| command is immediately followed by a
+|boc| command, or by a |post| command; in the latter case, there are no
+more characters in the file, and the remaining bytes form the postamble.
+Further details about the postamble will be explained later.
+
+Some parameters in \.{GF} commands are ``pointers.'' These are four-byte
+quantities that give the location number of some other byte in the file;
+the first file byte is number~0, then comes number~1, and so on.
+
+@ The \.{GF} format is intended to be both compact and easily interpreted
+by a machine. Compactness is achieved by making most of the information
+relative instead of absolute. When a \.{GF}-reading program reads the
+commands for a character, it keeps track of two quantities: (a)~the current
+column number,~|m|; and (b)~the current row number,~|n|. These are 32-bit
+signed integers, although most actual font formats produced from \.{GF}
+files will need to curtail this vast range because of practical
+limitations. (\MF\ output will never allow $\vert m\vert$ or $\vert
+n\vert$ to get extremely large, but the \.{GF} format tries to be more general.)
+
+How do \.{GF}'s row and column numbers correspond to the conventions
+of \TeX\ and \MF? Well, the ``reference point'' of a character, in \TeX's
+view, is considered to be at the lower left corner of the pixel in row~0
+and column~0. This point is the intersection of the baseline with the left
+edge of the type; it corresponds to location $(0,0)$ in \MF\ programs.
+Thus the pixel in \.{GF} row~0 and column~0 is \MF's unit square, comprising the
+region of the plane whose coordinates both lie between 0 and~1. The
+pixel in \.{GF} row~|n| and column~|m| consists of the points whose \MF\
+coordinates |(x,y)| satisfy |m<=x<=m+1| and |n<=y<=n+1|. Negative values of
+|m| and~|x| correspond to columns of pixels {\sl left\/} of the reference
+point; negative values of |n| and~|y| correspond to rows of pixels {\sl
+below\/} the baseline.
+
+Besides |m| and |n|, there's also a third aspect of the current
+state, namely the @!|paint_switch|, which is always either \\{black} or
+\\{white}. Each \\{paint} command advances |m| by a specified amount~|d|,
+and blackens the intervening pixels if |paint_switch=black|; then
+the |paint_switch| changes to the opposite state. \.{GF}'s commands are
+designed so that |m| will never decrease within a row, and |n| will never
+increase within a character; hence there is no way to whiten a pixel that
+has been blackened.
+
+@ Here is a list of all the commands that may appear in a \.{GF} file. Each
+command is specified by its symbolic name (e.g., |boc|), its opcode byte
+(e.g., 67), and its parameters (if any). The parameters are followed
+by a bracketed number telling how many bytes they occupy; for example,
+`|d[2]|' means that parameter |d| is two bytes long.
+
+\yskip\hang|paint_0| 0. This is a \\{paint} command with |d=0|; it does
+nothing but change the |paint_switch| from \\{black} to \\{white} or vice~versa.
+
+\yskip\hang\\{paint\_1} through \\{paint\_63} (opcodes 1 to 63).
+These are \\{paint} commands with |d=1| to~63, defined as follows: If
+|paint_switch=black|, blacken |d|~pixels of the current row~|n|,
+in columns |m| through |m+d-1| inclusive. Then, in any case,
+complement the |paint_switch| and advance |m| by~|d|.
+
+\yskip\hang|paint1| 64 |d[1]|. This is a \\{paint} command with a specified
+value of~|d|; \MF\ uses it to paint when |64<=d<256|.
+
+\yskip\hang|paint2| 65 |d[2]|. Same as |paint1|, but |d|~can be as high
+as~65535.
+
+\yskip\hang|paint3| 66 |d[3]|. Same as |paint1|, but |d|~can be as high
+as $2^{24}-1$. \MF\ never needs this command, and it is hard to imagine
+anybody making practical use of it; surely a more compact encoding will be
+desirable when characters can be this large. But the command is there,
+anyway, just in case.
+
+\yskip\hang|boc| 67 |c[4]| |p[4]| |min_m[4]| |max_m[4]| |min_n[4]|
+|max_n[4]|. Beginning of a character: Here |c| is the character code, and
+|p| points to the previous character beginning (if any) for characters having
+this code number modulo 256. (The pointer |p| is |-1| if there was no
+prior character with an equivalent code.) The values of registers |m| and |n|
+defined by the instructions that follow for this character must
+satisfy |min_m<=m<=max_m| and |min_n<=n<=max_n|. (The values of |max_m| and
+|min_n| need not be the tightest bounds possible.) When a \.{GF}-reading
+program sees a |boc|, it can use |min_m|, |max_m|, |min_n|, and |max_n| to
+initialize the bounds of an array. Then it sets |m:=min_m|, |n:=max_n|, and
+|paint_switch:=white|.
+
+\yskip\hang|boc1| 68 |c[1]| |@!del_m[1]| |max_m[1]| |@!del_n[1]| |max_n[1]|.
+Same as |boc|, but |p| is assumed to be~$-1$; also |del_m=max_m-min_m|
+and |del_n=max_n-min_n| are given instead of |min_m| and |min_n|.
+The one-byte parameters must be between 0 and 255, inclusive.
+\ (This abbreviated |boc| saves 19~bytes per character, in common cases.)
+
+\yskip\hang|eoc| 69. End of character: All pixels blackened so far
+constitute the pattern for this character. In particular, a completely
+blank character might have |eoc| immediately following |boc|.
+
+\yskip\hang|skip0| 70. Decrease |n| by 1 and set |m:=min_m|,
+|paint_switch:=white|. \ (This finishes one row and begins another,
+ready to whiten the leftmost pixel in the new row.)
+
+\yskip\hang|skip1| 71 |d[1]|. Decrease |n| by |d+1|, set |m:=min_m|, and set
+|paint_switch:=white|. This is a way to produce |d| all-white rows.
+
+\yskip\hang|skip2| 72 |d[2]|. Same as |skip1|, but |d| can be as large
+as 65535.
+
+\yskip\hang|skip3| 73 |d[3]|. Same as |skip1|, but |d| can be as large
+as $2^{24}-1$. \MF\ obviously never needs this command.
+
+\yskip\hang|new_row_0| 74. Decrease |n| by 1 and set |m:=min_m|,
+|paint_switch:=black|. \ (This finishes one row and begins another,
+ready to {\sl blacken\/} the leftmost pixel in the new row.)
+
+\yskip\hang|@!new_row_1| through |@!new_row_164| (opcodes 75 to 238). Same as
+|new_row_0|, but with |m:=min_m+1| through |min_m+164|, respectively.
+
+\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
+general; it functions as a $(k+2)$-byte |no_op| unless special \.{GF}-reading
+programs are being used. \MF\ generates \\{xxx} commands when encountering
+a \&{special} string; this occurs in the \.{GF} file only between
+characters, after the preamble, and before the postamble. However,
+\\{xxx} commands might appear within characters,
+in \.{GF} files generated by other
+processors. It is recommended that |x| be a string having the form of a
+keyword followed by possible parameters relevant to that keyword.
+
+\yskip\hang|xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
+
+\yskip\hang|xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
+\MF\ uses this when sending a \&{special} string whose length exceeds~255.
+
+\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be
+ridiculously large; |k| mustn't be negative.
+
+\yskip\hang|yyy| 243 |y[4]|. This command is undefined in general;
+it functions as a 5-byte |no_op| unless special \.{GF}-reading programs
+are being used. \MF\ puts |scaled| numbers into |yyy|'s, as a
+result of \&{numspecial} commands; the intent is to provide numeric
+parameters to \\{xxx} commands that immediately precede.
+
+\yskip\hang|no_op| 244. No operation, do nothing. Any number of |no_op|'s
+may occur between \.{GF} commands, but a |no_op| cannot be inserted between
+a command and its parameters or between two parameters.
+
+\yskip\hang|char_loc| 245 |c[1]| |dx[4]| |dy[4]| |w[4]| |p[4]|.
+This command will appear only in the postamble, which will be explained shortly.
+
+\yskip\hang|@!char_loc0| 246 |c[1]| |@!dm[1]| |w[4]| |p[4]|.
+Same as |char_loc|, except that |dy| is assumed to be zero, and the value
+of~|dx| is taken to be |65536*dm|, where |0<=dm<256|.
+
+\yskip\hang|pre| 247 |i[1]| |k[1]| |x[k]|.
+Beginning of the preamble; this must come at the very beginning of the
+file. Parameter |i| is an identifying number for \.{GF} format, currently
+131. The other information is merely commentary; it is not given
+special interpretation like \\{xxx} commands are. (Note that \\{xxx}
+commands may immediately follow the preamble, before the first |boc|.)
+
+\yskip\hang|post| 248. Beginning of the postamble, see below.
+
+\yskip\hang|post_post| 249. Ending of the postamble, see below.
+
+\yskip\noindent Commands 250--255 are undefined at the present time.
+
+@d gf_id_byte=131 {identifies the kind of \.{GF} files described here}
+
+@ Here are the opcodes that \.{GFtoDVI} actually refers to.
+
+@d paint_0=0 {beginning of the \\{paint} commands}
+@d paint1=64 {move right a given number of columns, then
+ black${}\swap{}$white}
+@d paint2=65 {ditto, with potentially larger number of columns}
+@d paint3=66 {ditto, with potentially excessive number of columns}
+@d boc=67 {beginning of a character}
+@d boc1=68 {abbreviated |boc|}
+@d eoc=69 {end of a character}
+@d skip0=70 {skip no blank rows}
+@d skip1=71 {skip over blank rows}
+@d skip2=72 {skip over lots of blank rows}
+@d skip3=73 {skip over a huge number of blank rows}
+@d new_row_0=74 {move down one row and then right}
+@d xxx1=239 {for \&{special} strings}
+@d xxx2=240 {for somewhat long \&{special} strings}
+@d xxx3=241 {for extremely long \&{special} strings}
+@d xxx4=242 {for incredibly long \&{special} strings}
+@d yyy=243 {for \&{numspecial} numbers}
+@d no_op=244 {no operation}
+
+@ The last character in a \.{GF} file is followed by `|post|'; this command
+introduces the postamble, which summarizes important facts that \MF\ has
+accumulated. The postamble has the form
+$$\vbox{\halign{\hbox{#\hfil}\cr
+ |post| |p[4]| |@!ds[4]| |@!cs[4]| |@!hppp[4]| |@!vppp[4]|
+ |@!min_m[4]| |@!max_m[4]| |@!min_n[4]| |@!max_n[4]|\cr
+ $\langle\,$character locators$\,\rangle$\cr
+ |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
+Here |p| is a pointer to the byte following the final |eoc| in the file
+(or to the byte following the preamble, if there are no characters);
+it can be used to locate the beginning of \\{xxx} commands
+that might have preceded the postamble. The |ds| and |cs| parameters
+@^design size@> @^check sum@>
+give the design size and check sum, respectively, of the font (see the
+description of \.{TFM} format below).
+Parameters |hppp| and |vppp| are the ratios of
+pixels per point, horizontally and vertically, expressed as |scaled| integers
+(i.e., multiplied by $2^{16}$); they can be used to correlate the font
+with specific device resolutions, magnifications, and ``at sizes.'' Then
+come |min_m|, |max_m|, |min_n|, and |max_n|, which bound the values that
+registers |m| and~|n| assume in all characters in this \.{GF} file.
+(These bounds need not be the best possible; |max_m| and |min_n| may, on the
+other hand, be tighter than the similar bounds in |boc| commands. For
+example, some character may have |min_n=-100| in its |boc|, but it might
+turn out that |n| never gets lower than |-50| in any character; then
+|min_n| can have any value |<=-50|. If there are no characters in the file,
+it's possible to have |min_m>max_m| and/or |min_n>max_n|.)
+
+@ Character locators are introduced by |char_loc| commands,
+which specify a character residue~|c|, character escapements (|dx,dy|),
+a character width~|w|, and a pointer~|p|
+to the beginning of that character. (If two or more characters have the
+same code~|c| modulo 256, only the last will be indicated; the others can be
+located by following backpointers. Characters whose codes differ by a
+multiple of 256 are assumed to share the same font metric information,
+hence the \.{TFM} file contains only residues of character codes modulo~256.
+This convention is intended for oriental languages, when there are many
+character shapes but few distinct widths.)
+@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
+
+The character escapements (|dx,dy|) are the values of \MF's \&{chardx}
+and \&{chardy} parameters; they are in units of |scaled| pixels;
+i.e., |dx| is in horizontal pixel units times $2^{16}$, and |dy| is in
+vertical pixel units times $2^{16}$. This is the intended amount of
+displacement after typesetting the character; for \.{DVI} files, |dy|
+should be zero, but other document file formats allow nonzero vertical
+escapement.
+
+The character width~|w| duplicates the information in the \.{TFM} file; it
+is $2^{20}$ times the ratio of the true width to the font's design size.
+
+The backpointer |p| points to the character's |boc|, or to the first of
+a sequence of consecutive \\{xxx} or |yyy| or |no_op| commands that
+immediately precede the |boc|, if such commands exist; such ``special''
+commands essentially belong to the characters, while the special commands
+after the final character belong to the postamble (i.e., to the font
+as a whole). This convention about |p| applies also to the backpointers
+in |boc| commands, even though it wasn't explained in the description
+of~|boc|. @^backpointers@>
+
+Pointer |p| might be |-1| if the character exists in the \.{TFM} file
+but not in the \.{GF} file. This unusual situation can arise in \MF\ output
+if the user had |proofing<0| when the character was being shipped out,
+but then made |proofing>=0| in order to get a \.{GF} file.
+
+@ The last part of the postamble, following the |post_post| byte that
+signifies the end of the character locators, contains |q|, a pointer to the
+|post| command that started the postamble. An identification byte, |i|,
+comes next; this currently equals~131, as in the preamble.
+
+The |i| byte is followed by four or more bytes that are all equal to
+the decimal number 223 (i.e., @'337 in octal). \MF\ puts out four to seven of
+these trailing bytes, until the total length of the file is a multiple of
+four bytes, since this works out best on machines that pack four bytes per
+word; but any number of 223's is allowed, as long as there are at least four
+of them. In effect, 223 is a sort of signature that is added at the very end.
+@^Fuchs, David Raymond@>
+
+This curious way to finish off a \.{GF} file makes it feasible for
+\.{GF}-reading programs to find the postamble first, on most computers,
+even though \MF\ wants to write the postamble last. Most operating
+systems permit random access to individual words or bytes of a file, so
+the \.{GF} reader can start at the end and skip backwards over the 223's
+until finding the identification byte. Then it can back up four bytes, read
+|q|, and move to byte |q| of the file. This byte should, of course,
+contain the value 248 (|post|); now the postamble can be read, so the
+\.{GF} reader can discover all the information needed for individual characters.
+
+Unfortunately, however, standard \PASCAL\ does not include the ability to
+@^system dependencies@>
+access a random position in a file, or even to determine the length of a file.
+Almost all systems nowadays provide the necessary capabilities, so \.{GF}
+format has been designed to work most efficiently with modern operating systems.
+But if \.{GF} files have to be processed under the restrictions of standard
+\PASCAL, one can simply read them from front to back. This will
+be adequate for most applications. However, the postamble-first approach
+would facilitate a program that merges two \.{GF} files, replacing data
+from one that is overridden by corresponding data in the other.
+
+@* Extensions to the generic format.
+The \\{xxx} and \\{yyy} instructions understood by \.{GFtoDVI} will be
+listed now, so that we have a convenient reference to all of the special
+assumptions made later.
+
+Each special instruction begins with an \\{xxx} command, which consists of
+either a keyword by itself, or a keyword followed by a space followed
+by arguments. This \\{xxx} command may then be followed by \\{yyy}
+commands that are understood to be arguments.
+
+The keywords of special instructions that are intended to be used at
+many different sites should be published as widely as possible in order
+to minimize conflicts. The first person to establish a keyword presumably
+has a right to define it; \.{GFtoDVI}, as the first program
+to use extended \.{GF} commands, has the opportunity of choosing any
+keywords it likes, and the responsibility of choosing reasonable ones.
+Since labels are expected to account for the bulk of extended commands
+in typical uses of \MF, the ``null'' keyword has been set aside to
+denote a labeling command.
+
+@ Here then are the special commands of \.{GFtoDVI}.
+
+\def\string{$\langle\,$string$\,\rangle$}
+\def\okpagebreak{\vfil\penalty-100\vfilneg}
+\smallskip\hang\noindent
+\.{\SP n}\string\ $x$ $y$. Here \.n denotes the type of label; the
+characters \.1, \.2, \.3,~\.4 respectively denote labels forced to be
+at the top, left, right, or bottom of their dot, and the characters
+\.5, \.6, \.7,~\.8 stand for the same possibilities but with no dot printed.
+The character \.0 instructs \.{GFtoDVI} to choose one of the first four
+possibilities, if there's no overlap with other labels or dots, otherwise
+an ``overflow'' entry is placed at the right of the figure. The character
+\./ is the same as \.0 except that overflow entries are not produced. The
+label itself is the \string\ that follows. \MF\ coordinates of the
+point that is to receive this label are given by arguments $x$ and~$y$,
+in units of scaled pixels. (These arguments appear in \\{yyy} commands.)
+(Precise definitions of the size and positioning of labels, and of the
+notion of ``conflicting'' labels, will be given later.)
+
+\smallskip\hang\noindent
+\.{rule} $x_1$ $y_1$ $x_2$ $y_2$. This command draws a line from
+$(x_1,y_1)$ to $(x_2,y_2)$ in \MF\ coordinates. The present implementation
+does this only if the line is either horizontal or vertical, or if its
+slope matches the slope of the slant font.
+
+\smallskip\hang\noindent
+\.{title\SP}\string. This command (which is output by \MF\
+when it sees a ``title statement'') specifies a string that will appear
+at the top of the next proofsheet to be output by \.{GFtoDVI}.
+If more than one title is given, they will appear in sequence; titles
+should be short enough to fit on a single line.
+
+\smallskip\hang\noindent
+\.{titlefont\SP}\string. This command, and the other font-naming
+commands below, must precede the first |boc| in the \.{GF} file.
+It overrides the current font used to
+typeset the titles at the top of proofsheets. \.{GFtoDVI} has default
+fonts that will be used if none other are specified; the ``current'' title
+font is initially the default title font.
+
+\smallskip\hang\noindent
+\.{titlefontarea\SP}\string. This command overrides the current
+file area (or directory name) from which \.{GFtoDVI} will try to
+find metric information for the title font.
+
+\smallskip\hang\noindent
+\.{titlefontat} $s$. This command overrides the current ``at size'' that
+will be used for the title font. (See the discussion of font metric files
+below, for the meaning of ``at size'' versus ``design size.'') The
+value of~$s$ is given in units of scaled points.
+
+\okpagebreak
+\smallskip\hang\noindent
+\.{labelfont\SP}\string. This command overrides the current font
+used to typeset the labels that are superimposed on proof figures.
+(The label font is fairly arbitrary, but it should be dark enough to
+stand out when superimposed on gray pixels, and it should contain at
+least the decimal digits and the characters `\.(', `\.)', `\.=', `\.+',
+`\.-', `\.,', and `\..'.)
+
+\smallskip\hang\noindent
+\.{labelfontarea\SP}\string. This command overrides the current
+file area (or directory name) from which \.{GFtoDVI} will try to
+find metric information for the label font.
+
+\smallskip\hang\noindent
+\.{labelfontat} $s$. This command overrides the current ``at size'' that
+will be used for the label font.
+
+\okpagebreak
+\smallskip\hang\noindent
+\.{grayfont\SP}\string. This command overrides the current font
+used to typeset the black pixels and the dots for labels. (Gray fonts
+will be explained in detail later.)
+@^gray fonts@>
+
+\smallskip\hang\noindent
+\.{grayfontarea\SP}\string. This command overrides the current
+file area (or directory name) from which \.{GFtoDVI} will try to
+find metric information for the gray font.
+
+\smallskip\hang\noindent
+\.{grayfontat} $s$. This command overrides the current ``at size'' that
+will be used for the gray font.
+
+\okpagebreak
+\smallskip\hang\noindent
+\.{slantfont\SP}\string. This command overrides the current font
+used to typeset rules that are neither horizontal nor vertical. (Slant
+fonts will be explained in detail later.)
+@^slant fonts@>
+
+\smallskip\hang\noindent
+\.{slantfontarea\SP}\string. This command overrides the current
+file area (or directory name) from which \.{GFtoDVI} will try to
+find metric information for the slant font.
+
+\smallskip\hang\noindent
+\.{slantfontat} $s$. This command overrides the current ``at size'' that
+will be used for the slant font.
+
+\okpagebreak
+\smallskip\hang\noindent
+\.{rulethickness} $t$. This command overrides the current value used
+for the thickness of rules. If the current value is negative, no rule
+will be drawn; if the current value is zero, the rule thickness will
+be specified by a parameter of the gray font. Each \.{rule} command
+uses the rule thickness that is current at the time the command appears;
+hence it is possible to get different thicknesses of rules on the same
+figure. The value of $t$ is given in units of scaled points (\TeX's `\.{sp}').
+At the beginning of each character the current rule thickness is zero.
+
+\smallskip\hang\noindent
+\.{offset} $x$ $y$. This command overrides the current offset values
+that are added to all coordinates of a character being output; $x$ and
+$y$ are given as scaled \MF\ coordinates. This simply has the effect
+of repositioning the figures on the pages; the title line always appears
+in the same place, but the figure can be moved up, down, left, or right.
+At the beginning of each character the current offsets are zero.
+
+\smallskip\hang\noindent
+\.{xoffset} $x$. This command is output by \MF\ just before shipping out
+a character whose $x$~offset is nonzero. \.{GFtoDVI} adds the specified
+amount to the $x$ coordinates of all dots, labels, and rules
+in the following character.
+
+\smallskip\hang\noindent
+\.{yoffset} $y$. This command is output by \MF\ just before shipping out
+a character whose $y$~offset is nonzero. \.{GFtoDVI} adds the specified
+amount to the $y$ coordinates of all dots, labels, and rules
+in the following character.
+
+@* Font metric data.
+Before we can get into the meaty details of \.{GFtoDVI}, we need to
+deal with yet another esoteric binary file format, since \.{GFtoDVI}
+also does elementary typesetting operations. Therefore it has to
+read important information about the fonts it will be using.
+The following material (again copied almost verbatim from \TeX)
+describes the contents of so-called \TeX\ font metric (\.{TFM}) files.
+
+The idea behind \.{TFM} files is that typesetting routines
+need a compact way to store the relevant information about
+fonts, and computer centers need a compact way to store the
+relevant information about several hundred fonts. \.{TFM} files are
+compact, and most of the information they contain is highly relevant,
+so they provide a solution to the problem. \.{GFtoDVI} uses only
+four fonts, but interesting changes in its output will occur when
+those fonts are varied.
+
+The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
+Since the number of bytes is always a multiple of 4, we could
+also regard the file as a sequence of 32-bit words; but \TeX\ uses the
+byte interpretation, and so does \.{GFtoDVI}. The individual bytes
+are considered to be unsigned numbers.
+
+@ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
+integers that give the lengths of the various subsequent portions
+of the file. These twelve integers are, in order:
+$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
+|@!lf|&length of the entire file, in words;\cr
+|@!lh|&length of the header data, in words;\cr
+|@!bc|&smallest character code in the font;\cr
+|@!ec|&largest character code in the font;\cr
+|@!nw|&number of words in the width table;\cr
+|@!nh|&number of words in the height table;\cr
+|@!nd|&number of words in the depth table;\cr
+|@!ni|&number of words in the italic correction table;\cr
+|@!nl|&number of words in the lig/kern table;\cr
+|@!nk|&number of words in the kern table;\cr
+|@!ne|&number of words in the extensible character table;\cr
+|@!np|&number of font parameter words.\cr}}$$
+They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
+and
+$$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
+Note that a font may contain as many as 256 characters (if |bc=0| and |ec=255|),
+and as few as 0 characters (if |bc=ec+1|). When two or more 8-bit bytes are
+combined to form an integer of 16 or more bits, the bytes appear in
+BigEndian order.
+@^BigEndian order@>
+
+@<Glob...@>=
+@!lf,@!lh,@!bc,@!ec,@!nw,@!nh,@!nd,@!ni,@!nl,@!nk,@!ne,@!np:0..@'77777;
+ {subfile sizes}
+
+@ The rest of the \.{TFM} file may be regarded as a sequence of ten data
+arrays having the informal specification
+$$\def\arr$[#1]#2${\&{array} $[#1]$ \&{of} #2}
+\vbox{\halign{\hfil\\{#}&$\,:\,$\arr#\hfil\cr
+header&|[0..lh-1]@t\\{stuff}@>|\cr
+char\_info&|[bc..ec]char_info_word|\cr
+width&|[0..nw-1]fix_word|\cr
+height&|[0..nh-1]fix_word|\cr
+depth&|[0..nd-1]fix_word|\cr
+italic&|[0..ni-1]fix_word|\cr
+lig\_kern&|[0..nl-1]lig_kern_command|\cr
+kern&|[0..nk-1]fix_word|\cr
+exten&|[0..ne-1]extensible_recipe|\cr
+param&|[1..np]fix_word|\cr}}$$
+The most important data type used here is a |@!fix_word|, which is
+a 32-bit representation of a binary fraction. A |fix_word| is a signed
+quantity, with the two's complement of the entire word used to represent
+negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
+binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
+the smallest is $-2048$. We will see below, however, that all but two of
+the |fix_word| values must lie between $-16$ and $+16$.
+
+@ The first data array is a block of header information, which contains
+general facts about the font. The header must contain at least two words,
+and for \.{TFM} files to be used with Xerox printing software it must
+contain at least 18 words, allocated as described below. When different
+kinds of devices need to be interfaced, it may be necessary to add further
+words to the header block.
+
+\yskip\hang|header[0]| is a 32-bit check sum that \.{GFtoDVI} will copy into the
+\.{DVI} output file whenever it uses the font. Later on when the \.{DVI}
+file is printed, possibly on another computer, the actual font that gets
+used is supposed to have a check sum that agrees with the one in the
+\.{TFM} file used by \.{GFtoDVI}. In this way, users will be warned about
+potential incompatibilities. (However, if the check sum is zero in either
+the font file or the \.{TFM} file, no check is made.) The actual relation
+between this check sum and the rest of the \.{TFM} file is not important;
+the check sum is simply an identification number with the property that
+incompatible fonts almost always have distinct check sums.
+@^check sum@>
+
+\yskip\hang|header[1]| is a |fix_word| containing the design size of the
+font, in units of \TeX\ points (7227 \TeX\ points = 254 cm). This number
+must be at least 1.0; it is fairly arbitrary, but usually the design size
+is 10.0 for a ``10 point'' font, i.e., a font that was designed to look
+best at a 10-point size, whatever that really means. When a \TeX\ user
+asks for a font `\.{at} $\delta$ \.{pt}', the effect is to override the
+design size and replace it by $\delta$, and to multiply the $x$ and~$y$
+coordinates of the points in the font image by a factor of $\delta$
+divided by the design size. Similarly, specific sizes can be substituted
+for the design size by \.{GFtoDVI} commands like `\.{titlefontat}'. {\sl
+All other dimensions in the\/\ \.{TFM} file are |fix_word| numbers in
+design-size units.} Thus, for example, the value of |param[6]|, one \.{em}
+or \.{\\quad}, is often the |fix_word| value $2^{20}=1.0$, since many
+fonts have a design size equal to one em. The other dimensions must be
+less than 16 design-size units in absolute value; thus, |header[1]| and
+|param[1]| are the only |fix_word| entries in the whole \.{TFM} file whose
+first byte might be something besides 0 or 255. @^design size@>@^at size@>
+
+\yskip\hang|header[2..11]|, if present, contains 40 bytes that identify
+the character coding scheme. The first byte, which must be between 0 and
+39, is the number of subsequent ASCII bytes actually relevant in this
+string, which is intended to specify what character-code-to-symbol
+convention is present in the font. Examples are \.{ASCII} for standard
+ASCII, \.{TeX text} for fonts like \.{cmr10} and \.{cmti9}, \.{TeX math
+extension} for \.{cmex10}, \.{XEROX text} for Xerox fonts, \.{GRAPHIC} for
+special-purpose non-alphabetic fonts, \.{GFGRAY} for \.{GFtoDVI}'s
+gray fonts, \.{GFSLANT} for \.{GFtoDVI}'s slant fonts, \.{UNSPECIFIED} for
+the default case when there is no information. Parentheses should not
+appear in this name. (Such a string is said to be in {\mc BCPL} format.)
+@^coding scheme@>@^gray fonts@>@^slant fonts@>
+
+\yskip\hang|header[12..@twhatever@>]| might also be present.
+
+@ Next comes the |char_info| array, which contains one |char_info_word|
+per character. Each |char_info_word| contains six fields packed into
+four bytes as follows.
+
+\yskip\hang first byte: |@!width_index| (8 bits)\par
+\hang second byte: |@!height_index| (4 bits) times 16, plus |@!depth_index|
+ (4~bits)\par
+\hang third byte: |@!italic_index| (6 bits) times 4, plus |@!tag|
+ (2~bits)\par
+\hang fourth byte: |@!remainder| (8 bits)\par
+\yskip\noindent
+The actual width of a character is \\{width}|[width_index]|, in design-size
+units; this is a device for compressing information, since many characters
+have the same width. Since it is quite common for many characters
+to have the same height, depth, or italic correction, the \.{TFM} format
+imposes a limit of 16 different heights, 16 different depths, and
+64 different italic corrections.
+
+Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
+\\{italic}[0]=0$ should always hold, so that an index of zero implies a
+value of zero. The |width_index| should never be zero unless the
+character does not exist in the font, since a character is valid if and
+only if it lies between |bc| and |ec| and has a nonzero |width_index|.
+
+@ The |tag| field in a |char_info_word| has four values that explain how to
+interpret the |remainder| field.
+
+\yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par
+\hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning
+program starting at |lig_kern[remainder]|.\par
+\hang|tag=2| (|list_tag|) means that this character is part of a chain of
+characters of ascending sizes, and not the largest in the chain. The
+|remainder| field gives the character code of the next larger character.\par
+\hang|tag=3| (|ext_tag|) means that this character code represents an
+extensible character, i.e., a character that is built up of smaller pieces
+so that it can be made arbitrarily large. The pieces are specified in
+|@!exten[remainder]|.\par
+
+@d no_tag=0 {vanilla character}
+@d lig_tag=1 {character has a ligature/kerning program}
+@d list_tag=2 {character has a successor in a charlist}
+@d ext_tag=3 {character is extensible}
+
+@ The |lig_kern| array contains instructions in a simple programming language
+that explains what to do for special letter pairs. Each word in this array is a
+|@!lig_kern_command| of four bytes.
+
+\yskip\hang first byte: |skip_byte|, indicates that this is the final program
+ step if the byte is 128 or more, otherwise the next step is obtained by
+ skipping this number of intervening steps.\par
+\hang second byte: |next_char|, ``if |next_char| follows the current character,
+ then perform the operation and stop, otherwise continue.''\par
+\hang third byte: |op_byte|, indicates a ligature step if less than~128,
+ a kern step otherwise.\par
+\hang fourth byte: |remainder|.\par
+\yskip\noindent
+In a kern step, an
+additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
+between the current character and |next_char|. This amount is
+often negative, so that the characters are brought closer together
+by kerning; but it might be positive.
+
+There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
+$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
+|remainder| is inserted between the current character and |next_char|;
+then the current character is deleted if $b=0$, and |next_char| is
+deleted if $c=0$; then we pass over $a$~characters to reach the next
+current character (which may have a ligature/kerning program of its own).
+
+If the very first instruction of the |lig_kern| array has |skip_byte=255|,
+the |next_char| byte is the so-called right boundary character of this font;
+the value of |next_char| need not lie between |bc| and~|ec|.
+If the very last instruction of the |lig_kern| array has |skip_byte=255|,
+there is a special ligature/kerning program for a left boundary character,
+beginning at location |256*op_byte+remainder|.
+The interpretation is that \TeX\ puts implicit boundary characters
+before and after each consecutive string of characters from the same font.
+These implicit characters do not appear in the output, but they can affect
+ligatures and kerning.
+
+If the very first instruction of a character's |lig_kern| program has
+|skip_byte>128|, the program actually begins in location
+|256*op_byte+remainder|. This feature allows access to large |lig_kern|
+arrays, because the first instruction must otherwise
+appear in a location |<=255|.
+
+Any instruction with |skip_byte>128| in the |lig_kern| array must have
+|256*op_byte+remainder<nl|. If such an instruction is encountered during
+normal program execution, it denotes an unconditional halt; no ligature
+or kerning command is performed.
+
+@d stop_flag=128 {value indicating `\.{STOP}' in a lig/kern program}
+@d kern_flag=128 {op code for a kern step}
+
+@ Extensible characters are specified by an |@!extensible_recipe|, which
+consists of four bytes called |@!top|, |@!mid|, |@!bot|, and |@!rep| (in this
+order). These bytes are the character codes of individual pieces used to
+build up a large symbol. If |top|, |mid|, or |bot| are zero, they are not
+present in the built-up result. For example, an extensible vertical line is
+like an extensible bracket, except that the top and bottom pieces are missing.
+
+@ The final portion of a \.{TFM} file is the |param| array, which is another
+sequence of |fix_word| values.
+
+\yskip\hang|param[1]=@!slant| is the amount of italic slant.
+For example, |slant=.25| means that when you go
+up one unit, you also go .25 units to the right. The |slant| is a pure
+number; it's the only |fix_word| other than the design size itself that is
+not scaled by the design size.
+
+\hang|param[2]=space| is the normal spacing between words in text.
+Note that character |" "| in the font need not have anything to do with
+blank spaces.
+
+\hang|param[3]=space_stretch| is the amount of glue stretching between words.
+
+\hang|param[4]=space_shrink| is the amount of glue shrinking between words.
+
+\hang|param[5]=x_height| is the height of letters for which accents don't
+have to be raised or lowered.
+
+\hang|param[6]=quad| is the size of one em in the font.
+
+\hang|param[7]=extra_space| is the amount added to |param[2]| at the
+ends of sentences.
+
+When the character coding scheme is \.{GFGRAY} or \.{GFSLANT}, the font is
+supposed to contain an additional parameter called
+|default_rule_thickness|. Other special parameters go with other coding
+schemes.
+
+@* Input from binary files.
+We have seen that \.{GF} and \.{DVI} and \.{TFM} files are sequences of
+8-bit bytes. The bytes appear physically in what is called a `|packed
+file of 0..255|' in \PASCAL\ lingo.
+
+Packing is system dependent, and many \PASCAL\ systems fail to implement
+such files in a sensible way (at least, from the viewpoint of producing
+good production software). For example, some systems treat all
+byte-oriented files as text, looking for end-of-line marks and such
+things. Therefore some system-dependent code is often needed to deal with
+binary files, even though most of the program in this section of
+\.{GFtoDVI} is written in standard \PASCAL.
+@^system dependencies@>
+
+One common way to solve the problem is to consider files of |integer|
+numbers, and to convert an integer in the range $-2^{31}\L x<2^{31}$ to
+a sequence of four bytes $(a,b,c,d)$ using the following code, which
+avoids the controversial integer division of negative numbers:
+$$\vbox{\halign{#\hfil\cr
+|if x>=0 then a:=x div @'100000000|\cr
+|else begin x:=(x+@'10000000000)+@'10000000000; a:=x div @'100000000+128;|\cr
+\quad|end|;\cr
+|x:=x mod @'100000000;|\cr
+|b:=x div @'200000; x:=x mod @'200000;|\cr
+|c:=x div @'400; d:=x mod @'400;|\cr}}$$
+The four bytes are then kept in a buffer and output one by one. (On 36-bit
+computers, an additional division by 16 is necessary at the beginning.
+Another way to separate an integer into four bytes is to use/abuse
+\PASCAL's variant records, storing an integer and retrieving bytes that are
+packed in the same place; {\sl caveat implementor!\/}) It is also desirable
+in some cases to read a hundred or so integers at a time, maintaining a
+larger buffer.
+
+We shall stick to simple \PASCAL\ in this program, for reasons of clarity,
+even if such simplicity is sometimes unrealistic.
+
+@<Types ...@>=
+@!eight_bits=0..255; {unsigned one-byte quantity}
+@!byte_file=packed file of eight_bits; {files that contain binary data}
+
+@ The program deals with three binary file variables: |gf_file| is the main
+input file that we are converting into a document; |dvi_file| is the main
+output file that will specify that document; and |tfm_file| is
+the current font metric file from which character-width information is
+being read.
+
+@<Glob...@>=
+@!gf_file:byte_file; {the character data we are reading}
+@!dvi_file:byte_file; {the typesetting instructions we are writing}
+@!tfm_file:byte_file; {a font metric file}
+
+@ To prepare these files for input or output, we |reset| or |rewrite|
+them. An extension of \PASCAL\ is needed, since we want to associate
+it with external files whose names are specified dynamically (i.e., not
+known at compile time). The following code assumes that `|reset(f,s)|' and
+`|rewrite(f,s)|' do this, when |f| is a file variable and |s| is a string
+variable that specifies the file name.
+@^system dependencies@>
+
+@p procedure open_gf_file; {prepares to read packed bytes in |gf_file|}
+begin reset(gf_file,name_of_file);
+cur_loc:=0;
+end;
+@#
+procedure open_tfm_file; {prepares to read packed bytes in |tfm_file|}
+begin reset(tfm_file,name_of_file);
+end;
+@#
+procedure open_dvi_file; {prepares to write packed bytes in |dvi_file|}
+begin rewrite(dvi_file,name_of_file);
+end;
+
+@ If you looked carefully at the preceding code, you probably asked,
+``What are |cur_loc| and |name_of_file|?'' Good question. They are global
+variables: The integer |cur_loc| tells which byte of the input file will
+be read next, and the string |name_of_file| will be set to the current
+file name before the file-opening procedures are called.
+
+@<Glob...@>=
+@!cur_loc:integer; {current byte number in |gf_file|}
+@!name_of_file:packed array[1..file_name_size] of char; {external file name}
+
+@ It turns out to be convenient to read four bytes at a time, when we are
+inputting from \.{TFM} files. The input goes into global variables
+|b0|, |b1|, |b2|, and |b3|, with |b0| getting the first byte and |b3|
+the fourth.
+
+@<Glob...@>=
+@!b0,@!b1,@!b2,@!b3: eight_bits; {four bytes input at once}
+
+@ The |read_tfm_word| procedure sets |b0| through |b3| to the next
+four bytes in the current \.{TFM} file.
+@^system dependencies@>
+
+@p procedure read_tfm_word;
+begin read(tfm_file,b0); read(tfm_file,b1);
+read(tfm_file,b2); read(tfm_file,b3);
+end;
+
+@ We shall use another set of simple functions to read the next byte or
+bytes from |gf_file|. There are four possibilities, each of which is
+treated as a separate function in order to minimize the overhead for
+subroutine calls.
+@^system dependencies@>
+
+@p function get_byte:integer; {returns the next byte, unsigned}
+var b:eight_bits;
+begin if eof(gf_file) then get_byte:=0
+else begin read(gf_file,b); incr(cur_loc); get_byte:=b;
+ end;
+end;
+@#
+function get_two_bytes:integer; {returns the next two bytes, unsigned}
+var a,@!b:eight_bits;
+begin read(gf_file,a); read(gf_file,b);
+cur_loc:=cur_loc+2;
+get_two_bytes:=a*256+b;
+end;
+@#
+function get_three_bytes:integer; {returns the next three bytes, unsigned}
+var a,@!b,@!c:eight_bits;
+begin read(gf_file,a); read(gf_file,b); read(gf_file,c);
+cur_loc:=cur_loc+3;
+get_three_bytes:=(a*256+b)*256+c;
+end;
+@#
+function signed_quad:integer; {returns the next four bytes, signed}
+var a,@!b,@!c,@!d:eight_bits;
+begin read(gf_file,a); read(gf_file,b); read(gf_file,c); read(gf_file,d);
+cur_loc:=cur_loc+4;
+if a<128 then signed_quad:=((a*256+b)*256+c)*256+d
+else signed_quad:=(((a-256)*256+b)*256+c)*256+d;
+end;
+
+@* Reading the font information.
+Now let's get down to brass tacks and consider the more substantial
+routines that actually convert \.{TFM} data into a form suitable for
+computation. The routines in this part of the program have been borrowed
+from \TeX, with slight changes, since \.{GFtoDVI} has to do some of the
+things that \TeX\ does.
+
+The \.{TFM} data is stored in a large array called
+|font_info|. Each item of |font_info| is a |memory_word|; the |fix_word|
+data gets converted into |scaled| entries, while everything else goes into
+words of type |four_quarters|. (These data structures are special cases of
+the more general memory words of \TeX. On some machines it is necessary to
+define |min_quarterword=-128| and |max_quarterword=127| in order to pack
+four quarterwords into a single word.)
+@^system dependencies@>
+
+@d min_quarterword=0 {change this to allow efficient packing, if necessary}
+@d max_quarterword=255 {ditto}
+@d qi(#)==#+min_quarterword
+ {to put an |eight_bits| item into a quarterword}
+@d qo(#)==#-min_quarterword
+ {to take an |eight_bits| item out of a quarterword}
+@d title_font=1
+@d label_font=2
+@d gray_font=3
+@d slant_font=4
+@d logo_font=5
+@d non_char==qi(256)
+@d non_address==font_mem_size
+
+@<Types ...@>=
+@!font_index = 0..font_mem_size;
+@!quarterword = min_quarterword..max_quarterword; {1/4 of a word}
+@!four_quarters = packed record@;@/
+ @!b0:quarterword;
+ @!b1:quarterword;
+ @!b2:quarterword;
+ @!b3:quarterword;
+ end;
+@!memory_word = record@;@/
+ case boolean of
+ true: (@!sc:scaled);
+ false: (@!qqqq:four_quarters);
+ end;
+@!internal_font_number=title_font..logo_font;
+
+@ Besides |font_info|, there are also a number of index arrays that point
+into it, so that we can locate width and height information, etc. For
+example, the |char_info| data for character |c| in font |f| will be in
+|font_info[char_base[f]+c].qqqq|; and if |w| is the |width_index| part of
+this word (the |b0| field), the width of the character is
+|font_info[width_base[f]+w].sc|. (These formulas assume that
+|min_quarterword| has already been added to |w|, but not to |c|.)
+
+@<Glob...@>=
+@!font_info:array[font_index] of memory_word; {the font metric data}
+@!fmem_ptr:font_index; {first unused word of |font_info|}
+@!font_check:array[internal_font_number] of four_quarters; {check sum}
+@!font_size:array[internal_font_number] of scaled; {``at'' size}
+@!font_dsize:array[internal_font_number] of scaled; {``design'' size}
+@!font_bc:array[internal_font_number] of eight_bits;
+ {beginning (smallest) character code}
+@!font_ec:array[internal_font_number] of eight_bits;
+ {ending (largest) character code}
+@!char_base:array[internal_font_number] of integer;
+ {base addresses for |char_info|}
+@!width_base:array[internal_font_number] of integer;
+ {base addresses for widths}
+@!height_base:array[internal_font_number] of integer;
+ {base addresses for heights}
+@!depth_base:array[internal_font_number] of integer;
+ {base addresses for depths}
+@!italic_base:array[internal_font_number] of integer;
+ {base addresses for italic corrections}
+@!lig_kern_base:array[internal_font_number] of integer;
+ {base addresses for ligature/kerning programs}
+@!kern_base:array[internal_font_number] of integer;
+ {base addresses for kerns}
+@!exten_base:array[internal_font_number] of integer;
+ {base addresses for extensible recipes}
+@!param_base:array[internal_font_number] of integer;
+ {base addresses for font parameters}
+@!bchar_label:array[internal_font_number] of font_index;
+ {start of |lig_kern| program for left boundary character,
+ |non_address| if there is none}
+@!font_bchar:array[internal_font_number] of min_quarterword..non_char;
+ {right boundary character, |non_char| if there is none}
+
+@ @<Set init...@>=
+fmem_ptr:=0;
+
+@ Of course we want to define macros that suppress the detail of how font
+information is actually packed, so that we don't have to write things like
+$$\hbox{|font_info[width_base[f]+font_info[char_base[f]+c].qqqq.b0].sc|}$$
+too often. The \.{WEB} definitions here make |char_info(f)(c)| the
+|four_quarters| word of font information corresponding to character
+|c| of font |f|. If |q| is such a word, |char_width(f)(q)| will be
+the character's width; hence the long formula above is at least
+abbreviated to
+$$\hbox{|char_width(f)(char_info(f)(c))|.}$$
+In practice we will try to fetch |q| first and look at several of its
+fields at the same time.
+
+The italic correction of a character will be denoted by
+|char_italic(f)(q)|, so it is analogous to |char_width|. But we will get
+at the height and depth in a slightly different way, since we usually want
+to compute both height and depth if we want either one. The value of
+|height_depth(q)| will be the 8-bit quantity
+$$b=|height_index|\times16+|depth_index|,$$ and if |b| is such a byte we
+will write |char_height(f)(b)| and |char_depth(f)(b)| for the height and
+depth of the character |c| for which |q=char_info(f)(c)|. Got that?
+
+The tag field will be called |char_tag(q)|; and the remainder byte will be
+called |rem_byte(q)|.
+
+@d char_info_end(#)==#].qqqq
+@d char_info(#)==font_info[char_base[#]+char_info_end
+@d char_width_end(#)==#.b0].sc
+@d char_width(#)==font_info[width_base[#]+char_width_end
+@d char_exists(#)==(#.b0>min_quarterword)
+@d char_italic_end(#)==(qo(#.b2)) div 4].sc
+@d char_italic(#)==font_info[italic_base[#]+char_italic_end
+@d height_depth(#)==qo(#.b1)
+@d char_height_end(#)==(#) div 16].sc
+@d char_height(#)==font_info[height_base[#]+char_height_end
+@d char_depth_end(#)==# mod 16].sc
+@d char_depth(#)==font_info[depth_base[#]+char_depth_end
+@d char_tag(#)==((qo(#.b2)) mod 4)
+@d skip_byte(#)==qo(#.b0)
+@d next_char(#)==#.b1
+@d op_byte(#)==qo(#.b2)
+@d rem_byte(#)==#.b3
+
+@ Here are some macros that help process ligatures and kerns.
+We write |char_kern(f)(j)| to find the amount of kerning specified by
+kerning command~|j| in font~|f|.
+
+@d lig_kern_start(#)==lig_kern_base[#]+rem_byte {beginning of lig/kern program}
+@d lig_kern_restart_end(#)==256*(op_byte(#))+rem_byte(#)
+@d lig_kern_restart(#)==lig_kern_base[#]+lig_kern_restart_end
+@d char_kern_end(#)==256*(op_byte(#)-128)+rem_byte(#)].sc
+@d char_kern(#)==font_info[kern_base[#]+char_kern_end
+
+@ Font parameters are referred to as |slant(f)|, |space(f)|, etc.
+
+@d param_end(#)==param_base[#]].sc
+@d param(#)==font_info[#+param_end
+@d slant==param(1) {slant to the right, per unit distance upward}
+@d space==param(2) {normal space between words}
+@d x_height==param(5) {one ex}
+@d default_rule_thickness==param(8) {thickness of rules}
+
+@ Here is the subroutine that inputs the information on |tfm_file|, assuming
+that the file has just been reset. Parameter~|f| tells which metric file is
+being read (either |title_font| or |label_font| or |gray_font| or |slant_font|
+or |logo_font|); parameter~|s| is the ``at'' size, which will be
+substituted for the design size if it is positive.
+
+This routine does only limited checking of the validity of the file,
+because another program (\.{TFtoPL}) is available to diagnose errors in
+the rare case that something is amiss.
+
+@d bad_tfm=11 {label for |read_font_info|}
+@d abend==goto bad_tfm {do this when the \.{TFM} data is wrong}
+
+@p procedure read_font_info(@!f:integer;@!s:scaled); {input a \.{TFM} file}
+label done,bad_tfm;
+var k:font_index; {index into |font_info|}
+@!lf,@!lh,@!bc,@!ec,@!nw,@!nh,@!nd,@!ni,@!nl,@!nk,@!ne,@!np:0..65535;
+ {sizes of subfiles}
+@!bch_label:integer; {left boundary label for ligatures}
+@!bchar:0..256; {right boundary character for ligatures}
+@!qw:four_quarters;@!sw:scaled; {accumulators}
+@!z:scaled; {the design size or the ``at'' size}
+@!alpha:integer;@!beta:1..16;
+ {auxiliary quantities used in fixed-point multiplication}
+begin @<Read and check the font data; |abend| if the \.{TFM} file is
+ malformed; otherwise |goto done|@>;
+bad_tfm: print_nl('Bad TFM file for');
+@.Bad TFM file...@>
+case f of
+title_font:abort('titles!');
+label_font:abort('labels!');
+gray_font:abort('pixels!');
+slant_font:abort('slants!');
+logo_font:abort('METAFONT logo!');
+end; {there are no other cases}
+done: {it might be good to close |tfm_file| now}
+end;
+
+@ @<Read and check...@>=
+@<Read the {\.{TFM}} size fields@>;
+@<Use size fields to allocate font information@>;
+@<Read the {\.{TFM}} header@>;
+@<Read character data@>;
+@<Read box dimensions@>;
+@<Read ligature/kern program@>;
+@<Read extensible character recipes@>;
+@<Read font parameters@>;
+@<Make final adjustments and |goto done|@>
+
+@ @d read_two_halves_end(#)==#:=b2*256+b3
+@d read_two_halves(#)==read_tfm_word; #:=b0*256+b1; read_two_halves_end
+
+@<Read the {\.{TFM}} size fields@>=
+begin read_two_halves(lf)(lh);
+read_two_halves(bc)(ec);
+if (bc>ec+1)or(ec>255) then abend;
+if bc>255 then {|bc=256| and |ec=255|}
+ begin bc:=1; ec:=0;
+ end;
+read_two_halves(nw)(nh);
+read_two_halves(nd)(ni);
+read_two_halves(nl)(nk);
+read_two_halves(ne)(np);
+if lf<>6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np then abend;
+end
+
+@ The preliminary settings of the index variables |width_base|,
+|lig_kern_base|, |kern_base|, and |exten_base| will be corrected later by
+subtracting |min_quarterword| from them; and we will subtract 1 from
+|param_base| too. It's best to forget about such anomalies until later.
+
+@<Use size fields to allocate font information@>=
+lf:=lf-6-lh; {|lf| words should be loaded into |font_info|}
+if np<8 then lf:=lf+8-np; {at least eight parameters will appear}
+if fmem_ptr+lf>font_mem_size then abort('No room for TFM file!');
+@.No room for TFM file@>
+char_base[f]:=fmem_ptr-bc;
+width_base[f]:=char_base[f]+ec+1;
+height_base[f]:=width_base[f]+nw;
+depth_base[f]:=height_base[f]+nh;
+italic_base[f]:=depth_base[f]+nd;
+lig_kern_base[f]:=italic_base[f]+ni;
+kern_base[f]:=lig_kern_base[f]+nl;
+exten_base[f]:=kern_base[f]+nk;
+param_base[f]:=exten_base[f]+ne
+
+@ Only the first two words of the header are needed by \.{GFtoDVI}.
+
+@d store_four_quarters(#)==
+ begin read_tfm_word;
+ qw.b0:=qi(b0); qw.b1:=qi(b1); qw.b2:=qi(b2); qw.b3:=qi(b3);
+ #:=qw;
+ end
+
+@<Read the {\.{TFM}} header@>=
+begin if lh<2 then abend;
+store_four_quarters(font_check[f]);
+read_tfm_word;
+if b0>127 then abend; {design size must be positive}
+z:=((b0*256+b1)*256+b2)*16+(b3 div 16);
+if z<unity then abend;
+while lh>2 do
+ begin read_tfm_word; decr(lh); {ignore the rest of the header}
+ end;
+font_dsize[f]:=z;
+if s>0 then z:=s;
+font_size[f]:=z;
+end
+
+@ @<Read character data@>=
+for k:=fmem_ptr to width_base[f]-1 do
+ begin store_four_quarters(font_info[k].qqqq);
+ if (b0>=nw)or(b1 div @'20>=nh)or(b1 mod @'20>=nd)or
+ (b2 div 4>=ni) then abend;
+ case b2 mod 4 of
+ lig_tag: if b3>=nl then abend;
+ ext_tag: if b3>=ne then abend;
+ no_tag,list_tag: do_nothing;
+ end; {there are no other cases}
+ end
+
+@ A |fix_word| whose four bytes are $(b0,b1,b2,b3)$ from left to right
+represents the number
+$$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
+b_1\cdot2^{-4}+b_2\cdot2^{-12}+b_3\cdot2^{-20}&b_0=0;\cr
+-16+b_1\cdot2^{-4}+b_2\cdot2^{-12}+b_3\cdot2^{-20}&b_0=255.\cr}}\right.$$
+(No other choices of |b0| are allowed, since the magnitude of a number in
+design-size units must be less than 16.) We want to multiply this
+quantity by the integer~|z|, which is known to be less than $2^{27}$. Let
+$\alpha=16z$. If $|z|<2^{23}$, the individual multiplications $b\cdot z$,
+$c\cdot z$, $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2,
+4, 8, or 16, to obtain a multiplier less than $2^{23}$, and we can
+compensate for this later. If |z| has thereby been replaced by
+$|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we shall compute
+$$\lfloor(b_1+b_2\cdot2^{-8}+b_3\cdot2^{-16})\,z^\prime/\beta\rfloor$$
+if $a=0$, or the same quantity minus $\alpha$ if $a=255$.
+
+@d store_scaled(#)==begin read_tfm_word;
+ sw:=(((((b3*z)div@'400)+(b2*z))div@'400)+(b1*z))div beta;
+ if b0=0 then #:=sw@+else if b0=255 then #:=sw-alpha@+else abend;
+ end
+
+@<Read box dimensions@>=
+begin @<Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$@>;
+for k:=width_base[f] to lig_kern_base[f]-1 do
+ store_scaled(font_info[k].sc);
+if font_info[width_base[f]].sc<>0 then abend; {\\{width}[0] must be zero}
+if font_info[height_base[f]].sc<>0 then abend; {\\{height}[0] must be zero}
+if font_info[depth_base[f]].sc<>0 then abend; {\\{depth}[0] must be zero}
+if font_info[italic_base[f]].sc<>0 then abend; {\\{italic}[0] must be zero}
+end
+
+@ @<Replace |z|...@>=
+begin alpha:=16*z; beta:=16;
+while z>=@'40000000 do
+ begin z:=z div 2; beta:=beta div 2;
+ end;
+end
+
+@ @d check_byte_range(#)==begin if (#<bc)or(#>ec) then abend@+end
+
+@<Read ligature/kern program@>=
+begin bch_label:=@'77777; bchar:=256;
+if nl>0 then
+ begin for k:=lig_kern_base[f] to kern_base[f]-1 do
+ begin store_four_quarters(font_info[k].qqqq);
+ if b0>stop_flag then
+ begin if 256*b2+b3>=nl then abend;
+ if b0=255 then if k=lig_kern_base[f] then bchar:=b1;
+ end
+ else begin if b1<>bchar then check_byte_range(b1);
+ if b2<kern_flag then check_byte_range(b3)
+ else if 256*(b2-128)+b3>=nk then abend;
+ end;
+ end;
+ if b0=255 then bch_label:=256*b2+b3;
+ end;
+for k:=kern_base[f] to exten_base[f]-1 do
+ store_scaled(font_info[k].sc);
+end
+
+@ @<Read extensible character recipes@>=
+for k:=exten_base[f] to param_base[f]-1 do
+ begin store_four_quarters(font_info[k].qqqq);
+ if b0<>0 then check_byte_range(b0);
+ if b1<>0 then check_byte_range(b1);
+ if b2<>0 then check_byte_range(b2);
+ check_byte_range(b3);
+ end
+
+@ @<Read font parameters@>=
+begin for k:=1 to np do
+ if k=1 then {the |slant| parameter is a pure number}
+ begin read_tfm_word;
+ if b0>127 then sw:=b0-256@+else sw:=b0;
+ sw:=sw*@'400+b1; sw:=sw*@'400+b2;
+ font_info[param_base[f]].sc:=(sw*@'20)+(b3 div@'20);
+ end
+ else store_scaled(font_info[param_base[f]+k-1].sc);
+for k:=np+1 to 8 do font_info[param_base[f]+k-1].sc:=0;
+end
+
+@ Now to wrap it up, we have checked all the necessary things about the \.{TFM}
+file, and all we need to do is put the finishing touches on the data for
+the new font.
+
+@d adjust(#)==#[f]:=qo(#[f])
+ {correct for the excess |min_quarterword| that was added}
+
+@<Make final adjustments...@>=
+font_bc[f]:=bc; font_ec[f]:=ec;
+if bch_label<nl then bchar_label[f]:=bch_label+lig_kern_base[f]
+else bchar_label[f]:=non_address;
+font_bchar[f]:=qi(bchar);
+adjust(width_base); adjust(lig_kern_base);
+adjust(kern_base); adjust(exten_base);
+decr(param_base[f]);
+fmem_ptr:=fmem_ptr+lf; goto done
+
+@* The string pool.
+\.{GFtoDVI} remembers strings by putting them into an array called
+|str_pool|. The |str_start| array tells where each string starts in the pool.
+
+@<Types ...@>=
+@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|}
+@!str_number = 0..max_strings; {for variables that point into |str_start|}
+
+@ As new strings enter, we keep track of the storage currently used, by
+means of two global variables called |pool_ptr| and |str_ptr|. These are
+periodically reset to their initial values when we move from one character
+to another, because most strings are of only temporary interest.
+
+@<Glob...@>=
+@!str_pool:packed array[pool_pointer] of ASCII_code; {the characters}
+@!str_start : array[str_number] of pool_pointer; {the starting pointers}
+@!pool_ptr : pool_pointer; {first unused position in |str_pool|}
+@!str_ptr : str_number; {start of the current string being created}
+@!init_str_ptr:str_number; {|str_ptr| setting when a new character starts}
+
+@ Several of the elementary string operations are performed using \.{WEB}
+macros instead of using \PASCAL\ procedures, because many of the
+operations are done quite frequently and we want to avoid the
+overhead of procedure calls. For example, here is
+a simple macro that computes the length of a string.
+@.WEB@>
+
+@d length(#)==(str_start[#+1]-str_start[#]) {the number of characters
+ in string number \#}
+
+@ Strings are created by appending character codes to |str_pool|.
+The macro called |append_char|, defined here, does not check to see if the
+value of |pool_ptr| has gotten too high; that test is supposed to be
+made before |append_char| is used.
+
+To test if there is room to append |l| more characters to |str_pool|,
+we shall write |str_room(l)|, which aborts \.{GFtoDVI} and gives an
+apologetic error message if there isn't enough room.
+
+@d append_char(#) == {put |ASCII_code| \# at the end of |str_pool|}
+begin str_pool[pool_ptr]:=#; incr(pool_ptr);
+end
+@d str_room(#) == {make sure that the pool hasn't overflowed}
+ begin if pool_ptr+# > pool_size then
+ abort('Too many strings!');
+@.Too many strings@>
+ end
+
+@ Once a sequence of characters has been appended to |str_pool|, it
+officially becomes a string when the function |make_string| is called.
+This function returns the identification number of the new string as its
+value.
+
+@p function make_string : str_number; {current string enters the pool}
+begin if str_ptr=max_strings then
+ abort('Too many labels!');
+@.Too many labels@>
+incr(str_ptr); str_start[str_ptr]:=pool_ptr;
+make_string:=str_ptr-1;
+end;
+
+@ The first strings in the string pool are the keywords that \.{GFtoDVI}
+recognizes in the \\{xxx} commands of a \.{GF} file. They are entered
+into |str_pool| by means of a tedious bunch of assignment statements,
+together with calls on the |first_string| subroutine.
+
+@d init_str0(#)==first_string(#)
+@d init_str1(#)==buffer[1]:=#; init_str0
+@d init_str2(#)==buffer[2]:=#; init_str1
+@d init_str3(#)==buffer[3]:=#; init_str2
+@d init_str4(#)==buffer[4]:=#; init_str3
+@d init_str5(#)==buffer[5]:=#; init_str4
+@d init_str6(#)==buffer[6]:=#; init_str5
+@d init_str7(#)==buffer[7]:=#; init_str6
+@d init_str8(#)==buffer[8]:=#; init_str7
+@d init_str9(#)==buffer[9]:=#; init_str8
+@d init_str10(#)==buffer[10]:=#; init_str9
+@d init_str11(#)==buffer[11]:=#; init_str10
+@d init_str12(#)==buffer[12]:=#; init_str11
+@d init_str13(#)==buffer[13]:=#; init_str12
+@d longest_keyword=13
+
+@p procedure first_string(@!c:integer);
+begin if str_ptr<>c then abort('?'); {internal consistency check}
+@.?@>
+while l>0 do
+ begin append_char(buffer[l]); decr(l);
+ end;
+incr(str_ptr); str_start[str_ptr]:=pool_ptr;
+end;
+
+@ @<Glob...@>=
+@!l:integer; {length of string being made by |first_string|}
+
+@ Here are the tedious assignments just promised.
+String number 0 is the empty string.
+
+@d null_string=0 {the empty keyword}
+@d area_code=4 {add to font code for the `\.{area}' keywords}
+@d at_code=8 {add to font code for the `\.{at}' keywords}
+@d rule_code=13 {code for the keyword `\.{rule}'}
+@d title_code=14 {code for the keyword `\.{title}'}
+@d rule_thickness_code=15 {code for the keyword `\.{rulethickness}'}
+@d offset_code=16 {code for the keyword `\.{offset}'}
+@d x_offset_code=17 {code for the keyword `\.{xoffset}'}
+@d y_offset_code=18 {code for the keyword `\.{yoffset}'}
+@d max_keyword=18 {largest keyword code number}
+
+@<Initialize the strings@>=
+str_ptr:=0; pool_ptr:=0; str_start[0]:=0;@/
+l:=0; init_str0(null_string);@/
+l:=9; init_str9("t")("i")("t")("l")("e")("f")("o")("n")("t")(title_font);@/
+l:=9; init_str9("l")("a")("b")("e")("l")("f")("o")("n")("t")(label_font);@/
+l:=8; init_str8("g")("r")("a")("y")("f")("o")("n")("t")(gray_font);@/
+l:=9; init_str9("s")("l")("a")("n")("t")("f")("o")("n")("t")(slant_font);@/
+l:=13; init_str13("t")("i")("t")("l")("e")
+ ("f")("o")("n")("t")("a")("r")("e")("a")(title_font+area_code);@/
+l:=13; init_str13("l")("a")("b")("e")("l")
+ ("f")("o")("n")("t")("a")("r")("e")("a")(label_font+area_code);@/
+l:=12; init_str12("g")("r")("a")("y")
+ ("f")("o")("n")("t")("a")("r")("e")("a")(gray_font+area_code);@/
+l:=13; init_str13("s")("l")("a")("n")("t")
+ ("f")("o")("n")("t")("a")("r")("e")("a")(slant_font+area_code);@/
+l:=11; init_str11("t")("i")("t")("l")("e")
+ ("f")("o")("n")("t")("a")("t")(title_font+at_code);@/
+l:=11; init_str11("l")("a")("b")("e")("l")
+ ("f")("o")("n")("t")("a")("t")(label_font+at_code);@/
+l:=10; init_str10("g")("r")("a")("y")
+ ("f")("o")("n")("t")("a")("t")(gray_font+at_code);@/
+l:=11; init_str11("s")("l")("a")("n")("t")
+ ("f")("o")("n")("t")("a")("t")(slant_font+at_code);@/
+l:=4; init_str4("r")("u")("l")("e")(rule_code);@/
+l:=5; init_str5("t")("i")("t")("l")("e")(title_code);@/
+l:=13; init_str13("r")("u")("l")("e")
+ ("t")("h")("i")("c")("k")("n")("e")("s")("s")(rule_thickness_code);@/
+l:=6; init_str6("o")("f")("f")("s")("e")("t")(offset_code);@/
+l:=7; init_str7("x")("o")("f")("f")("s")("e")("t")(x_offset_code);@/
+l:=7; init_str7("y")("o")("f")("f")("s")("e")("t")(y_offset_code);@/
+
+@ We will also find it useful to have the following strings. (The names of
+default fonts will presumably be different at different sites.)
+@^system dependencies@>
+@^default fonts@>
+
+@d gf_ext=max_keyword+1 {string number for `\.{.gf}'}
+@d dvi_ext=max_keyword+2 {string number for `\.{.dvi}'}
+@d tfm_ext=max_keyword+3 {string number for `\.{.tfm}'}
+@d page_header=max_keyword+4 {string number for `\.{\ \ Page\ }'}
+@d char_header=max_keyword+5 {string number for `\.{\ \ Character\ }'}
+@d ext_header=max_keyword+6 {string number for `\.{\ \ Ext\ }'}
+@d left_quotes=max_keyword+7 {string number for `\.{\ \ ``}'}
+@d right_quotes=max_keyword+8 {string number for `\.{''}'}
+@d equals_sign=max_keyword+9 {string number for `\.{ = }'}
+@d plus_sign=max_keyword+10 {string number for `\.{ + (}'}
+@d default_title_font=max_keyword+11
+ {string number for the default |title_font|}
+@d default_label_font=max_keyword+12
+ {string number for the default |label_font|}
+@d default_gray_font=max_keyword+13 {string number for the default |gray_font|}
+@d logo_font_name=max_keyword+14 {string number for the font with \MF\ logo}
+@d small_logo=max_keyword+15 {string number for `\.{METAFONT}'}
+@d home_font_area=max_keyword+16 {string number for system-dependent font area}
+
+@<Initialize the strings@>=
+l:=3; init_str3(".")("g")("f")(gf_ext);@/
+l:=4; init_str4(".")("d")("v")("i")(dvi_ext);@/
+l:=4; init_str4(".")("t")("f")("m")(tfm_ext);@/
+l:=7; init_str7(" ")(" ")("P")("a")("g")("e")(" ")(page_header);@/
+l:=12; init_str12(" ")(" ")("C")("h")("a")("r")("a")("c")("t")("e")("r")(" ")
+ (char_header);@/
+l:=6; init_str6(" ")(" ")("E")("x")("t")(" ")(ext_header);@/
+l:=4; init_str4(" ")(" ")("`")("`")(left_quotes);@/
+l:=2; init_str2("'")("'")(right_quotes);@/
+l:=3; init_str3(" ")("=")(" ")(equals_sign);@/
+l:=4; init_str4(" ")("+")(" ")("(")(plus_sign);@/
+l:=4; init_str4("c")("m")("r")("8")(default_title_font);@/
+l:=6; init_str6("c")("m")("t")("t")("1")("0")(default_label_font);@/
+l:=4; init_str4("g")("r")("a")("y")(default_gray_font);@/
+l:=5; init_str5("l")("o")("g")("o")("8")(logo_font_name);@/
+l:=8; init_str8("M")("E")("T")("A")("F")("O")("N")("T")(small_logo);
+
+@ If an \\{xxx} command has just been encountered in the \.{GF} file,
+the following procedure interprets its keyword. More precisely, we assume
+that |cur_gf| contains an op-code byte just read from the \.{GF} file,
+where |xxx1<=cur_gf<=no_op|. The |interpret_xxx| procedure will read the
+rest of the command, in the following way:
+\smallskip
+\item{1)} If |cur_gf| is |no_op| or |yyy|, or if it's an \\{xxx} command with
+an unknown keyword, the bytes are simply read and ignored, and the
+value |no_operation| is returned.
+
+\item{2)} If |cur_gf| is an \\{xxx} command (either |xxx1| or $\cdots$
+or |xxx4|), and if the associated string matches a keyword exactly,
+the string number of that keyword is returned (e.g., |rule_thickness_code|).
+
+\item{3)} If |cur_gf| is an \\{xxx} command whose string begins with
+keyword and space, the string number of that keyword is returned, and
+the remainder of the string is put into the string pool (where it will be
+string number |cur_string|. Exception: If the keyword is |null_string|,
+the character immediately following the blank space is put into the
+global variable |label_type|, and the remaining characters go into the
+string pool.
+
+\smallskip\noindent
+In all cases, |cur_gf| will then be reset to the op-code byte that
+immediately follows the original command.
+
+@d no_operation=max_keyword+1
+
+@<Types ...@>=
+@!keyword_code=null_string..no_operation;
+
+@ @<Glob...@>=
+@!cur_gf:eight_bits; {the byte most recently read from |gf_file|}
+@!cur_string:str_number; {the string following a keyword and space}
+@!label_type:eight_bits; {the character following a null keyword and space}
+
+@ We will be using this procedure when reading the \.{GF} file just
+after the preamble and just after |eoc| commands.
+
+@p function interpret_xxx:keyword_code;
+label done,done1,not_found;
+var @!k:integer; {number of bytes in an \\{xxx} command}
+@!j:integer; {number of bytes read so far}
+@!l:0..longest_keyword; {length of keyword to check}
+@!m:keyword_code; {runs through the list of known keywords}
+@!n1:0..longest_keyword; {buffered character being checked}
+@!n2:pool_pointer; {pool character being checked}
+@!c:keyword_code; {the result to return}
+begin c:=no_operation; cur_string:=null_string;
+case cur_gf of
+no_op:goto done;
+yyy:begin k:=signed_quad; goto done;
+ end;
+xxx1:k:=get_byte;
+xxx2:k:=get_two_bytes;
+xxx3:k:=get_three_bytes;
+xxx4:k:=signed_quad;
+end; {there are no other cases}
+@<Read the next |k| characters of the \.{GF} file;
+ change |c| and |goto done| if a keyword is recognized@>;
+done: cur_gf:=get_byte; interpret_xxx:=c;
+end;
+
+@ @<Read the next |k|...@>=
+j:=0;@+if k<2 then goto not_found;
+loop@+ begin l:=j;
+ if j=k then goto done1;
+ if j=longest_keyword then goto not_found;
+ incr(j); buffer[j]:=get_byte;
+ if buffer[j]=" " then goto done1;
+ end;
+done1:@<If the keyword in |buffer[1..l]| is known, change |c| and |goto done|@>;
+not_found: while j<k do
+ begin incr(j); cur_gf:=get_byte;
+ end
+
+@ @<If the keyword...@>=
+for m:=null_string to max_keyword do if length(m)=l then
+ begin n1:=0; n2:=str_start[m];
+ while (n1<l)and(buffer[n1+1]=str_pool[n2]) do
+ begin incr(n1); incr(n2);
+ end;
+ if n1=l then
+ begin c:=m;
+ if m=null_string then
+ begin incr(j); label_type:=get_byte;
+ end;
+ str_room(k-j);
+ while j<k do
+ begin incr(j); append_char(get_byte);
+ end;
+ cur_string:=make_string; goto done;
+ end;
+ end
+
+@ When an \\{xxx} command takes a numeric argument, |get_yyy| reads
+that argument and puts the following byte into |cur_gf|.
+
+@p function get_yyy:scaled;
+var @!v:scaled; {value just read}
+begin if cur_gf<>yyy then get_yyy:=0
+else begin v:=signed_quad; cur_gf:=get_byte; get_yyy:=v;
+ end;
+end;
+
+@ A simpler method is used for special commands between |boc| and |eoc|,
+since \.{GFtoDVI} doesn't even look at them.
+
+@p procedure skip_nop;
+label done;
+var @!k:integer; {number of bytes in an \\{xxx} command}
+@!j:integer; {number of bytes read so far}
+begin case cur_gf of
+no_op:goto done;
+yyy:begin k:=signed_quad; goto done;
+ end;
+xxx1:k:=get_byte;
+xxx2:k:=get_two_bytes;
+xxx3:k:=get_three_bytes;
+xxx4:k:=signed_quad;
+end; {there are no other cases}
+for j:=1 to k do cur_gf:=get_byte;
+done: cur_gf:=get_byte;
+end;
+
+@* File names.
+It's time now to fret about file names. \.{GFtoDVI} uses the conventions of
+\TeX\ and \MF\ to convert file names into strings that can be used to open
+files. Three routines called |begin_name|, |more_name|, and |end_name| are
+involved, so that the system-dependent parts of file naming conventions are
+isolated from the system-independent ways in which file names are used.
+(See the \TeX\ or \MF\ program listing for further explanation.)
+@^system dependencies@>
+
+@<Glob...@>=
+@!cur_name:str_number; {name of file just scanned}
+@!cur_area:str_number; {file area just scanned, or |null_string|}
+@!cur_ext:str_number; {file extension just scanned, or |null_string|}
+
+@ The file names we shall deal with for illustrative purposes have the
+following structure: If the name contains `\.>' or `\.:', the file area
+consists of all characters up to and including the final such character;
+otherwise the file area is null. If the remaining file name contains
+`\..', the file extension consists of all such characters from the first
+remaining `\..' to the end, otherwise the file extension is null.
+@^system dependencies@>
+
+We can scan such file names easily by using two global variables that keep track
+of the occurrences of area and extension delimiters:
+
+@<Glob...@>=
+@!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any}
+@!ext_delimiter:pool_pointer; {the relevant `\..', if any}
+
+@ Font metric files whose areas are not given
+explicitly are assumed to appear in a standard system area called
+|home_font_area|. This system area name will, of course, vary from place
+to place. The program here sets it to `\.{TeXfonts:}'.
+@^system dependencies@>
+@.TeXfonts@>
+
+@<Initialize the strings@>=
+l:=9; init_str9("T")("e")("X")("f")("o")("n")("t")("s")(":")(home_font_area);@/
+
+@ Here now is the first of the system-dependent routines for file name scanning.
+@^system dependencies@>
+
+@p procedure begin_name;
+begin area_delimiter:=0; ext_delimiter:=0;
+end;
+
+@ And here's the second.
+@^system dependencies@>
+
+@p function more_name(@!c:ASCII_code):boolean;
+begin if c=" " then more_name:=false
+else begin if (c=">")or(c=":") then
+ begin area_delimiter:=pool_ptr; ext_delimiter:=0;
+ end
+ else if (c=".")and(ext_delimiter=0) then ext_delimiter:=pool_ptr;
+ str_room(1); append_char(c); {contribute |c| to the current string}
+ more_name:=true;
+ end;
+end;
+
+@ The third.
+@^system dependencies@>
+
+@p procedure end_name;
+begin if str_ptr+3>max_strings then
+ abort('Too many strings!');
+@.Too many strings@>
+if area_delimiter=0 then cur_area:=null_string
+else begin cur_area:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=area_delimiter+1;
+ end;
+if ext_delimiter=0 then
+ begin cur_ext:=null_string; cur_name:=make_string;
+ end
+else begin cur_name:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=ext_delimiter; cur_ext:=make_string;
+ end;
+end;
+
+@ Another system-dependent routine is needed to convert three strings
+into the |name_of_file| value that is used to open files. The present code
+allows both lowercase and uppercase letters in the file name.
+@^system dependencies@>
+
+@d append_to_name(#)==begin c:=#; incr(k);
+ if k<=file_name_size then name_of_file[k]:=xchr[c];
+ end
+
+@p procedure pack_file_name(@!n,@!a,@!e:str_number);
+var k:integer; {number of positions filled in |name_of_file|}
+@!c: ASCII_code; {character being packed}
+@!j:integer; {index into |str_pool|}
+@!name_length:0..file_name_size; {number of characters packed}
+begin k:=0;
+for j:=str_start[a] to str_start[a+1]-1 do append_to_name(str_pool[j]);
+for j:=str_start[n] to str_start[n+1]-1 do append_to_name(str_pool[j]);
+for j:=str_start[e] to str_start[e+1]-1 do append_to_name(str_pool[j]);
+if k<=file_name_size then name_length:=k@+else name_length:=file_name_size;
+for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
+end;
+
+@ Now let's consider the routines by which \.{GFtoDVI} deals with file names
+in a system-independent manner.
+The global variable |job_name| contains the \.{GF} file name that is
+being input. This name is extended by `\.{dvi}'
+in order to make the name of the output file.
+
+@<Glob...@>=
+@!job_name:str_number; {principal file name}
+
+@ The |start_gf| procedure prompts the user for the name of the generic
+font file to be input. It opens the file, making sure that some input is
+present; then it opens the output file.
+
+Although this routine is system-independent, it should probably be
+modified to take the file name from the command line (without an initial
+prompt), on systems that permit such things.
+
+@p procedure start_gf;
+label found,done;
+begin loop@+begin print_nl('GF file name: '); input_ln;
+@.GF file name@>
+ buf_ptr:=0; buffer[line_length]:="?";
+ while buffer[buf_ptr]=" " do incr(buf_ptr);
+ if buf_ptr<line_length then
+ begin @<Scan the file name in the buffer@>;
+ if cur_ext=null_string then cur_ext:=gf_ext;
+ pack_file_name(cur_name,cur_area,cur_ext); open_gf_file;
+ if not eof(gf_file) then goto found;
+ print_nl('Oops... I can''t find file '); print(name_of_file);
+@.Oops...@>
+@.I can't find...@>
+ end;
+ end;
+found:job_name:=cur_name; pack_file_name(job_name,null_string,dvi_ext);
+open_dvi_file;
+end;
+
+@ @<Scan the file name in the buffer@>=
+if buffer[line_length-1]="/" then
+ begin interaction:=true; decr(line_length);
+ end;
+begin_name;
+loop@+ begin if buf_ptr=line_length then goto done;
+ if not more_name(buffer[buf_ptr]) then goto done;
+ incr(buf_ptr);
+ end;
+done:end_name
+
+@ Special instructions found near the beginning of the \.{GF} file might
+change the names, areas, and ``at'' sizes of the fonts that \.{GFtoDVI}
+will be using. But when we reach the first |boc| instruction, we input
+all of the \.{TFM} files. The global variable |interaction| is set |true|
+if a |"/"| was removed at the end of the file name; this means that the
+user will have a chance to issue special instructions online just before
+the fonts are loaded.
+
+@d check_fonts==@+if fonts_not_loaded then load_fonts
+
+@<Glob...@>=
+@!interaction:boolean; {is the user allowed to type specials online?}
+@!fonts_not_loaded:boolean; {have the \.{TFM} files still not been input?}
+@!font_name:array[internal_font_number] of str_number; {current font names}
+@!font_area:array[internal_font_number] of str_number; {current font areas}
+@!font_at:array[internal_font_number] of scaled; {current font ``at'' sizes}
+
+@ @<Set init...@>=
+interaction:=false; fonts_not_loaded:=true;
+font_name[title_font]:=default_title_font;
+font_name[label_font]:=default_label_font;
+font_name[gray_font]:=default_gray_font;
+font_name[slant_font]:=null_string;
+font_name[logo_font]:=logo_font_name;
+for k:=title_font to logo_font do
+ begin font_area[k]:=null_string; font_at[k]:=0;
+ end;
+
+@ After the following procedure has been performed, there will be no
+turning back; the fonts will have been firmly established in
+\.{GFtoDVI}'s memory.
+
+@<Declare the procedure called |load_fonts|@>=
+procedure load_fonts;
+label done,continue,found,not_found;
+var @!f:internal_font_number;
+@!i:four_quarters; {font information word}
+@!j,@!k,@!v:integer; {registers for initializing font tables}
+@!m:title_font..slant_font+area_code; {keyword found}
+@!n1:0..longest_keyword; {buffered character being checked}
+@!n2:pool_pointer; {pool character being checked}
+begin if interaction then @<Get online special input@>;
+fonts_not_loaded:=false;
+for f:=title_font to logo_font do
+ if (f<>slant_font)or(length(font_name[f])>0) then
+ begin if length(font_area[f])=0 then font_area[f]:=home_font_area;
+ pack_file_name(font_name[f],font_area[f],tfm_ext);
+ open_tfm_file; read_font_info(f,font_at[f]);
+ if font_area[f]=home_font_area then font_area[f]:=null_string;
+ dvi_font_def(f); {put the font name in the \.{DVI} file}
+ end;
+@<Initialize global variables that depend on the font data@>;
+end;
+
+@ @<Get online special input@>=
+loop@+ begin not_found: print_nl('Special font substitution: ');
+@.Special font subst...@>
+ continue: input_ln;
+ if line_length=0 then goto done;
+ @<Search buffer for valid keyword; if successful, |goto found|@>;
+ print('Please say, e.g., "grayfont foo" or "slantfontarea baz".');
+ goto not_found;
+ found: @<Update the font name or area@>;
+ print('OK; any more? '); goto continue;
+ end;
+done:
+
+@ @<Search buffer for valid keyword; if successful, |goto found|@>=
+buf_ptr:=0; buffer[line_length]:=" ";
+while buffer[buf_ptr]<>" " do incr(buf_ptr);
+for m:=title_font to slant_font+area_code do if length(m)=buf_ptr then
+ begin n1:=0; n2:=str_start[m];
+ while (n1<buf_ptr)and(buffer[n1]=str_pool[n2]) do
+ begin incr(n1); incr(n2);
+ end;
+ if n1=buf_ptr then goto found;
+ end
+
+@ @<Update the font name or area@>=
+incr(buf_ptr); str_room(line_length-buf_ptr);
+while buf_ptr<line_length do
+ begin append_char(buffer[buf_ptr]); incr(buf_ptr);
+ end;
+if m>area_code then font_area[m-area_code]:=make_string
+else begin font_name[m]:=make_string; font_area[m]:=null_string;
+ font_at[m]:=0;
+ end;
+init_str_ptr:=str_ptr
+
+@* Shipping pages out.
+The following routines are used to write the \.{DVI} file. They have
+been copied from \TeX, but simplified; we don't have to handle
+nearly as much generality as \TeX\ does.
+
+Statistics about the entire set of pages that will be shipped out must be
+reported in the \.{DVI} postamble. The global variables |total_pages|,
+|max_v|, |max_h|, and |last_bop| are used to record this information.
+
+@<Glob...@>=
+@!total_pages:integer; {the number of pages that have been shipped out}
+@!max_v:scaled; {maximum height-plus-depth of pages shipped so far}
+@!max_h:scaled; {maximum width of pages shipped so far}
+@!last_bop:integer; {location of previous |bop| in the \.{DVI} output}
+
+@ @<Set init...@>=
+total_pages:=0; max_v:=0; max_h:=0; last_bop:=-1;
+
+@ The \.{DVI} bytes are output to a buffer instead of being written directly
+to the output file. This makes it possible to reduce the overhead of
+subroutine calls.
+
+The output buffer is divided into two parts of equal size; the bytes found
+in |dvi_buf[0..half_buf-1]| constitute the first half, and those in
+|dvi_buf[half_buf..dvi_buf_size-1]| constitute the second. The global
+variable |dvi_ptr| points to the position that will receive the next
+output byte. When |dvi_ptr| reaches |dvi_limit|, which is always equal
+to one of the two values |half_buf| or |dvi_buf_size|, the half buffer that
+is about to be invaded next is sent to the output and |dvi_limit| is
+changed to its other value. Thus, there is always at least a half buffer's
+worth of information present, except at the very beginning of the job.
+
+Bytes of the \.{DVI} file are numbered sequentially starting with 0;
+the next byte to be generated will be number |dvi_offset+dvi_ptr|.
+
+@<Types ...@>=
+@!dvi_index=0..dvi_buf_size; {an index into the output buffer}
+
+@ Some systems may find it more efficient to make |dvi_buf| a |packed|
+array, since output of four bytes at once may be facilitated.
+@^system dependencies@>
+
+@<Glob...@>=
+@!dvi_buf:array[dvi_index] of eight_bits; {buffer for \.{DVI} output}
+@!half_buf:dvi_index; {half of |dvi_buf_size|}
+@!dvi_limit:dvi_index; {end of the current half buffer}
+@!dvi_ptr:dvi_index; {the next available buffer address}
+@!dvi_offset:integer; {|dvi_buf_size| times the number of times the
+ output buffer has been fully emptied}
+
+@ Initially the buffer is all in one piece; we will output half of it only
+after it first fills up.
+
+@<Set init...@>=
+half_buf:=dvi_buf_size div 2; dvi_limit:=dvi_buf_size; dvi_ptr:=0;
+dvi_offset:=0;
+
+@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
+|write_dvi(a,b)|. It is safe to assume that |a| and |b+1| will both be
+multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on
+many machines to use efficient methods to pack four bytes per word and to
+output an array of words with one system call.
+@^system dependencies@>
+
+@p procedure write_dvi(@!a,@!b:dvi_index);
+var k:dvi_index;
+begin for k:=a to b do write(dvi_file,dvi_buf[k]);
+end;
+
+@ To put a byte in the buffer without paying the cost of invoking a procedure
+each time, we use the macro |dvi_out|.
+
+@d dvi_out(#)==@+begin dvi_buf[dvi_ptr]:=#; incr(dvi_ptr);
+ if dvi_ptr=dvi_limit then dvi_swap;
+ end
+
+@p procedure dvi_swap; {outputs half of the buffer}
+begin if dvi_limit=dvi_buf_size then
+ begin write_dvi(0,half_buf-1); dvi_limit:=half_buf;
+ dvi_offset:=dvi_offset+dvi_buf_size; dvi_ptr:=0;
+ end
+else begin write_dvi(half_buf,dvi_buf_size-1); dvi_limit:=dvi_buf_size;
+ end;
+end;
+
+@ Here is how we clean out the buffer when \TeX\ is all through; |dvi_ptr|
+will be a multiple of~4.
+
+@<Empty the last bytes out of |dvi_buf|@>=
+if dvi_limit=half_buf then write_dvi(half_buf,dvi_buf_size-1);
+if dvi_ptr>0 then write_dvi(0,dvi_ptr-1)
+
+@ The |dvi_four| procedure outputs four bytes in two's complement notation,
+without risking arithmetic overflow.
+
+@p procedure dvi_four(@!x:integer);
+begin if x>=0 then dvi_out(x div @'100000000)
+else begin x:=x+@'10000000000;
+ x:=x+@'10000000000;
+ dvi_out((x div @'100000000) + 128);
+ end;
+x:=x mod @'100000000; dvi_out(x div @'200000);
+x:=x mod @'200000; dvi_out(x div @'400);
+dvi_out(x mod @'400);
+end;
+
+@ Here's a procedure that outputs a font definition.
+
+@d select_font(#)==dvi_out(fnt_num_0+#) {set current font to \#}
+
+@p procedure dvi_font_def(@!f:internal_font_number);
+var k:integer; {index into |str_pool|}
+begin dvi_out(fnt_def1);
+dvi_out(f);@/
+dvi_out(qo(font_check[f].b0));
+dvi_out(qo(font_check[f].b1));
+dvi_out(qo(font_check[f].b2));
+dvi_out(qo(font_check[f].b3));@/
+dvi_four(font_size[f]);
+dvi_four(font_dsize[f]);@/
+dvi_out(length(font_area[f]));
+dvi_out(length(font_name[f]));
+@<Output the font name whose internal number is |f|@>;
+end;@/
+@t\4@>@<Declare the procedure called |load_fonts|@>@;
+
+@ @<Output the font name whose internal number is |f|@>=
+for k:=str_start[font_area[f]] to str_start[font_area[f]+1]-1 do
+ dvi_out(str_pool[k]);
+for k:=str_start[font_name[f]] to str_start[font_name[f]+1]-1 do
+ dvi_out(str_pool[k])
+
+@ The |typeset| subroutine typesets any eight-bit character.
+
+@p procedure typeset(@!c:eight_bits);
+begin if c>=128 then dvi_out(set1);
+dvi_out(c);
+end;
+
+@ The |dvi_scaled| subroutine takes a |real| value |x| and outputs
+a decimal approximation to |x/unity|, correct to one decimal place.
+
+@p procedure dvi_scaled(@!x:real);
+var @!n:integer; {an integer approximation to |10*x/unity|}
+@!m:integer; {the integer part of the answer}
+@!k:integer; {the number of digits in |m|}
+begin n:=round(x/6553.6);
+if n<0 then
+ begin dvi_out("-"); n:=-n;
+ end;
+m:=n div 10; k:=0;
+repeat incr(k); buffer[k]:=(m mod 10)+"0"; m:=m div 10;
+until m=0;
+repeat dvi_out(buffer[k]); decr(k);
+until k=0;
+if n mod 10 <> 0 then
+ begin dvi_out("."); dvi_out((n mod 10)+"0");
+ end;
+end;
+
+@ At the end of the program, we must finish things off by writing the
+post\-amble. An integer variable~|k| will be declared for use by this routine.
+
+@<Finish the \.{DVI} file and |goto final_end|@>=
+begin dvi_out(post); {beginning of the postamble}
+dvi_four(last_bop); last_bop:=dvi_offset+dvi_ptr-5; {|post| location}
+dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp}
+dvi_four(1000); {magnification factor}
+dvi_four(max_v); dvi_four(max_h);@/
+dvi_out(0); dvi_out(3); {`\\{max\_push}' is said to be 3}@/
+dvi_out(total_pages div 256); dvi_out(total_pages mod 256);@/
+if not fonts_not_loaded then
+ for k:=title_font to logo_font do
+ if length(font_name[k])>0 then dvi_font_def(k);
+dvi_out(post_post); dvi_four(last_bop); dvi_out(dvi_id_byte);@/
+k:=4+((dvi_buf_size-dvi_ptr) mod 4); {the number of 223's}
+while k>0 do
+ begin dvi_out(223); decr(k);
+ end;
+@<Empty the last bytes out of |dvi_buf|@>;
+goto final_end;
+end
+
+@* Rudimentary typesetting.
+One of \.{GFtoDVI}'s little duties is to be a mini-\TeX: It must be able
+to typeset the equivalent of `\.{\\hbox\{}$\langle$string$\rangle$\.\}' for
+a given string of ASCII characters, using either the title font or the
+label font.
+
+The |hbox| procedure does this. The width, height, and depth of the
+box defined by string~|s| in font~|f| are computed in global variables
+|box_width|, |box_height|, and |box_depth|.
+
+The task would be trivial if it weren't for ligatures and kerns, which
+are implemented here in full generality. (Infinite looping is possible
+if the \.{TFM} file is malformed; \.{TFtoPL} will diagnose such problems.)
+
+We assume that |" "| is a space character; character code @'40 will not
+be typeset unless it is accessed via a ligature.
+
+If parameter |send_it| is |false|, we merely want to know the box dimensions.
+Otherwise typesetting commands are also sent to
+the \.{DVI} file; we assume in this case that font |f| has already been
+selected in the \.{DVI} file as the current font.
+
+@d set_cur_r==if k<end_k then cur_r:=qi(str_pool[k])
+ else cur_r:=bchar
+
+@p procedure hbox(@!s:str_number;@!f:internal_font_number;@!send_it:boolean);
+label continue, done;
+var @!k,@!end_k,@!max_k:pool_pointer; {indices into |str_pool|}
+@!i,@!j:four_quarters; {font information words}
+@!cur_l:0..256; {character to the left of the ``cursor''}
+@!cur_r:min_quarterword..non_char; {character to the right of the ``cursor''}
+@!bchar:min_quarterword..non_char; {right boundary character}
+@!stack_ptr:0..lig_lookahead; {number of entries on |lig_stack|}
+@!l:font_index; {pointer to lig/kern instruction}
+@!kern_amount:scaled; {extra space to be typeset}
+@!hd:eight_bits; {height and depth indices for a character}
+@!x:scaled; {temporary register}
+@!save_c:ASCII_code; {character temporarily blanked out}
+begin box_width:=0; box_height:=0; box_depth:=0;@/
+k:=str_start[s]; max_k:=str_start[s+1];
+save_c:=str_pool[max_k]; str_pool[max_k]:=" ";
+while k<max_k do
+ begin if str_pool[k]=" " then @<Typeset a space in font |f| and advance~|k|@>
+ else begin end_k:=k;
+ repeat incr(end_k); until str_pool[end_k]=" ";
+ kern_amount:=0; cur_l:=256; stack_ptr:=0; bchar:=font_bchar[f];
+ set_cur_r; suppress_lig:=false;
+continue: @<If there's a ligature or kern at the cursor position,
+ update the cursor data structures, possibly advancing~|k|; continue
+ until the cursor wants to move right@>;
+ @<Typeset character |cur_l|, if it exists in the font;
+ also append an optional kern@>;
+ @<Move the cursor to the right and |goto continue|, if there's
+ more work to do in the current word@>;
+ end; {now |k=end_k|}
+ end;
+str_pool[max_k]:=save_c;
+end;
+
+@ @<Glob...@>=
+@!box_width:scaled; {width of box constructed by |hbox|}
+@!box_height:scaled; {height of box constructed by |hbox|}
+@!box_depth:scaled; {depth of box constructed by |hbox|}
+@!lig_stack:array[1..lig_lookahead] of quarterword; {inserted ligature chars}
+@!dummy_info:four_quarters; {fake |char_info| for nonexistent character}
+@!suppress_lig:boolean; {should we bypass checking for ligatures next time?}
+
+@ @<Set init...@>=
+dummy_info.b0:=qi(0); dummy_info.b1:=qi(0); dummy_info.b2:=qi(0);
+dummy_info.b3:=qi(0);
+
+@ @<Typeset a space...@>=
+begin box_width:=box_width+space(f);
+if send_it then
+ begin dvi_out(right4); dvi_four(space(f));
+ end;
+incr(k);
+end
+
+@ @<If there's a ligature...@>=
+if(cur_l<font_bc[f])or(cur_l>font_ec[f]) then
+ begin i:=dummy_info;
+ if cur_l=256 then l:=bchar_label[f]@+else l:=non_address;
+ end
+else begin i:=char_info(f)(cur_l);
+ if char_tag(i)<>lig_tag then l:=non_address
+ else begin l:=lig_kern_start(f)(i); j:=font_info[l].qqqq;
+ if skip_byte(j)>stop_flag then l:=lig_kern_restart(f)(j);
+ end;
+ end;
+if suppress_lig then suppress_lig:=false
+else while l<qi(kern_base[f]) do
+ begin j:=font_info[l].qqqq;
+ if next_char(j)=cur_r then if skip_byte(j)<=stop_flag then
+ if op_byte(j)>=kern_flag then
+ begin kern_amount:=char_kern(f)(j); goto done;
+ end
+ else @<Carry out a ligature operation, updating the cursor structure
+ and possibly advancing~|k|; |goto continue| if the cursor doesn't
+ advance, otherwise |goto done|@>;
+ if skip_byte(j)>=stop_flag then goto done;
+ l:=l+skip_byte(j)+1;
+ end;
+done:
+
+@ At this point |i| contains |char_info| for |cur_l|.
+
+@<Typeset character...@>=
+if char_exists(i) then
+ begin box_width:=box_width+char_width(f)(i)+kern_amount;@/
+ hd:=height_depth(i);
+ x:=char_height(f)(hd);
+ if x>box_height then box_height:=x;
+ x:=char_depth(f)(hd);
+ if x>box_depth then box_depth:=x;
+ if send_it then
+ begin typeset(cur_l);
+ if kern_amount<>0 then
+ begin dvi_out(right4); dvi_four(kern_amount);
+ end;
+ end;
+ kern_amount:=0;
+ end
+
+@ @d pop_stack==begin decr(stack_ptr);
+ if stack_ptr>0 then cur_r:=lig_stack[stack_ptr]
+ else set_cur_r;
+ end
+
+@<Carry out a ligature operation, updating the cursor structure...@>=
+begin case op_byte(j) of
+1,5:cur_l:=qo(rem_byte(j));
+2,6:begin cur_r:=rem_byte(j);
+ if stack_ptr=0 then
+ begin stack_ptr:=1;
+ if k<end_k then incr(k) {a non-space character is consumed}
+ else bchar:=non_char; {the right boundary character is consumed}
+ end;
+ lig_stack[stack_ptr]:=cur_r;
+ end;
+3,7,11:begin cur_r:=rem_byte(j); incr(stack_ptr); lig_stack[stack_ptr]:=cur_r;
+ if op_byte(j)=11 then suppress_lig:=true;
+ end;
+othercases begin cur_l:=qo(rem_byte(j));
+ if stack_ptr>0 then pop_stack
+ else if k=end_k then goto done
+ else begin incr(k); set_cur_r;
+ end;
+ end
+endcases;
+if op_byte(j)>3 then goto done;
+goto continue;
+end
+
+@ @<Move the cursor to the right and |goto continue|...@>=
+cur_l:=qo(cur_r);
+if stack_ptr>0 then
+ begin pop_stack; goto continue;
+ end;
+if k<end_k then
+ begin incr(k); set_cur_r; goto continue;
+ end
+
+@* Gray fonts.
+A proof diagram constructed by \.{GFtoDVI}
+can be regarded as an array of rectangles, where each rectangle is either
+blank or filled with a special symbol that we shall call $x$. A blank
+rectangle represents a white pixel, while $x$ represents a black pixel.
+Additional labels and reference lines are often superimposed on this
+array of rectangles; hence it is usually best to choose a symbol $x$ that
+has a somewhat gray appearance, although any symbol can actually be used.
+
+In order to construct such proofs, \.{GFtoDVI} needs to work with
+a special type of font known as a ``gray font''; it's possible to
+obtain a wide variety of different sorts of proofs by using different
+sorts of gray fonts. The next few paragraphs explain exactly what gray
+fonts are supposed to contain, in case you want to design your own.
+@^gray fonts@>
+
+@ The simplest gray font contains only two characters, namely $x$
+and another symbol that is used for dots that identify key points.
+If proofs with relatively large pixels are desired, a two-character
+gray font is all that's needed. However, if the pixel size is to be
+relatively small, practical considerations make a two-character
+font too inefficient, since it requires the typesetting of tens
+of thousands of tiny little characters; printing device drivers
+rarely work very well when they are presented with data that is
+so different from ordinary text. Therefore a gray font with small
+pixels usually has a number of characters that replicate $x$ in
+such a way that comparatively few characters actually need to be
+typeset.
+
+Since many printing devices are not able to cope with
+arbitrarily large or complex characters, it is not possible for a
+single gray font to work well on all machines. In fact,
+$x$ must have a width that is an integer multiple of the printing
+device's unit of horizontal position, since rounding the positions of grey
+characters would otherwise produce unsightly streaks on proof output.
+Thus, there is no way to make the gray font as device-independent as
+the rest of the system, in the sense that we would expect approximately
+identical output on machines with different resolution. Fortunately,
+proof sheets are rarely considered to be final documents; hence
+\.{GFtoDVI} is set up to provide results that adapt suitably to
+local conditions.
+
+@ With such constraints understood, we can now take a look at what
+\.{GFtoDVI} expects to see in a gray font. The character~$x$ always
+appears in position~1. It must have positive height~$h$ and positive
+width~$w$; its depth and italic correction are ignored.
+
+Positions 2--120 of a gray font are reserved for special combinations
+of $x$'s and blanks, stacked on top of each other. None of these character
+codes need be present in the font; but if they are, the slots should be
+occupied by characters of width~$w$ that have certain configurations of
+$x$'s and blanks, prescribed for each character position. For example,
+position~3 of the font should either contain no character at all,
+or it should contain a character consisting of two $x$'s, one above
+the other; one of these $x$'s should appear immediately above the
+baseline, and the other should appear immediately below.
+
+It will be convenient to use a horizontal notation like `\.{XOXXO}'
+to stand for a vertical stack of $x$'s and blanks. The convention
+will be that the stack is built from bottom to top, and the topmost
+rectangle should sit on the baseline. Thus, `\.{XOXXO}' stands
+actually for a character of depth~$4h$ that looks like this:
+$$\vcenter{\halign{\hfil#\hfil\cr
+blank\cr
+$x$\rlap{\qquad\raise8pt\hbox{\smash{\hbox{$\longleftarrow$ baseline}}}}\cr
+$x$\cr
+blank\cr
+$x$\cr
+}}$$
+(We use a horizontal notation instead of a vertical one in this explanation,
+because column
+vectors take too much space, and because the horizontal notation corresponds
+to binary numbers in a convenient way.)
+
+Positions 1--63 of a gray font are reserved for the patterns \.X, \.{XO},
+\.{XX}, \.{XOO}, \.{XOX}, \dots, \.{XXXXXX}, just as in the normal
+binary notation of the numbers 1--63. Positions 64--70 are reserved for
+the special patterns \.{XOOOOOO}, \.{XXOOOOO}, \dots, \.{XXXXXXO},
+\.{XXXXXXX} of length seven; positions 71--78 are, similarly, reserved for
+the length-eight patterns \.{XOOOOOOO} through \.{XXXXXXXX}. The
+length-nine patterns \.{XOOOOOOOO} through \.{XXXXXXXXX} are assigned
+to positions 79--87, the length-ten patterns to positions 88--97,
+the length-eleven patterns to positions 98--108, and the length-twelve
+patterns to positions 109--120.
+
+The following program sets a global array |c[1..120]| to the bit patterns
+just described. Another array |d[1..120]| is set to contain only the next
+higher bit; this determines the depth of the corresponding character.
+
+@<Set init...@>=
+c[1]:=1; d[1]:=2; two_to_the[0]:=1; m:=1;
+for k:=1 to 13 do two_to_the[k]:=2*two_to_the[k-1];
+for k:=2 to 6 do @<Add a full set of |k|-bit characters@>;
+for k:=7 to 12 do @<Add special |k|-bit characters of the form \.{X..XO..O}@>;
+
+@ @<Glob...@>=
+@!c:array[1..120] of 1..4095; {bit patterns for a gray font}
+@!d:array[1..120] of 2..4096; {the superleading bits}
+@!two_to_the:array[0..13] of 1..8192; {powers of 2}
+
+@ @<Add a full set of |k|-bit...@>=
+begin n:=two_to_the[k-1];
+for j:=0 to n-1 do
+ begin incr(m); c[m]:=m; d[m]:=n+n;
+ end;
+end
+
+@ @<Add special |k|-bit...@>=
+begin n:=two_to_the[k-1];
+for j:=k downto 1 do
+ begin incr(m); d[m]:=n+n;
+ if j=k then c[m]:=n
+ else c[m]:=c[m-1]+two_to_the[j-1];
+ end;
+end
+
+@ Position 0 of a gray font is reserved for the ``dot'' character, which
+should have positive height~$h'$ and positive width~$w'$. When \.{GFtoDVI}
+wants to put a dot at some place $(x,y)$ on the figure, it positions
+the dot character so that its reference point is at $(x,y)$. The
+dot will be considered to occupy a rectangle $(x+\delta,y+\epsilon)$
+for $-w'\leq\delta\leq w'$ and $-h'\leq\epsilon\leq h'$; the rectangular
+box for a label will butt up against the rectangle enclosing the dot.
+
+@ All other character positions of a gray font (namely, positions 121--255)
+are unreserved, in the sense that they have no predefined meaning.
+But \.{GFtoDVI} may access them via the ``character list'' feature of
+\.{TFM} files, starting with any of the characters in positions
+1--120. In such a case each succeeding character in a list should be
+equivalent to two of its predecessors, horizontally adjacent to each other.
+For example, in a character list like
+$$53,\;121,\;122,\;123$$
+character 121 will stand for two 53's, character 122 for two 121's (i.e.,
+four 53's), and character 123 for two 122's (i.e., eight 53's). Since
+position~53 contains the pattern \.{XXOXOX}, character~123 in this example
+would have height~$h$, depth~$5h$, and width~$8w$, and it would stand for
+the pattern
+$$\vcenter{\halign{&$\hfil#\hfil$\cr
+x&x&x&x&x&x&x&x\cr
+&&&&&&&\cr
+x&x&x&x&x&x&x&x\cr
+&&&&&&&\cr
+x&x&x&x&x&x&x&x\cr
+x&x&x&x&x&x&x&x\cr}}$$
+Such a pattern is, of course, rather unlikely to occur in a \.{GF} file,
+but \.{GFtoDVI} would be able to use if it were present. Designers
+of gray fonts should provide characters only for patterns that they think
+will occur often enough to make the doubling worthwhile. For example,
+the character in position 120 (\.{XXXXXXXXXXXX}), or whatever is the
+tallest stack of $x$'s present in the font, is a natural candidate for
+repeated doubling.
+
+Here's how \.{GFtoDVI} decides what characters of the gray font will be used,
+given a configuration of black and white pixels: If there are no black
+pixels, stop. Otherwise look at the top row that contains at least one
+black pixel, and the eleven rows that follow. For each such column,
+find the largest~$k$ such that $1\leq k\leq120$ and the gray font contains
+character~$k$ and the pattern assigned to position~$k$ appears in the
+given column. Typeset character $k$ (unless no such character exists)
+and erase the corresponding black pixels; use doubled characters,
+if they are present in the gray font, if two or more consecutive equal
+characters need to be typeset. Repeat the same process on the remaining
+configuration, until all the black pixels have been erased.
+
+If all characters in positions 1--120 are present, this process is guaranteed to
+take care of at least six rows each time; and it usually takes care of
+twelve, since all patterns that contain at most one ``run'' of $x$'s
+are present.
+
+@ Fonts have optional parameters, as described in Appendix~F of {\sl The
+\TeX book}, and some of these are important in gray fonts. The
+slant parameter~$s$, if nonzero, will cause \.{GFtoDVI} to skew its
+output; in this case the character $x$ will presumably be a parallelogram
+with a corresponding slant, rather than the usual rectangle. \MF's
+coordinate $(x,y)$ will appear in physical position $(xw+yhs,yh)$
+on the proofsheets.
+
+Parameter number~8 of a gray font specifies the thickness of rules
+that go on the proofs. If this parameter is zero, \TeX's default
+rule thickness (0.4\thinspace pt) will be used.
+
+The other parameters of a gray font are ignored by \.{GFtoDVI}, but
+it is conventional to set the font space parameter to~$w$ and the
+xheight parameter to~$h$.
+
+@ For best results the designer of a gray font should choose $h$ and~$w$
+so that the user's \.{DVI}-to-hardcopy software will not make any
+rounding errors. Furthermore, the dot should be an even number~$2m$ of
+pixels in diameter, and the rule thickness should work out to an
+even number~$2n$ of pixels; then the dots and rules will be centered on
+the correct positions, in case of integer coordinates. Gray fonts
+are almost always intended for particular output devices, even though
+`\.{DVI}' stands for `device independent'; we use \.{DVI} files for \MF\
+proofs chiefly because software to print \.{DVI} files is already in place.
+
+@* Slant fonts.
+\.{GFtoDVI} also makes use of another special type of font, if it is
+necessary to typeset slanted rules. The format of such so-called
+``slant fonts'' is quite a bit simpler than the format of gray fonts.
+
+A slant font should contain exactly $n$ characters, in positions 1 to~$n$,
+where the character in position~$k$ represents a slanted line $k$ units
+tall, starting at the baseline. These lines all have a fixed slant ratio~$s$.
+
+The following simple algorithm is used to typeset a rule that is $m$ units
+high: Compute $q=\lceil m/n\rceil$; then typeset $q$~characters of
+approximately equal size, namely $(m\bmod q)$ copies of character number
+$\lceil m/q\rceil$ and $q-(m\bmod q)$ copies of character number
+$\lfloor m/q\rfloor$. For example, if $n=15$ and $m=100$, we have $q=7$;
+a 100-unit-high rule will be composed of 7~pieces, using characters
+14,~14, 14, 14, 14, 15,~15.
+
+@<Glob...@>=
+@!rule_slant:real; {the slant ratio $s$ in the slant font,
+ or zero if there is no slant font}
+@!slant_n:integer; {the number of characters in the slant font}
+@!slant_unit:real; {the number of scaled points in the slant font unit}
+@!slant_reported:real; {invalid slant ratio reported to the user}
+
+@ \.{GFtoDVI} looks only at the height of character $n$, so the \.{TFM} file
+need not be accurate about the heights of the other characters. (This is
+fortunate, since \.{TFM} format allows at most 16 different heights per font.)
+
+The width of character~$k$ should be $k/n$ times $s$ times the height of
+character~$n$.
+
+The slant parameter of a slant file should be $s$. It is customary to
+set the |default_rule_thickness| parameter (number~8) to the thickness of
+the slanted rules, but \.{GFtoDVI} doesn't look at it.
+
+@ For best results on a particular output device, it is usually wise to
+choose the `unit' in the above discussion to be an integer number of pixels,
+and to make it no larger than the default rule thickness in the gray font
+being used.
+
+@ @<Initialize glob...@>=
+if length(font_name[slant_font])=0 then rule_slant:=0.0
+else begin rule_slant:=slant(slant_font)/unity;
+ slant_n:=font_ec[slant_font];
+ i:=char_info(slant_font)(slant_n);
+ slant_unit:=char_height(slant_font)(height_depth(i))/slant_n;
+ end;
+slant_reported:=0.0;
+
+@ The following error message is given when an absent slant has been
+requested.
+
+@p procedure slant_complaint(@!r:real);
+begin if abs(r-slant_reported)>0.001 then
+ begin print_nl('Sorry, I can''t make diagonal rules of slant ',r:10:5,'!');
+@.Sorry, I can't...@>
+ slant_reported:=r;
+ end;
+end;
+
+@* Representation of rectangles.
+OK---the preliminary spadework has now been done. We're ready at last
+to concentrate on \.{GFtoDVI}'s {\sl raison d'\^^Detre}.
+
+One of the most interesting tasks remaining is to make
+a ``map'' of the labels that have been allocated.
+There usually aren't a great many labels, so we don't need fancy data
+structures; but we do make use of linked nodes containing nine fields.
+The nodes generally represent rectangular boxes according to the
+following conventions:
+\smallskip\hang\noindent
+|xl|, |xr|, |yt|, and |yb| are the left, right, top, and bottom locations
+of a rectangle, expressed in \.{DVI} coordinates. (This program uses
+scaled points as \.{DVI} coordinates. Since \.{DVI} coordinates increase
+as one moves down the page, |yb| will be greater than |yt|.)
+\smallskip\hang\noindent
+|xx| and |yy| are the coordinates of the reference point of a box to be
+typeset from this node, again in \.{DVI} coordinates.
+\smallskip\hang\noindent
+|prev| and |next| point to the predecessor and successor of this node.
+Sometimes the nodes are singly linked and only |next| is relevant; otherwise
+the nodes are doubly linked in order of their |yy| coordinates, so that we
+can move down by going to |next|, or up by going to |prev|.
+\smallskip\hang\noindent
+|info| is the number of a string associated with this node.
+\smallskip\noindent
+
+The nine fields of a node appear in nine global arrays.
+Null pointers are denoted by |null|, which happens to be zero.
+
+@d null=0
+
+@<Types ...@>=
+@!node_pointer=null..max_labels;
+
+@ @<Glob...@>=
+@!xl,@!xr,@!yt,@!yb:array[1..max_labels] of scaled; {boundary coordinates}
+@!xx,@!yy:array[0..max_labels] of scaled; {reference coordinates}
+@!prev,@!next:array[0..max_labels] of node_pointer; {links}
+@!info:array[1..max_labels] of str_number; {associated strings}
+@!max_node:node_pointer; {the largest node in use}
+@!max_height:scaled; {greatest difference between |yy| and |yt|}
+@!max_depth:scaled; {greatest difference between |yb| and |yy|}
+
+
+@ It's easy to allocate a new node (unless no more room is left):
+
+@p function get_avail:node_pointer;
+begin incr(max_node);
+if max_node=max_labels then abort('Too many labels and/or rules!');
+@.Too many labels@>
+get_avail:=max_node;
+end;
+
+@ The doubly linked nodes are sorted by |yy| coordinates so that we don't have
+to work too hard to find nearest neighbors or to determine if rectangles overlap.
+The first node in the doubly linked rectangle list is always in location~0,
+and the last node is always in location |max_labels|; the |yy| coordinates
+of these nodes are very small and very large, respectively.
+
+@d end_of_list==max_labels
+
+@<Set init...@>=
+yy[0]:=-@'10000000000; yy[end_of_list]:=@'10000000000;
+
+@ The |node_ins| procedure inserts a new rectangle, represented by node~|p|,
+into the doubly linked list. There's a second parameter, |q|; node~|q| should
+already be in the doubly linked list, preferably with |yy[q]| near |yy[p]|.
+
+@p procedure node_ins(@!p,@!q:node_pointer);
+var @!r:node_pointer; {for tree traversal}
+begin if yy[p]>=yy[q] then
+ begin repeat r:=q; q:=next[q];@+until yy[p]<=yy[q];
+ next[r]:=p; prev[p]:=r; next[p]:=q; prev[q]:=p;
+ end
+else begin repeat r:=q; q:=prev[q];@+until yy[p]>=yy[q];
+ prev[r]:=p; next[p]:=r; prev[p]:=q; next[q]:=p;
+ end;
+if yy[p]-yt[p]>max_height then max_height:=yy[p]-yt[p];
+if yb[p]-yy[p]>max_depth then max_depth:=yb[p]-yy[p];
+end;
+
+@ The data structures need to be initialized for each character in the
+\.{GF} file.
+
+@<Initialize variables for the next character@>=
+max_node:=0; next[0]:=end_of_list; prev[end_of_list]:=0;
+max_height:=0; max_depth:=0;
+
+@ The |overlap| subroutine determines whether or not the rectangle specified
+in node~|p| has a nonempty intersection with some rectangle in the doubly
+linked list. Again |q|~is a parameter that gives us a starting point
+in the list. We assume that |q<>end_of_list|, so that |next[q]| is meaningful.
+
+@p function overlap(@!p,@!q:node_pointer):boolean;
+label exit;
+var @!y_thresh:scaled; {cutoff value to speed the search}
+@!x_left,@!x_right,@!y_top,@!y_bot:scaled; {boundaries to test for overlap}
+@!r:node_pointer; {runs through the neighbors of |q|}
+begin x_left:=xl[p]; x_right:=xr[p]; y_top:=yt[p]; y_bot:=yb[p];
+@<Look for overlaps in the successors of node |q|@>;
+@<Look for overlaps in node |q| and its predecessors@>;
+overlap:=false;
+exit: end;
+
+@ @<Look for overlaps in the successors of node |q|@>=
+y_thresh:=y_bot+max_height; r:=next[q];
+while yy[r]<y_thresh do
+ begin if y_bot > yt[r] then if x_left<xr[r] then
+ if x_right>xl[r] then if y_top<yb[r] then
+ begin overlap:=true; return;
+ end;
+ r:=next[r];
+ end
+
+@ @<Look for overlaps in node |q| and its predecessors@>=
+y_thresh:=y_top-max_depth; r:=q;
+while yy[r]>y_thresh do
+ begin if y_bot > yt[r] then if x_left<xr[r] then
+ if x_right>xl[r] then if y_top<yb[r] then
+ begin overlap:=true; return;
+ end;
+ r:=prev[r];
+ end
+
+@ Nodes that represent dots instead of labels satisfy the following
+constraints:
+$$\vcenter{\halign{#\hfil&\quad#\hfil\cr
+|info[p]<0;|&|p>=first_dot|;\cr
+|xl[p]=xx[p]-dot_width|,&|xr[p]=xx[p]+dot_width|;\cr
+|yt[p]=yy[p]-dot_height|,&|yb[p]=yy[p]+dot_height|.\cr}}$$
+
+The |nearest_dot| subroutine finds a node whose reference point is as
+close as possible to a given position, ignoring nodes that are too close.
+More precisely, the ``nearest'' node
+minimizes$$d(q,p)=\max\bigl(\vert |xx|[q]-|xx|[p]\vert,
+ \vert |yy|[q]-|yy|[p]\vert\bigr)$$ over all nodes~|q|
+with |d(q,p)>=d0|. We call the subroutine |nearest_dot| because it is used only
+when the doubly linked list contains nothing but dots.
+
+The routine also sets the global variable |twin| to |true|, if there is a
+node |q<>p| with |d(q,p)<d0|.
+
+@ @<Glob...@>=
+@!first_dot:node_pointer; {the node address where dots begin}
+@!twin:boolean; {is there a nearer dot than the ``nearest'' dot?}
+
+@ If there is no nearest dot, the value |null| is returned;
+otherwise a pointer to the nearest dot is returned.
+
+@p function nearest_dot(@!p:node_pointer; @!d0:scaled):node_pointer;
+var @!best_q:node_pointer; {value to return}
+@!d_min,@!d:scaled; {distances}
+begin twin:=false; best_q:=0; d_min:=@'2000000000;
+@<Search for the nearest dot in nodes following |p|@>;
+@<Search for the nearest dot in nodes preceding |p|@>;
+nearest_dot:=best_q;
+end;
+
+@ @<Search for the nearest dot in nodes following |p|@>=
+q:=next[p];
+while yy[q]<yy[p]+d_min do
+ begin d:=abs(xx[q]-xx[p]);
+ if d<yy[q]-yy[p] then d:=yy[q]-yy[p];
+ if d<d0 then twin:=true
+ else if d<d_min then
+ begin d_min:=d; best_q:=q;
+ end;
+ q:=next[q];
+ end
+
+@ @<Search for the nearest dot in nodes preceding |p|@>=
+q:=prev[p];
+while yy[q]>yy[p]-d_min do
+ begin d:=abs(xx[q]-xx[p]);
+ if d<yy[p]-yy[q] then d:=yy[p]-yy[q];
+ if d<d0 then twin:=true
+ else if d<d_min then
+ begin d_min:=d; best_q:=q;
+ end;
+ q:=prev[q];
+ end
+
+@* Doing the labels.
+Each ``character'' in the \.{GF} file is preceded by a number of special
+commands that define labels, titles, rules, etc. We store these away,
+to be considered later when the |boc| command appears. The |boc|
+command establishes the size information by which labels and rules
+can be positioned, so we spew out the label information as soon as
+we see the |boc|. The gray pixels will be typeset after all the labels
+for a particular character have been finished.
+
+@ Here is the part of \.{GFtoDVI} that stores information preceding a~|boc|.
+It comes into play when |cur_gf| is between |xxx1| and~|no_op|, inclusive.
+
+@d font_change(#)==if fonts_not_loaded then
+ begin #; end
+ else print_nl('(Tardy font change will be ignored (byte ',
+@.Tardy font change...@>
+ cur_loc:1,')!)')
+
+@<Process a no-op command@>=
+begin k:=interpret_xxx;
+case k of
+no_operation: do_nothing;
+title_font,label_font,gray_font,slant_font:font_change(font_name[k]:=cur_string;
+ font_area[k]:=null_string;font_at[k]:=0;init_str_ptr:=str_ptr);
+title_font+area_code,label_font+area_code,gray_font+area_code,
+ slant_font+area_code:@|
+ font_change(font_area[k-area_code]:=cur_string;init_str_ptr:=str_ptr);
+title_font+at_code,label_font+at_code,gray_font+at_code,
+ slant_font+at_code:@|
+ font_change(font_at[k-at_code]:=get_yyy;init_str_ptr:=str_ptr);
+rule_thickness_code:rule_thickness:=get_yyy;
+rule_code:@<Store a rule@>;
+offset_code:@<Override the offsets@>;
+x_offset_code:x_offset:=get_yyy;
+y_offset_code:y_offset:=get_yyy;
+title_code:@<Store a title@>;
+null_string:@<Store a label@>;
+end; {there are no other cases}
+end
+
+@ The following quantities are cleared just before reading the
+\.{GF} commands pertaining to a character.
+
+@<Glob...@>=
+@!rule_thickness:scaled; {the current rule thickness
+ (zero means use the default)}
+@!offset_x,@!offset_y:scaled; {the current offsets for images}
+@!x_offset,@!y_offset:scaled; {the current offsets for labels}
+@!pre_min_x,@!pre_max_x,@!pre_min_y,@!pre_max_y:scaled;
+ {extreme values of coordinates preceding a character, in \MF\ pixels}
+
+@ @<Initialize variables for the next character@>=
+rule_thickness:=0;
+offset_x:=0; offset_y:=0; x_offset:=0; y_offset:=0;
+pre_min_x:=@'2000000000; pre_max_x:=-@'2000000000;
+pre_min_y:=@'2000000000; pre_max_y:=-@'2000000000;
+
+@ @<Override the offsets@>=
+begin offset_x:=get_yyy; offset_y:=get_yyy;
+end
+
+@ Rules that will need to be drawn are kept in a linked list accessible
+via |rule_ptr|, in last-in-first-out order. The nodes of this list will
+never get into the doubly linked list, and indeed these nodes use different
+field conventions entirely (because rules may be slanted).
+
+@d x0==xl {starting |x| coordinate of a stored rule}
+@d y0==yt {starting |y| coordinate (in scaled \MF\ pixels)}
+@d x1==xr {ending |x| coordinate of a stored rule}
+@d y1==yb {ending |y| coordinate of a stored rule}
+@d rule_size==xx {thickness of a stored rule, in scaled points}
+
+@<Glob...@>=
+@!rule_ptr:node_pointer; {top of the stack of remembered rules}
+
+@ @<Store a rule@>=
+begin p:=get_avail; next[p]:=rule_ptr; rule_ptr:=p;@/
+x0[p]:=get_yyy; y0[p]:=get_yyy; x1[p]:=get_yyy; y1[p]:=get_yyy;
+if x0[p]<pre_min_x then pre_min_x:=x0[p];
+if x0[p]>pre_max_x then pre_max_x:=x0[p];
+if y0[p]<pre_min_y then pre_min_y:=y0[p];
+if y0[p]>pre_max_y then pre_max_y:=y0[p];
+if x1[p]<pre_min_x then pre_min_x:=x1[p];
+if x1[p]>pre_max_x then pre_max_x:=x1[p];
+if y1[p]<pre_min_y then pre_min_y:=y1[p];
+if y1[p]>pre_max_y then pre_max_y:=y1[p];
+rule_size[p]:=rule_thickness;
+end
+
+@ Titles and labels are, likewise, stored temporarily in singly linked lists.
+In this case the lists are first-in-first-out.
+Variables |title_tail| and |label_tail| point to the most recently inserted
+title or label; variables |title_head| and |label_head|
+point to the beginning of the list. (A standard coding trick is used
+for |label_head|, which is kept in |next[end_of_list]|; we have
+|label_tail=end_of_list| when the list is empty.)
+
+The |prev| field in nodes of the temporary label list specifies the
+type of label, so we call it |lab_typ|.
+
+@d lab_typ==prev {the type of a stored label (|"/"..."8"|)}
+@d label_head==next[end_of_list]
+
+@<Glob...@>=
+@!label_tail:node_pointer; {tail of the queue of remembered labels}
+@!title_head,@!title_tail:node_pointer; {head and tail of the queue for titles}
+
+@ We must start the lists out empty.
+
+@<Initialize variables for the next char...@>=
+rule_ptr:=null;
+title_head:=null; title_tail:=null; label_head:=null; label_tail:=end_of_list;
+first_dot:=max_labels;
+
+@ @<Store a title@>=
+begin p:=get_avail; info[p]:=cur_string;
+if title_head=null then title_head:=p
+else next[title_tail]:=p;
+title_tail:=p;
+end
+
+@ We store the coordinates of each label in units of \MF\ pixels; they
+will be converted to \.{DVI} coordinates later.
+
+@<Store a label@>=
+if (label_type<"/")or(label_type>"8") then
+ print_nl('Bad label type precedes byte ',cur_loc:1,'!')
+@.Bad label type...@>
+else begin p:=get_avail; next[label_tail]:=p; label_tail:=p;@/
+ lab_typ[p]:=label_type; info[p]:=cur_string;@/
+ xx[p]:=get_yyy; yy[p]:=get_yyy;
+ if xx[p]<pre_min_x then pre_min_x:=xx[p];
+ if xx[p]>pre_max_x then pre_max_x:=xx[p];
+ if yy[p]<pre_min_y then pre_min_y:=yy[p];
+ if yy[p]>pre_max_y then pre_max_y:=yy[p];
+ end
+
+@ The process of ferreting everything away comes to an abrupt halt
+when a |boc| command is sensed. The following steps are performed
+at such times:
+
+@<Process a character@>=
+begin check_fonts;
+@<Finish reading the parameters of the |boc|@>;
+@<Get ready to convert \MF\ coordinates to \.{DVI} coordinates@>;
+@<Output the |bop| and the title line@>;
+print('[',total_pages:1); update_terminal; {print a progress report}
+@<Output all rules for the current character@>;
+@<Output all labels for the current character@>;
+do_pixels;
+dvi_out(eop); {finish the page}
+@<Adjust the maximum page width@>;
+print(']'); update_terminal;
+end
+
+@ @<Finish reading the parameters of the |boc|@>=
+if cur_gf=boc then
+ begin ext:=signed_quad; {read the character code}
+ char_code:=ext mod 256;
+ if char_code<0 then char_code:=char_code+256;
+ ext:=(ext-char_code) div 256;
+ k:=signed_quad; {read and ignore the prev pointer}
+ min_x:=signed_quad; {read the minimum $x$ coordinate}
+ max_x:=signed_quad; {read the maximum $x$ coordinate}
+ min_y:=signed_quad; {read the minimum $y$ coordinate}
+ max_y:=signed_quad; {read the maximum $y$ coordinate}
+ end
+else begin ext:=0; char_code:=get_byte; {|cur_gf=boc1|}
+ min_x:=get_byte; max_x:=get_byte; min_x:=max_x-min_x;@/
+ min_y:=get_byte; max_y:=get_byte; min_y:=max_y-min_y;
+ end;
+if max_x-min_x>widest_row then abort('Character too wide!')
+@.Character too wide@>
+
+@ @<Glob...@>=
+@!char_code,@!ext:integer; {the current character code and extension}
+@!min_x,@!max_x,@!min_y,@!max_y:integer; {character boundaries, in pixels}
+@!x,@!y:integer; {current painting position, in pixels}
+@!z:integer; {initial painting position in row, relative to |min_x|}
+
+@ \MF\ coordinates $(x,y)$ are converted to \.{DVI} coordinates by the
+following routine. Real values |x_ratio|, |y_ratio|, and |slant_ratio|
+will have been calculated based on the gray font; |scaled| values
+|delta_x| and |delta_y| will have been computed so that, in the absence
+of slanting and offsets, the \MF\ coordinates |(min_x,max_y+1)| will correspond
+to the \.{DVI} coordinates $(0,50\,\rm pt)$.
+
+@p procedure convert(@!x,@!y:scaled);
+begin x:=x+x_offset; y:=y+y_offset;
+dvi_y:=-round(y_ratio*y)+delta_y;
+dvi_x:=round(x_ratio*x+slant_ratio*y)+delta_x;
+end;
+
+@ @<Glob...@>=
+@!x_ratio,@!y_ratio,@!slant_ratio:real; {conversion factors}
+@!unsc_x_ratio,@!unsc_y_ratio,@!unsc_slant_ratio:real;
+ {ditto, times |unity|}
+@!fudge_factor:real; {unconversion factor}
+@!delta_x,@!delta_y:scaled; {magic constants used by |convert|}
+@!dvi_x,@!dvi_y:scaled; {outputs of |convert|, in scaled points}
+@!over_col:scaled; {overflow labels start here}
+@!page_height,page_width:scaled; {size of the current page}
+
+@ @<Initialize global variables that depend on the font data@>=
+i:=char_info(gray_font)(1);
+if not char_exists(i) then abort('Missing pixel char!');
+@.Missing pixel char@>
+unsc_x_ratio:=char_width(gray_font)(i);
+x_ratio:=unsc_x_ratio/unity;
+unsc_y_ratio:=char_height(gray_font)(height_depth(i));
+y_ratio:=unsc_y_ratio/unity;
+unsc_slant_ratio:=slant(gray_font)*y_ratio;
+slant_ratio:=unsc_slant_ratio/unity;
+if x_ratio*y_ratio=0 then abort('Vanishing pixel size!');
+@.Vanishing pixel size@>
+fudge_factor:=(slant_ratio/x_ratio)/y_ratio;
+
+@ @<Get ready to convert...@>=
+if pre_min_x<min_x*unity then offset_x:=offset_x+min_x*unity-pre_min_x;
+if pre_max_y>max_y*unity then offset_y:=offset_y+max_y*unity-pre_max_y;
+if pre_max_x>max_x*unity then pre_max_x:=pre_max_x div unity
+else pre_max_x:=max_x;
+if pre_min_y<min_y*unity then pre_min_y:=pre_min_y div unity
+else pre_min_y:=min_y;
+delta_y:=round(unsc_y_ratio*(max_y+1)-y_ratio*offset_y)+3276800;
+delta_x:=round(x_ratio*offset_x-unsc_x_ratio*min_x);
+if slant_ratio>=0 then
+ over_col:=round(unsc_x_ratio*pre_max_x+unsc_slant_ratio*max_y)
+else over_col:=round(unsc_x_ratio*pre_max_x+unsc_slant_ratio*min_y);
+over_col:=over_col+delta_x+10000000;
+page_height:=round(unsc_y_ratio*(max_y+1-pre_min_y))+3276800-offset_y;
+if page_height>max_v then max_v:=page_height;
+page_width:=over_col-10000000
+
+@ The |dvi_goto| subroutine outputs bytes to the \.{DVI} file that
+will initiate typesetting at given \.{DVI} coordinates, assuming that
+the current position of the \.{DVI} reader is $(0,0)$. This subroutine
+begins by outputting a |push| command; therefore, a |pop| command should
+be given later. That |pop| will restore the \.{DVI} position to $(0,0)$.
+
+@p procedure dvi_goto(@!x,@!y:scaled);
+begin dvi_out(push);
+if x<>0 then
+ begin dvi_out(right4); dvi_four(x);
+ end;
+if y<>0 then
+ begin dvi_out(down4); dvi_four(y);
+ end;
+end;
+
+@ @<Output the |bop| and the title line@>=
+dvi_out(bop); incr(total_pages); dvi_four(total_pages);
+dvi_four(char_code); dvi_four(ext);
+for k:=3 to 9 do dvi_four(0);
+dvi_four(last_bop); last_bop:=dvi_offset+dvi_ptr-45;@/
+dvi_goto(0,655360); {the top baseline is 10\thinspace pt down}
+if use_logo then
+ begin select_font(logo_font); hbox(small_logo,logo_font,true);
+ end;
+select_font(title_font); hbox(time_stamp,title_font,true);@/
+hbox(page_header,title_font,true); dvi_scaled(total_pages*65536.0);@/
+if (char_code<>0)or(ext<>0) then
+ begin hbox(char_header,title_font,true); dvi_scaled(char_code*65536.0);
+ if ext<>0 then
+ begin hbox(ext_header,title_font,true); dvi_scaled(ext*65536.0);
+ end;
+ end;
+if title_head<>null then
+ begin next[title_tail]:=null;
+ repeat hbox(left_quotes,title_font,true);
+ hbox(info[title_head],title_font,true);
+ hbox(right_quotes,title_font,true);
+ title_head:=next[title_head];
+ until title_head=null;
+ end;
+dvi_out(pop)
+
+@ @d tol==6554 {one tenth of a point, in \.{DVI} coordinates}
+
+@<Output all rules for the current character@>=
+if rule_slant<>0 then select_font(slant_font);
+while rule_ptr<>null do
+ begin p:=rule_ptr; rule_ptr:=next[p];@/
+ if rule_size[p]=0 then rule_size[p]:=gray_rule_thickness;
+ if rule_size[p]>0 then
+ begin convert(x0[p],y0[p]); temp_x:=dvi_x; temp_y:=dvi_y;
+ convert(x1[p],y1[p]);
+ if abs(temp_x-dvi_x)<tol then @<Output a vertical rule@>
+ else if abs(temp_y-dvi_y)<tol then @<Output a horizontal rule@>
+ else @<Try to output a diagonal rule@>;
+ end;
+ end
+
+@ @<Glob...@>=
+@!gray_rule_thickness:scaled; {thickness of rules, according to the gray font}
+@!temp_x,@!temp_y:scaled; {temporary registers for intermediate calculations}
+
+@ @<Initialize glob...@>=
+gray_rule_thickness:=default_rule_thickness(gray_font);
+if gray_rule_thickness=0 then gray_rule_thickness:=26214; {0.4\thinspace pt}
+
+@ @<Output a vertical rule@>=
+begin if temp_y>dvi_y then
+ begin k:=temp_y; temp_y:=dvi_y; dvi_y:=k;
+ end;
+dvi_goto(dvi_x-(rule_size[p] div 2), dvi_y);
+dvi_out(put_rule); dvi_four(dvi_y-temp_y); dvi_four(rule_size[p]);
+dvi_out(pop);
+end
+
+@ @<Output a horizontal rule@>=
+begin if temp_x<dvi_x then
+ begin k:=temp_x; temp_x:=dvi_x; dvi_x:=k;
+ end;
+dvi_goto(dvi_x,dvi_y+(rule_size[p] div 2));
+dvi_out(put_rule); dvi_four(rule_size[p]); dvi_four(temp_x-dvi_x);
+dvi_out(pop);
+end
+
+@ @<Try to output a diagonal rule@>=
+if (rule_slant=0)or@|
+ (abs(temp_x+rule_slant*(temp_y-dvi_y)-dvi_x)>rule_size[p]) then
+ slant_complaint((dvi_x-temp_x)/(temp_y-dvi_y))
+else begin if temp_y>dvi_y then
+ begin k:=temp_y; temp_y:=dvi_y; dvi_y:=k;@/
+ k:=temp_x; temp_x:=dvi_x; dvi_x:=k;
+ end;
+ m:=round((dvi_y-temp_y)/slant_unit);
+ if m>0 then
+ begin dvi_goto(dvi_x,dvi_y);
+ q:=((m-1) div slant_n)+1; k:=m div q;
+ p:=m mod q; q:=q-p;
+ @<Vertically typeset |q| copies of character |k|@>;
+ @<Vertically typeset |p| copies of character |k+1|@>;
+ dvi_out(pop);
+ end;
+ end
+
+@ @<Vertically typeset |q| copies of character |k|@>=
+typeset(k); dy:=round(k*slant_unit); dvi_out(z4); dvi_four(-dy);
+while q>1 do
+ begin typeset(k); dvi_out(z0); decr(q);
+ end
+
+@ @<Vertically typeset |p| copies of character |k+1|@>=
+if p>0 then
+ begin incr(k); typeset(k);
+ dy:=round(k*slant_unit); dvi_out(z4); dvi_four(-dy);
+ while p>1 do
+ begin typeset(k); dvi_out(z0); decr(p);
+ end;
+ end
+
+@ Now we come to a more interesting part of the computation, where we
+go through the stored labels and try to fit them in the illustration for
+the current character, together with their associated dots.
+
+It would simplify font-switching slightly if we were to typeset the labels
+first, but we find it desirable to typeset the dots first and then turn to the
+labels. This procedure makes it possible for us to allow the dots to
+overlap each other without allowing the labels to overlap. After the
+dots are in place, we typeset all prescribed labels, that is, labels with a
+|lab_typ| of |"1".."8"|; these, too, are allowed to overlap the dots and
+each other.
+
+@<Output all labels for the current character@>=
+overflow_line:=1;
+if label_head<>null then
+ begin next[label_tail]:=null; select_font(gray_font);
+ @<Output all dots@>;
+ @<Find nearest dots, to help in label positioning@>;
+ select_font(label_font);
+ @<Output all prescribed labels@>;
+ @<Output all attachable labels@>;
+ @<Output all overflow labels@>;
+ end
+
+@ @<Glob...@>=
+@!overflow_line:integer; {the number of labels that didn't fit, plus~1}
+
+@ A label that appears above its dot is considered to occupy a
+rectangle of height~$h+\Delta$, depth~$d$, and width~$w+2\Delta$, where
+$(h,w,d)$ are the height, width, and depth of the label computed by |hbox|,
+and $\Delta$ is an additional amount of blank space that keeps labels from
+coming too close to each other. (\.{GFtoDVI} arbitrarily defines $\Delta$
+to be one half the width of a space in the label font.) This label is
+centered over its dot, with its baseline $d+h'$ above the center of the dot;
+here $h'=|dot_height|$ is the height of character~0 in the gray font.
+
+Similarly, a label that appears below its dot is considered to occupy
+a rectangle of height~$h$, depth~$d+\Delta$, and width~$w+2\Delta$; the
+baseline is $h+h'$ below the center of the dot.
+
+A label at the right of its dot is considered to occupy a rectangle of
+height~$h+\Delta$, depth~$d+\Delta$, and width~$w+\Delta$. Its
+reference point can be found by starting at the center of the dot and
+moving right $w'=|dot_width|$ (i.e., the width of character~0 in the
+gray font), then moving down by half the x-height of the label font.
+A label at the left of its dot is similar.
+
+A dot is considered to occupy a rectangle of height $2h'$ and width~$2w'$,
+centered on the dot.
+
+When the label type is |"1"| or more, the labels
+are put into the doubly linked list unconditionally.
+ Otherwise they are put into the list
+only if we can find a way to fit them in without
+overlapping any previously inserted rectangles.
+
+@<Glob...@>=
+@!delta:scaled; {extra padding to keep labels from being too close}
+@!half_x_height:scaled; {amount to drop baseline of label below the dot center}
+@!thrice_x_height:scaled; {baseline separation for overflow labels}
+@!dot_width,@!dot_height:scaled; {$w'$ and $h'$ in the discussion above}
+
+@ @<Initialize global variables that depend on the font data@>=
+i:=char_info(gray_font)(0);
+if not char_exists(i) then abort('Missing dot char!');
+@.Missing dot char@>
+dot_width:=char_width(gray_font)(i);
+dot_height:=char_height(gray_font)(height_depth(i));
+delta:=space(label_font) div 2;
+thrice_x_height:=3*x_height(label_font);
+half_x_height:=thrice_x_height div 6;
+
+@ Here is a subroutine that computes the rectangle boundaries
+|xl[p]|, |xr[p]|, |yt[p]|, |yb[p]|, and the reference point coordinates
+|xx[p]|,~|yy[p]|, for a label that is to be placed above a dot.
+The coordinates of the dot's center are assumed given in |dvi_x|
+and |dvi_y|; the |hbox| subroutine is assumed to have
+already computed the height, width, and depth of the label box.
+
+@p procedure top_coords(@!p:node_pointer);
+begin xx[p]:=dvi_x-(box_width div 2); xl[p]:=xx[p]-delta;
+xr[p]:=xx[p]+box_width+delta;@/
+yb[p]:=dvi_y-dot_height; yy[p]:=yb[p]-box_depth;
+yt[p]:=yy[p]-box_height-delta;
+end;
+
+@ The other three label positions are handled by similar routines.
+
+@p procedure bot_coords(@!p:node_pointer);
+begin xx[p]:=dvi_x-(box_width div 2); xl[p]:=xx[p]-delta;
+xr[p]:=xx[p]+box_width+delta;@/
+yt[p]:=dvi_y+dot_height; yy[p]:=yt[p]+box_height;
+yb[p]:=yy[p]+box_depth+delta;
+end;
+@#
+procedure right_coords(@!p:node_pointer);
+begin xl[p]:=dvi_x+dot_width; xx[p]:=xl[p]; xr[p]:=xx[p]+box_width+delta;@/
+yy[p]:=dvi_y+half_x_height; yb[p]:=yy[p]+box_depth+delta;
+yt[p]:=yy[p]-box_height-delta;
+end;
+@#
+procedure left_coords(@!p:node_pointer);
+begin xr[p]:=dvi_x-dot_width; xx[p]:=xr[p]-box_width; xl[p]:=xx[p]-delta;@/
+yy[p]:=dvi_y+half_x_height; yb[p]:=yy[p]+box_depth+delta;
+yt[p]:=yy[p]-box_height-delta;
+end;
+
+@ @<Output all dots@>=
+p:=label_head; first_dot:=max_node+1;
+while p<>null do
+ begin convert(xx[p],yy[p]); xx[p]:=dvi_x; yy[p]:=dvi_y;
+ if lab_typ[p]<"5" then
+ @<Enter a dot for label |p| in the rectangle list,
+ and typeset the dot@>;
+ p:=next[p];
+ end
+
+@ We plant links between dots and their labels by using (or abusing) the
+|xl| and |info| fields, which aren't needed for their normal purposes.
+
+@d dot_for_label==xl
+@d label_for_dot==info
+
+@<Enter a dot...@>=
+begin q:=get_avail; dot_for_label[p]:=q; label_for_dot[q]:=p;@/
+xx[q]:=dvi_x; xl[q]:=dvi_x-dot_width; xr[q]:=dvi_x+dot_width;@/
+yy[q]:=dvi_y; yt[q]:=dvi_y-dot_height; yb[q]:=dvi_y+dot_height;@/
+node_ins(q,0);@/
+dvi_goto(xx[q],yy[q]); dvi_out(0); dvi_out(pop);
+end
+
+@ Prescribed labels are now taken out of the singly linked list and
+inserted into the doubly linked list.
+
+@<Output all prescribed labels@>=
+q:=end_of_list; {|label_head=next[q]|}
+while next[q]<>null do
+ begin p:=next[q];
+ if lab_typ[p]>"0" then
+ begin next[q]:=next[p];
+ @<Enter a prescribed label for node |p| into the rectangle list,
+ and typeset it@>;
+ end
+ else q:=next[q];
+ end
+
+@ @<Enter a prescr...@>=
+begin hbox(info[p],label_font,false); {Compute the size of this label}
+dvi_x:=xx[p]; dvi_y:=yy[p];
+if lab_typ[p]<"5" then r:=dot_for_label[p]@+else r:=0;
+case lab_typ[p] of
+"1","5":top_coords(p);
+"2","6":left_coords(p);
+"3","7":right_coords(p);
+"4","8":bot_coords(p);
+end; {no other cases are possible}
+node_ins(p,r);@/
+dvi_goto(xx[p],yy[p]); hbox(info[p],label_font,true); dvi_out(pop);
+end
+
+@ \.{GFtoDVI}'s algorithm for positioning the ``floating'' labels
+was devised by Arthur~L. Samuel.
+@^Samuel, Arthur Lee@>
+It tries to place labels in a priority order, based on the position of
+the nearest dot to a given dot. If that dot, for example, lies in the first
+octant (i.e., east to northeast of the given dot), the given label will
+be put into the west slot unless that slot is already blocked; then the
+south slot will be tried, etc.
+
+First we need to compute the octants. We also note if two or more dots
+are nearly coincident, since Samuel's algorithm modifies the priority
+order on that case. The information is temporarily recorded in the |xr| array.
+
+@d octant==xr {octant code for nearest dot, plus 8 for coincident dots}
+
+@<Find nearest dots, to help in label positioning@>=
+p:=label_head;
+while p<>null do
+ begin if lab_typ[p]<="0" then
+ @<Compute the octant code for floating label |p|@>;
+ p:=next[p];
+ end;
+
+@ There's a sneaky way to identify octant numbers, represented by the
+code shown here. (Remember that |y|~coordinates increase downward
+in the \.{DVI} convention.)
+
+@d first_octant=0
+@d second_octant=1
+@d third_octant=2
+@d fourth_octant=3
+@d fifth_octant=7
+@d sixth_octant=6
+@d seventh_octant=5
+@d eighth_octant=4
+
+@<Compute the octant code for floating label |p|@>=
+begin r:=dot_for_label[p]; q:=nearest_dot(r,10);
+if twin then octant[p]:=8@+else octant[p]:=0;
+if q<>null then
+ begin dx:=xx[q]-xx[r]; dy:=yy[q]-yy[r];
+ if dy>0 then octant[p]:=octant[p]+4;
+ if dx<0 then incr(octant[p]);
+ if dy>dx then incr(octant[p]);
+ if -dy>dx then incr(octant[p]);
+ end;
+end
+
+@ A procedure called |place_label| will try to place the remaining
+labels in turn. If it fails, we ``disconnect'' the dot from this
+label so that an unlabeled dot will not appear as a reference in the
+overflow column.
+
+@<Output all attachable labels@>=
+q:=end_of_list; {now |next[q]=label_head|}
+while next[q]<>null do
+ begin p:=next[q]; r:=next[p]; s:=dot_for_label[p];
+ if place_label(p) then next[q]:=r
+ else begin label_for_dot[s]:=null; {disconnect the dot}
+ if lab_typ[p]="/" then next[q]:=r {remove label from list}
+ else q:=p; {retain label in list for the overflow column}
+ end;
+ end
+
+@ Here is the |place_label| routine, which uses the previously computed
+|octant| information as a heuristic. If the label can be placed, it
+is inserted into the rectangle list and typeset.
+
+@p function place_label(@!p:node_pointer):boolean;
+label exit, found;
+var @!oct:0..15; {octant code}
+@!dfl:node_pointer; {saved value of |dot_for_label[p]|}
+begin hbox(info[p],label_font,false); {Compute the size of this label}
+dvi_x:=xx[p]; dvi_y:=yy[p];
+@<Find non-overlapping coordinates, if possible, and |goto| found;
+ otherwise set |place_label:=false| and |return|@>;
+found:node_ins(p,dfl);@/
+dvi_goto(xx[p],yy[p]); hbox(info[p],label_font,true); dvi_out(pop);
+place_label:=true;
+exit:end;
+
+@ @<Find non-overlapping coordinates, if possible...@>=
+dfl:=dot_for_label[p]; oct:=octant[p];
+@<Try the first choice for label direction@>;
+@<Try the second choice for label direction@>;
+@<Try the third choice for label direction@>;
+@<Try the fourth choice for label direction@>;
+xx[p]:=dvi_x; yy[p]:=dvi_y; dot_for_label[p]:=dfl; {no luck; restore the coordinates}
+place_label:=false; return
+
+@ @<Try the first choice for label direction@>=
+case oct of
+first_octant,eighth_octant,second_octant+8,seventh_octant+8: left_coords(p);
+second_octant,third_octant,first_octant+8,fourth_octant+8: bot_coords(p);
+fourth_octant,fifth_octant,third_octant+8,sixth_octant+8: right_coords(p);
+sixth_octant,seventh_octant,fifth_octant+8,eighth_octant+8: top_coords(p);
+end;
+if not overlap(p,dfl) then goto found
+
+@ @<Try the second choice for label direction@>=
+case oct of
+first_octant,fourth_octant,fifth_octant+8,eighth_octant+8: bot_coords(p);
+second_octant,seventh_octant,third_octant+8,sixth_octant+8: left_coords(p);
+third_octant,sixth_octant,second_octant+8,seventh_octant+8: right_coords(p);
+fifth_octant,eighth_octant,first_octant+8,fourth_octant+8: top_coords(p);
+end;
+if not overlap(p,dfl) then goto found
+
+@ @<Try the third choice for label direction@>=
+case oct of
+first_octant,fourth_octant,sixth_octant+8,seventh_octant+8: top_coords(p);
+second_octant,seventh_octant,fourth_octant+8,fifth_octant+8: right_coords(p);
+third_octant,sixth_octant,first_octant+8,eighth_octant+8: left_coords(p);
+fifth_octant,eighth_octant,second_octant+8,third_octant+8: bot_coords(p);
+end;
+if not overlap(p,dfl) then goto found
+
+@ @<Try the fourth choice for label direction@>=
+case oct of
+first_octant,eighth_octant,first_octant+8,eighth_octant+8: right_coords(p);
+second_octant,third_octant,second_octant+8,third_octant+8: top_coords(p);
+fourth_octant,fifth_octant,fourth_octant+8,fifth_octant+8: left_coords(p);
+sixth_octant,seventh_octant,sixth_octant+8,seventh_octant+8: bot_coords(p);
+end;
+if not overlap(p,dfl) then goto found
+
+@ @<Output all overflow labels@>=
+@<Remove all rectangles from list, except for dots that have labels@>;
+p:=label_head;
+while p<>null do
+ begin @<Typeset an overflow label for |p|@>;
+ p:=next[p];
+ end
+
+@ When we remove a dot that couldn't be labeled, we set its |next| field
+to the preceding node that survives, so that we can use the |nearest_dot|
+routine later. (This is a bit of a kludge.)
+
+@<Remove all rectangles from list, except for dots that have labels@>=
+p:=next[0];
+while p<>end_of_list do
+ begin q:=next[p];
+ if (p<first_dot) or (label_for_dot[p]=null) then
+ begin r:=prev[p]; next[r]:=q; prev[q]:=r; next[p]:=r;
+ end;
+ p:=q;
+ end
+
+@ Now we have to insert |p| into the list temporarily, because of the
+way |nearest_dot| works.
+
+@<Typeset an overflow label for |p|@>=
+begin r:=next[dot_for_label[p]]; s:=next[r]; t:=next[p];
+next[p]:=s; prev[s]:=p; next[r]:=p; prev[p]:=r;@/
+q:=nearest_dot(p,0);@/
+next[r]:=s; prev[s]:=r; next[p]:=t; {remove |p| again}
+incr(overflow_line);
+dvi_goto(over_col,overflow_line*thrice_x_height+655360);
+hbox(info[p],label_font,true);
+if q<>null then
+ begin hbox(equals_sign,label_font,true);
+ hbox(info[label_for_dot[q]],label_font,true);
+ hbox(plus_sign,label_font,true);
+ dvi_scaled((xx[p]-xx[q])/x_ratio+(yy[p]-yy[q])*fudge_factor);
+ dvi_out(",");
+ dvi_scaled((yy[q]-yy[p])/y_ratio);
+ dvi_out(")");
+ end;
+dvi_out(pop);
+end
+
+@ @<Adjust the maximum page width@>=
+if overflow_line>1 then page_width:=over_col+10000000;
+ {overflow labels are estimated to occupy $10^7\,$sp}
+if page_width>max_h then max_h:=page_width
+
+@* Doing the pixels.
+The most interesting part of \.{GFtoDVI} is the way it makes use of a gray
+font to typeset the pixels of a character. In fact, the author must admit having
+great fun devising the algorithms below. Perhaps the reader will also
+enjoy reading them.
+
+The basic idea will be to use an array of 12-bit integers to represent the next
+twelve rows that need to be typeset. The binary expansions of these integers,
+reading from least significant bit to most significant bit, will represent
+pixels from top to bottom.
+
+@ We have already used such a binary representation in the tables
+|c[1..120]| and |d[1..120]| of bit patterns and lengths that are potentially
+present in a gray font; we shall now use those tables to compute
+an auxiliary array |b[0..4095]|. Given a 12-bit number~$v$, the gray-font
+character appropriate to $v$'s binary pattern will be~|b[v]|. If no
+character should be typeset for this pattern in the current row,
+|b[v]| will be~0.
+
+The array |b| can have many different configurations, depending on how
+many characters are actually present in the gray font. But
+it's not difficult to compute |b| by going through the existing characters
+in increasing order and marking all patterns~$x$ to which they apply.
+
+@<Initialize glob...@>=
+for k:=0 to 4095 do b[k]:=0;
+for k:=font_bc[gray_font] to font_ec[gray_font] do
+ if k>=1 then if k<=120 then
+ if char_exists(char_info(gray_font)(k)) then
+ begin v:=c[k];
+ repeat b[v]:=k; v:=v+d[k];
+ until v>4095;
+ end;
+
+@ We also compute an auxiliary array |rho[0..4095]| such that $\\{rho}[v]=2^j$
+when |v| is an odd multiple of~$2^j$; we also set $\\{rho}[0]=2^{12}$.
+
+@<Initialize g...@>=
+for j:=0 to 11 do
+ begin k:=two_to_the[j]; v:=k;
+ repeat rho[v]:=k; v:=v+k+k;
+ until v>4095;
+ end;
+rho[0]:=4096;
+
+@ @<Glob...@>=
+@!b:array[0..4095] of 0..120; {largest existing character for a given pattern}
+@!rho:array[0..4095] of 1..4096; {the ``ruler function''}
+
+@ But how will we use these tables? Let's imagine that the \.{DVI} file
+already contains instructions that have selected the gray font and moved
+to the proper horizontal coordinate for the row that we wish to process next.
+Let's suppose that 12-bit patterns have been set up in array~|a|, and that
+the global variables |starting_col| and |finishing_col| are known such
+that |a[j]| is zero unless |starting_col<=j<=finishing_col|. Here's what
+we can do, assuming that appropriate local variables and labels have
+been declared:
+
+@<Typeset the pixels of the current row@>=
+j:=starting_col;
+loop@+ begin while (j<=finishing_col)and(b[a[j]]=0) do incr(j);
+ if j>finishing_col then goto done;
+ dvi_out(push); @<Move to column |j| in the \.{DVI} output@>;
+ repeat v:=b[a[j]]; a[j]:=a[j]-c[v];
+ k:=j; incr(j);
+ while b[a[j]]=v do
+ begin a[j]:=a[j]-c[v]; incr(j);
+ end;
+ k:=j-k; @<Output the equivalent of |k| copies of character |v|@>;
+ until b[a[j]]=0;
+ dvi_out(pop);
+ end;
+done:
+
+@ @<Move to column |j| in the \.{DVI} output@>=
+dvi_out(right4);
+dvi_four(round(unsc_x_ratio*j+unsc_slant_ratio*y)+delta_x)
+
+@ The doubling-up property of gray font character lists is utilized here.
+
+@<Output the equivalent of |k| copies of character |v|@>=
+reswitch: if k=1 then typeset(v)
+else begin i:=char_info(gray_font)(v);
+ if char_tag(i)=list_tag then {|v| has a successor}
+ begin if odd(k) then typeset(v);
+ k:=k div 2; v:=qo(rem_byte(i)); goto reswitch;
+ end
+ else repeat typeset(v); decr(k);
+ until k=0;
+ end
+
+@ @<Glob...@>=
+@!a:array[0..widest_row] of 0..4095; {bit patterns for twelve rows}
+
+@ In order to use the approach above, we need to be able to initialize
+array~|a|, and we need to be able to keep it up to date as new rows
+scroll by. A moment's thought about the problem reveals that we will either
+have to read an entire character from the \.{GF} file into memory,
+or we'll need to adopt a coroutine-like approach: A single \\{skip}
+command in the \.{GF} file might need to be processed in pieces, since
+it might generate more rows of zeroes than we are ready to absorb
+all at once into~|a|.
+
+The coroutine method actually turns out to be quite simple, so we shall
+introduce a global variable |blank_rows|, which tells how many rows of
+blanks should be generated before we read the \.{GF} instructions
+for another row.
+
+@<Glob...@>=
+@!blank_rows:integer;
+ {rows of blanks carried over from a previous \.{GF} command}
+
+@ Initialization and updating of~|a| can now be handled as follows,
+if we introduce another variable~|l| that is set initially to~1:
+
+@<Add more rows to |a|, until 12-bit entries are obtained@>=
+repeat @<Put the bits for the next row, times |l|, into |a|@>;
+l:=l+l; decr(y);
+until l=4096;
+
+@ As before, |cur_gf| will contain the first \.{GF} command that has
+not yet been interpreted.
+
+@<Put the bits...@>=
+if blank_rows>0 then decr(blank_rows)
+else if cur_gf<>eoc then
+ begin x:=z;
+ if starting_col>x then starting_col:=x;
+ @<Read and process \.{GF} commands until coming to the end of this row@>;
+ end;
+
+@ @d do_skip==z:=0; paint_black:=false
+@d end_with(#)==begin #; cur_gf:=get_byte; goto done1;@+end
+@d five_cases(#)==#,#+1,#+2,#+3,#+4
+@d eight_cases(#)==#,#+1,#+2,#+3,#+4,#+5,#+6,#+7
+@d thirty_two_cases(#)==eight_cases(#),eight_cases(#+8),
+ eight_cases(#+16), eight_cases(#+24)
+@d sixty_four_cases(#)==thirty_two_cases(#), thirty_two_cases(#+32)
+
+@<Read and process...@>=
+loop @+begin continue: case cur_gf of
+ sixty_four_cases(0): k:=cur_gf;
+ paint1:k:=get_byte;
+ paint2:k:=get_two_bytes;
+ paint3:k:=get_three_bytes;
+ eoc:goto done1;
+ skip0:end_with(blank_rows:=0; do_skip);
+ skip1:end_with(blank_rows:=get_byte; do_skip);
+ skip2:end_with(blank_rows:=get_two_bytes; do_skip);
+ skip3:end_with(blank_rows:=get_three_bytes; do_skip);
+ sixty_four_cases(new_row_0),sixty_four_cases(new_row_0+64),
+ thirty_two_cases(new_row_0+128),five_cases(new_row_0+160):
+ end_with(z:=cur_gf-new_row_0;paint_black:=true);
+ xxx1,xxx2,xxx3,xxx4,yyy,no_op:begin skip_nop; goto continue;
+ end;
+ othercases bad_gf('Improper opcode')
+ endcases;@/
+ @<Paint |k| bits and read another command@>;
+ end;
+done1:
+
+@ @<Paint |k| bits and read another command@>=
+if x+k>finishing_col then finishing_col:=x+k;
+if paint_black then for j:=x to x+k-1 do a[j]:=a[j]+l;
+paint_black:=not paint_black;
+x:=x+k;
+cur_gf:=get_byte
+
+@ When the current row has been typeset, all entries of |a| will be even;
+we want to divide them by~2 and incorporate a new row with $l=2^{11}$.
+However, if they are all multiples of~4, we actually want to divide by~4
+and incorporate two new rows, with $l=2^{10}$ and $l=2^{11}$. In general,
+we want to divide by the maximum possible power of~2 and add the corresponding
+number of new rows; that's where the |rho|~array comes in handy:
+
+@<Advance to the next row that needs to be typeset;
+ or |return|, if we're all done@>=
+l:=rho[a[starting_col]];
+for j:=starting_col+1 to finishing_col do if l>rho[a[j]] then l:=rho[a[j]];
+if l=4096 then
+ if cur_gf=eoc then return
+ else begin y:=y-blank_rows; blank_rows:=0; l:=1;
+ starting_col:=z; finishing_col:=z;
+ end
+else begin while a[starting_col]=0 do incr(starting_col);
+ while a[finishing_col]=0 do decr(finishing_col);
+ for j:=starting_col to finishing_col do a[j]:=a[j] div l;
+ l:=4096 div l;
+ end
+
+@ We now have constructed the major components of the necessary routine;
+it simply remains to glue them all together in the proper framework.
+
+@p procedure do_pixels;
+label done,done1,reswitch,continue,exit;
+var @!paint_black:boolean; {the paint switch}
+@!starting_col,@!finishing_col:0..widest_row; {currently nonzero area}
+@!j:0..widest_row; {for traversing that area}
+@!l:integer; {power of two used to manipulate bit patterns}
+@!i:four_quarters; {character information word}
+@!v:eight_bits; {character corresponding to a pixel pattern}
+begin select_font(gray_font);
+delta_x:=delta_x+round(unsc_x_ratio*min_x);
+for j:=0 to max_x-min_x do a[j]:=0;
+l:=1; z:=0; starting_col:=0; finishing_col:=0; y:=max_y+12; paint_black:=false;
+blank_rows:=0; cur_gf:=get_byte;
+loop@+ begin @<Add more rows...@>;
+ dvi_goto(0,delta_y-round(unsc_y_ratio*y)); @<Typeset the pixels...@>;
+ dvi_out(pop); @<Advance to the next...@>;
+ end;
+exit:end;
+
+@* The main program.
+Now we are ready to put it all together. This is where \.{GFtoDVI} starts,
+and where it ends.
+
+@p begin initialize; {get all variables initialized}
+@<Initialize the strings@>;
+start_gf; {open the input and output files}
+@<Process the preamble@>;
+cur_gf:=get_byte; init_str_ptr:=str_ptr;
+loop@+ begin @<Initialize variables for the next character@>;
+ while (cur_gf>=xxx1)and(cur_gf<=no_op) do @<Process a no-op command@>;
+ if cur_gf=post then @<Finish the \.{DVI} file and |goto final_end|@>;
+ if cur_gf<>boc then if cur_gf<>boc1 then abort('Missing boc!');
+@.Missing boc@>
+ @<Process a character@>;
+ cur_gf:=get_byte; str_ptr:=init_str_ptr; pool_ptr:=str_start[str_ptr];
+ end;
+final_end:end.
+
+@ The main program needs a few global variables in order to do its work.
+
+@<Glob...@>=
+@!k,@!m,@!p,@!q,@!r,@!s,@!t,@!dx,@!dy:integer; {general purpose registers}
+@!time_stamp:str_number; {the date and time when the input file was made}
+@!use_logo:boolean; {should \MF's logo be put on the title line?}
+
+@ \MF\ sets the opening string to 32 bytes that give date and time as follows:
+$$\hbox{|' METAFONT output yyyy.mm.dd:tttt'|}$$
+We copy this to the \.{DVI} file, but remove the `\.{METAFONT}' part so that
+it can be replaced by its proper logo.
+
+@<Process the preamble@>=
+if get_byte<>pre then bad_gf('No preamble');
+@.No preamble@>
+if get_byte<>gf_id_byte then bad_gf('Wrong ID');
+@.Wrong ID@>
+k:=get_byte; {|k| is the length of the initial string to be copied}
+for m:=1 to k do append_char(get_byte);
+dvi_out(pre); dvi_out(dvi_id_byte); {output the preamble}
+dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp}
+dvi_four(1000); {magnification factor}
+dvi_out(k); use_logo:=false; s:=str_start[str_ptr];
+for m:=1 to k do dvi_out(str_pool[s+m-1]);
+if str_pool[s]=" " then
+ if str_pool[s+1]="M" then
+ if str_pool[s+2]="E" then
+ if str_pool[s+3]="T" then
+ if str_pool[s+4]="A" then
+ if str_pool[s+5]="F" then
+ if str_pool[s+6]="O" then
+ if str_pool[s+7]="N" then
+ if str_pool[s+8]="T" then
+ begin incr(str_ptr); str_start[str_ptr]:=s+9; use_logo:=true;
+ end; {we will substitute `\MF' for \.{METAFONT}}
+time_stamp:=make_string
+
+@* System-dependent changes.
+This section should be replaced, if necessary, by changes to the program
+that are necessary to make \.{GFtoDVI} work at a particular installation.
+It is usually best to design your change file so that all changes to
+previous sections preserve the section numbering; then everybody's version
+will be consistent with the printed program. More extensive changes,
+which introduce new sections, can be inserted here; then only the index
+itself will get a new section number.
+@^system dependencies@>
+
+@* Index.
+Here is a list of the section numbers where each identifier is used.
+Cross references to error messages and a few other tidbits of information
+also appear.