modernc.org/knuth@v0.0.4/web/testdata/ctan.org/tex-archive/systems/knuth/dist/mfware/gftype.web (about)

     1  % This program by D. R. Fuchs is not copyrighted and can be used freely.
     2  % Version 0 was implemented in March 1984, before METAFONT itself was complete.
     3  % Version 1.0 incorporated refinements for the TRAP test (August 1984).
     4  % Version 1.1 fixed a trivial bug in the stated initial y value (August 1984).
     5  % Version 1.2 clarified the pixel coordinates (September 1984).
     6  % Version 2.0 changed over to new GF format (December 1984).
     7  % Version 2.1 changed over to newer GF format (February 1985).
     8  % Version 2.2 changed `family' to `extension' (October 1985).
     9  % Version 3.0 changed the default prompts (April 1989).
    10  % Version 3.1 checked character locators (Breitenlohner, March 1991).
    11  
    12  % Here is TeX material that gets inserted after \input webmac
    13  \def\hang{\hangindent 3em\noindent\ignorespaces}
    14  \def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
    15  \font\ninerm=cmr9
    16  \let\mc=\ninerm % medium caps for names like SAIL
    17  \font\tenss=cmss10 % for `The METAFONTbook'
    18  \def\PASCAL{Pascal}
    19  \def\ph{\hbox{Pascal-H}}
    20  \font\logo=manfnt % font used for the METAFONT logo
    21  \def\MF{{\logo META}\-{\logo FONT}}
    22  \def\<#1>{$\langle#1\rangle$}
    23  \def\section{\mathhexbox278}
    24  \let\swap=\leftrightarrow
    25  \def\round{\mathop{\rm round}\nolimits}
    26  
    27  \def\(#1){} % this is used to make section names sort themselves better
    28  \def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
    29  
    30  \def\title{GFtype}
    31  \def\contentspagenumber{101}
    32  \def\topofcontents{\null
    33    \titlefalse % include headline on the contents page
    34    \def\rheader{\mainfont\hfil \contentspagenumber}
    35    \vfill
    36    \centerline{\titlefont The {\ttitlefont GFtype} processor}
    37    \vskip 15pt
    38    \centerline{(Version 3.1, March 1991)}
    39    \vfill}
    40  \def\botofcontents{\vfill
    41    \centerline{\hsize 5in\baselineskip9pt
    42      \vbox{\ninerm\noindent
    43      The preparation of this report
    44      was supported in part by the National Science
    45      Foundation under grants IST-8201926, MCS-8300984, and
    46      CCR-8610181,
    47      and by the System Development Foundation. `\TeX' is a
    48      trademark of the American Mathematical Society.
    49      `{\logo hijklmnj}\kern1pt' is a trademark of Addison-Wesley
    50      Publishing Company.}}}
    51  \pageno=\contentspagenumber \advance\pageno by 1
    52  
    53  @* Introduction.
    54  The \.{GFtype} utility program reads binary generic-font (``\.{GF}'')
    55  files that are produced by font compilers such as \MF, and converts them
    56  into symbolic form. This program has three chief purposes:
    57  (1)~It can be used to look at the pixels of a font, with one pixel per
    58  character in a text file; (2)~it can be used to
    59  determine whether a \.{GF} file is valid or invalid, when diagnosing
    60  compiler errors; and (3)~it serves as an example of a program that reads
    61  \.{GF} files correctly, for system programmers who are developing
    62  \.{GF}-related software.
    63  
    64  The original version of this program was written by David R. Fuchs in
    65  March, 1984. Donald E. Knuth made a few modifications later that year as
    66  \MF\ was taking shape.
    67  @^Fuchs, David Raymond@>
    68  @^Knuth, Donald Ervin@>
    69  
    70  The |banner| string defined here should be changed whenever \.{GFtype}
    71  gets modified.
    72  
    73  @d banner=='This is GFtype, Version 3.1' {printed when the program starts}
    74  
    75  @ This program is written in standard \PASCAL, except where it is
    76  necessary to use extensions; for example, one extension is to use a
    77  default |case| as in \.{TANGLE}, \.{WEAVE}, etc.  All places where
    78  nonstandard constructions are used have been listed in the index under
    79  ``system dependencies.''
    80  @!@^system dependencies@>
    81  
    82  @d othercases == others: {default for cases not listed explicitly}
    83  @d endcases == @+end {follows the default case in an extended |case| statement}
    84  @f othercases == else
    85  @f endcases == end
    86  
    87  @ The binary input comes from |gf_file|, and the symbolic output is written
    88  on \PASCAL's standard |output| file. The term |print| is used instead of
    89  |write| when this program writes on |output|, so that all such output
    90  could easily be redirected if desired.
    91  
    92  @d print(#)==write(#)
    93  @d print_ln(#)==write_ln(#)
    94  @d print_nl==write_ln
    95  
    96  @p program GF_type(@!gf_file,@!output);
    97  label @<Labels in the outer block@>@/
    98  const @<Constants in the outer block@>@/
    99  type @<Types in the outer block@>@/
   100  var @<Globals in the outer block@>@/
   101  procedure initialize; {this procedure gets things started properly}
   102    var i:integer; {loop index for initializations}
   103    begin print_ln(banner);@/
   104    @<Set initial values@>@/
   105    end;
   106  
   107  @ If the program has to stop prematurely, it goes to the
   108  `|final_end|'.
   109  
   110  @d final_end=9999 {label for the end of it all}
   111  
   112  @<Labels...@>=final_end;
   113  
   114  @ Four parameters can be changed at compile time to extend or
   115  reduce \.{GFtype}'s capacity.
   116  Note that the total number of bits in the main |image_array| will be
   117  $$\hbox{$(|max_row|+1)\;\times\;(|max_col|+1)$}.$$
   118  (\MF's full pixel range is rarely implemented, because it would require
   119  8~megabytes of memory.)
   120  
   121  @<Constants...@>=
   122  @!terminal_line_length=150; {maximum number of characters input in a single
   123    line of input from the terminal}
   124  @!line_length=79; {\\{xxx} strings will not produce lines longer than this}
   125  @!max_row=79; {vertical extent of pixel image array}
   126  @!max_col=79; {horizontal extent of pixel image array}
   127  
   128  @ Here are some macros for common programming idioms.
   129  
   130  @d incr(#) == #:=#+1 {increase a variable by unity}
   131  @d decr(#) == #:=#-1 {decrease a variable by unity}
   132  @d negate(#) == #:=-# {change the sign of a variable}
   133  
   134  @ If the \.{GF} file is badly malformed, the whole process must be aborted;
   135  \.{GFtype} will give up, after issuing an error message about the symptoms
   136  that were noticed.
   137  
   138  Such errors might be discovered inside of subroutines inside of subroutines,
   139  so a procedure called |jump_out| has been introduced. This procedure, which
   140  simply transfers control to the label |final_end| at the end of the program,
   141  contains the only non-local |goto| statement in \.{GFtype}.
   142  @^system dependencies@>
   143  
   144  @d abort(#)==begin print(' ',#); jump_out;
   145      end
   146  @d bad_gf(#)==abort('Bad GF file: ',#,'!')
   147  @.Bad GF file@>
   148  
   149  @p procedure jump_out;
   150  begin goto final_end;
   151  end;
   152  
   153  @* The character set.
   154  Like all programs written with the  \.{WEB} system, \.{GFtype} can be
   155  used with any character set. But it uses ASCII code internally, because
   156  the programming for portable input-output is easier when a fixed internal
   157  code is used.
   158  
   159  The next few sections of \.{GFtype} have therefore been copied from the
   160  analogous ones in the \.{WEB} system routines. They have been considerably
   161  simplified, since \.{GFtype} need not deal with the controversial
   162  ASCII codes less than @'40 or greater than @'176.
   163  If such codes appear in the \.{GF} file,
   164  they will be printed as question marks.
   165  
   166  @<Types...@>=
   167  @!ASCII_code=" ".."~"; {a subrange of the integers}
   168  
   169  @ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
   170  character sets were common, so it did not make provision for lower case
   171  letters. Nowadays, of course, we need to deal with both upper and lower case
   172  alphabets in a convenient way, especially in a program like \.{GFtype}.
   173  So we shall assume that the \PASCAL\ system being used for \.{GFtype}
   174  has a character set containing at least the standard visible characters
   175  of ASCII code (|"!"| through |"~"|).
   176  
   177  Some \PASCAL\ compilers use the original name |char| for the data type
   178  associated with the characters in text files, while other \PASCAL s
   179  consider |char| to be a 64-element subrange of a larger data type that has
   180  some other name.  In order to accommodate this difference, we shall use
   181  the name |text_char| to stand for the data type of the characters in the
   182  output file.  We shall also assume that |text_char| consists of
   183  the elements |chr(first_text_char)| through |chr(last_text_char)|,
   184  inclusive. The following definitions should be adjusted if necessary.
   185  @^system dependencies@>
   186  
   187  @d text_char == char {the data type of characters in text files}
   188  @d first_text_char=0 {ordinal number of the smallest element of |text_char|}
   189  @d last_text_char=127 {ordinal number of the largest element of |text_char|}
   190  
   191  @<Types...@>=
   192  @!text_file=packed file of text_char;
   193  
   194  @ The \.{GFtype} processor converts between ASCII code and
   195  the user's external character set by means of arrays |xord| and |xchr|
   196  that are analogous to \PASCAL's |ord| and |chr| functions.
   197  
   198  @<Globals...@>=
   199  @!xord: array [text_char] of ASCII_code;
   200    {specifies conversion of input characters}
   201  @!xchr: array [0..255] of text_char;
   202    {specifies conversion of output characters}
   203  
   204  @ Under our assumption that the visible characters of standard ASCII are
   205  all present, the following assignment statements initialize the
   206  |xchr| array properly, without needing any system-dependent changes.
   207  
   208  @<Set init...@>=
   209  for i:=0 to @'37 do xchr[i]:='?';
   210  xchr[@'40]:=' ';
   211  xchr[@'41]:='!';
   212  xchr[@'42]:='"';
   213  xchr[@'43]:='#';
   214  xchr[@'44]:='$';
   215  xchr[@'45]:='%';
   216  xchr[@'46]:='&';
   217  xchr[@'47]:='''';@/
   218  xchr[@'50]:='(';
   219  xchr[@'51]:=')';
   220  xchr[@'52]:='*';
   221  xchr[@'53]:='+';
   222  xchr[@'54]:=',';
   223  xchr[@'55]:='-';
   224  xchr[@'56]:='.';
   225  xchr[@'57]:='/';@/
   226  xchr[@'60]:='0';
   227  xchr[@'61]:='1';
   228  xchr[@'62]:='2';
   229  xchr[@'63]:='3';
   230  xchr[@'64]:='4';
   231  xchr[@'65]:='5';
   232  xchr[@'66]:='6';
   233  xchr[@'67]:='7';@/
   234  xchr[@'70]:='8';
   235  xchr[@'71]:='9';
   236  xchr[@'72]:=':';
   237  xchr[@'73]:=';';
   238  xchr[@'74]:='<';
   239  xchr[@'75]:='=';
   240  xchr[@'76]:='>';
   241  xchr[@'77]:='?';@/
   242  xchr[@'100]:='@@';
   243  xchr[@'101]:='A';
   244  xchr[@'102]:='B';
   245  xchr[@'103]:='C';
   246  xchr[@'104]:='D';
   247  xchr[@'105]:='E';
   248  xchr[@'106]:='F';
   249  xchr[@'107]:='G';@/
   250  xchr[@'110]:='H';
   251  xchr[@'111]:='I';
   252  xchr[@'112]:='J';
   253  xchr[@'113]:='K';
   254  xchr[@'114]:='L';
   255  xchr[@'115]:='M';
   256  xchr[@'116]:='N';
   257  xchr[@'117]:='O';@/
   258  xchr[@'120]:='P';
   259  xchr[@'121]:='Q';
   260  xchr[@'122]:='R';
   261  xchr[@'123]:='S';
   262  xchr[@'124]:='T';
   263  xchr[@'125]:='U';
   264  xchr[@'126]:='V';
   265  xchr[@'127]:='W';@/
   266  xchr[@'130]:='X';
   267  xchr[@'131]:='Y';
   268  xchr[@'132]:='Z';
   269  xchr[@'133]:='[';
   270  xchr[@'134]:='\';
   271  xchr[@'135]:=']';
   272  xchr[@'136]:='^';
   273  xchr[@'137]:='_';@/
   274  xchr[@'140]:='`';
   275  xchr[@'141]:='a';
   276  xchr[@'142]:='b';
   277  xchr[@'143]:='c';
   278  xchr[@'144]:='d';
   279  xchr[@'145]:='e';
   280  xchr[@'146]:='f';
   281  xchr[@'147]:='g';@/
   282  xchr[@'150]:='h';
   283  xchr[@'151]:='i';
   284  xchr[@'152]:='j';
   285  xchr[@'153]:='k';
   286  xchr[@'154]:='l';
   287  xchr[@'155]:='m';
   288  xchr[@'156]:='n';
   289  xchr[@'157]:='o';@/
   290  xchr[@'160]:='p';
   291  xchr[@'161]:='q';
   292  xchr[@'162]:='r';
   293  xchr[@'163]:='s';
   294  xchr[@'164]:='t';
   295  xchr[@'165]:='u';
   296  xchr[@'166]:='v';
   297  xchr[@'167]:='w';@/
   298  xchr[@'170]:='x';
   299  xchr[@'171]:='y';
   300  xchr[@'172]:='z';
   301  xchr[@'173]:='{';
   302  xchr[@'174]:='|';
   303  xchr[@'175]:='}';
   304  xchr[@'176]:='~';
   305  for i:=@'177 to 255 do xchr[i]:='?';
   306  
   307  @ The following system-independent code makes the |xord| array contain a
   308  suitable inverse to the information in |xchr|.
   309  
   310  @<Set init...@>=
   311  for i:=first_text_char to last_text_char do xord[chr(i)]:=@'40;
   312  for i:=" " to "~" do xord[xchr[i]]:=i;
   313  
   314  @* Generic font file format.
   315  The most important output produced by a typical run of \MF\ is the
   316  ``generic font'' (\.{GF}) file that specifies the bit patterns of the
   317  characters that have been drawn. The term {\sl generic\/} indicates that
   318  this file format doesn't match the conventions of any name-brand manufacturer;
   319  but it is easy to convert \.{GF} files to the special format required by
   320  almost all digital phototypesetting equipment. There's a strong analogy
   321  between the \.{DVI} files written by \TeX\ and the \.{GF} files written
   322  by \MF; and, in fact, the file formats have a lot in common.
   323  It is therefore not surprising that \.{GFtype} is identical in many
   324  respects to the \.{DVItype} program.
   325  
   326  A \.{GF} file is a stream of 8-bit bytes that may be
   327  regarded as a series of commands in a machine-like language. The first
   328  byte of each command is the operation code, and this code is followed by
   329  zero or more bytes that provide parameters to the command. The parameters
   330  themselves may consist of several consecutive bytes; for example, the
   331  `|boc|' (beginning of character) command has six parameters, each of
   332  which is four bytes long. Parameters are usually regarded as nonnegative
   333  integers; but four-byte-long parameters can be either positive or
   334  negative, hence they range in value from $-2^{31}$ to $2^{31}-1$.
   335  As in \.{TFM} files, numbers that occupy
   336  more than one byte position appear in BigEndian order,
   337  and negative numbers appear in two's complement notation.
   338  
   339  A \.{GF} file consists of a ``preamble,'' followed by a sequence of one or
   340  more ``characters,'' followed by a ``postamble.'' The preamble is simply a
   341  |pre| command, with its parameters that introduce the file; this must come
   342  first.  Each ``character'' consists of a |boc| command, followed by any
   343  number of other commands that specify ``black'' pixels,
   344  followed by an |eoc| command. The characters appear in the order that \MF\
   345  generated them. If we ignore no-op commands (which are allowed between any
   346  two commands in the file), each |eoc| command is immediately followed by a
   347  |boc| command, or by a |post| command; in the latter case, there are no
   348  more characters in the file, and the remaining bytes form the postamble.
   349  Further details about the postamble will be explained later.
   350  
   351  Some parameters in \.{GF} commands are ``pointers.'' These are four-byte
   352  quantities that give the location number of some other byte in the file;
   353  the first file byte is number~0, then comes number~1, and so on.
   354  
   355  @ The \.{GF} format is intended to be both compact and easily interpreted
   356  by a machine. Compactness is achieved by making most of the information
   357  relative instead of absolute. When a \.{GF}-reading program reads the
   358  commands for a character, it keeps track of two quantities: (a)~the current
   359  column number,~|m|; and (b)~the current row number,~|n|.  These are 32-bit
   360  signed integers, although most actual font formats produced from \.{GF}
   361  files will need to curtail this vast range because of practical
   362  limitations. (\MF\ output will never allow $\vert m\vert$ or $\vert
   363  n\vert$ to get extremely large, but the \.{GF} format tries to be more general.)
   364  
   365  How do \.{GF}'s row and column numbers correspond to the conventions
   366  of \TeX\ and \MF? Well, the ``reference point'' of a character, in \TeX's
   367  view, is considered to be at the lower left corner of the pixel in row~0
   368  and column~0. This point is the intersection of the baseline with the left
   369  edge of the type; it corresponds to location $(0,0)$ in \MF\ programs.
   370  Thus the pixel in \.{GF} row~0 and column~0 is \MF's unit square, comprising the
   371  region of the plane whose coordinates both lie between 0 and~1. The
   372  pixel in \.{GF} row~|n| and column~|m| consists of the points whose \MF\
   373  coordinates |(x,y)| satisfy |m<=x<=m+1| and |n<=y<=n+1|.  Negative values of
   374  |m| and~|x| correspond to columns of pixels {\sl left\/} of the reference
   375  point; negative values of |n| and~|y| correspond to rows of pixels {\sl
   376  below\/} the baseline.
   377  
   378  Besides |m| and |n|, there's also a third aspect of the current
   379  state, namely the @!|paint_switch|, which is always either \\{black} or
   380  \\{white}. Each \\{paint} command advances |m| by a specified amount~|d|,
   381  and blackens the intervening pixels if |paint_switch=black|; then
   382  the |paint_switch| changes to the opposite state. \.{GF}'s commands are
   383  designed so that |m| will never decrease within a row, and |n| will never
   384  increase within a character; hence there is no way to whiten a pixel that
   385  has been blackened.
   386  
   387  @ Here is a list of all the commands that may appear in a \.{GF} file. Each
   388  command is specified by its symbolic name (e.g., |boc|), its opcode byte
   389  (e.g., 67), and its parameters (if any). The parameters are followed
   390  by a bracketed number telling how many bytes they occupy; for example,
   391  `|d[2]|' means that parameter |d| is two bytes long.
   392  
   393  \yskip\hang|paint_0| 0. This is a \\{paint} command with |d=0|; it does
   394  nothing but change the |paint_switch| from \\{black} to \\{white} or vice~versa.
   395  
   396  \yskip\hang\\{paint\_1} through \\{paint\_63} (opcodes 1 to 63).
   397  These are \\{paint} commands with |d=1| to~63, defined as follows: If
   398  |paint_switch=black|, blacken |d|~pixels of the current row~|n|,
   399  in columns |m| through |m+d-1| inclusive. Then, in any case,
   400  complement the |paint_switch| and advance |m| by~|d|.
   401  
   402  \yskip\hang|paint1| 64 |d[1]|. This is a \\{paint} command with a specified
   403  value of~|d|; \MF\ uses it to paint when |64<=d<256|.
   404  
   405  \yskip\hang|@!paint2| 65 |d[2]|. Same as |paint1|, but |d|~can be as high
   406  as~65535.
   407  
   408  \yskip\hang|@!paint3| 66 |d[3]|. Same as |paint1|, but |d|~can be as high
   409  as $2^{24}-1$. \MF\ never needs this command, and it is hard to imagine
   410  anybody making practical use of it; surely a more compact encoding will be
   411  desirable when characters can be this large. But the command is there,
   412  anyway, just in case.
   413  
   414  \yskip\hang|boc| 67 |c[4]| |p[4]| |min_m[4]| |max_m[4]| |min_n[4]|
   415  |max_n[4]|. Beginning of a character:  Here |c| is the character code, and
   416  |p| points to the previous character beginning (if any) for characters having
   417  this code number modulo 256.  (The pointer |p| is |-1| if there was no
   418  prior character with an equivalent code.) The values of registers |m| and |n|
   419  defined by the instructions that follow for this character must
   420  satisfy |min_m<=m<=max_m| and |min_n<=n<=max_n|.  (The values of |max_m| and
   421  |min_n| need not be the tightest bounds possible.)  When a \.{GF}-reading
   422  program sees a |boc|, it can use |min_m|, |max_m|, |min_n|, and |max_n| to
   423  initialize the bounds of an array. Then it sets |m:=min_m|, |n:=max_n|, and
   424  |paint_switch:=white|.
   425  
   426  \yskip\hang|boc1| 68 |c[1]| |@!del_m[1]| |max_m[1]| |@!del_n[1]| |max_n[1]|.
   427  Same as |boc|, but |p| is assumed to be~$-1$; also |del_m=max_m-min_m|
   428  and |del_n=max_n-min_n| are given instead of |min_m| and |min_n|.
   429  The one-byte parameters must be between 0 and 255, inclusive.
   430  \ (This abbreviated |boc| saves 19~bytes per character, in common cases.)
   431  
   432  \yskip\hang|eoc| 69. End of character: All pixels blackened so far
   433  constitute the pattern for this character. In particular, a completely
   434  blank character might have |eoc| immediately following |boc|.
   435  
   436  \yskip\hang|skip0| 70. Decrease |n| by 1 and set |m:=min_m|,
   437  |paint_switch:=white|. \ (This finishes one row and begins another,
   438  ready to whiten the leftmost pixel in the new row.)
   439  
   440  \yskip\hang|skip1| 71 |d[1]|. Decrease |n| by |d+1|, set |m:=min_m|, and set
   441  |paint_switch:=white|. This is a way to produce |d| all-white rows.
   442  
   443  \yskip\hang|@!skip2| 72 |d[2]|. Same as |skip1|, but |d| can be as large
   444  as 65535.
   445  
   446  \yskip\hang|@!skip3| 73 |d[3]|. Same as |skip1|, but |d| can be as large
   447  as $2^{24}-1$. \MF\ obviously never needs this command.
   448  
   449  \yskip\hang|new_row_0| 74. Decrease |n| by 1 and set |m:=min_m|,
   450  |paint_switch:=black|. \ (This finishes one row and begins another,
   451  ready to {\sl blacken\/} the leftmost pixel in the new row.)
   452  
   453  \yskip\hang|@!new_row_1| through |@!new_row_164| (opcodes 75 to 238). Same as
   454  |new_row_0|, but with |m:=min_m+1| through |min_m+164|, respectively.
   455  
   456  \yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
   457  general; it functions as a $(k+2)$-byte |no_op| unless special \.{GF}-reading
   458  programs are being used. \MF\ generates \\{xxx} commands when encountering
   459  a \&{special} string; this occurs in the \.{GF} file only between
   460  characters, after the preamble, and before the postamble. However,
   461  \\{xxx} commands might appear within characters,
   462  in \.{GF} files generated by other
   463  processors. It is recommended that |x| be a string having the form of a
   464  keyword followed by possible parameters relevant to that keyword.
   465  
   466  \yskip\hang|@!xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
   467  
   468  \yskip\hang|xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
   469  \MF\ uses this when sending a \&{special} string whose length exceeds~255.
   470  
   471  \yskip\hang|@!xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be
   472  ridiculously large; |k| mustn't be negative.
   473  
   474  \yskip\hang|yyy| 243 |y[4]|. This command is undefined in general;
   475  it functions as a 5-byte |no_op| unless special \.{GF}-reading programs
   476  are being used. \MF\ puts |scaled| numbers into |yyy|'s, as a
   477  result of \&{numspecial} commands; the intent is to provide numeric
   478  parameters to \\{xxx} commands that immediately precede.
   479  
   480  \yskip\hang|no_op| 244. No operation, do nothing. Any number of |no_op|'s
   481  may occur between \.{GF} commands, but a |no_op| cannot be inserted between
   482  a command and its parameters or between two parameters.
   483  
   484  \yskip\hang|char_loc| 245 |c[1]| |dx[4]| |dy[4]| |w[4]| |p[4]|.
   485  This command will appear only in the postamble, which will be explained shortly.
   486  
   487  \yskip\hang|@!char_loc0| 246 |c[1]| |@!dm[1]| |w[4]| |p[4]|.
   488  Same as |char_loc|, except that |dy| is assumed to be zero, and the value
   489  of~|dx| is taken to be |65536*dm|, where |0<=dm<256|.
   490  
   491  \yskip\hang|pre| 247 |i[1]| |k[1]| |x[k]|.
   492  Beginning of the preamble; this must come at the very beginning of the
   493  file. Parameter |i| is an identifying number for \.{GF} format, currently
   494  131. The other information is merely commentary; it is not given
   495  special interpretation like \\{xxx} commands are. (Note that \\{xxx}
   496  commands may immediately follow the preamble, before the first |boc|.)
   497  
   498  \yskip\hang|post| 248. Beginning of the postamble, see below.
   499  
   500  \yskip\hang|post_post| 249. Ending of the postamble, see below.
   501  
   502  \yskip\noindent Commands 250--255 are undefined at the present time.
   503  
   504  @d gf_id_byte=131 {identifies the kind of \.{GF} files described here}
   505  
   506  @ Here are the opcodes that \.{GFtype} actually refers to.
   507  
   508  @d paint_0=0 {beginning of the \\{paint} commands}
   509  @d paint1=64 {move right a given number of columns, then
   510    black${}\swap{}$white}
   511  @d boc=67 {beginning of a character}
   512  @d boc1=68 {abbreviated |boc|}
   513  @d eoc=69 {end of a character}
   514  @d skip0=70 {skip no blank rows}
   515  @d skip1=71 {skip over blank rows}
   516  @d new_row_0=74 {move down one row and then right}
   517  @d xxx1=239 {for \&{special} strings}
   518  @d yyy=243 {for \&{numspecial} numbers}
   519  @d no_op=244 {no operation}
   520  @d char_loc=245 {character locators in the postamble}
   521  @d pre=247 {preamble}
   522  @d post=248 {postamble beginning}
   523  @d post_post=249 {postamble ending}
   524  @d undefined_commands==250,251,252,253,254,255
   525  
   526  @ The last character in a \.{GF} file is followed by `|post|'; this command
   527  introduces the postamble, which summarizes important facts that \MF\ has
   528  accumulated. The postamble has the form
   529  $$\vbox{\halign{\hbox{#\hfil}\cr
   530    |post| |p[4]| |@!ds[4]| |@!cs[4]| |@!hppp[4]| |@!vppp[4]|
   531     |min_m[4]| |max_m[4]| |min_n[4]| |max_n[4]|\cr
   532    $\langle\,$character locators$\,\rangle$\cr
   533    |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
   534  Here |p| is a pointer to the byte following the final |eoc| in the file
   535  (or to the byte following the preamble, if there are no characters);
   536  it can be used to locate the beginning of \\{xxx} commands
   537  that might have preceded the postamble. The |ds| and |cs| parameters
   538  @^design size@> @^check sum@>
   539  give the design size and check sum, respectively, which are exactly the
   540  values put into the header of any \.{TFM} file that shares information with this
   541  \.{GF} file. Parameters |hppp| and |vppp| are the ratios of
   542  pixels per point, horizontally and vertically, expressed as |scaled| integers
   543  (i.e., multiplied by $2^{16}$); they can be used to correlate the font
   544  with specific device resolutions, magnifications, and ``at sizes.''  Then
   545  come |min_m|, |max_m|, |min_n|, and |max_n|, which bound the values that
   546  registers |m| and~|n| assume in all characters in this \.{GF} file.
   547  (These bounds need not be the best possible; |max_m| and |min_n| may, on the
   548  other hand, be tighter than the similar bounds in |boc| commands. For
   549  example, some character may have |min_n=-100| in its |boc|, but it might
   550  turn out that |n| never gets lower than |-50| in any character; then
   551  |min_n| can have any value |<=-50|. If there are no characters in the file,
   552  it's possible to have |min_m>max_m| and/or |min_n>max_n|.)
   553  
   554  @ Character locators are introduced by |char_loc| commands,
   555  which specify a character residue~|c|, character escapements (|dx,dy|),
   556  a character width~|w|, and a pointer~|p|
   557  to the beginning of that character. (If two or more characters have the
   558  same code~|c| modulo 256, only the last will be indicated; the others can be
   559  located by following backpointers. Characters whose codes differ by a
   560  multiple of 256 are assumed to share the same font metric information,
   561  hence the \.{TFM} file contains only residues of character codes modulo~256.
   562  This convention is intended for oriental languages, when there are many
   563  character shapes but few distinct widths.)
   564  @^oriental characters@>@^Chinese characters@>@^Japanese characters@>
   565  
   566  The character escapements (|dx,dy|) are the values of \MF's \&{chardx}
   567  and \&{chardy} parameters; they are in units of |scaled| pixels;
   568  i.e., |dx| is in horizontal pixel units times $2^{16}$, and |dy| is in
   569  vertical pixel units times $2^{16}$.  This is the intended amount of
   570  displacement after typesetting the character; for \.{DVI} files, |dy|
   571  should be zero, but other document file formats allow nonzero vertical
   572  escapement.
   573  
   574  The character width~|w| duplicates the information in the \.{TFM} file; it
   575  is $2^{20}$ times the ratio of the true width to the font's design size.
   576  
   577  The backpointer |p| points to the character's |boc|, or to the first of
   578  a sequence of consecutive \\{xxx} or |yyy| or |no_op| commands that
   579  immediately precede the |boc|, if such commands exist; such ``special''
   580  commands essentially belong to the characters, while the special commands
   581  after the final character belong to the postamble (i.e., to the font
   582  as a whole). This convention about |p| applies also to the backpointers
   583  in |boc| commands, even though it wasn't explained in the description
   584  of~|boc|. @^backpointers@>
   585  
   586  Pointer |p| might be |-1| if the character exists in the \.{TFM} file
   587  but not in the \.{GF} file. This unusual situation can arise in \MF\ output
   588  if the user had |proofing<0| when the character was being shipped out,
   589  but then made |proofing>=0| in order to get a \.{GF} file.
   590  
   591  @ The last part of the postamble, following the |post_post| byte that
   592  signifies the end of the character locators, contains |q|, a pointer to the
   593  |post| command that started the postamble.  An identification byte, |i|,
   594  comes next; this currently equals~131, as in the preamble.
   595  
   596  The |i| byte is followed by four or more bytes that are all equal to
   597  the decimal number 223 (i.e., @"DF in hexadecimal).
   598  @^Fuchs, David Raymond@>
   599  \MF\ puts out four to seven of
   600  these trailing bytes, until the total length of the file is a multiple of
   601  four bytes, since this works out best on machines that pack four bytes per
   602  word; but any number of 223's is allowed, as long as there are at least four
   603  of them. In effect, 223 is a sort of signature that is added at the very end.
   604  
   605  This curious way to finish off a \.{GF} file makes it feasible for
   606  \.{GF}-reading programs to find the postamble first, on most computers,
   607  even though \MF\ wants to write the postamble last. Most operating
   608  systems permit random access to individual words or bytes of a file, so
   609  the \.{GF} reader can start at the end and skip backwards over the 223's
   610  until finding the identification byte. Then it can back up four bytes, read
   611  |q|, and move to byte |q| of the file. This byte should, of course,
   612  contain the value 248 (|post|); now the postamble can be read, so the
   613  \.{GF} reader can discover all the information needed for individual characters.
   614  
   615  Unfortunately, however, standard \PASCAL\ does not include the ability to
   616  @^system dependencies@>
   617  access a random position in a file, or even to determine the length of a file.
   618  Almost all systems nowadays provide the necessary capabilities, so \.{GF}
   619  format has been designed to work most efficiently with modern operating systems.
   620  But if \.{GF} files have to be processed under the restrictions of standard
   621  \PASCAL, one can simply read them from front to back. This will
   622  be adequate for most applications. However, the postamble-first approach
   623  would facilitate a program that merges two \.{GF} files, replacing data
   624  from one that is overridden by corresponding data in the other.
   625  
   626  @* Input from binary files.
   627  We have seen that a \.{GF} file is a sequence of 8-bit bytes. The bytes
   628  appear physically in what is called a `|packed file of 0..255|'
   629  in \PASCAL\ lingo.
   630  
   631  Packing is system dependent, and many \PASCAL\ systems fail to implement
   632  such files in a sensible way (at least, from the viewpoint of producing
   633  good production software).  For example, some systems treat all
   634  byte-oriented files as text, looking for end-of-line marks and such
   635  things. Therefore some system-dependent code is often needed to deal with
   636  binary files, even though most of the program in this section of
   637  \.{GFtype} is written in standard \PASCAL.
   638  @^system dependencies@>
   639  
   640  We shall stick to simple \PASCAL\ in this program, for reasons of clarity,
   641  even if such simplicity is sometimes unrealistic.
   642  
   643  @<Types...@>=
   644  @!eight_bits=0..255; {unsigned one-byte quantity}
   645  @!byte_file=packed file of eight_bits; {files that contain binary data}
   646  
   647  @ The program deals with one binary file variable: |gf_file| is the main
   648  input file that we are translating into symbolic form.
   649  
   650  @<Glob...@>=
   651  @!gf_file:byte_file; {the stuff we are \.{GF}typing}
   652  
   653  @ To prepare this file for input, we |reset| it.
   654  
   655  @p procedure open_gf_file; {prepares to read packed bytes in |gf_file|}
   656  begin reset(gf_file);
   657  cur_loc:=0;
   658  end;
   659  
   660  @ If you looked carefully at the preceding code, you probably asked,
   661  ``What is |cur_loc|?'' Good question. It's a global variable that holds
   662  the number of the byte about to be read next from |gf_file|.
   663  
   664  @<Glob...@>=
   665  @!cur_loc:integer; {where we are about to look, in |gf_file|}
   666  
   667  @ We shall use a set of simple functions to read the next byte or
   668  bytes from |gf_file|. There are four possibilities, each of which is
   669  treated as a separate function in order to minimize the overhead for
   670  subroutine calls.
   671  @^system dependencies@>
   672  
   673  @p function get_byte:integer; {returns the next byte, unsigned}
   674  var b:eight_bits;
   675  begin if eof(gf_file) then get_byte:=0
   676  else  begin read(gf_file,b); incr(cur_loc); get_byte:=b;
   677    end;
   678  end;
   679  @#
   680  function get_two_bytes:integer; {returns the next two bytes, unsigned}
   681  var a,@!b:eight_bits;
   682  begin read(gf_file,a); read(gf_file,b);
   683  cur_loc:=cur_loc+2;
   684  get_two_bytes:=a*256+b;
   685  end;
   686  @#
   687  function get_three_bytes:integer; {returns the next three bytes, unsigned}
   688  var a,@!b,@!c:eight_bits;
   689  begin read(gf_file,a); read(gf_file,b); read(gf_file,c);
   690  cur_loc:=cur_loc+3;
   691  get_three_bytes:=(a*256+b)*256+c;
   692  end;
   693  @#
   694  function signed_quad:integer; {returns the next four bytes, signed}
   695  var a,@!b,@!c,@!d:eight_bits;
   696  begin read(gf_file,a); read(gf_file,b); read(gf_file,c); read(gf_file,d);
   697  cur_loc:=cur_loc+4;
   698  if a<128 then signed_quad:=((a*256+b)*256+c)*256+d
   699  else signed_quad:=(((a-256)*256+b)*256+c)*256+d;
   700  end;
   701  
   702  @* Optional modes of output.
   703  \.{GFtype} will print different quantities of information based on some
   704  options that the user must specify: We set |wants_mnemonics| if the
   705  user wants to see a mnemonic dump of the \.{GF} file; and we set
   706  |wants_pixels| if the user wants to see a pixel image of each
   707  character.
   708  
   709  When \.{GFtype} begins, it engages the user in a brief dialog so that the
   710  options will be specified. This part of \.{GFtype} requires nonstandard
   711  \PASCAL\ constructions to handle the online interaction; so it may be
   712  preferable in some cases to omit the dialog and simply to produce the maximum
   713  possible output (|wants_mnemonics=wants_pixels=true|). On other hand, the
   714  necessary system-dependent routines are not complicated, so they can be
   715  introduced without terrible trauma.
   716  @^system dependencies@>
   717  
   718  @<Glob...@>=
   719  @!wants_mnemonics: boolean; {controls mnemonic output}
   720  @!wants_pixels: boolean; {controls pixel output}
   721  
   722  @ @<Set init...@>=
   723  wants_mnemonics:=true; wants_pixels:=true;
   724  
   725  @ The |input_ln| routine waits for the user to type a line at his or her
   726  terminal; then it puts ASCII-code equivalents for the characters on that line
   727  into the |buffer| array. The |term_in| file is used for terminal input,
   728  and |term_out| for terminal output.
   729  @^system dependencies@>
   730  
   731  @<Glob...@>=
   732  @!buffer:array[0..terminal_line_length] of ASCII_code;
   733  @!term_in:text_file; {the terminal, considered as an input file}
   734  @!term_out:text_file; {the terminal, considered as an output file}
   735  
   736  @ Since the terminal is being used for both input and output, some systems
   737  need a special routine to make sure that the user can see a prompt message
   738  before waiting for input based on that message. (Otherwise the message
   739  may just be sitting in a hidden buffer somewhere, and the user will have
   740  no idea what the program is waiting for.) We shall invoke a system-dependent
   741  subroutine |update_terminal| in order to avoid this problem.
   742  @^system dependencies@>
   743  
   744  @d update_terminal == break(term_out) {empty the terminal output buffer}
   745  
   746  @ During the dialog, extensions of \.{GFtype} might treat the first blank
   747  space in a line as the end of that line. Therefore |input_ln| makes sure
   748  that there is always at least one blank space in |buffer|.
   749  
   750  (This routine is more complex than the present implementation needs, but
   751  it has been copied from \.{DVItype} so that system-dependent changes that
   752  worked before will work again.)
   753  @^system dependencies@>
   754  
   755  @p procedure input_ln; {inputs a line from the terminal}
   756  var k:0..terminal_line_length;
   757  begin update_terminal; reset(term_in);
   758  if eoln(term_in) then read_ln(term_in);
   759  k:=0;
   760  while (k<terminal_line_length)and not eoln(term_in) do
   761    begin buffer[k]:=xord[term_in^]; incr(k); get(term_in);
   762    end;
   763  buffer[k]:=" ";
   764  end;
   765  
   766  @ This is humdrum.
   767  
   768  @p function lower_casify(@!c:ASCII_code):ASCII_code;
   769  begin
   770  if (c>="A") and (c<="Z") then lower_casify:=c+"a"-"A"
   771  else lower_casify:=c;
   772  end;
   773  
   774  @ The selected options are put into global variables by the |dialog|
   775  procedure, which is called just as \.{GFtype} begins.
   776  @^system dependencies@>
   777  
   778  @p procedure dialog;
   779  label 1,2;
   780  begin rewrite(term_out); {prepare the terminal for output}
   781  write_ln(term_out,banner);@/
   782  @<Determine whether the user |wants_mnemonics|@>;
   783  @<Determine whether the user |wants_pixels|@>;
   784  @<Print all the selected options@>;
   785  end;
   786  
   787  @ @<Determine whether the user |wants_mnemonics|@>=
   788  1: write(term_out,'Mnemonic output? (default=no, ? for help): ');
   789  @.Mnemonic output?@>
   790  input_ln;
   791  buffer[0]:=lower_casify(buffer[0]);
   792  if buffer[0]<>"?" then
   793    wants_mnemonics:=(buffer[0]="y")or(buffer[0]="1")or(buffer[0]="t")
   794  else  begin write(term_out,'Type Y for complete listing,');
   795    write_ln(term_out,' N for errors/images only.');
   796    goto 1;
   797    end
   798  
   799  @ @<Determine whether the user |wants_pixels|@>=
   800  2: write(term_out,'Pixel output? (default=yes, ? for help): ');
   801  @.Pixel output?@>
   802  input_ln;
   803  buffer[0]:=lower_casify(buffer[0]);
   804  if buffer[0]<>"?" then
   805    wants_pixels:=(buffer[0]="y")or(buffer[0]="1")or(buffer[0]="t")
   806      or(buffer[0]=" ")
   807  else  begin write(term_out,'Type Y to list characters pictorially');
   808    write_ln(term_out,' with *''s, N to omit this option.');
   809    goto 2;
   810    end
   811  
   812  @ After the dialog is over, we print the options so that the user
   813  can see what \.{GFtype} thought was specified.
   814  
   815  @<Print all the selected options@>=
   816  print('Options selected: Mnemonic output = ');
   817  @.Options selected@>
   818  if wants_mnemonics then print('true')@+else print('false');
   819  print('; pixel output = ');
   820  if wants_pixels then print('true')@+else print('false');
   821  print_ln('.')
   822  
   823  @* The image array.
   824  The definition of \.{GF} files refers to two registers,
   825  |m| and~|n|, which hold integer column and row numbers. We actually
   826  keep the values $m'=m-|min_m|$ and $n'=|max_n|-n$ instead, so that
   827  our internal image array always has |m,n>=0|. We also
   828  need to remember |paint_switch|, whose value is either |black|
   829  or |white|.
   830  
   831  @<Glob...@>=
   832  @!m,@!n:integer; {current state values, modified by |min_m| and |max_n|}
   833  @!paint_switch: pixel;
   834  
   835  @ We'll need a big array of pixels to hold the character image.  Each
   836  pixel should be represented as a single bit in order to save space.
   837  Some systems may prefer the following definitions, while others
   838  may do better using the |boolean| type and boolean constants.
   839  @^system dependencies@>
   840  
   841  @d white=0 {could also be |false|}
   842  @d black=1 {could also be |true|}
   843  
   844  @<Types...@>=
   845  @!pixel=white..black; {could also be |boolean|}
   846  
   847  @ In order to allow different systems to change the |image| array easily from
   848  row-major order to column-major order (or vice versa), or to transpose it top
   849  and bottom or left and right, we declare and access it as follows.
   850  @^system dependencies@>
   851  
   852  @d image==image_array[m,n]
   853  
   854  @<Glob...@>=
   855  @!image_array: packed array [0..max_col,0..max_row] of pixel;
   856  
   857  @ A |boc| command has parameters |min_m|, |max_m|, |min_n|, and |max_n|
   858  that define a rectangular subarray in which the pixels of the current
   859  character must lie. The program here computes limits on \.{GFtype}'s
   860  modified |m| and |n| variables, and clears the resulting subarray
   861  to all |white|.
   862  
   863  (There may be a faster way to clear a subarray on particular systems,
   864  using nonstandard extensions of \PASCAL.)
   865  @^system dependencies@>
   866  
   867  @<Clear the image@>=
   868  begin max_subcol:=max_m_stated-min_m_stated-1;
   869  if max_subcol>max_col then max_subcol:=max_col;
   870  max_subrow:=max_n_stated-min_n_stated;
   871  if max_subrow>max_row then max_subrow:=max_row;
   872  n:=0;
   873  while n<=max_subrow do
   874    begin m:=0;
   875    while m<=max_subcol do
   876      begin image:=white; incr(m);
   877      end;
   878    incr(n);
   879    end;
   880  end
   881  
   882  @ @<Glob...@>=
   883  @!max_subrow,@!max_subcol:integer; {size of current subarray of interest}
   884  
   885  @ As we paint the pixels of a character, we will record its actual
   886  boundaries in variables |max_m_observed| and |max_n_observed|.
   887  Then the following routine will be called on to output the image,
   888  using blanks for |white| and asterisks for |black|. Blanks are
   889  emitted only when they are followed by nonblanks, in order to conserve
   890  space in the output. Further compaction could be achieved on many
   891  systems by using tab marks.
   892  @^system dependencies@>
   893  
   894  An integer variable |b| will be declared for use in counting blanks.
   895  
   896  @<Print the image@>=
   897  begin @<Compare the subarray boundaries with the observed boundaries@>;
   898  if max_subcol>=0 then {there was at least one \\{paint} command}
   899    @<Print asterisk patterns for rows 0 to |max_subrow|@>
   900  else print_ln('(The character is entirely blank.)');
   901  end
   902  
   903  @ @<Glob...@>=
   904  @!min_m_stated, @!max_m_stated, @!min_n_stated, @!max_n_stated: integer;
   905    {bounds stated in the \.{GF} file}
   906  @!max_m_observed,@!max_n_observed: integer;
   907    {bounds on $(m',n')$ actually observed when painting}
   908  @!min_m_overall, @!max_m_overall, @!min_n_overall, @!max_n_overall: integer;
   909    {bounds observed in the entire file so far}
   910  
   911  @ If the given character is substantially smaller than the |boc|
   912  command predicted, we don't want to bother to output rows and columns
   913  that are all blank.
   914  
   915  @<Compare the subarray boundaries with the observed boundaries@>=
   916  if (max_m_observed>max_col)or(max_n_observed>max_row) then
   917    print_ln('(The character is too large to be displayed in full.)');
   918  @.The character is too large...@>
   919  if max_subcol>max_m_observed then max_subcol:=max_m_observed;
   920  if max_subrow>max_n_observed then max_subrow:=max_n_observed;
   921  
   922  @ @<Print asterisk patterns...@>=
   923  begin print_ln('.<--This pixel''s lower left corner is at (',
   924    min_m_stated:1,',',max_n_stated+1:1,') in METAFONT coordinates');
   925  @.This pixel's lower...@>
   926  n:=0;
   927  while n<=max_subrow do
   928    begin m:=0; b:=0;
   929    while m<=max_subcol do
   930      begin if image=white then incr(b)
   931      else  begin while b>0 do
   932          begin print(' '); decr(b);
   933          end;
   934        print('*');
   935        end;
   936      incr(m);
   937      end;
   938    print_nl; incr(n);
   939    end;
   940  print_ln('.<--This pixel''s upper left corner is at (',
   941    min_m_stated:1,',',max_n_stated-max_subrow:1,
   942    ') in METAFONT coordinates');
   943  @.This pixel's upper@>
   944  end
   945  
   946  @* Translation to symbolic form.
   947  The main work of \.{GFtype} is accomplished by the |do_char| procedure,
   948  which produces the output for an entire character, assuming that the |boc|
   949  command for that character has already been processed. This procedure is
   950  essentially an interpretive routine that reads and acts on the \.{GF}
   951  commands.
   952  
   953  @ We steal the following routine from \MF.
   954  
   955  @d unity == @'200000 {$2^{16}$, represents 1.00000}
   956  
   957  @p procedure print_scaled(@!s:integer);
   958    {prints a scaled number, rounded to five digits}
   959  var @!delta:integer; {amount of allowable inaccuracy}
   960  begin if s<0 then
   961    begin print('-'); negate(s); {print the sign, if negative}
   962    end;
   963  print(s div unity:1); {print the integer part}
   964  s:=10*(s mod unity)+5;
   965  if s<>5 then
   966    begin delta:=10; print('.');
   967    repeat if delta>unity then
   968      s:=s+@'100000-(delta div 2); {round the final digit}
   969    print(chr(ord('0')+(s div unity))); s:=10*(s mod unity); delta:=delta*10;
   970    until s<=delta;
   971    end;
   972  end;
   973  
   974  @ Let's keep track of how many characters are in the font, and the
   975  locations of where each one occurred in the file.
   976  
   977  @<Glob...@>=
   978  @!total_chars:integer; {the total number of characters seen so far}
   979  @!char_ptr: array[0..255] of integer; {correct character location pointer}
   980  @!gf_prev_ptr: integer; {|char_ptr| for next character}
   981  @!character_code: integer; {current character number}
   982  
   983  @ @<Set init...@>=
   984  for i:=0 to 255 do char_ptr[i]:=-1; {mark characters as not being in the file}
   985  total_chars:=0;
   986  
   987  @ Before we get into the details of |do_char|, it is convenient to
   988  consider a simpler routine that computes the first parameter of each
   989  opcode.
   990  
   991  @d four_cases(#)==#,#+1,#+2,#+3
   992  @d eight_cases(#)==four_cases(#),four_cases(#+4)
   993  @d sixteen_cases(#)==eight_cases(#),eight_cases(#+8)
   994  @d thirty_two_cases(#)==sixteen_cases(#),sixteen_cases(#+16)
   995  @d thirty_seven_cases(#)==thirty_two_cases(#),four_cases(#+32),#+36
   996  @d sixty_four_cases(#)==thirty_two_cases(#),thirty_two_cases(#+32)
   997  
   998  @p function first_par(o:eight_bits):integer;
   999  begin case o of
  1000  sixty_four_cases(paint_0): first_par:=o-paint_0;
  1001  paint1,skip1,char_loc,char_loc+1,xxx1: first_par:=get_byte;
  1002  paint1+1,skip1+1,xxx1+1: first_par:=get_two_bytes;
  1003  paint1+2,skip1+2,xxx1+2: first_par:=get_three_bytes;
  1004  xxx1+3,yyy: first_par:=signed_quad;
  1005  boc,boc1,eoc,skip0,no_op,pre,post,post_post,undefined_commands: first_par:=0;
  1006  sixty_four_cases(new_row_0), sixty_four_cases(new_row_0+64),
  1007    thirty_seven_cases(new_row_0+128): first_par:=o-new_row_0;
  1008  end;
  1009  end;
  1010  
  1011  @ Strictly speaking, the |do_char| procedure is really a function with
  1012  side effects, not a `\&{procedure}'\thinspace; it returns the value |false|
  1013  if \.{GFtype} should be aborted because of some unusual happening. The
  1014  subroutine is organized as a typical interpreter, with a multiway branch
  1015  on the command code.
  1016  
  1017  @p function do_char:boolean;
  1018  label 9998,9999;
  1019  var o:eight_bits; {operation code of the current command}
  1020  @!p,@!q:integer; {parameters of the current command}
  1021  @!aok:boolean; {the value to return}
  1022  begin {we've already scanned the |boc|}
  1023  aok:=true;
  1024  while true do @<Translate the next command in the \.{GF} file;
  1025      |goto 9999| if it was |eoc|;
  1026      |goto 9998| if premature termination is needed@>;
  1027  9998: print_ln('!'); aok:=false;
  1028  9999: do_char:=aok;
  1029  end;
  1030  
  1031  @ @d show_label(#)==print(a:1,': ',#)
  1032  @d show_mnemonic(#)==if wants_mnemonics then begin print_nl; show_label(#); end
  1033  @d error(#)==begin show_label('! ',#); print_nl; end
  1034  @d nl_error(#)==begin print_nl; show_label('! ',#); print_nl; end
  1035  @d start_op==a:=cur_loc; o:=get_byte; p:=first_par(o);
  1036    if eof(gf_file) then bad_gf('the file ended prematurely')
  1037  @.the file ended prematurely@>
  1038  
  1039  @<Translate the next command...@>=
  1040  begin start_op;
  1041  @<Start translation of command |o| and |goto| the appropriate label to
  1042    finish the job@>;
  1043  end
  1044  
  1045  @ The multiway switch in |first_par|, above, was organized by the length
  1046  of each command; the one in |do_char| is organized by the semantics.
  1047  
  1048  @<Start translation...@>=
  1049  if o<=paint1+3 then @<Translate a sequence of |paint| commands,
  1050    until reaching a non-|paint|@>;
  1051  case o of
  1052  four_cases(skip0): @<Translate a |skip| command@>;
  1053  sixty_four_cases(new_row_0), sixty_four_cases(new_row_0+64),
  1054   thirty_seven_cases(new_row_0+128):
  1055    @<Translate a |new_row| command@>;
  1056  @t\4@>@<Cases for commands |no_op|, |pre|, |post|, |post_post|, |boc|,
  1057    and |eoc|@>@;
  1058  four_cases(xxx1): @<Translate an |xxx| command@>;
  1059  yyy: @<Translate a |yyy| command@>;
  1060  othercases error('undefined command ',o:1,'!')
  1061  @.undefined command@>
  1062  endcases
  1063  
  1064  @ @<Cases for commands |no_op|...@>=
  1065  no_op: show_mnemonic('no op');
  1066  pre: begin error('preamble command within a character!'); goto 9998;
  1067    end;
  1068  @.preamble command within...@>
  1069  post,post_post: begin error('postamble command within a character!');
  1070  @.postamble command within...@>
  1071    goto 9998;
  1072    end;
  1073  boc,boc1: begin error('boc occurred before eoc!'); goto 9998;
  1074  @.boc occurred before eoc@>
  1075    end;
  1076  eoc: begin show_mnemonic('eoc');
  1077    print_nl; goto 9999;
  1078    end;
  1079  
  1080  @ @<Translate an |xxx| command@>=
  1081  begin show_mnemonic('xxx '''); bad_char:=false; b:=16;
  1082  if p<0 then nl_error('string of negative length!');
  1083  @.string of negative length@>
  1084  while p>0 do
  1085    begin q:=get_byte;
  1086    if (q<" ")or(q>"~") then bad_char:=true;
  1087    if wants_mnemonics then
  1088      begin print(xchr[q]);
  1089      if b<line_length then incr(b)
  1090      else  begin print_nl; b:=2;
  1091        end;
  1092      end;
  1093    decr(p);
  1094    end;
  1095  if wants_mnemonics then print('''');
  1096  if bad_char then nl_error('non-ASCII character in xxx command!');
  1097  @.non-ASCII character...@>
  1098  end
  1099  
  1100  @ @<Glob...@>=
  1101  @!bad_char:boolean; {has a non-ASCII character code appeared in this \\{xxx}?}
  1102  
  1103  @ @<Translate a |yyy| command@>=
  1104  begin show_mnemonic('yyy ',p:1,' (');
  1105  if wants_mnemonics then
  1106    begin print_scaled(p); print(')');
  1107    end;
  1108  end
  1109  
  1110  @ The bulk of a \.{GF} file generally consists of |paint| commands,
  1111  so we collect them together and print them in an abbreviated format
  1112  on one line.
  1113  
  1114  @<Translate a sequence of |paint| commands...@>=
  1115  begin if wants_mnemonics then print(' paint ');
  1116  repeat @<Paint the next |p| pixels@>;
  1117  start_op;
  1118  until o>paint1+3;
  1119  end
  1120  
  1121  @ @<Paint the next...@>=
  1122  if wants_mnemonics then
  1123    if paint_switch=white then print('(',p:1,')')@+else print(p:1);
  1124  m:=m+p;
  1125  if m>max_m_observed then max_m_observed:=m-1;
  1126  if wants_pixels then
  1127    @<Paint pixels |m-p| through |m-1| in row |n| of the subarray@>;
  1128  paint_switch:=white+black-paint_switch
  1129    {could also be |paint_switch:=not paint_switch|}
  1130  
  1131  @ We use the fact that the subarray has been initialized to all |white|.
  1132  
  1133  @<Paint pixels |m-p|...@>=
  1134  if paint_switch=black then if n<=max_subrow then
  1135    begin l:=m-p; r:=m-1;
  1136    if r>max_subcol then r:=max_subcol;
  1137    m:=l;
  1138    while m<=r do
  1139      begin image:=black; incr(m);
  1140      end;
  1141    m:=l+p;
  1142    end
  1143  
  1144  @ @<Translate a |new_row| command@>=
  1145  begin show_mnemonic('newrow ',p:1);
  1146  incr(n); m:=p; paint_switch:=black;
  1147  if wants_mnemonics then print(' (n=',max_n_stated-n:1,')');
  1148  end
  1149  
  1150  @ @<Translate a |skip| command@>=
  1151  begin show_mnemonic('skip',(o-skip1+1)mod 4:1,' ',p:1);
  1152  n:=n+p+1; m:=0; paint_switch:=white;
  1153  if wants_mnemonics then print(' (n=',max_n_stated-n:1,')');
  1154  end
  1155  
  1156  @* Reading the postamble.
  1157  Now imagine that we are reading the \.{GF} file and positioned just
  1158  after the |post| command. That, in fact, is the situation,
  1159  when the following part of \.{GFtype} is called upon to read, translate,
  1160  and check the rest of the postamble.
  1161  
  1162  @p procedure read_postamble;
  1163  var k:integer; {loop index}
  1164  @!p,@!q,@!m,@!u,@!v,@!w,@!c:integer; {general purpose registers}
  1165  begin post_loc:=cur_loc-1;
  1166  print('Postamble starts at byte ',post_loc:1);
  1167  @.Postamble starts at byte n@>
  1168  if post_loc=gf_prev_ptr then print_ln('.')
  1169  else print_ln(', after special info at byte ',gf_prev_ptr:1,'.');
  1170  p:=signed_quad;
  1171  if p<>gf_prev_ptr then
  1172    error('backpointer in byte ',cur_loc-4:1,
  1173      ' should be ',gf_prev_ptr:1,' not ',p:1,'!');
  1174  @.backpointer...should be p@>
  1175  design_size:=signed_quad; check_sum:=signed_quad;@/
  1176  print('design size = ',design_size:1,' (');
  1177  print_scaled(design_size div 16); print_ln('pt)');
  1178  print_ln('check sum = ',check_sum:1);@/
  1179  hppp:=signed_quad; vppp:=signed_quad;@/
  1180  print('hppp = ',hppp:1,' ('); print_scaled(hppp); print_ln(')');
  1181  print('vppp = ',vppp:1,' ('); print_scaled(vppp); print_ln(')');
  1182  pix_ratio:=(design_size/1048576)*(hppp/1048576);
  1183  min_m_stated:=signed_quad; max_m_stated:=signed_quad;
  1184  min_n_stated:=signed_quad; max_n_stated:=signed_quad;@/
  1185  print_ln('min m = ',min_m_stated:1,', max m = ',max_m_stated:1);@/
  1186  if min_m_stated>min_m_overall then
  1187    error('min m should be <=',min_m_overall:1,'!');
  1188  if max_m_stated<max_m_overall then
  1189    error('max m should be >=',max_m_overall:1,'!');
  1190  print_ln('min n = ',min_n_stated:1,', max n = ',max_n_stated:1);@/
  1191  if min_n_stated>min_n_overall then
  1192    error('min n should be <=',min_n_overall:1,'!');
  1193  if max_n_stated<max_n_overall then
  1194    error('max n should be >=',max_n_overall:1,'!');
  1195  @<Process the character locations in the postamble@>;
  1196  @<Make sure that the end of the file is well-formed@>;
  1197  end;
  1198  
  1199  @ @<Glob...@>=
  1200  @!design_size,@!check_sum: integer; {\.{TFM}-oriented parameters}
  1201  @!hppp, @!vppp: integer; {magnification-oriented parameters}
  1202  @!post_loc: integer; {location of the |post| command}
  1203  @!pix_ratio: real; {multiply by this to convert \.{TFM} width to scaled pixels}
  1204  
  1205  @ @<Set init...@>=
  1206  min_m_overall:=max_int; max_m_overall:=-max_int;
  1207  min_n_overall:=max_int; max_n_overall:=-max_int;
  1208  
  1209  @ When we get to the present code, the |post_post| command has
  1210  just been read.
  1211  
  1212  @<Make sure that the end of the file is well-formed@>=
  1213  if k<>post_post then
  1214    error('should be postpost!');
  1215  @.should be postpost@>
  1216  for k:=0 to 255 do if char_ptr[k]>0 then
  1217    error('missing locator for character ',k:1,'!');
  1218  @.missing locator...@>
  1219  q:=signed_quad;
  1220  if q<>post_loc then
  1221    error('postamble pointer should be ',post_loc:1,' not ',q:1,'!');
  1222  @.postamble pointer should be...@>
  1223  m:=get_byte;
  1224  if m<>gf_id_byte then error('identification byte should be ',gf_id_byte:1,
  1225    ', not ',m:1,'!');
  1226  @.identification byte should be n@>
  1227  k:=cur_loc; m:=223;
  1228  while (m=223)and not eof(gf_file) do m:=get_byte;
  1229  if not eof(gf_file) then bad_gf('signature in byte ',cur_loc-1:1,
  1230  @.signature...should be...@>
  1231      ' should be 223')
  1232  else if cur_loc<k+4 then
  1233    error('not enough signature bytes at end of file!')
  1234  @.not enough signature bytes...@>
  1235  
  1236  @ @<Process the character locations...@>=
  1237  repeat a:=cur_loc; k:=get_byte;
  1238  if (k=char_loc)or(k=char_loc+1) then
  1239    begin c:=first_par(k);
  1240    if k=char_loc then
  1241      begin u:=signed_quad; v:=signed_quad;
  1242      end
  1243    else  begin u:=get_byte*unity; v:=0;
  1244      end;
  1245    w:=signed_quad; p:=signed_quad;
  1246    print('Character ',c:1,': dx ',u:1,' (');
  1247    print_scaled(u);
  1248    if v<>0 then
  1249      begin print('), dy ',v:1,' ('); print_scaled(v);
  1250      end;
  1251    print('), width ',w:1,' (');
  1252    w:=round(w*pix_ratio);
  1253    print_scaled(w);
  1254    print_ln('), loc ',p:1);
  1255    if char_ptr[c]=0 then
  1256      error('duplicate locator for this character!')
  1257  @.duplicate locator...@>
  1258    else if p<>char_ptr[c] then
  1259      error('character location should be ',char_ptr[c]:1,'!');
  1260  @.character location should be...@>
  1261    char_ptr[c]:=0;
  1262    k:=no_op;
  1263    end;
  1264  until k<>no_op
  1265  
  1266  @* The main program.
  1267  Now we are ready to put it all together. This is where \.{GFtype} starts,
  1268  and where it ends.
  1269  
  1270  @p begin initialize; {get all variables initialized}
  1271  dialog; {set up all the options}
  1272  @<Process the preamble@>;
  1273  @<Translate all the characters@>;
  1274  print_nl;
  1275  read_postamble;
  1276  print('The file had ',total_chars:1,' character');
  1277  if total_chars<>1 then print('s');
  1278  print(' altogether.');
  1279  @.The file had n characters...@>
  1280  final_end:end.
  1281  
  1282  @ The main program needs a few global variables in order to do its work.
  1283  
  1284  @<Glob...@>=
  1285  @!a:integer; {byte number of the current command}
  1286  @!b,@!c,@!l,@!o,@!p,@!q,@!r:integer; {general purpose registers}
  1287  
  1288  @ \.{GFtype} looks at the preamble in order to do error checking, and to
  1289  display the introductory comment.
  1290  
  1291  @<Process the preamble@>=
  1292  open_gf_file;
  1293  o:=get_byte; {fetch the first byte}
  1294  if o<>pre then bad_gf('First byte isn''t start of preamble!');
  1295  @.First byte isn't...@>
  1296  o:=get_byte; {fetch the identification byte}
  1297  if o<>gf_id_byte then
  1298    bad_gf('identification byte should be ',gf_id_byte:1,
  1299    ' not ',o:1);
  1300  @.identification byte should be n@>
  1301  o:=get_byte; {fetch the length of the introductory comment}
  1302  print('''');
  1303  while o>0 do
  1304    begin decr(o); print(xchr[get_byte]);
  1305    end;
  1306  print_ln('''');
  1307  
  1308  @ @<Translate all...@>=
  1309  repeat gf_prev_ptr:=cur_loc;
  1310    @<Pass |no_op|, |xxx| and |yyy| commands@>;
  1311    if o<>post then
  1312      begin if o<>boc then if o<>boc1 then
  1313        bad_gf('byte ',cur_loc-1:1,' is not boc (',o:1,')');
  1314  @.byte n is not boc@>
  1315      print_nl; print(cur_loc-1:1,': beginning of char ');
  1316      @<Pass a |boc| command@>;
  1317      if not do_char then bad_gf('char ended unexpectedly');
  1318  @.char ended unexpectedly@>
  1319      max_n_observed:=n;
  1320      if wants_pixels then @<Print the image@>;
  1321      @<Pass an |eoc| command@>;
  1322      end;
  1323  until o=post;
  1324  
  1325  @ @<Pass |no_op|, |xxx| and |yyy| commands@>=
  1326  repeat start_op;
  1327    if o=yyy then
  1328      begin @<Translate a |yyy|...@>; o:=no_op;
  1329      end
  1330    else if (o>=xxx1) and (o<=xxx1+3) then
  1331      begin @<Translate an |xxx|...@>; o:=no_op;
  1332      end
  1333    else if o=no_op then show_mnemonic('no op');
  1334  until o<>no_op;
  1335  
  1336  @ @<Pass a |boc|...@>=
  1337  a:=cur_loc-1; incr(total_chars);
  1338  if o=boc then
  1339    begin character_code:=signed_quad;
  1340    p:=signed_quad;
  1341    c:=character_code mod 256;
  1342    if c<0 then c:=c+256;
  1343    min_m_stated:=signed_quad; max_m_stated:=signed_quad;
  1344    min_n_stated:=signed_quad; max_n_stated:=signed_quad;
  1345    end
  1346  else  begin character_code:=get_byte; p:=-1; c:=character_code;
  1347    q:=get_byte; max_m_stated:=get_byte; min_m_stated:=max_m_stated-q;
  1348    q:=get_byte; max_n_stated:=get_byte; min_n_stated:=max_n_stated-q;
  1349    end;
  1350  print(c:1);
  1351  if character_code<>c then
  1352    print(' with extension ',(character_code-c) div 256 : 1);
  1353  if wants_mnemonics then
  1354    print_ln(': ',min_m_stated:1,'<=m<=',max_m_stated:1,' ',
  1355     min_n_stated:1,'<=n<=',max_n_stated:1);
  1356  max_m_observed:=-1;
  1357  if char_ptr[c]<>p then
  1358    error('previous character pointer should be ',char_ptr[c]:1,
  1359      ', not ',p:1,'!')
  1360  @.previous character...@>
  1361  else if p>0 then if wants_mnemonics then
  1362    print_ln('(previous character with the same code started at byte ',
  1363      p:1,')');
  1364  char_ptr[c]:=gf_prev_ptr;
  1365  if wants_mnemonics then print('(initially n=',max_n_stated:1,')');
  1366  if wants_pixels then @<Clear the image@>;
  1367  m:=0; n:=0; paint_switch:=white;
  1368  
  1369  @ @<Pass an |eoc|...@>=
  1370  max_m_observed:=min_m_stated+max_m_observed+1;
  1371  n:=max_n_stated-max_n_observed; {now |n| is the minimum |n| observed}
  1372  if min_m_stated<min_m_overall then min_m_overall:=min_m_stated;
  1373  if max_m_observed>max_m_overall then max_m_overall:=max_m_observed;
  1374  if n<min_n_overall then min_n_overall:=n;
  1375  if max_n_stated>max_n_overall then max_n_overall:=max_n_stated;
  1376  if max_m_observed>max_m_stated then
  1377    print_ln('The previous character should have had max m >= ',
  1378      max_m_observed:1,'!');
  1379  @.previous character...@>
  1380  if n<min_n_stated then
  1381    print_ln('The previous character should have had min n <= ',n:1,'!')
  1382  
  1383  @* System-dependent changes.
  1384  This section should be replaced, if necessary, by changes to the program
  1385  that are necessary to make \.{GFtype} work at a particular installation.
  1386  It is usually best to design your change file so that all changes to
  1387  previous sections preserve the section numbering; then everybody's version
  1388  will be consistent with the printed program. More extensive changes,
  1389  which introduce new sections, can be inserted here; then only the index
  1390  itself will get a new section number.
  1391  @^system dependencies@>
  1392  @* Index.
  1393  Pointers to error messages appear here together with the section numbers
  1394  where each ident\-i\-fier is used.