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.