diff options
author | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
---|---|---|
committer | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
commit | c6101f91d071883b48b1b4b51e5eba0f36d9a78d (patch) | |
tree | 1bf7f5a881d7a4f5c5bf59d0b2821943dd822372 /Build/source/texk/web2c/gftodvi.web | |
parent | 07ee7222e389b0777456b427a55c22d0e6ffd267 (diff) |
French translation for tlmgr updated
git-svn-id: svn://tug.org/texlive/trunk@57912 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/gftodvi.web')
-rw-r--r-- | Build/source/texk/web2c/gftodvi.web | 4393 |
1 files changed, 0 insertions, 4393 deletions
diff --git a/Build/source/texk/web2c/gftodvi.web b/Build/source/texk/web2c/gftodvi.web deleted file mode 100644 index 9fb263a7e35..00000000000 --- a/Build/source/texk/web2c/gftodvi.web +++ /dev/null @@ -1,4393 +0,0 @@ -% 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. |