196  PART 30: FONT METRIC DATA  TEX82 §539

539. Font metric data. TEX gets its knowledge about fonts from font metric files, also called files; the ‘ ’ in ‘ ’ stands for TEX, but other programs know about them too.

The information in a file appears in a sequence of 8-bit bytes. Since the number of bytes is always a multiple of 4, we could also regard the file as a sequence of 32-bit words, but TEX uses the byte interpretation. The format of files was designed by Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds of information in a compact but useful form. ⟨ Global variables 13 ⟩ +≡ tfm file: byte file;

540. The first 24 bytes (6 words) of a file contain twelve 16-bit integers that give the lengths of the various subsequent portions of the file. These twelve integers are, in order:

lf = length of the entire file, in words;
lh = length of the header data, in words;
bc = smallest character code in the font;
ec = largest character code in the font;
nw = number of words in the width table;
nh = number of words in the height table;
nd = number of words in the depth table;
ni = number of words in the italic correction table;
nl = number of words in the lig/kern table;
nk = number of words in the kern table;
ne = number of words in the extensible character table;
np = number of font parameter words.

They are all nonnegative and less than 2^{15}. We must have bc − 1 ≤ ec ≤ 255, and

lf = 6 + lh + (ec − bc + 1) + nw + nh + nd + ni + nl + nk + ne + np.

Note that a font may contain as many as 256 characters (if bc = 0 and ec = 255), and as few as 0 characters (if bc = ec + 1).

Incidentally, when two or more 8-bit bytes are combined to form an integer of 16 or more bits, the most significant bytes appear first in the file. This is called BigEndian order.

541. The rest of the file may be regarded as a sequence of ten data arrays having the informal specification

header : array [0 . . lh − 1] of stuff
char info : array [bc . . ec] of char info word
width : array [0 . . nw − 1] of fix word
height : array [0 . . nh − 1] of fix word
depth : array [0 . . nd − 1] of fix word
italic : array [0 . . ni − 1] of fix word
lig kern : array [0 . . nl − 1] of lig kern command
kern : array [0 . . nk − 1] of fix word
exten : array [0 . . ne − 1] of extensible recipe
param : array [1 . . np] of fix word

The most important data type used here is a fix word , which is a 32-bit representation of a binary fraction. A fix word is a signed quantity, with the two’s complement of the entire word used to represent negation. Of the 32 bits in a fix word , exactly 12 are to the left of the binary point; thus, the largest fix word value is 2048 − 2^{−20}, and the smallest is −2048. We will see below, however, that all but two of the fix word values must lie between −16 and +16.

§542  TEX82  PART 30: FONT METRIC DATA 197

542. The first data array is a block of header information, which contains general facts about the font. The header must contain at least two words, header [0] and header [1], whose meaning is explained below. Additional header information of use to other software routines might also be included, but TEX82 does not need to know about such details. For example, 16 more words of header information are in use at the Xerox Palo Alto Research Center; the first ten specify the character coding scheme used (e.g., ‘ ’ or ‘ ’), the next five give the font identifier (e.g., ‘ ’ or ‘ ’), and the last gives the “face byte.” The program that converts files to Xerox printing format gets this information by looking at the file, which it needs to read anyway because of other information that is not explicitly repeated in format. header [0] is a 32-bit check sum that TEX will copy into the output file. Later on when the file is

printed, possibly on another computer, the actual font that gets used is supposed to have a check sum that agrees with the one in the file used by TEX. In this way, users will be warned about potential incompatibilities. (However, if the check sum is zero in either the font file or the file, no check is made.) The actual relation between this check sum and the rest of the file is not important; the check sum is simply an identification number with the property that incompatible fonts almost always have distinct check sums.

header [1] is a fix word containing the design size of the font, in units of TEX points. This number must be at least 1.0; it is fairly arbitrary, but usually the design size is 10.0 for a “10 point” font, i.e., a font that was designed to look best at a 10-point size, whatever that really means. When a TEX user asks for a font ‘ δ ’, the effect is to override the design size and replace it by δ, and to multiply the x and y coordinates of the points in the font image by a factor of δ divided by the design size. All other dimensions in the file are fix word numbers in design-size units, with the exception of param[1] (which denotes the slant ratio). Thus, for example, the value of param[6], which defines the unit, is often the fix word value 2^{20} = 1.0, since many fonts have a design size equal to one em. The other dimensions must be less than 16 design-size units in absolute value; thus, header [1] and param[1] are the only fix word entries in the whole file whose first byte might be something besides 0 or 255.

543. Next comes the char info array, which contains one char info word per character. Each word in this part of the file contains six fields packed into four bytes as follows. first byte: width index (8 bits) second byte: height index (4 bits) times 16, plus depth index (4 bits) third byte: italic index (6 bits) times 4, plus tag (2 bits) fourth byte: remainder (8 bits) The actual width of a character is width[width index ], in design-size units; this is a device for compressing information, since many characters have the same width. Since it is quite common for many characters to have the same height, depth, or italic correction, the format imposes a limit of 16 different heights, 16 different depths, and 64 different italic corrections.

The italic correction of a character has two different uses. (a) In ordinary text, the italic correction is added to the width only if the TEX user specifies ‘ ’ after the character. (b) In math formulas, the italic correction is always added to the width, except with respect to the positioning of subscripts.

Incidentally, the relation width[0] = height [0] = depth[0] = italic[0] = 0 should always hold, so that an index of zero implies a value of zero. The width index should never be zero unless the character does not exist in the font, since a character is valid if and only if it lies between bc and ec and has a nonzero width index .

544. The tag field in a char info word has four values that explain how to interpret the remainder field. tag = 0 (no tag ) means that remainder is unused. tag = 1 (lig tag ) means that this character has a ligature/kerning program starting at position remainder

in the lig kern array. tag = 2 (list tag ) means that this character is part of a chain of characters of ascending sizes, and not the

largest in the chain. The remainder field gives the character code of the next larger character. tag = 3 (ext tag ) means that this character code represents an extensible character, i.e., a character that

is built up of smaller pieces so that it can be made arbitrarily large. The pieces are specified in exten[remainder ].

Characters with tag = 2 and tag = 3 are treated as characters with tag = 0 unless they are used in special circumstances in math formulas. For example, the operation looks for a list tag , and the operation looks for both list tag and ext tag .

define no tag = 0 { vanilla character }

define lig tag = 1 { character has a ligature/kerning program } define list tag = 2 { character has a successor in a charlist } define ext tag = 3 { character is extensible } 545. The lig kern array contains instructions in a simple programming language that explains what to do for special letter pairs. Each word in this array is a lig kern command of four bytes. first byte: skip byte, indicates that this is the final program step if the byte is 128 or more, otherwise the

next step is obtained by skipping this number of intervening steps. second byte: next char , “if next char follows the current character, then perform the operation and stop,

otherwise continue.” third byte: op byte, indicates a ligature step if less than 128, a kern step otherwise. fourth byte: remainder . In a kern step, an additional space equal to kern[256 ∗ (op byte − 128) + remainder ] is inserted between the current character and next char . This amount is often negative, so that the characters are brought closer together by kerning; but it might be positive.

There are eight kinds of ligature steps, having op byte codes 4a+2b+c where 0 ≤ a ≤ b+c and 0 ≤ b, c ≤ 1. The character whose code is remainder is inserted between the current character and next char ; then the current character is deleted if b = 0, and next char is deleted if c = 0; then we pass over a characters to reach the next current character (which may have a ligature/kerning program of its own).

If the very first instruction of the lig kern array has skip byte = 255, the next char byte is the so-called right boundary character of this font; the value of next char need not lie between bc and ec. If the very last instruction of the lig kern array has skip byte = 255, there is a special ligature/kerning program for a left boundary character, beginning at location 256 ∗ op byte + remainder . The interpretation is that TEX puts implicit boundary characters before and after each consecutive string of characters from the same font. These implicit characters do not appear in the output, but they can affect ligatures and kerning.

If the very first instruction of a character’s lig kern program has skip byte > 128, the program actually begins in location 256 ∗ op byte + remainder . This feature allows access to large lig kern arrays, because the first instruction must otherwise appear in a location ≤ 255.

Any instruction with skip byte > 128 in the lig kern array must satisfy the condition

256 ∗ op byte + remainder < nl .

If such an instruction is encountered during normal program execution, it denotes an unconditional halt; no ligature or kerning command is performed.

define stop flag ≡ qi (128) { value indicating ‘ ’ in a lig/kern program }

define kern flag ≡ qi (128) { op code for a kern step }

define skip byte(#) ≡ #.b0

define next char (#) ≡ #.b1

define op byte(#) ≡ #.b2

define rem byte(#) ≡ #.b3

546. Extensible characters are specified by an extensible recipe, which consists of four bytes called top, mid , bot , and rep (in this order). These bytes are the character codes of individual pieces used to build up a large symbol. If top, mid , or bot are zero, they are not present in the built-up result. For example, an extensible vertical line is like an extensible bracket, except that the top and bottom pieces are missing.

Let T, M, B, and R denote the respective pieces, or an empty box if the piece isn’t present. Then the extensible characters have the form T R^{k}MR^{k}B from top to bottom, for some k ≥ 0, unless M is absent; in the latter case we can have T R^{k}B for both even and odd values of k. The width of the extensible character is the width of R; and the height-plus-depth is the sum of the individual height-plus-depths of the components used, since the pieces are butted together in a vertical list.

define ext top(#) ≡ #.b0 { top piece in a recipe }

define ext mid (#) ≡ #.b1 { mid piece in a recipe }

define ext bot (#) ≡ #.b2 { bot piece in a recipe }

define ext rep(#) ≡ #.b3 { rep piece in a recipe } 547. The final portion of a file is the param array, which is another sequence of fix word values. param[1] = slant is the amount of italic slant, which is used to help position accents. For example, slant = .25

means that when you go up one unit, you also go .25 units to the right. The slant is a pure number; it’s the only fix word other than the design size itself that is not scaled by the design size.

param[2] = space is the normal spacing between words in text. Note that character ␣ in the font need not

have anything to do with blank spaces. param[3] = space stretch is the amount of glue stretching between words. param[4] = space shrink is the amount of glue shrinking between words. param[5] = x height is the size of one ex in the font; it is also the height of letters for which accents don’t

have to be raised or lowered. param[6] = quad is the size of one em in the font. param[7] = extra space is the amount added to param[2] at the ends of sentences. If fewer than seven parameters are present, TEX sets the missing parameters to zero. Fonts used for math symbols are required to have additional parameter information, which is explained later.

define slant code = 1

define space code = 2

define space stretch code = 3

define space shrink code = 4

define x height code = 5

define quad code = 6

define extra space code = 7

548. So that is what files hold. Since TEX has to absorb such information about lots of fonts, it stores most of the data in a large array called font info. Each item of font info is a memory word ; the fix word data gets converted into scaled entries, while everything else goes into words of type four quarters .

When the user defines , say, TEX assigns an internal number to the user’s font . Adding this number to font id base gives the eqtb location of a “frozen” control sequence that will always select the font. ⟨ Types in the outer block 18 ⟩ +≡

internal font number = font base . . font max ; { font in a char node }

font index = 0 . . font mem size; { index into font info } 549. Here now is the (rather formidable) array of font arrays.

define non char ≡ qi (256) { a halfword code that can’t match a real character } define non address = 0 { a spurious bchar label }

⟨ Global variables 13 ⟩ +≡ font info: array [font index ] of memory word ; { the big collection of font data } fmem ptr : font index ; { first unused word of font info } font ptr : internal font number ; { largest internal font number in use } font check : array [internal font number ] of four quarters ; { check sum } font size: array [internal font number ] of scaled ; { “at” size } font dsize: array [internal font number ] of scaled ; { “design” size } font params : array [internal font number ] of font index ; { how many font parameters are present } font name: array [internal font number ] of str number ; { name of the font } font area: array [internal font number ] of str number ; { area of the font } font bc: array [internal font number ] of eight bits ; { beginning (smallest) character code } font ec: array [internal font number ] of eight bits ; { ending (largest) character code } font glue: array [internal font number ] of pointer ;

{ glue specification for interword space, null if not allocated }

font used : array [internal font number ] of boolean;

{ has a character from this font actually appeared in the output? }

hyphen char : array [internal font number ] of integer ; { current values } skew char : array [internal font number ] of integer ; { current values } bchar label : array [internal font number ] of font index ;

{ start of lig kern program for left boundary character, non address if there is none }

font bchar : array [internal font number ] of min quarterword . . non char ;

{ right boundary character, non char if there is none }

font false bchar : array [internal font number ] of min quarterword . . non char ; { font bchar if it doesn’t exist in the font, otherwise non char }

550. Besides the arrays just enumerated, we have directory arrays that make it easy to get at the individual entries in font info. For example, the char info data for character c in font f will be in font info[char base[f] + c].qqqq ; and if w is the width index part of this word (the b0 field), the width of the character is font info[width base[f] + w].sc. (These formulas assume that min quarterword has already been added to c and to w, since TEX stores its quarterwords that way.) ⟨ Global variables 13 ⟩ +≡ char base: array [internal font number ] of integer ; { base addresses for char info } width base: array [internal font number ] of integer ; { base addresses for widths } height base: array [internal font number ] of integer ; { base addresses for heights } depth base: array [internal font number ] of integer ; { base addresses for depths } italic base: array [internal font number ] of integer ; { base addresses for italic corrections } lig kern base: array [internal font number ] of integer ; { base addresses for ligature/kerning programs } kern base: array [internal font number ] of integer ; { base addresses for kerns } exten base: array [internal font number ] of integer ; { base addresses for extensible recipes } param base: array [internal font number ] of integer ; { base addresses for font parameters }

551. ⟨ Set initial values of key variables 21 ⟩ +≡ for k ← font base to font max do font used [k] ← false; 552. TEX always knows at least one font, namely the null font. It has no characters, and its seven parameters are all equal to zero. ⟨ Initialize table entries (done by only) 164 ⟩ +≡

font ptr ← null font ; fmem ptr ← 7; font name[null font ] ← ; font area[null font ] ← ; hyphen char [null font ] ← ; skew char [null font ] ← −1; bchar label [null font ] ← non address ; font bchar [null font ] ← non char ; font false bchar [null font ] ← non char ; font bc[null font ] ← 1; font ec[null font ] ← 0; font size[null font ] ← 0; font dsize[null font ] ← 0; char base[null font ] ← 0; width base[null font ] ← 0; height base[null font ] ← 0; depth base[null font ] ← 0; italic base[null font ] ← 0; lig kern base[null font ] ← 0; kern base[null font ] ← 0; exten base[null font ] ← 0; font glue[null font ] ← null ; font params [null font ] ← 7; param base[null font ] ← −1; for k ← 0 to 6 do font info[k].sc ← 0;

553. ⟨ Put each of TEX’s primitives into the hash table 226 ⟩ +≡ primitive( , set font , null font ); text (frozen null font ) ← ; eqtb[frozen null font ] ← eqtb[cur val ]; 554. Of course we want to define macros that suppress the detail of how font information is actually packed, so that we don’t have to write things like

font info[width base[f] + font info[char base[f] + c].qqqq .b0 ].sc

too often. The definitions here make char info(f)(c) the four quarters word of font information corresponding to character c of font f. If q is such a word, char width(f)(q) will be the character’s width; hence the long formula above is at least abbreviated to

char width(f)(char info(f)(c)).

Usually, of course, we will fetch q first and look at several of its fields at the same time.

The italic correction of a character will be denoted by char italic(f)(q), so it is analogous to char width. But we will get at the height and depth in a slightly different way, since we usually want to compute both height and depth if we want either one. The value of height depth(q) will be the 8-bit quantity

b = height index × 16 + depth index ,

and if b is such a byte we will write char height (f)(b) and char depth(f)(b) for the height and depth of the character c for which q = char info(f)(c). Got that?

The tag field will be called char tag (q); the remainder byte will be called rem byte(q), using a macro that we have already defined above.

Access to a character’s width, height , depth, and tag fields is part of TEX’s inner loop, so we want these macros to produce code that is as fast as possible under the circumstances.

define char info end (#) ≡ # ] .qqqq define char info(#) ≡ font info [ char base[#] + char info end define char width end (#) ≡ #.b0 ] .sc define char width(#) ≡ font info [ width base[#] + char width end define char exists (#) ≡ (#.b0 > min quarterword ) define char italic end (#) ≡ (qo(#.b2 )) div 4 ] .sc define char italic(#) ≡ font info [ italic base[#] + char italic end define height depth(#) ≡ qo(#.b1 ) define char height end (#) ≡ (#) div 16 ] .sc define char height (#) ≡ font info [ height base[#] + char height end define char depth end (#) ≡ (#) mod 16 ] .sc define char depth(#) ≡ font info [ depth base[#] + char depth end define char tag (#) ≡ ((qo(#.b2 )) mod 4)

555. The global variable null character is set up to be a word of char info for a character that doesn’t exist. Such a word provides a convenient way to deal with erroneous situations. ⟨ Global variables 13 ⟩ +≡ null character : four quarters ; { nonexistent character information }

556. ⟨ Set initial values of key variables 21 ⟩ +≡ null character .b0 ← min quarterword ; null character .b1 ← min quarterword ; null character .b2 ← min quarterword ; null character .b3 ← min quarterword ; 557. Here are some macros that help process ligatures and kerns. We write char kern(f)(j) to find the amount of kerning specified by kerning command j in font f. If j is the char info for a character with a ligature/kern program, the first instruction of that program is either i = font info[lig kern start (f)(j)] or font info[lig kern restart (f)(i)], depending on whether or not skip byte(i) ≤ stop flag .

The constant kern base offset should be simplified, for Pascal compilers that do not do local optimization. define char kern end (#) ≡ 256 ∗ op byte(#) + rem byte(#) ] .sc define char kern(#) ≡ font info [ kern base[#] + char kern end define kern base offset ≡ 256 ∗ (128 + min quarterword ) define lig kern start (#) ≡ lig kern base[#] + rem byte { beginning of lig/kern program } define lig kern restart end (#) ≡ 256 ∗ op byte(#) + rem byte(#) + 32768 − kern base offset define lig kern restart (#) ≡ lig kern base[#] + lig kern restart end

558. Font parameters are referred to as slant (f), space(f), etc.

define param end (#) ≡ param base[#] ] .sc define param(#) ≡ font info [ # + param end define slant ≡ param(slant code) { slant to the right, per unit distance upward } define space ≡ param(space code) { normal space between words } define space stretch ≡ param(space stretch code) { stretch between words } define space shrink ≡ param(space shrink code) { shrink between words } define x height ≡ param(x height code) { one ex } define quad ≡ param(quad code) { one em } define extra space ≡ param(extra space code) { additional space at end of sentence }

⟨ The em width for cur font 558 ⟩ ≡

quad (cur font )

This code is used in section 455.

559. ⟨ The x-height for cur font 559 ⟩ ≡ x height (cur font )

This code is used in section 455.

560. TEX checks the information of a file for validity as the file is being read in, so that no further checks will be needed when typesetting is going on. The somewhat tedious subroutine that does this is called read font info. It has four parameters: the user font identifier u, the file name and area strings nom and aire, and the “at” size s. If s is negative, it’s the negative of a scale factor to be applied to the design size; s = −1000 is the normal case. Otherwise s will be substituted for the design size; in this case, s must be positive and less than 2048 pt (i.e., it must be less than 2^{27} when considered as an integer).

The subroutine opens and closes a global file variable called tfm file. It returns the value of the internal font number that was just loaded. If an error is detected, an error message is issued and no font information is stored; null font is returned in this case.

define bad tfm = 11 { label for read font info }

define abort ≡ goto bad tfm { do this when the data is wrong } function read font info(u : pointer ; nom, aire : str number ; s : scaled ): internal font number ;

{ input a file } label done, bad tfm, not found ; var k: font index ; { index into font info }

file opened : boolean; { was tfm file successfully opened? }

lf , lh, bc, ec, nw , nh, nd , ni , nl , nk , ne, np: halfword ; { sizes of subfiles }

f: internal font number ; { the new font’s number } g: internal font number ; { the number to return } a, b, c, d: eight bits ; { byte variables } qw : four quarters ; sw : scaled ; { accumulators } bch label : integer ; { left boundary start location, or infinity } bchar : 0 . . 256; { right boundary character, or 256 } z: scaled ; { the design size or the “at” size } alpha: integer ; beta: 1 . . 16; { auxiliary quantities used in fixed-point multiplication }

begin g ← null font ;

⟨ Read and check the font data; abort if the file is malformed; if there’s no room for this font, say so

and goto done; otherwise incr (font ptr ) and goto done 562 ⟩; bad tfm: ⟨ Report that the font won’t be loaded 561 ⟩; done: if file opened then b close(tfm file);

read font info ← g;

end;

561. There are programs called  and  that convert between the  format and a symbolic

property-list format that can be easily edited. These programs contain extensive diagnostic information, so TEX does not have to bother giving precise details about why it rejects a particular file.

define start font error message ≡ print err ( ␣ ); sprint cs (u); print char ( ); print file name(nom, aire, ); if s ≥ 0 then

begin print ( ␣ ␣ ); print scaled (s); print ( ); end

else if s ≠ −1000 then begin print ( ␣ ␣ ); print int (−s); end

⟨ Report that the font won’t be loaded 561 ⟩ ≡ start font error message; if file opened then print ( ␣ ␣ ␣ ␣ ␣ ␣ ) else print ( ␣ ␣ ␣ ␣ ␣ ␣ ␣ );

help5 ( ␣    ´ ␣    ␣  ␣    ␣   ␣    ␣    ␣   ␣    ␣  )
( ␣ ␣    ␣      ␣   ␣    ␣  )
(  ␣   ␣   ␣   ␣     ␣     ␣  )
(  ␣     ␣   ␣         ␣ ␣         ␣    ␣  )

(  ␣    ␣` ␣    ␣              ␣    ␣  ´  ); error

This code is used in section 560.

562. ⟨ Read and check the font data; abort if the file is malformed; if there’s no room for this font,

say so and goto done; otherwise incr (font ptr ) and goto done 562 ⟩ ≡ ⟨ Open tfm file for input 563 ⟩; ⟨ Read the size fields 565 ⟩; ⟨ Use size fields to allocate font information 566 ⟩; ⟨ Read the header 568 ⟩; ⟨ Read character data 569 ⟩; ⟨ Read box dimensions 571 ⟩; ⟨ Read ligature/kern program 573 ⟩; ⟨ Read extensible character recipes 574 ⟩; ⟨ Read font parameters 575 ⟩; ⟨ Make final adjustments and goto done 576 ⟩

This code is used in section 560.

563. ⟨ Open tfm file for input 563 ⟩ ≡ file opened ← false; if aire = then pack file name(nom, TEX font area, ) else pack file name(nom, aire, ); if ¬b open in(tfm file) then abort ; file opened ← true

This code is used in section 562.

564. Note: A malformed file might be shorter than it claims to be; thus eof (tfm file) might be true when read font info refers to tfm file↑ or when it says get (tfm file). If such circumstances cause system error messages, you will have to defeat them somehow, for example by defining fget to be ‘begin get (tfm file); if eof (tfm file) then abort ; end’.

define fget ≡ get (tfm file) define fbyte ≡ tfm file↑ define read sixteen(#) ≡

begin # ← fbyte;

if # > 127 then abort ; fget ; # ← # ∗ ´ 400 + fbyte; end

define store four quarters (#) ≡ begin fget ; a ← fbyte; qw .b0 ← qi (a); fget ; b ← fbyte; qw .b1 ← qi (b); fget ; c ← fbyte; qw .b2 ← qi (c); fget ; d ← fbyte; qw .b3 ← qi (d); # ← qw ; end

565. ⟨ Read the size fields 565 ⟩ ≡ begin read sixteen(lf ); fget ; read sixteen(lh); fget ; read sixteen(bc); fget ; read sixteen(ec); if (bc > ec + 1) ∨ (ec > 255) then abort ; if bc > 255 then { bc = 256 and ec = 255 }

begin bc ← 1; ec ← 0;

end; fget ; read sixteen(nw ); fget ; read sixteen(nh); fget ; read sixteen(nd ); fget ; read sixteen(ni ); fget ; read sixteen(nl ); fget ; read sixteen(nk ); fget ; read sixteen(ne); fget ; read sixteen(np); if lf ≠ 6 + lh + (ec − bc + 1) + nw + nh + nd + ni + nl + nk + ne + np then abort ; end

This code is used in section 562.

566. The preliminary settings of the index-offset variables char base, width base, lig kern base, kern base, and exten base will be corrected later by subtracting min quarterword from them; and we will subtract 1 from param base too. It’s best to forget about such anomalies until later. ⟨ Use size fields to allocate font information 566 ⟩ ≡

lf ← lf − 6 − lh; { lf words should be loaded into font info } if np < 7 then lf ← lf + 7 − np; { at least seven parameters will appear } if (font ptr = font max ) ∨ (fmem ptr + lf > font mem size) then

⟨ Apologize for not loading the font, goto done 567 ⟩; f ← font ptr + 1; char base[f] ← fmem ptr − bc; width base[f] ← char base[f] + ec + 1; height base[f] ← width base[f] + nw ; depth base[f] ← height base[f] + nh; italic base[f] ← depth base[f] + nd ; lig kern base[f] ← italic base[f] + ni ; kern base[f] ← lig kern base[f] + nl − kern base offset ; exten base[f] ← kern base[f] + kern base offset + nk ; param base[f] ← exten base[f] + ne

This code is used in section 562.

567. ⟨ Apologize for not loading the font, goto done 567 ⟩ ≡ begin start font error message; print ( ␣ ␣ ␣ ␣ ␣ ␣ );

help4 ( ´ ␣      ␣ ␣   ´ ␣  ␣    ␣  ␣    ␣   ␣  ␣    ␣  )
(  ␣  ␣      ␣   ␣             ␣    ␣  ␣   ␣  )
( ␣   ´ ␣      ␣      ␣   ␣ ␣      ␣  ␣       ␣  )

( ␣     ␣   ␣` ␣    ␣         ␣  ␣      ␣  ´  ); error ; goto done;

end

This code is used in section 566.

568. Only the first two words of the header are needed by TEX82. ⟨ Read the header 568 ⟩ ≡

begin if lh < 2 then abort ; store four quarters (font check [f]); fget ; read sixteen(z); { this rejects a negative design size } fget ; z ← z ∗ ´ 400 + fbyte; fget ; z ← (z ∗ ´ 20 ) + (fbyte div ´ 20 ); if z < unity then abort ; while lh > 2 do

begin fget ; fget ; fget ; fget ; decr (lh); { ignore the rest of the header } end;

font dsize[f] ← z; if s ≠ −1000 then

if s ≥ 0 then z ← s else z ← xn over d (z, −s, 1000);

font size[f] ← z; end

This code is used in section 562.

569. ⟨ Read character data 569 ⟩ ≡

for k ← fmem ptr to width base[f] − 1 do begin store four quarters (font info[k].qqqq ); if (a ≥ nw ) ∨ (b div ´ 20 ≥ nh) ∨ (b mod ´ 20 ≥ nd ) ∨ (c div 4 ≥ ni ) then abort ; case c mod 4 of lig tag : if d ≥ nl then abort ; ext tag : if d ≥ ne then abort ; list tag : ⟨ Check for charlist cycle 570 ⟩; othercases do nothing { no tag } endcases; end

This code is used in section 562.

570. We want to make sure that there is no cycle of characters linked together by list tag entries, since such a cycle would get TEX into an endless loop. If such a cycle exists, the routine here detects it when processing the largest character code in the cycle.

define check byte range(#) ≡ begin if (# < bc) ∨ (# > ec) then abort end

define current character being worked on ≡ k + bc − fmem ptr ⟨ Check for charlist cycle 570 ⟩ ≡

begin check byte range(d); while d < current character being worked on do

begin qw ← char info(f)(d); { N.B.: not qi (d), since char base[f] hasn’t been adjusted yet } if char tag (qw ) ≠ list tag then goto not found ; d ← qo(rem byte(qw )); { next character on the list } end;

if d = current character being worked on then abort ; { yes, there’s a cycle } not found : end

This code is used in section 569.

571. A fix word whose four bytes are (a, b, c, d) from left to right represents the number

x = \begin{cases}b · 2^{−4} + c · 2^{−12} + d · 2^{−20}, & if a = 0; \\ −16 + b · 2^{−4} + c · 2^{−12} + d · 2^{−20}, & if a = 255. \end{cases}

(No other choices of a are allowed, since the magnitude of a number in design-size units must be less than 16.) We want to multiply this quantity by the integer z, which is known to be less than 2^{27}. If z < 2^{23}, the individual multiplications b · z, c · z, d · z cannot overflow; otherwise we will divide z by 2, 4, 8, or 16, to obtain a multiplier less than 2^{23}, and we can compensate for this later. If z has thereby been replaced by z′ = z/2^{e}, let β = 2^{4−e}; we shall compute

⌊(b + c · 2^{−8} + d · 2^{−16}) z′/β⌋

if a = 0, or the same quantity minus α = 2^{4+e}z′ if a = 255. This calculation must be done exactly, in order to guarantee portability of TEX between computers.

define store scaled (#) ≡ begin fget ; a ← fbyte; fget ; b ← fbyte; fget ; c ← fbyte; fget ; d ← fbyte; sw ← (((((d ∗ z) div ´ 400 ) + (c ∗ z)) div ´ 400 ) + (b ∗ z)) div beta; if a = 0 then # ← sw else if a = 255 then # ← sw − alpha else abort ; end

⟨ Read box dimensions 571 ⟩ ≡ begin ⟨ Replace z by z′ and compute α, β 572 ⟩; for k ← width base[f] to lig kern base[f] − 1 do store scaled (font info[k].sc); if font info[width base[f]].sc ≠ 0 then abort ; { width[0] must be zero } if font info[height base[f]].sc ≠ 0 then abort ; { height [0] must be zero } if font info[depth base[f]].sc ≠ 0 then abort ; { depth[0] must be zero } if font info[italic base[f]].sc ≠ 0 then abort ; { italic[0] must be zero } end

This code is used in section 562.

572. ⟨ Replace z by z′ and compute α, β 572 ⟩ ≡ begin alpha ← 16; while z ≥ ´ 40000000 do

begin z ← z div 2; alpha ← alpha + alpha; end;

beta ← 256 div alpha; alpha ← alpha ∗ z; end

This code is used in section 571.

573. define check existence(#) ≡ begin check byte range(#); qw ← char info(f)(#); { N.B.: not qi (#) } if ¬char exists (qw ) then abort ; end

⟨ Read ligature/kern program 573 ⟩ ≡ bch label ← ´ 77777 ; bchar ← 256; if nl > 0 then

begin for k ← lig kern base[f] to kern base[f] + kern base offset − 1 do begin store four quarters (font info[k].qqqq ); if a > 128 then

begin if 256 ∗ c + d ≥ nl then abort ;

if a = 255 then

if k = lig kern base[f] then bchar ← b; end

else begin if b ≠ bchar then check existence(b); if c < 128 then check existence(d) { check ligature } else if 256 ∗ (c − 128) + d ≥ nk then abort ; { check kern } if a < 128 then

if k − lig kern base[f] + a + 1 ≥ nl then abort ; end;

end; if a = 255 then bch label ← 256 ∗ c + d; end;

for k ← kern base[f] + kern base offset to exten base[f] − 1 do store scaled (font info[k].sc);

This code is used in section 562.

574. ⟨ Read extensible character recipes 574 ⟩ ≡

for k ← exten base[f] to param base[f] − 1 do begin store four quarters (font info[k].qqqq ); if a ≠ 0 then check existence(a); if b ≠ 0 then check existence(b); if c ≠ 0 then check existence(c); check existence(d); end

This code is used in section 562.

575. We check to see that the file doesn’t end prematurely; but no error message is given for files having more than lf words. ⟨ Read font parameters 575 ⟩ ≡

begin for k ← 1 to np do

if k = 1 then { the slant parameter is a pure number } begin fget ; sw ← fbyte; if sw > 127 then sw ← sw − 256; fget ; sw ← sw ∗ ´ 400 + fbyte; fget ; sw ← sw ∗ ´ 400 + fbyte; fget ; font info[param base[f]].sc ← (sw ∗ ´ 20 ) + (fbyte div ´ 20 ); end

else store scaled (font info[param base[f] + k − 1].sc); if eof (tfm file) then abort ; for k ← np + 1 to 7 do font info[param base[f] + k − 1].sc ← 0; end

This code is used in section 562.

576. Now to wrap it up, we have checked all the necessary things about the file, and all we need to do is put the finishing touches on the data for the new font.

define adjust (#) ≡ #[f] ← qo(#[f]) { correct for the excess min quarterword that was added } ⟨ Make final adjustments and goto done 576 ⟩ ≡

if np ≥ 7 then font params [f] ← np else font params [f] ← 7; hyphen char [f] ← default hyphen char ; skew char [f] ← default skew char ; if bch label < nl then bchar label [f] ← bch label + lig kern base[f] else bchar label [f] ← non address ; font bchar [f] ← qi (bchar ); font false bchar [f] ← qi (bchar ); if bchar ≤ ec then

if bchar ≥ bc then begin qw ← char info(f)(bchar ); { N.B.: not qi (bchar ) } if char exists (qw ) then font false bchar [f] ← non char ; end;

font name[f] ← nom; font area[f] ← aire; font bc[f] ← bc; font ec[f] ← ec; font glue[f] ← null ; adjust (char base); adjust (width base); adjust (lig kern base); adjust (kern base); adjust (exten base); decr (param base[f]); fmem ptr ← fmem ptr + lf ; font ptr ← f; g ← f; goto done

This code is used in section 562.

577. Before we forget about the format of these tables, let’s deal with two of TEX’s basic scanning routines related to font information. ⟨ Declare procedures that scan font-related stuff 577 ⟩ ≡ procedure scan font ident ;

var f: internal font number ; m: halfword ; begin ⟨ Get the next non-blank non-call token 406 ⟩; if cur cmd = def font then f ← cur font else if cur cmd = set font then f ← cur chr

else if cur cmd = def family then begin m ← cur chr ; scan four bit int ; f ← equiv (m + cur val ); end

else begin print err (  ␣    ␣  );

      help2 ( ␣   ␣       ␣   ␣ ␣       ␣        ␣  )

(  ␣       ␣   ␣    ␣       ␣  ␣  ); back error ; f ← null font ;

end; cur val ← f; end;

See also section 578. This code is used in section 409.

578. The following routine is used to implement ‘ n f’. The boolean parameter writing is set true if the calling program intends to change the parameter value. ⟨ Declare procedures that scan font-related stuff 577 ⟩ +≡ procedure find font dimen(writing : boolean); { sets cur val to font info location }

var f: internal font number ; n: integer ; { the parameter number } begin scan int ; n ← cur val ; scan font ident ; f ← cur val ; if n ≤ 0 then cur val ← fmem ptr else begin if writing ∧ (n ≤ space shrink code) ∧ (n ≥ space code) ∧ (font glue[f] ≠ null ) then

begin delete glue ref (font glue[f]); font glue[f] ← null ; end;

if n > font params [f] then if f < font ptr then cur val ← fmem ptr else ⟨ Increase the number of parameters in the last font 580 ⟩

else cur val ← n + param base[f];

end; ⟨ Issue an error message if cur val = fmem ptr 579 ⟩; end;

579. ⟨ Issue an error message if cur val = fmem ptr 579 ⟩ ≡

if cur val = fmem ptr then begin print err ( ␣ ); print esc(font id text (f)); print ( ␣ ␣ ␣ ); print int (font params [f]); print ( ␣ ␣ );

  help2 ( ␣        ␣   ␣      ␣  ␣    ␣          ␣   ␣  )

(  ␣          ␣          ␣     ␣   ␣     ␣  ␣  ); error ;

end

This code is used in section 578.

580. ⟨ Increase the number of parameters in the last font 580 ⟩ ≡

begin repeat if fmem ptr = font mem size then overflow ( ␣ , font mem size);

font info[fmem ptr ].sc ← 0; incr (fmem ptr ); incr (font params [f]); until n = font params [f]; cur val ← fmem ptr − 1; { this equals param base[f] + font params [f] } end

This code is used in section 578.

581. When TEX wants to typeset a character that doesn’t exist, the character node is not created; thus the output routine can assume that characters exist when it sees them. The following procedure prints a warning message unless the user has suppressed it. procedure char warning (f : internal font number ; c : eight bits );

begin if tracing lost chars > 0 then begin begin diagnostic; print nl ( ␣ ␣ ␣ ␣ ␣ ); print ASCII (c); print ( ␣ ␣ ␣ ); slow print (font name[f]); print char ( ); end diagnostic(false); end;

end; 582. Here is a function that returns a pointer to a character node for a given character in a given font. If that character doesn’t exist, null is returned instead. function new character (f : internal font number ; c : eight bits ): pointer ;

label exit ;

var p: pointer ; { newly allocated node } begin if font bc[f] ≤ c then

if font ec[f] ≥ c then

if char exists (char info(f)(qi (c))) then begin p ← get avail ; font (p) ← f; character (p) ← qi (c); new character ← p; return; end;

char warning (f, c); new character ← null ; exit : end;