62  PART 12: DISPLAYING BOXES  TEX82 §173

173. Displaying boxes. We can reinforce our knowledge of the data structures just introduced by considering two procedures that display a list in symbolic form. The first of these, called short display , is used in “overfull box” messages to give the top-level description of a list. The other one, called show node list , prints a detailed description of exactly what is in the data structure.

The philosophy of short display is to ignore the fine points about exactly what is inside boxes, except that ligatures and discretionary breaks are expanded. As a result, short display is a recursive procedure, but the recursion is never more than one level deep.

A global variable font in short display keeps track of the font code that is assumed to be present when short display begins; deviations from this font will be printed. ⟨ Global variables 13 ⟩ +≡ font in short display : integer ; { an internal font number }

174. Boxes, rules, inserts, whatsits, marks, and things in general that are sort of “complicated” are indicated only by printing ‘ ’. procedure short display (p : integer ); { prints highlights of list p }

var n: integer ; { for replacement counts } begin while p > mem min do

begin if is char node(p) then

begin if p ≤ mem end then

begin if font (p) ≠ font in short display then begin if (font (p) < font base) ∨ (font (p) > font max ) then print char ( ) else ⟨ Print the font identifier for font (p) 267 ⟩; print char ( ␣ ); font in short display ← font (p); end;

print ASCII (qo(character (p)));

end; end

else ⟨ Print a short indication of the contents of node p 175 ⟩; p ← link (p); end;

end;

175. ⟨ Print a short indication of the contents of node p 175 ⟩ ≡ case type(p) of hlist node, vlist node, ins node, whatsit node, mark node, adjust node, unset node: print ( ); rule node: print char ( ); glue node: if glue ptr (p) ≠ zero glue then print char ( ␣ ); math node: print char ( $ ); ligature node: short display (lig ptr (p)); disc node: begin short display (pre break (p)); short display (post break (p));

n ← replace count (p);

while n > 0 do begin if link (p) ≠ null then p ← link (p); decr (n); end;

end;

othercases do nothing

endcases

This code is used in section 174.

§176  TEX82  PART 12: DISPLAYING BOXES 63

176. The show node list routine requires some auxiliary subroutines: one to print a font-and-character combination, one to print a token list without its reference count, and one to print a rule dimension. procedure print font and char (p : integer ); { prints char node data }

begin if p > mem end then print esc( ) else begin if (font (p) < font base) ∨ (font (p) > font max ) then print char ( )

else ⟨ Print the font identifier for font (p) 267 ⟩; print char ( ␣ ); print ASCII (qo(character (p))); end;

end; procedure print mark (p : integer ); { prints token list data in braces }

begin print char ( ); if (p < hi mem min) ∨ (p > mem end ) then print esc( ) else show token list (link (p), null , max print line − 10); print char ( ); end;

procedure print rule dimen(d : scaled ); { prints dimension in rule node } begin if is running (d) then print char ( ) else print scaled (d); end;

177. Then there is a subroutine that prints glue stretch and shrink, possibly followed by the name of finite units: procedure print glue(d : scaled ; order : integer ; s : str number ); { prints a glue component }

begin print scaled (d); if (order < normal ) ∨ (order > filll ) then print ( ) else if order > normal then

begin print ( ); while order > fil do

begin print char ( ); decr (order ); end; end

else if s ≠ 0 then print (s); end;

178. The next subroutine prints a whole glue specification. procedure print spec(p : integer ; s : str number ); { prints a glue specification }

begin if (p < mem min) ∨ (p ≥ lo mem max ) then print char ( ) else begin print scaled (width(p));

if s ≠ 0 then print (s);

if stretch(p) ≠ 0 then begin print ( ␣ ␣ ); print glue(stretch(p), stretch order (p), s); end;

if shrink (p) ≠ 0 then begin print ( ␣ ␣ ); print glue(shrink (p), shrink order (p), s); end;

end; end;

179. We also need to declare some procedures that appear later in this documentation.

⟨ Declare procedures needed for displaying the elements of mlists 691 ⟩ ⟨ Declare the procedure called print skip param 225 ⟩ 180. Since boxes can be inside of boxes, show node list is inherently recursive, up to a given maximum number of levels. The history of nesting is indicated by the current string, which will be printed at the beginning of each line; the length of this string, namely cur length, is the depth of nesting.

Recursive calls on show node list therefore use the following pattern:

define node list display (#) ≡ begin append char ( ); show node list (#); flush char ; end { str room need not be checked; see show box below }

181. A global variable called depth threshold is used to record the maximum depth of nesting for which show node list will show information. If we have depth threshold = 0, for example, only the top level information will be given and no sublists will be traversed. Another global variable, called breadth max , tells the maximum number of items to show at each level; breadth max had better be positive, or you won’t see anything. ⟨ Global variables 13 ⟩ +≡ depth threshold : integer ; { maximum nesting depth in box displays } breadth max : integer ; { maximum number of items shown at the same list level }

182. Now we are ready for show node list itself. This procedure has been written to be “extra robust” in the sense that it should not crash or get into a loop even if the data structures have been messed up by bugs in the rest of the program. You can safely call its parent routine show box (p) for arbitrary values of p when you are debugging TEX. However, in the presence of bad data, the procedure may fetch a memory word whose variant is different from the way it was stored; for example, it might try to read mem[p].hh when mem[p] contains a scaled integer, if p is a pointer that has been clobbered or chosen at random. procedure show node list (p : integer ); { prints a node list symbolically }

label exit ;

var n: integer ; { the number of items already printed at this level }

g: real ; { a glue ratio, as a floating point number } begin if cur length > depth threshold then

begin if p > null then print ( ␣ ); { indicate that there’s been some truncation } return; end;

n ← 0;

while p > mem min do begin print ln; print current string ; { display the nesting history } if p > mem end then { pointer out of range }

begin print ( ␣ ␣ ␣ ); return; end; incr (n); if n > breadth max then { time to stop }

begin print ( ); return;

end; ⟨ Display node p 183 ⟩; p ← link (p); end;

exit : end; 183. ⟨ Display node p 183 ⟩ ≡

if is char node(p) then print font and char (p) else case type(p) of

hlist node, vlist node, unset node: ⟨ Display box p 184 ⟩; rule node: ⟨ Display rule p 187 ⟩; ins node: ⟨ Display insertion p 188 ⟩; whatsit node: ⟨ Display the whatsit node p 1356 ⟩; glue node: ⟨ Display glue p 189 ⟩; kern node: ⟨ Display kern p 191 ⟩; math node: ⟨ Display math node p 192 ⟩; ligature node: ⟨ Display ligature p 193 ⟩; penalty node: ⟨ Display penalty p 194 ⟩; disc node: ⟨ Display discretionary p 195 ⟩; mark node: ⟨ Display mark p 196 ⟩; adjust node: ⟨ Display adjustment p 197 ⟩; ⟨ Cases of show node list that arise in mlists only 690 ⟩ othercases print ( ␣ ␣ ) endcases

This code is used in section 182.

184. ⟨ Display box p 184 ⟩ ≡ begin if type(p) = hlist node then print esc( ) else if type(p) = vlist node then print esc( )

else print esc( ); print ( ); print scaled (height (p)); print char ( ); print scaled (depth(p)); print ( ); print scaled (width(p)); if type(p) = unset node then ⟨ Display special fields of the unset node p 185 ⟩ else begin ⟨ Display the value of glue set (p) 186 ⟩;

if shift amount (p) ≠ 0 then begin print ( ␣ ␣ ); print scaled (shift amount (p)); end;

end; node list display (list ptr (p)); { recursive call } end

This code is used in section 183.

185. ⟨ Display special fields of the unset node p 185 ⟩ ≡

begin if span count (p) ≠ min quarterword then begin print ( ␣ ); print int (qo(span count (p)) + 1); print ( ␣ ); end;

if glue stretch(p) ≠ 0 then begin print ( ␣ ␣ ); print glue(glue stretch(p), glue order (p), 0); end;

if glue shrink (p) ≠ 0 then begin print ( ␣ ␣ ); print glue(glue shrink (p), glue sign(p), 0); end;

end

This code is used in section 184.

186. The code will have to change in this place if glue ratio is a structured type instead of an ordinary real . Note that this routine should avoid arithmetic errors even if the glue set field holds an arbitrary random value. The following code assumes that a properly formed nonzero real number has absolute value 2^{20} or more when it is regarded as an integer; this precaution was adequate to prevent floating point underflow on the author’s computer. ⟨ Display the value of glue set (p) 186 ⟩ ≡

g ← float (glue set (p)); if (g ≠ float constant (0)) ∧ (glue sign(p) ≠ normal ) then

begin print ( ␣ ␣ ␣ );

if glue sign(p) = shrinking then print ( ␣ );

if abs (mem[p + glue offset ].int ) < ´ 4000000 then print ( )

else if abs (g) > float constant (20000) then begin if g > float constant (0) then print char ( ) else print ( ␣ ); print glue(20000 ∗ unity , glue order (p), 0); end

else print glue(round (unity ∗ g), glue order (p), 0); end

This code is used in section 184.

187. ⟨ Display rule p 187 ⟩ ≡ begin print esc( ); print rule dimen(height (p)); print char ( ); print rule dimen(depth(p)); print ( ); print rule dimen(width(p)); end

This code is used in section 183.

188. ⟨ Display insertion p 188 ⟩ ≡ begin print esc( ); print int (qo(subtype(p))); print ( ␣ ␣ ␣ ); print scaled (height (p)); print ( ␣ ); print spec(split top ptr (p), 0); print char ( ); print scaled (depth(p)); print ( ␣ ␣ ␣ ); print int (float cost (p)); node list display (ins ptr (p));

{ recursive call } end

This code is used in section 183.

189. ⟨ Display glue p 189 ⟩ ≡ if subtype(p) ≥ a leaders then ⟨ Display leaders p 190 ⟩ else begin print esc( );

if subtype(p) ≠ normal then begin print char ( ); if subtype(p) < cond math glue then print skip param(subtype(p) − 1) else if subtype(p) = cond math glue then print esc( )

else print esc( ); print char ( ); end;

if subtype(p) ≠ cond math glue then begin print char ( ␣ ); if subtype(p) < cond math glue then print spec(glue ptr (p), 0) else print spec(glue ptr (p), ); end;

end

This code is used in section 183.

190. ⟨ Display leaders p 190 ⟩ ≡ begin print esc( ); if subtype(p) = c leaders then print char ( ) else if subtype(p) = x leaders then print char ( ); print ( ␣ ); print spec(glue ptr (p), 0); node list display (leader ptr (p)); { recursive call } end

This code is used in section 189.

191. An “explicit” kern value is indicated implicitly by an explicit space. ⟨ Display kern p 191 ⟩ ≡

if subtype(p) ≠ mu glue then begin print esc( ); if subtype(p) ≠ normal then print char ( ␣ ); print scaled (width(p)); if subtype(p) = acc kern then print ( ␣ ␣ ); end

else begin print esc( ); print scaled (width(p)); print ( );

end

This code is used in section 183.

192. ⟨ Display math node p 192 ⟩ ≡ begin print esc( ); if subtype(p) = before then print ( ) else print ( ); if width(p) ≠ 0 then

begin print ( ␣ ␣ ); print scaled (width(p)); end;

end

This code is used in section 183.

193. ⟨ Display ligature p 193 ⟩ ≡ begin print font and char (lig char (p)); print ( ␣ ␣ ); if subtype(p) > 1 then print char ( ); font in short display ← font (lig char (p)); short display (lig ptr (p)); if odd (subtype(p)) then print char ( ); print char ( ); end

This code is used in section 183.

194. ⟨ Display penalty p 194 ⟩ ≡ begin print esc( ␣ ); print int (penalty (p)); end

This code is used in section 183.

195. The post break list of a discretionary node is indicated by a prefixed ‘ ’ instead of the ‘ ’ before the pre break list. ⟨ Display discretionary p 195 ⟩ ≡

begin print esc( ); if replace count (p) > 0 then

begin print ( ␣ ␣ ); print int (replace count (p)); end;

node list display (pre break (p)); { recursive call } append char ( ); show node list (post break (p)); flush char ; { recursive call } end

This code is used in section 183.

196. ⟨ Display mark p 196 ⟩ ≡ begin print esc( ); print mark (mark ptr (p)); end

This code is used in section 183.

197. ⟨ Display adjustment p 197 ⟩ ≡ begin print esc( ); node list display (adjust ptr (p)); { recursive call } end

This code is used in section 183.

198. The recursive machinery is started by calling show box . procedure show box (p : pointer );

begin ⟨ Assign the values depth threshold ← show box depth and breadth max ← show box breadth 236 ⟩; if breadth max ≤ 0 then breadth max ← 5; if pool ptr + depth threshold ≥ pool size then depth threshold ← pool size − pool ptr − 1;

{ now there’s enough room for prefix string } show node list (p); { the show starts at p } print ln; end;