1% omdir.ch: Primitives to deal with multiple-direction text
2%
3% This file is part of the Omega projet, which
4% is based on the web2c distribution of TeX.
5%
6% Copyright (c) 1994--2000 John Plaice and Yannis Haralambous
7%
8% This library is free software; you can redistribute it and/or
9% modify it under the terms of the GNU Library General Public
10% License as published by the Free Software Foundation; either
11% version 2 of the License, or (at your option) any later version.
12%
13% This library is distributed in the hope that it will be useful,
14% but WITHOUT ANY WARRANTY; without even the implied warranty of
15% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16% Library General Public License for more details.
17%
18% You should have received a copy of the GNU Library General Public
19% License along with this library; if not, write to the Free Software
20% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21%
22%-------------------------
23@x [10] m.135
24@d hlist_node=0 {|type| of hlist nodes}
25@d box_node_size=7 {number of words to allocate for a box node}
26@d width_offset=1 {position of |width| field in a box node}
27@d depth_offset=2 {position of |depth| field in a box node}
28@d height_offset=3 {position of |height| field in a box node}
29@d width(#) == mem[#+width_offset].sc {width of the box, in sp}
30@d depth(#) == mem[#+depth_offset].sc {depth of the box, in sp}
31@d height(#) == mem[#+height_offset].sc {height of the box, in sp}
32@d shift_amount(#) == mem[#+4].sc {repositioning distance, in sp}
33@d list_offset=5 {position of |list_ptr| field in a box node}
34@d list_ptr(#) == link(#+list_offset) {beginning of the list inside the box}
35@d glue_order(#) == subtype(#+list_offset) {applicable order of infinity}
36@d glue_sign(#) == type(#+list_offset) {stretching or shrinking}
37@d normal=0 {the most common case when several cases are named}
38@d stretching = 1 {glue setting applies to the stretch components}
39@d shrinking = 2 {glue setting applies to the shrink components}
40@d glue_offset = 6 {position of |glue_set| in a box node}
41@d glue_set(#) == mem[#+glue_offset].gr
42  {a word of type |glue_ratio| for glue setting}
43@y
44@d hlist_node=0 {|type| of hlist nodes}
45@d box_node_size=8 {number of words to allocate for a box node}
46@d width_offset=1 {position of |width| field in a box node}
47@d depth_offset=2 {position of |depth| field in a box node}
48@d height_offset=3 {position of |height| field in a box node}
49@d width(#) == mem[#+width_offset].sc {width of the box, in sp}
50@d depth(#) == mem[#+depth_offset].sc {depth of the box, in sp}
51@d height(#) == mem[#+height_offset].sc {height of the box, in sp}
52@d shift_amount(#) == mem[#+4].sc {repositioning distance, in sp}
53@d list_offset=5 {position of |list_ptr| field in a box node}
54@d list_ptr(#) == link(#+list_offset) {beginning of the list inside the box}
55@d glue_order(#) == subtype(#+list_offset) {applicable order of infinity}
56@d glue_sign(#) == type(#+list_offset) {stretching or shrinking}
57@d normal=0 {the most common case when several cases are named}
58@d stretching = 1 {glue setting applies to the stretch components}
59@d shrinking = 2 {glue setting applies to the shrink components}
60@d glue_offset = 6 {position of |glue_set| in a box node}
61@d glue_set(#) == mem[#+glue_offset].gr
62  {a word of type |glue_ratio| for glue setting}
63@d dir_offset = 7 {position of |box_dir| in a box node}
64@d box_dir(#) == mem[#+dir_offset].int
65@z
66%-------------------------
67@x [10] m.136
68@p function new_null_box:pointer; {creates a new box node}
69var p:pointer; {the new node}
70begin p:=get_node(box_node_size); type(p):=hlist_node;
71subtype(p):=min_quarterword;
72width(p):=0; depth(p):=0; height(p):=0; shift_amount(p):=0; list_ptr(p):=null;
73glue_sign(p):=normal; glue_order(p):=normal; set_glue_ratio_zero(glue_set(p));
74new_null_box:=p;
75@y
76@p function new_null_box:pointer; {creates a new box node}
77var p:pointer; {the new node}
78begin p:=get_node(box_node_size); type(p):=hlist_node;
79subtype(p):=min_quarterword;
80width(p):=0; depth(p):=0; height(p):=0; shift_amount(p):=0; list_ptr(p):=null;
81glue_sign(p):=normal; glue_order(p):=normal; set_glue_ratio_zero(glue_set(p));
82box_dir(p):=text_direction;
83new_null_box:=p;
84@z
85%-------------------------
86@x [10] m.138
87@d rule_node=2 {|type| of rule nodes}
88@d rule_node_size=4 {number of words to allocate for a rule node}
89@d null_flag==-@'10000000000 {$-2^{30}$, signifies a missing item}
90@d is_running(#) == (#=null_flag) {tests for a running dimension}
91@y
92@d rule_node=2 {|type| of rule nodes}
93@d rule_node_size=5 {number of words to allocate for a rule node}
94@d null_flag==-@'10000000000 {$-2^{30}$, signifies a missing item}
95@d is_running(#) == (#=null_flag) {tests for a running dimension}
96@d rule_dir(#)==info(#+4)
97@z
98%-------------------------
99@x [10] m.139
100@p function new_rule:pointer;
101var p:pointer; {the new node}
102begin p:=get_node(rule_node_size); type(p):=rule_node;
103subtype(p):=0; {the |subtype| is not used}
104width(p):=null_flag; depth(p):=null_flag; height(p):=null_flag;
105new_rule:=p;
106end;
107@y
108@p function new_rule:pointer;
109var p:pointer; {the new node}
110begin p:=get_node(rule_node_size); type(p):=rule_node;
111subtype(p):=0; {the |subtype| is not used}
112width(p):=null_flag; depth(p):=null_flag; height(p):=null_flag;
113rule_dir(p):=-1;
114new_rule:=p;
115end;
116@z
117%-------------------------
118@x [10] m.176
119procedure print_rule_dimen(@!d:scaled); {prints dimension in rule node}
120begin if is_running(d) then print_char("*") else print_scaled(d);
121@.*\relax@>
122end;
123@y
124procedure print_rule_dimen(@!d:scaled); {prints dimension in rule node}
125begin if is_running(d) then print_char("*") else print_scaled(d);
126@.*\relax@>
127end;
128@#
129procedure print_dir(d:integer);
130begin
131print(dir_names[dir_primary[d]]);
132print(dir_names[dir_secondary[d]]);
133print(dir_names[dir_tertiary[d]]);
134end;
135@z
136%-------------------------
137@x [12] m.184
138@ @<Display box |p|@>=
139begin if type(p)=hlist_node then print_esc("h")
140else if type(p)=vlist_node then print_esc("v")
141else print_esc("unset");
142print("box("); print_scaled(height(p)); print_char("+");
143print_scaled(depth(p)); print(")x"); print_scaled(width(p));
144if type(p)=unset_node then
145  @<Display special fields of the unset node |p|@>
146else  begin @<Display the value of |glue_set(p)|@>;
147  if shift_amount(p)<>0 then
148    begin print(", shifted "); print_scaled(shift_amount(p));
149    end;
150  end;
151node_list_display(list_ptr(p)); {recursive call}
152end
153@y
154@ @<Display box |p|@>=
155begin if type(p)=hlist_node then print_esc("h")
156else if type(p)=vlist_node then print_esc("v")
157else print_esc("unset");
158print("box("); print_scaled(height(p)); print_char("+");
159print_scaled(depth(p)); print(")x"); print_scaled(width(p));
160if type(p)=unset_node then
161  @<Display special fields of the unset node |p|@>
162else  begin @<Display the value of |glue_set(p)|@>;
163  if shift_amount(p)<>0 then
164    begin print(", shifted "); print_scaled(shift_amount(p));
165    end;
166  print(", direction "); print_dir(box_dir(p));
167  end;
168node_list_display(list_ptr(p)); {recursive call}
169end
170@z
171%-------------------------
172@x [10] m.206
173hlist_node,vlist_node,unset_node: begin r:=get_node(box_node_size);
174  mem[r+6]:=mem[p+6]; mem[r+5]:=mem[p+5]; {copy the last two words}
175@y
176hlist_node,vlist_node,unset_node: begin r:=get_node(box_node_size);
177  mem[r+7]:=mem[p+7]; mem[r+6]:=mem[p+6]; mem[r+5]:=mem[p+5];
178  {copy the last three words}
179@z
180%-------------------------
181@x [15] m.209
182@d max_internal=register
183   {the largest code that can follow \.{\\the}}
184@y
185@d assign_dir=register+1 {(\.{\\pagedir}, \.{\\textdir})}
186@d max_internal=assign_dir
187   {the largest code that can follow \.{\\the}}
188@z
189%-------------------------
190@x [16] m.212
191  @!aux_field: memory_word;
192@y
193  @!aux_field: memory_word;
194  @!dirs_field: halfword;
195  @!math_field: integer;
196@z
197%-------------------------
198@x [16] m.212
199@d mode_line==cur_list.ml_field {source file line number at beginning of list}
200@y
201@d mode_line==cur_list.ml_field {source file line number at beginning of list}
202@d dir_save==cur_list.dirs_field {dir stack when a paragraph is interrupted}
203@d dir_math_save==cur_list.math_field
204   {should begin/end dir nodes be placed around mathematics?}
205@z
206%-------------------------
207@x [16] m.215
208prev_graf:=0; shown_mode:=0;
209@y
210prev_graf:=0; shown_mode:=0;
211dir_save:=null; dir_math_save:=false;
212@z
213%-------------------------
214@x [16] m.216 l.4351
215@ @p @<LOCAL: Declare |make_local_par_node|@>;
216@y
217@ @p @<LOCAL: Declare |make_local_par_node|@>;
218
219@ @p @<DIR: Declare |new_dir|@>;
220@z
221%-------------------------
222@x [16] m.216
223incr(nest_ptr); head:=get_avail; tail:=head; prev_graf:=0; mode_line:=line;
224@y
225incr(nest_ptr); head:=get_avail; tail:=head; prev_graf:=0; mode_line:=line;
226dir_save:=null; dir_math_save:=false;
227@z
228%-------------------------
229@x [16] m.217
230free_avail(head); decr(nest_ptr); cur_list:=nest[nest_ptr];
231@y
232free_avail(head); decr(nest_ptr); cur_list:=nest[nest_ptr];
233@z
234%-------------------------
235@x [17] m.236
236@d int_pars=58 {total number of integer parameters}
237@d count_base=int_base+int_pars {|number_regs| user \.{\\count} registers}
238@y
239@d no_local_dirs_code=58
240@d level_local_dir_code=59
241@d int_pars=61 {total number of integer parameters}
242@d dir_base=int_base+int_pars
243@d page_direction_code=0
244@d body_direction_code=1
245@d par_direction_code=2
246@d text_direction_code=3
247@d math_direction_code=4
248@d dir_pars=5
249@d count_base=dir_base+dir_pars {|number_regs| user \.{\\count} registers}
250@z
251%-------------------------
252@x [17] m.238
253@d no_local_whatsits==int_par(no_local_whatsits_code)
254@y
255@d no_local_whatsits==int_par(no_local_whatsits_code)
256@d no_local_dirs==int_par(no_local_dirs_code)
257@d level_local_dir==int_par(level_local_dir_code)
258@d dir_par(#)==new_eqtb_int(dir_base+#) {a direction parameter}
259@d page_direction==dir_par(page_direction_code)
260@d body_direction==dir_par(body_direction_code)
261@d par_direction==dir_par(par_direction_code)
262@d text_direction==dir_par(text_direction_code)
263@d math_direction==dir_par(math_direction_code)
264@z
265%-------------------------
266@x [17] m.240
267set_new_eqtb_int(int_base+end_line_char_code,carriage_return);
268@y
269set_new_eqtb_int(int_base+end_line_char_code,carriage_return);
270set_new_eqtb_int(int_base+level_local_dir_code,level_one);
271@z
272%-------------------------
273@x [17] m.247
274@d dimen_pars=21 {total number of dimension parameters}
275@y
276@d page_width_code=21
277@d page_height_code=22
278@d page_right_offset_code=23
279@d page_bottom_offset_code=24
280@d dimen_pars=25 {total number of dimension parameters}
281@z
282%-------------------------
283@x [17] m.247
284@d emergency_stretch==dimen_par(emergency_stretch_code)
285@y
286@d emergency_stretch==dimen_par(emergency_stretch_code)
287@d page_width==dimen_par(page_width_code)
288@d page_height==dimen_par(page_height_code)
289@d page_right_offset==dimen_par(page_right_offset_code)
290@d page_bottom_offset==dimen_par(page_bottom_offset_code)
291@z
292%-------------------------
293@x [26] m.410
294@d int_val=0 {integer values}
295@d dimen_val=1 {dimension values}
296@d glue_val=2 {glue specifications}
297@d mu_val=3 {math glue specifications}
298@d ident_val=4 {font identifier}
299@d tok_val=5 {token lists}
300
301@<Glob...@>=
302@!cur_val:integer; {value returned by numeric scanners}
303@!cur_val_level:int_val..tok_val; {the ``level'' of this value}
304@y
305@d int_val=0 {integer values}
306@d dimen_val=1 {dimension values}
307@d glue_val=2 {glue specifications}
308@d mu_val=3 {math glue specifications}
309@d dir_val=4 {directions}
310@d ident_val=5 {font identifier}
311@d tok_val=6 {token lists}
312
313@<Glob...@>=
314@!cur_val:integer; {value returned by numeric scanners}
315@!cur_val1:integer; {delcodes are now 51 digits}
316@!cur_val_level:int_val..dir_val; {the ``level'' of this value}
317@z
318%-------------------------
319@x [26] m.413
320assign_int: scanned_result(new_eqtb_int(m))(int_val);
321@y
322assign_int: scanned_result(new_eqtb_int(m))(int_val);
323assign_dir: scanned_result(new_eqtb_int(m))(dir_val);
324@z
325%-------------------------
326@x [26] m.437
327@ @<Declare procedures that scan restricted classes of integers@>=
328procedure scan_eight_bit_int;
329@y
330@
331@d dir_T=0
332@d dir_L=1
333@d dir_B=2
334@d dir_R=3
335@d dir_eq_end(#)==(#)
336@d dir_eq(#)==(#)=dir_eq_end
337@d dir_ne_end(#)==(#)
338@d dir_ne(#)==(#)<>dir_ne_end
339@d dir_opposite_end(#)==((#) mod 4)
340@d dir_opposite(#)==(((#)+2) mod 4)=dir_opposite_end
341@d dir_parallel_end(#)==((#) mod 2)
342@d dir_parallel(#)==((#) mod 2)=dir_parallel_end
343@d dir_orthogonal_end(#)==(# mod 2)
344@d dir_orthogonal(#)==((#) mod 2)<>dir_orthogonal_end
345@d dir_next_end(#)==((#) mod 4)
346@d dir_next(#)==(((#)+3) mod 4)=dir_next_end
347@d dir_prev_end(#)==((#) mod 4)
348@d dir_prev(#)==(((#)+1) mod 4)=dir_prev_end
349
350{box directions}
351@d dir_TL_=0
352@d dir_TR_=1
353@d dir_LT_=2
354@d dir_LB_=3
355@d dir_BL_=4
356@d dir_BR_=5
357@d dir_RT_=6
358@d dir_RB_=7
359
360{font directions}
361@d dir__LT= 0
362@d dir__LL= 1
363@d dir__LB= 2
364@d dir__LR= 3
365@d dir__RT= 4
366@d dir__RL= 5
367@d dir__RB= 6
368@d dir__RR= 7
369@d dir__TT= 8
370@d dir__TL= 9
371@d dir__TB=10
372@d dir__TR=11
373@d dir__BT=12
374@d dir__BL=13
375@d dir__BB=14
376@d dir__BR=15
377
378@d is_mirrored(#)==dir_opposite(dir_primary[#])(dir_tertiary[#])
379@d is_rotated(#)==dir_parallel(dir_secondary[#])(dir_tertiary[#])
380@d font_direction(#)==(# mod 16)
381@d box_direction(#)==(# div 4)
382
383@d scan_single_dir(#)==begin
384if scan_keyword("T") then #:=dir_T
385else if scan_keyword("L") then #:=dir_L
386else if scan_keyword("B") then #:=dir_B
387else if scan_keyword("R") then #:=dir_R
388else begin
389  print_err("Bad direction"); cur_val:=0;
390  goto exit;
391  end
392end
393
394@<Declare procedures that scan restricted classes of integers@>=
395procedure scan_dir;
396var d1,d2,d3: integer;
397begin
398get_x_token;
399if cur_cmd=assign_dir then begin
400  cur_val:=new_eqtb_int(cur_chr);
401  goto exit;
402  end
403else back_input;
404scan_single_dir(d1);
405scan_single_dir(d2);
406if dir_parallel(d1)(d2) then begin
407  print_err("Bad direction"); cur_val:=0;
408  goto exit;
409  end;
410scan_single_dir(d3);
411cur_val:=d1*8+dir_rearrange[d2]*4+d3;
412exit:
413end;
414
415@ @<Declare procedures that scan restricted classes of integers@>=
416procedure scan_eight_bit_int;
417@z
418%-------------------------
419@x [27] m.463
420@p function scan_rule_spec:pointer;
421label reswitch;
422var q:pointer; {the rule node being created}
423begin q:=new_rule; {|width|, |depth|, and |height| all equal |null_flag| now}
424if cur_cmd=vrule then width(q):=default_rule
425else  begin height(q):=default_rule; depth(q):=0;
426  end;
427@y
428@p function scan_rule_spec:pointer;
429label reswitch;
430var q:pointer; {the rule node being created}
431begin q:=new_rule; {|width|, |depth|, and |height| all equal |null_flag| now}
432if cur_cmd=vrule then begin
433  width(q):=default_rule;
434  rule_dir(q):=body_direction;
435  end
436else begin
437  height(q):=default_rule; depth(q):=0;
438  rule_dir(q):=text_direction;
439end;
440@z
441%-------------------------
442@x [27] m.465
443  int_val:print_int(cur_val);
444@y
445  int_val:print_int(cur_val);
446  dir_val:print_dir(cur_val);
447@z
448%-------------------------
449@x [30] m.550
450@d offset_false_bchar=offset_bchar+1
451@d offset_ivalues_start=offset_false_bchar+1
452@y
453@d offset_false_bchar=offset_bchar+1
454@d offset_natural_dir=offset_false_bchar+1
455@d offset_ivalues_start=offset_natural_dir+1
456@z
457%-------------------------
458@x [30] m.550
459@d font_false_bchar(#)==font_info(#)(offset_false_bchar).int
460@y
461@d font_false_bchar(#)==font_info(#)(offset_false_bchar).int
462@d font_natural_dir(#)==font_info(#)(offset_natural_dir).int
463@z
464%-------------------------
465@x [30] m.560
466@p function read_font_info(@!u:pointer;@!nom,@!aire:str_number;
467   @!s:scaled;offset:quarterword):internal_font_number; {input a \.{TFM} file}
468@y
469@p function read_font_info(@!u:pointer;@!nom,@!aire:str_number;
470   @!s:scaled;offset:quarterword;natural_dir:integer):internal_font_number;
471   {input a \.{TFM} file}
472@z
473%-------------------------
474@x [30] m.560
475font_offset(f):=offset;
476@y
477font_offset(f):=offset;
478font_natural_dir(f):=natural_dir;
479@z
480%-------------------------
481@x [31] m.586
482@d set_rule=132 {typeset a rule and move right}
483@y
484@d set_rule=132 {typeset a rule and move right}
485@d put1==133 {typeset a character without moving}
486@z
487%-------------------------
488@x [31] m.586
489@d right1=143 {move right}
490@y
491@d right1==143 {move right}
492@d right4==146 {move right, 4 bytes}
493@z
494%-------------------------
495@x [31] m.586
496@d down1=157 {move down}
497@y
498@d down1=157 {move down}
499@d down4=160 {move down, 4 bytes}
500@z
501%-------------------------
502@x [32] m.607
503@p procedure movement(@!w:scaled;@!o:eight_bits);
504label exit,found,not_found,2,1;
505var mstate:small_number; {have we seen a |y| or |z|?}
506@!p,@!q:pointer; {current and top nodes on the stack}
507@!k:integer; {index into |dvi_buf|, modulo |dvi_buf_size|}
508begin q:=get_node(movement_node_size); {new node for the top of the stack}
509width(q):=w; location(q):=dvi_offset+dvi_ptr;
510if o=down1 then
511  begin link(q):=down_ptr; down_ptr:=q;
512  end
513else  begin link(q):=right_ptr; right_ptr:=q;
514  end;
515@<Look at the other stack entries until deciding what sort of \.{DVI} command
516  to generate; |goto found| if node |p| is a ``hit''@>;
517@<Generate a |down| or |right| command for |w| and |return|@>;
518found: @<Generate a |y0| or |z0| command in order to reuse a previous
519  appearance of~|w|@>;
520exit:end;
521@y
522@d dvi_set(#)==oval:=#-font_offset(f); ocmd:=set1; out_cmd
523@d dvi_put(#)==oval:=#-font_offset(f); ocmd:=put1; out_cmd
524@d dvi_set_rule_end(#)==dvi_four(#)
525@d dvi_set_rule(#)==dvi_out(set_rule); dvi_four(#); dvi_set_rule_end
526@d dvi_put_rule_end(#)==dvi_four(#)
527@d dvi_put_rule(#)==dvi_out(put_rule); dvi_four(#); dvi_put_rule_end
528@d dvi_right(#)==dvi_out(right4); dvi_four(#);
529@d dvi_left(#)==dvi_out(right4); dvi_four(-#);
530@d dvi_down(#)==dvi_out(down4); dvi_four(#);
531@d dvi_up(#)==dvi_out(down4); dvi_four(-#);
532
533@p procedure movement(@!w:scaled;@!o:eight_bits);
534label exit,found,not_found,2,1;
535var mstate:small_number; {have we seen a |y| or |z|?}
536@!p,@!q:pointer; {current and top nodes on the stack}
537@!k:integer; {index into |dvi_buf|, modulo |dvi_buf_size|}
538begin
539case box_direction(dvi_direction) of
540  dir_TL_: begin
541    end;
542  dir_TR_: begin
543    if o=right1 then negate(w);
544    end;
545  dir_LT_: begin
546    if o=right1 then o:=down1
547    else o:=right1;
548    end;
549  dir_LB_: begin
550    if o=right1 then begin
551      o:=down1; negate(w);
552      end
553    else o:=right1;
554    end;
555  dir_BL_: begin
556    if o=down1 then negate(w);
557    end;
558  dir_BR_: begin
559    negate(w);
560    end;
561  dir_RT_: begin
562    if o=right1 then o:=down1
563    else begin o:=right1; negate(w);
564      end;
565    end;
566  dir_RB_: begin
567    if o=right1 then o:=down1 else o:=right1;
568    negate(w);
569    end;
570  end;
571if false then begin
572q:=get_node(movement_node_size); {new node for the top of the stack}
573width(q):=w; location(q):=dvi_offset+dvi_ptr;
574if o=down1 then
575  begin link(q):=down_ptr; down_ptr:=q;
576  end
577else  begin link(q):=right_ptr; right_ptr:=q;
578  end;
579@<Look at the other stack entries until deciding what sort of \.{DVI} command
580  to generate; |goto found| if node |p| is a ``hit''@>;
581end;
582@<Generate a |down| or |right| command for |w| and |return|@>;
583found: @<Generate a |y0| or |z0| command in order to reuse a previous
584  appearance of~|w|@>;
585exit:end;
586@z
587%-------------------------
588@x [32] m.610
589info(q):=yz_OK;
590@y
591@z
592%-------------------------
593@x [32] m.617
594dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font;
595@y
596dvi_h:=0; dvi_v:=0; cur_h:=0; cur_v:=0; dvi_f:=null_font;
597@z
598%-------------------------
599@x [32] m.619
600procedure hlist_out; {output an |hlist_node| box}
601label reswitch, move_past, fin_rule, next_p;
602var base_line: scaled; {the baseline coordinate for this box}
603@y
604procedure hlist_out; {output an |hlist_node| box}
605label reswitch, move_past, fin_rule, next_p;
606var base_line: scaled; {the baseline coordinate for this box}
607c_wd,c_ht,c_dp: scaled;
608  {the real width, height and depth of the character}
609c_htdp: quarterword; {height-depth entry in |char_info|}
610c_info: four_quarters; {|char_info| entry}
611edge_v: scaled;
612edge_h: scaled;
613effective_horizontal: scaled;
614basepoint_horizontal: scaled;
615basepoint_vertical: scaled;
616saving_h: scaled;
617saving_v: scaled;
618save_direction: integer;
619dir_tmp,dir_ptr:pointer;
620dvi_dir_h,dvi_dir_ptr,dvi_temp_ptr:integer;
621@z
622%-------------------------
623@x [32] m.619
624incr(cur_s);
625if cur_s>0 then dvi_out(push);
626if cur_s>max_push then max_push:=cur_s;
627save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; left_edge:=cur_h;
628while p<>null do @<Output node |p| for |hlist_out| and move to the next node,
629  maintaining the condition |cur_v=base_line|@>;
630prune_movements(save_loc);
631if cur_s>0 then dvi_pop(save_loc);
632decr(cur_s);
633@y
634save_direction:=dvi_direction;
635dvi_direction:=box_dir(this_box);
636@<DIR: Initialize |dir_ptr| for |ship_out|@>;
637saving_h:=dvi_h; saving_v:=dvi_v;
638incr(cur_s);
639if cur_s>0 then dvi_out(push);
640if cur_s>max_push then max_push:=cur_s;
641save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; left_edge:=cur_h;
642while p<>null do @<Output node |p| for |hlist_out| and move to the next node,
643  maintaining the condition |cur_v=base_line|@>;
644cur_h:=saving_h; cur_v:=saving_v;
645synch_h; synch_v;
646prune_movements(save_loc);
647if cur_s>0 then dvi_pop(save_loc);
648decr(cur_s);
649dvi_direction:=save_direction;
650@<DIR: Reset |dir_ptr|@>;
651@z
652%-------------------------
653@x [32] m.620
654  oval:=c-font_offset(f); ocmd:=set1; out_cmd;@/
655  cur_h:=cur_h+char_width(f)(char_info(f)(c));
656@y
657  c_info:=char_info(f)(c);
658  c_htdp:=height_depth(c_info);
659  if is_rotated(dvi_direction) then begin
660    c_ht:=char_width(f)(c_info) div 2;
661    c_wd:=char_height(f)(c_htdp)+char_depth(f)(c_htdp);
662    end
663  else begin
664    c_ht:=char_height(f)(c_htdp);
665    c_dp:=char_depth(f)(c_htdp);
666    c_wd:=char_width(f)(c_info);
667    end;
668  cur_h:=cur_h+c_wd;
669  if (font_natural_dir(f)<>-1) then
670    case font_direction(dvi_direction) of
671    dir__LT,dir__LB: begin
672      dvi_set(c);
673      end;
674    dir__RT,dir__RB: begin
675      dvi_put(c);
676      dvi_left(c_wd);
677      end;
678    dir__TL,dir__TR: begin
679      dvi_put(c);
680      dvi_down(c_wd);
681      end;
682    dir__BL,dir__BR: begin
683      dvi_put(c);
684      dvi_up(c_wd);
685      end;
686    dir__LL,dir__LR: begin
687      dvi_put(c);
688      dvi_right(c_wd);
689      end;
690    dir__RL,dir__RR: begin
691      dvi_put(c);
692      dvi_left(c_wd);
693      end;
694    dir__TT,dir__TB: begin
695      dvi_put(c);
696      dvi_down(c_wd);
697      end;
698    dir__BT,dir__BB: begin
699      dvi_put(c);
700      dvi_up(c_wd);
701      end;
702    end
703  else
704    case font_direction(dvi_direction) of
705    dir__LT: begin
706      dvi_set(c);
707      end;
708    dir__LB: begin
709      dvi_down(c_ht);
710      dvi_set(c);
711      dvi_up(c_ht);
712      end;
713    dir__RT: begin
714      dvi_left(c_wd);
715      dvi_put(c);
716      end;
717    dir__RB: begin
718      dvi_left(c_wd);
719      dvi_down(c_ht);
720      dvi_put(c);
721      dvi_up(c_ht);
722      end;
723    dir__TL: begin
724      dvi_down(c_wd);
725      dvi_left(c_ht);
726      dvi_put(c);
727      dvi_right(c_ht);
728      end;
729    dir__TR: begin
730      dvi_down(c_wd);
731      dvi_left(c_dp);
732      dvi_put(c);
733      dvi_right(c_dp);
734      end;
735    dir__BL: begin
736      dvi_left(c_ht);
737      dvi_put(c);
738      dvi_right(c_ht);
739      dvi_up(c_wd);
740      end;
741    dir__BR: begin
742      dvi_left(c_dp);
743      dvi_put(c);
744      dvi_right(c_dp);
745      dvi_up(c_wd);
746      end;
747    dir__LL,dir__LR: begin
748      dvi_down(c_ht);
749      dvi_put(c);
750      dvi_up(c_ht);
751      dvi_right(c_wd);
752      end;
753    dir__RL,dir__RR: begin
754      dvi_left(c_wd);
755      dvi_down(c_ht);
756      dvi_put(c);
757      dvi_up(c_ht);
758      end;
759    dir__TT,dir__TB: begin
760      dvi_down(c_wd);
761      dvi_left(c_ht);
762      dvi_put(c);
763      dvi_right(c_ht);
764      end;
765    dir__BT,dir__BB: begin
766      dvi_left(c_ht);
767      dvi_put(c);
768      dvi_right(c_ht);
769      dvi_up(c_wd);
770      end;
771    end;
772@z
773%-------------------------
774@x [32] m.622
775rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p);
776  goto fin_rule;
777  end;
778@y
779rule_node: begin
780  if not (dir_orthogonal(dir_primary[rule_dir(p)])(dir_primary[dvi_direction]))
781    then begin
782    rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p);
783    end
784  else begin
785    rule_ht:=width(p) div 2;
786    rule_dp:=width(p) div 2;
787    rule_wd:=height(p)+depth(p);
788    end;
789  goto fin_rule;
790  end;
791@z
792%-------------------------
793@x [32] m.623
794if list_ptr(p)=null then cur_h:=cur_h+width(p)
795else  begin save_h:=dvi_h; save_v:=dvi_v;
796  cur_v:=base_line+shift_amount(p); {shift the box down}
797  temp_ptr:=p; edge:=cur_h;
798  if type(p)=vlist_node then vlist_out@+else hlist_out;
799  dvi_h:=save_h; dvi_v:=save_v;
800  cur_h:=edge+width(p); cur_v:=base_line;
801  end
802@y
803begin
804if not (dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[dvi_direction]))
805  then begin
806  effective_horizontal:=width(p);
807  basepoint_vertical:=0;
808  if dir_opposite(dir_secondary[box_dir(p)])(dir_secondary[dvi_direction]) then
809    basepoint_horizontal:=width(p)
810  else
811    basepoint_horizontal:=0;
812  end
813else begin
814  effective_horizontal:=height(p)+depth(p);
815  if not (is_mirrored(box_dir(p))) then
816    if dir_eq(dir_primary[box_dir(p)])(dir_secondary[dvi_direction]) then
817      basepoint_horizontal:=height(p)
818    else
819      basepoint_horizontal:=depth(p)
820  else
821    if dir_eq(dir_primary[box_dir(p)])(dir_secondary[dvi_direction]) then
822      basepoint_horizontal:=depth(p)
823    else
824      basepoint_horizontal:=height(p);
825  if dir_eq(dir_secondary[box_dir(p)])(dir_primary[dvi_direction]) then
826    basepoint_vertical:= -(width(p) div 2)
827  else
828    basepoint_vertical:= (width(p) div 2);
829  end;
830if not (is_mirrored(dvi_direction)) then
831  basepoint_vertical := basepoint_vertical + shift_amount(p)
832    {shift the box `down'}
833else
834  basepoint_vertical := basepoint_vertical - shift_amount(p);
835    {shift the box `up'}
836if list_ptr(p)=null then cur_h:=cur_h + effective_horizontal
837else begin
838  temp_ptr:=p; edge:=cur_h; cur_h:=cur_h + basepoint_horizontal;
839  edge_v:=cur_v; cur_v:=base_line + basepoint_vertical;
840  synch_h; synch_v; save_h:=dvi_h; save_v:=dvi_v;
841  if type(p)=vlist_node then vlist_out@+else hlist_out;
842  dvi_h:=save_h; dvi_v:=save_v;
843  cur_h:=edge+effective_horizontal; cur_v:=base_line;
844  end
845end
846@z
847%-------------------------
848@x [32] m.624
849  dvi_out(set_rule); dvi_four(rule_ht); dvi_four(rule_wd);
850@y
851  case font_direction(dvi_direction) of
852  dir__LT: begin
853    dvi_set_rule(rule_ht)(rule_wd);
854    end;
855  dir__LB: begin
856    dvi_down(rule_ht);
857    dvi_set_rule(rule_ht)(rule_wd);
858    dvi_up(rule_ht);
859    end;
860  dir__RT: begin
861    dvi_left(rule_wd);
862    dvi_put_rule(rule_ht)(rule_wd);
863    end;
864  dir__RB: begin
865    dvi_left(rule_wd);
866    dvi_down(rule_ht);
867    dvi_put_rule(rule_ht)(rule_wd);
868    dvi_up(rule_ht);
869    end;
870  dir__TL: begin
871    dvi_down(rule_wd);
872    dvi_left(rule_ht);
873    dvi_set_rule(rule_wd)(rule_ht);
874    end;
875  dir__TR: begin
876    dvi_down(rule_wd);
877    dvi_put_rule(rule_wd)(rule_ht);
878    end;
879  dir__BL: begin
880    dvi_left(rule_ht);
881    dvi_set_rule(rule_wd)(rule_ht);
882    dvi_up(rule_wd);
883    end;
884  dir__BR: begin
885    dvi_put_rule(rule_wd)(rule_ht);
886    dvi_up(rule_wd);
887    end;
888  end;
889@z
890%-------------------------
891@x [32] m.626
892leader_wd:=width(leader_box);
893@y
894if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_direction]))
895  then leader_wd:=width(leader_box)
896else
897  leader_wd:=height(leader_box)+depth(leader_box);
898@z
899-------------------------
900@x [32] m.628
901@<Output a leader box at |cur_h|, ...@>=
902begin cur_v:=base_line+shift_amount(leader_box); synch_v; save_v:=dvi_v;@/
903synch_h; save_h:=dvi_h; temp_ptr:=leader_box;
904outer_doing_leaders:=doing_leaders; doing_leaders:=true;
905if type(leader_box)=vlist_node then vlist_out@+else hlist_out;
906doing_leaders:=outer_doing_leaders;
907dvi_v:=save_v; dvi_h:=save_h; cur_v:=base_line;
908cur_h:=save_h+leader_wd+lx;
909end
910@y
911@<Output a leader box at |cur_h|, ...@>=
912begin
913if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_direction]))
914  then begin
915  basepoint_vertical:=0;
916 if dir_opposite(dir_secondary[box_dir(leader_box)])(dir_secondary[dvi_direction]) then
917    basepoint_horizontal:=width(leader_box)
918  else
919    basepoint_horizontal:=0;
920  end
921else begin
922  if not (is_mirrored(box_dir(leader_box))) then
923    if dir_eq(dir_primary[box_dir(leader_box)])(dir_secondary[dvi_direction]) then
924      basepoint_horizontal:=height(leader_box)
925    else
926      basepoint_horizontal:=depth(leader_box)
927  else
928    if dir_eq(dir_primary[box_dir(leader_box)])(dir_secondary[dvi_direction]) then
929      basepoint_horizontal:=depth(leader_box)
930    else
931      basepoint_horizontal:=height(leader_box);
932  if dir_eq(dir_secondary[box_dir(leader_box)])(dir_primary[dvi_direction]) then
933    basepoint_vertical:= -(width(leader_box) div 2)
934  else
935    basepoint_vertical:= (width(leader_box) div 2);
936  end;
937if not (is_mirrored(dvi_direction)) then
938  basepoint_vertical := basepoint_vertical + shift_amount(leader_box)
939    {shift the box `down'}
940else
941  basepoint_vertical := basepoint_vertical - shift_amount(leader_box);
942    {shift the box `up'}
943temp_ptr:=leader_box;
944edge_h:=cur_h; cur_h:=cur_h + basepoint_horizontal;
945edge_v:=cur_v; cur_v:=base_line + basepoint_vertical;
946synch_h; synch_v; save_h:=dvi_h; save_v:=dvi_v;
947outer_doing_leaders:=doing_leaders; doing_leaders:=true;
948if type(leader_box)=vlist_node then vlist_out@+else hlist_out;
949doing_leaders:=outer_doing_leaders;
950dvi_h:=save_h; dvi_v:=save_v;
951cur_h:=edge_h+leader_wd+lx; cur_v:=base_line;
952end
953@z
954%-------------------------
955@x [32] m.629
956@!glue_temp:real; {glue value before rounding}
957@!cur_glue:real; {glue seen so far}
958@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio}
959begin cur_g:=0; cur_glue:=float_constant(0);
960this_box:=temp_ptr; g_order:=glue_order(this_box);
961g_sign:=glue_sign(this_box); p:=list_ptr(this_box);
962incr(cur_s);
963if cur_s>0 then dvi_out(push);
964if cur_s>max_push then max_push:=cur_s;
965save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; cur_v:=cur_v-height(this_box);
966top_edge:=cur_v;
967while p<>null do @<Output node |p| for |vlist_out| and move to the next node,
968  maintaining the condition |cur_h=left_edge|@>;
969prune_movements(save_loc);
970if cur_s>0 then dvi_pop(save_loc);
971decr(cur_s);
972@y
973@!glue_temp:real; {glue value before rounding}
974@!cur_glue:real; {glue seen so far}
975@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio}
976@!save_direction: integer;
977@!effective_vertical: scaled;
978@!basepoint_horizontal: scaled;
979@!basepoint_vertical: scaled;
980@!edge_v: scaled;
981@!saving_v: scaled;
982@!saving_h: scaled;
983begin cur_g:=0; cur_glue:=float_constant(0);
984this_box:=temp_ptr; g_order:=glue_order(this_box);
985g_sign:=glue_sign(this_box); p:=list_ptr(this_box);
986saving_v:=dvi_v; saving_h:=dvi_h;
987save_direction:=dvi_direction;
988dvi_direction:=box_dir(this_box);
989incr(cur_s);
990if cur_s>0 then dvi_out(push);
991if cur_s>max_push then max_push:=cur_s;
992save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; cur_v:=cur_v-height(this_box);
993top_edge:=cur_v;
994while p<>null do @<Output node |p| for |vlist_out| and move to the next node,
995  maintaining the condition |cur_h=left_edge|@>;
996cur_v:=saving_v; cur_h:=saving_h;
997synch_v; synch_h;
998prune_movements(save_loc);
999if cur_s>0 then dvi_pop(save_loc);
1000decr(cur_s);
1001dvi_direction:=save_direction;
1002@z
1003%-------------------------
1004@x [32] m.631
1005rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p);
1006  goto fin_rule;
1007  end;
1008@y
1009rule_node: begin
1010  if not (dir_orthogonal(dir_primary[rule_dir(p)])(dir_primary[dvi_direction]))
1011    then begin
1012    rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p);
1013    end
1014  else begin
1015    rule_ht:=width(p) div 2;
1016    rule_dp:=width(p) div 2;
1017    rule_wd:=height(p)+depth(p);
1018    end;
1019  goto fin_rule;
1020  end;
1021@z
1022%-------------------------
1023@x [32] m.632
1024@<Output a box in a vlist@>=
1025if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p)
1026else  begin cur_v:=cur_v+height(p); synch_v;
1027  save_h:=dvi_h; save_v:=dvi_v;
1028  cur_h:=left_edge+shift_amount(p); {shift the box right}
1029  temp_ptr:=p;
1030  if type(p)=vlist_node then vlist_out@+else hlist_out;
1031  dvi_h:=save_h; dvi_v:=save_v;
1032  cur_v:=save_v+depth(p); cur_h:=left_edge;
1033  end
1034@y
1035@<Output a box in a vlist@>=
1036begin
1037if not (dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[dvi_direction]))
1038  then begin
1039  effective_vertical:=height(p)+depth(p);
1040  if (type(p)=hlist_node) and (is_mirrored(box_dir(p))) then
1041    basepoint_vertical:=depth(p)
1042  else
1043    basepoint_vertical:=height(p);
1044  if dir_opposite(dir_secondary[box_dir(p)])(dir_secondary[dvi_direction]) then
1045    basepoint_horizontal:=width(p)
1046  else
1047    basepoint_horizontal:=0;
1048  end
1049else begin
1050  effective_vertical:=width(p);
1051  if not (is_mirrored(box_dir(p))) then
1052    if dir_eq(dir_primary[box_dir(p)])(dir_secondary[dvi_direction]) then
1053      basepoint_horizontal:=height(p)
1054    else
1055      basepoint_horizontal:=depth(p)
1056  else
1057    if dir_eq(dir_primary[box_dir(p)])(dir_secondary[dvi_direction]) then
1058      basepoint_horizontal:=depth(p)
1059    else
1060      basepoint_horizontal:=height(p);
1061  if dir_eq(dir_secondary[box_dir(p)])(dir_primary[dvi_direction]) then
1062    basepoint_vertical:=0
1063  else
1064    basepoint_vertical:=width(p);
1065  end;
1066basepoint_horizontal := basepoint_horizontal + shift_amount(p);
1067  {shift the box `right'}
1068if list_ptr(p)=null then begin
1069  cur_v:=cur_v+effective_vertical;
1070  end
1071else  begin
1072  synch_h; synch_v; edge_v:=cur_v;
1073  cur_h:=left_edge + basepoint_horizontal;
1074  cur_v:=cur_v + basepoint_vertical;
1075  synch_h; synch_v; save_h:=dvi_h; save_v:=dvi_v;
1076  temp_ptr:=p;
1077  if type(p)=vlist_node then vlist_out@+else hlist_out;
1078  dvi_h:=save_h; dvi_v:=save_v;
1079  cur_h:=left_edge; cur_v:=edge_v + effective_vertical;
1080  end
1081end
1082@z
1083%-------------------------
1084@x [32] m.633
1085  dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd);
1086@y
1087  case font_direction(dvi_direction) of
1088  dir__LT: begin
1089    dvi_put_rule(rule_ht)(rule_wd);
1090    end;
1091  dir__LB: begin
1092    dvi_down(rule_ht);
1093    dvi_put_rule(rule_ht)(rule_wd);
1094    dvi_up(rule_ht);
1095    end;
1096  dir__RT: begin
1097    dvi_left(rule_wd);
1098    dvi_set_rule(rule_ht)(rule_wd);
1099    end;
1100  dir__RB: begin
1101    dvi_down(rule_ht);
1102    dvi_left(rule_wd);
1103    dvi_set_rule(rule_ht)(rule_wd);
1104    dvi_up(rule_ht);
1105    end;
1106  dir__TL: begin
1107    dvi_down(rule_wd);
1108    dvi_left(rule_ht);
1109    dvi_set_rule(rule_wd)(rule_ht);
1110    dvi_up(rule_wd);
1111    end;
1112  dir__TR: begin
1113    dvi_down(rule_wd);
1114    dvi_put_rule(rule_wd)(rule_ht);
1115    dvi_up(rule_wd);
1116    end;
1117  dir__BL: begin
1118    dvi_left(rule_ht);
1119    dvi_set_rule(rule_wd)(rule_ht);
1120    end;
1121  dir__BR: begin
1122    dvi_put_rule(rule_wd)(rule_ht);
1123    end;
1124  end;
1125@z
1126%-------------------------
1127@x [32] m.635
1128leader_ht:=height(leader_box)+depth(leader_box);
1129@y
1130if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_direction]))
1131  then leader_ht:=height(leader_box)+depth(leader_box)
1132else
1133  leader_ht:=width(leader_box);
1134@z
1135%-------------------------
1136@x [32] m.637
1137@<Output a leader box at |cur_v|, ...@>=
1138begin cur_h:=left_edge+shift_amount(leader_box); synch_h; save_h:=dvi_h;@/
1139cur_v:=cur_v+height(leader_box); synch_v; save_v:=dvi_v;
1140temp_ptr:=leader_box;
1141outer_doing_leaders:=doing_leaders; doing_leaders:=true;
1142if type(leader_box)=vlist_node then vlist_out@+else hlist_out;
1143doing_leaders:=outer_doing_leaders;
1144dvi_v:=save_v; dvi_h:=save_h; cur_h:=left_edge;
1145cur_v:=save_v-height(leader_box)+leader_ht+lx;
1146end
1147@y
1148@<Output a leader box at |cur_v|, ...@>=
1149begin
1150if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_direction]))
1151  then begin
1152  effective_vertical:=height(leader_box)+depth(leader_box);
1153  if (type(leader_box)=hlist_node) and (is_mirrored(box_dir(leader_box))) then
1154    basepoint_vertical:=depth(leader_box)
1155  else
1156    basepoint_vertical:=height(leader_box);
1157  if dir_opposite(dir_secondary[box_dir(leader_box)])(dir_secondary[dvi_direction]) then
1158    basepoint_horizontal:=width(leader_box)
1159  else
1160    basepoint_horizontal:=0;
1161  end
1162else begin
1163  effective_vertical:=width(leader_box);
1164  if not (is_mirrored(box_dir(leader_box))) then
1165    if dir_eq(dir_primary[box_dir(leader_box)])(dir_secondary[dvi_direction]) then
1166      basepoint_horizontal:=height(leader_box)
1167    else
1168      basepoint_horizontal:=depth(leader_box)
1169  else
1170    if dir_eq(dir_primary[box_dir(leader_box)])(dir_secondary[dvi_direction]) then
1171      basepoint_horizontal:=depth(leader_box)
1172    else
1173      basepoint_horizontal:=height(leader_box);
1174  if dir_eq(dir_secondary[box_dir(leader_box)])(dir_primary[dvi_direction]) then
1175    basepoint_vertical:= width(leader_box)
1176  else
1177    basepoint_vertical:= 0;
1178  end;
1179basepoint_horizontal := basepoint_horizontal + shift_amount(leader_box);
1180  {shift the box `right'}
1181temp_ptr:=leader_box;
1182cur_h:=left_edge + basepoint_horizontal;
1183edge_v:=cur_v ;
1184cur_v:=cur_v + basepoint_vertical;
1185synch_h; synch_v; save_h:=dvi_h; save_v:=dvi_v;
1186outer_doing_leaders:=doing_leaders; doing_leaders:=true;
1187if type(leader_box)=vlist_node then vlist_out@+else hlist_out;
1188doing_leaders:=outer_doing_leaders;
1189dvi_h:=save_h; dvi_v:=save_v;
1190cur_h:=left_edge; cur_v:=edge_v+leader_ht+lx;
1191end
1192@z
1193%-------------------------
1194@x [32] m.640
1195cur_v:=height(p)+v_offset; temp_ptr:=p;
1196if type(p)=vlist_node then vlist_out@+else hlist_out;
1197@y
1198dvi_direction:=page_direction;
1199case box_direction(dvi_direction) of
1200dir_TL_,dir_LT_: begin
1201  end;
1202dir_TR_,dir_RT_: begin
1203  dvi_right(page_right_offset);
1204  end;
1205dir_RB_,dir_BR_: begin
1206  dvi_right(page_right_offset);
1207  dvi_down(page_bottom_offset);
1208  end;
1209dir_BL_,dir_LB_: begin
1210  dvi_down(page_bottom_offset);
1211  end;
1212end;
1213cur_h:=h_offset;
1214cur_v:=height(p)+v_offset;
1215case box_direction(dvi_direction) of
1216dir_TL_: begin
1217  dvi_down(cur_v);
1218  dvi_right(cur_h);
1219  end;
1220dir_TR_: begin
1221  dvi_down(cur_v);
1222  dvi_right(-cur_h);
1223  end;
1224dir_LT_: begin
1225  dvi_right(cur_v);
1226  dvi_down(cur_h);
1227  end;
1228dir_LB_: begin
1229  dvi_right(cur_v);
1230  dvi_down(-cur_h);
1231  end;
1232dir_BL_: begin
1233  dvi_down(-cur_v);
1234  dvi_right(cur_h);
1235  end;
1236dir_BR_: begin
1237  dvi_down(-cur_v);
1238  dvi_right(-cur_h);
1239  end;
1240dir_RT_: begin
1241  dvi_right(-cur_v);
1242  dvi_down(cur_h);
1243  end;
1244dir_RB_: begin
1245  dvi_right(-cur_v);
1246  dvi_down(-cur_h);
1247  end;
1248end;
1249dvi_h:=cur_h;
1250dvi_v:=cur_v;
1251temp_ptr:=p;
1252if type(p)=vlist_node then vlist_out@+else hlist_out;
1253@z
1254%-------------------------
1255@x [33] m.644
1256@d exactly=0 {a box dimension is pre-specified}
1257@d additional=1 {a box dimension is increased from the natural one}
1258@d natural==0,additional {shorthand for parameters to |hpack| and |vpack|}
1259@y
1260@d exactly=0 {a box dimension is pre-specified}
1261@d additional=1 {a box dimension is increased from the natural one}
1262@d natural==0,additional {shorthand for parameters to |hpack| and |vpack|}
1263
1264@<Glob...@>=
1265pack_direction:integer;
1266spec_direction:integer;
1267
1268@z
1269%-------------------------
1270@x [33] m.645
1271@p procedure scan_spec(@!c:group_code;@!three_codes:boolean);
1272  {scans a box specification and left brace}
1273label found;
1274var @!s:integer; {temporarily saved value}
1275@!spec_code:exactly..additional;
1276begin if three_codes then s:=saved(0);
1277if scan_keyword("to") then spec_code:=exactly
1278@.to@>
1279else if scan_keyword("spread") then spec_code:=additional
1280@.spread@>
1281else  begin spec_code:=additional; cur_val:=0;
1282  goto found;
1283  end;
1284scan_normal_dimen;
1285found: if three_codes then
1286  begin saved(0):=s; incr(save_ptr);
1287  end;
1288saved(0):=spec_code; saved(1):=cur_val; save_ptr:=save_ptr+2;
1289new_save_level(c); scan_left_brace;
1290end;
1291@y
1292@p procedure scan_spec(@!c:group_code;@!three_codes:boolean);
1293  {scans a box specification and left brace}
1294label found;
1295var @!s:integer; {temporarily saved value}
1296@!spec_code:exactly..additional;
1297begin if three_codes then s:=saved(0);
1298if (c<>align_group) and (c<>vcenter_group) then begin
1299  if scan_keyword("dir") then begin
1300    scan_dir; spec_direction:=cur_val;
1301    end;
1302  end;
1303if scan_keyword("to") then spec_code:=exactly
1304@.to@>
1305else if scan_keyword("spread") then spec_code:=additional
1306@.spread@>
1307else  begin spec_code:=additional; cur_val:=0;
1308  goto found;
1309  end;
1310scan_normal_dimen;
1311found: if three_codes then
1312  begin saved(0):=s; incr(save_ptr);
1313  end;
1314saved(0):=spec_code; saved(1):=cur_val;
1315if (c<>align_group) and (c<>vcenter_group) then begin
1316  saved(2):=spec_direction;
1317  @<DIR: Adjust |text_dir_ptr| for |scan_spec|@>;
1318  save_ptr:=save_ptr+4;
1319  new_save_level(c); scan_left_brace;
1320  eq_word_define(dir_base+body_direction_code,spec_direction);
1321  eq_word_define(dir_base+par_direction_code,spec_direction);
1322  eq_word_define(dir_base+text_direction_code,spec_direction);
1323  eq_word_define(int_base+level_local_dir_code,cur_level);
1324  end
1325else begin
1326  save_ptr:=save_ptr+2;
1327  new_save_level(c); scan_left_brace;
1328  end;
1329spec_direction:=-1;
1330end;
1331@z
1332%-------------------------
1333@x [33] m.649
1334@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer;
1335label reswitch, common_ending, exit;
1336var r:pointer; {the box node that will be returned}
1337@!q:pointer; {trails behind |p|}
1338@!h,@!d,@!x:scaled; {height, depth, and natural width}
1339@!s:scaled; {shift amount}
1340@!g:pointer; {points to a glue specification}
1341@!o:glue_ord; {order of infinity}
1342@!f:internal_font_number; {the font in a |char_node|}
1343@!i:four_quarters; {font information about a |char_node|}
1344@!hd:eight_bits; {height and depth indices for a character}
1345begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node;
1346@y
1347@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer;
1348label reswitch, common_ending, exit;
1349var r:pointer; {the box node that will be returned}
1350@!q:pointer; {trails behind |p|}
1351@!h,@!d,@!x:scaled; {height, depth, and natural width}
1352@!s:scaled; {shift amount}
1353@!g:pointer; {points to a glue specification}
1354@!o:glue_ord; {order of infinity}
1355@!f:internal_font_number; {the font in a |char_node|}
1356@!i:four_quarters; {font information about a |char_node|}
1357@!hd:eight_bits; {height and depth indices for a character}
1358@!dir_tmp,@!dir_ptr:pointer; {for managing the direction stack}
1359@!hpack_dir:integer; {the current direction}
1360begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node;
1361if pack_direction=-1 then
1362  box_dir(r):=text_direction
1363else begin
1364  box_dir(r):=pack_direction; pack_direction:=-1;
1365  end;
1366hpack_dir:=box_dir(r);
1367@<DIR: Initialize |dir_ptr| for |hpack|@>;
1368@z
1369%-------------------------
1370@x [33] m.649
1371exit: hpack:=r;
1372@y
1373exit:
1374@<DIR: Reset |dir_ptr|@>;
1375hpack:=r;
1376@z
1377%-------------------------
1378@x [33] m.653
1379@<Incorporate box dimensions into the dimensions of the hbox...@>=
1380begin x:=x+width(p);
1381if type(p)>=rule_node then s:=0 @+else s:=shift_amount(p);
1382if height(p)-s>h then h:=height(p)-s;
1383if depth(p)+s>d then d:=depth(p)+s;
1384end
1385@y
1386@<Incorporate box dimensions into the dimensions of the hbox...@>=
1387begin
1388if (type(p)=hlist_node) or (type(p)=vlist_node) then begin
1389  if dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[hpack_dir]) then begin
1390    x:=x+height(p)+depth(p);
1391    s:=shift_amount(p);
1392    if (width(p) div 2)-s>h then h:=(width(p) div 2)-s;
1393    if (width(p) div 2)+s>d then d:=(width(p) div 2)+s;
1394    end
1395  else if (type(p)=hlist_node) and (is_mirrored(hpack_dir)) then begin
1396    x:=x+width(p);
1397    s:=shift_amount(p);
1398    if depth(p)-s>h then h:=depth(p)-s;
1399    if height(p)+s>d then d:=height(p)+s;
1400    end
1401  else begin
1402    x:=x+width(p);
1403    s:=shift_amount(p);
1404    if height(p)-s>h then h:=height(p)-s;
1405    if depth(p)+s>d then d:=depth(p)+s;
1406    end
1407  end
1408else begin
1409  x:=x+width(p);
1410  if type(p)>=rule_node then s:=0 @+else s:=shift_amount(p);
1411  if height(p)-s>h then h:=height(p)-s;
1412  if depth(p)+s>d then d:=depth(p)+s;
1413  end;
1414end
1415@z
1416%-------------------------
1417@x [33] m.654
1418@<Incorporate character dimensions into the dimensions of the hbox...@>=
1419begin f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i);
1420x:=x+char_width(f)(i);@/
1421s:=char_height(f)(hd);@+if s>h then h:=s;
1422s:=char_depth(f)(hd);@+if s>d then d:=s;
1423p:=link(p);
1424end
1425@y
1426@<Incorporate character dimensions into the dimensions of the hbox...@>=
1427begin f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i);
1428if is_rotated(hpack_dir) then begin
1429  x:=x+char_height(f)(hd)+char_depth(f)(hd);@/
1430  s:=char_width(f)(i) div 2;@+if s>h then h:=s;
1431  s:=char_width(f)(i) div 2;@+if s>d then d:=s;
1432  end
1433else if dir_opposite(dir_tertiary[hpack_dir])(dir_tertiary[box_dir(r)])
1434  then begin
1435  x:=x+char_width(f)(i);@/
1436  s:=char_depth(f)(hd);@+if s>h then h:=s;
1437  s:=char_height(f)(hd);@+if s>d then d:=s;
1438  end
1439else begin
1440  x:=x+char_width(f)(i);@/
1441  s:=char_height(f)(hd);@+if s>h then h:=s;
1442  s:=char_depth(f)(hd);@+if s>d then d:=s;
1443  end;
1444p:=link(p);
1445end
1446@z
1447%-------------------------
1448@x [33] m.666
1449@ @<Report an overfull hbox and |goto common_ending|, if...@>=
1450if (-x-total_shrink[normal]>hfuzz)or(hbadness<100) then
1451  begin if (overfull_rule>0)and(-x-total_shrink[normal]>hfuzz) then
1452    begin while link(q)<>null do q:=link(q);
1453    link(q):=new_rule;
1454    width(link(q)):=overfull_rule;
1455    end;
1456@y
1457@ @<Report an overfull hbox and |goto common_ending|, if...@>=
1458if (-x-total_shrink[normal]>hfuzz)or(hbadness<100) then
1459  begin if (overfull_rule>0)and(-x-total_shrink[normal]>hfuzz) then
1460    begin while link(q)<>null do q:=link(q);
1461    link(q):=new_rule; rule_dir(link(q)):=box_dir(r);
1462    width(link(q)):=overfull_rule;
1463    end;
1464@z
1465%-------------------------
1466@x [33] m.668
1467@p function vpackage(@!p:pointer;@!h:scaled;@!m:small_number;@!l:scaled):
1468  pointer;
1469label common_ending, exit;
1470var r:pointer; {the box node that will be returned}
1471@!w,@!d,@!x:scaled; {width, depth, and natural height}
1472@!s:scaled; {shift amount}
1473@!g:pointer; {points to a glue specification}
1474@!o:glue_ord; {order of infinity}
1475begin last_badness:=0; r:=get_node(box_node_size); type(r):=vlist_node;
1476@y
1477@p function vpackage(@!p:pointer;@!h:scaled;@!m:small_number;@!l:scaled):
1478  pointer;
1479label common_ending, exit;
1480var r:pointer; {the box node that will be returned}
1481@!w,@!d,@!x:scaled; {width, depth, and natural height}
1482@!s:scaled; {shift amount}
1483@!g:pointer; {points to a glue specification}
1484@!o:glue_ord; {order of infinity}
1485begin last_badness:=0; r:=get_node(box_node_size); type(r):=vlist_node;
1486if pack_direction=-1 then
1487  box_dir(r):=body_direction
1488else begin
1489  box_dir(r):=pack_direction; pack_direction:=-1;
1490  end;
1491@z
1492%-------------------------
1493@x [33] m.670
1494@ @<Incorporate box dimensions into the dimensions of the vbox...@>=
1495begin x:=x+d+height(p); d:=depth(p);
1496if type(p)>=rule_node then s:=0 @+else s:=shift_amount(p);
1497if width(p)+s>w then w:=width(p)+s;
1498end
1499@y
1500@ @<Incorporate box dimensions into the dimensions of the vbox...@>=
1501begin
1502if (type(p)=hlist_node) or (type(p)=vlist_node) then begin
1503  if dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[box_dir(r)]) then begin
1504    x:=x+d+(width(p) div 2); d:=width(p) div 2;
1505    s:=shift_amount(p);
1506    if depth(p)+height(p)+s>w then w:=depth(p)+height(p)+s;
1507    end
1508  else if (type(p)=hlist_node) and (is_mirrored(box_dir(p))) then begin
1509    x:=x+d+depth(p); d:=height(p);
1510    s:=shift_amount(p);
1511    if width(p)+s>w then w:=width(p)+s;
1512    end
1513  else begin
1514    x:=x+d+height(p); d:=depth(p);
1515    s:=shift_amount(p);
1516    if width(p)+s>w then w:=width(p)+s;
1517    end
1518  end
1519else
1520  begin x:=x+d+height(p); d:=depth(p);
1521  if type(p)>=rule_node then s:=0 @+else s:=shift_amount(p);
1522  if width(p)+s>w then w:=width(p)+s;
1523  end;
1524end
1525@z
1526%-------------------------
1527@x [33] m.679
1528  begin d:=width(baseline_skip)-prev_depth-height(b);
1529  if d<line_skip_limit then p:=new_param_glue(line_skip_code)
1530  else  begin p:=new_skip_param(baseline_skip_code);
1531    width(temp_ptr):=d; {|temp_ptr=glue_ptr(p)|}
1532    end;
1533  link(tail):=p; tail:=p;
1534  end;
1535link(tail):=b; tail:=b; prev_depth:=depth(b);
1536@y
1537  begin
1538  if (type(b)=hlist_node) and (is_mirrored(box_dir(b))) then
1539    d:=width(baseline_skip)-prev_depth-depth(b)
1540  else
1541    d:=width(baseline_skip)-prev_depth-height(b);
1542  if d<line_skip_limit then p:=new_param_glue(line_skip_code)
1543  else  begin p:=new_skip_param(baseline_skip_code);
1544    width(temp_ptr):=d; {|temp_ptr=glue_ptr(p)|}
1545    end;
1546  link(tail):=p; tail:=p;
1547  end;
1548link(tail):=b; tail:=b;
1549if (type(b)=hlist_node) and (is_mirrored(box_dir(b))) then
1550  prev_depth:=height(b)
1551else
1552  prev_depth:=depth(b);
1553@z
1554%-------------------------
1555@x [35] m.704
1556@p function fraction_rule(@!t:scaled):pointer;
1557  {construct the bar for a fraction}
1558var p:pointer; {the new node}
1559begin p:=new_rule; height(p):=t; depth(p):=0; fraction_rule:=p;
1560end;
1561@y
1562@p function fraction_rule(@!t:scaled):pointer;
1563  {construct the bar for a fraction}
1564var p:pointer; {the new node}
1565begin p:=new_rule; rule_dir(p):=math_direction;
1566height(p):=t; depth(p):=0; fraction_rule:=p;
1567end;
1568@z
1569%-------------------------
1570@x [35] m.705
1571@p function overbar(@!b:pointer;@!k,@!t:scaled):pointer;
1572var p,@!q:pointer; {nodes being constructed}
1573begin p:=new_kern(k); link(p):=b; q:=fraction_rule(t); link(q):=p;
1574p:=new_kern(t); link(p):=q; overbar:=vpack(p,natural);
1575end;
1576@y
1577@p function overbar(@!b:pointer;@!k,@!t:scaled):pointer;
1578var p,@!q:pointer; {nodes being constructed}
1579begin p:=new_kern(k); link(p):=b; q:=fraction_rule(t); link(q):=p;
1580p:=new_kern(t); link(p):=q;
1581pack_direction:=math_direction; overbar:=vpack(p,natural);
1582end;
1583@z
1584%-------------------------
1585@x [36] m.735
1586procedure make_under(@!q:pointer);
1587var p,@!x,@!y: pointer; {temporary registers for box construction}
1588@!delta:scaled; {overall height plus depth}
1589begin x:=clean_box(nucleus(q),cur_style);
1590p:=new_kern(3*default_rule_thickness); link(x):=p;
1591link(p):=fraction_rule(default_rule_thickness);
1592y:=vpack(x,natural);
1593delta:=height(y)+depth(y)+default_rule_thickness;
1594height(y):=height(x); depth(y):=delta-height(y);
1595info(nucleus(q)):=y; math_type(nucleus(q)):=sub_box;
1596end;
1597@y
1598procedure make_under(@!q:pointer);
1599var p,@!x,@!y: pointer; {temporary registers for box construction}
1600@!delta:scaled; {overall height plus depth}
1601begin x:=clean_box(nucleus(q),cur_style);
1602p:=new_kern(3*default_rule_thickness); link(x):=p;
1603link(p):=fraction_rule(default_rule_thickness);
1604pack_direction:=math_direction; y:=vpack(x,natural);
1605delta:=height(y)+depth(y)+default_rule_thickness;
1606height(y):=height(x); depth(y):=delta-height(y);
1607info(nucleus(q)):=y; math_type(nucleus(q)):=sub_box;
1608end;
1609@z
1610%-------------------------
1611@x [36] m.738
1612  y:=vpack(y,natural); width(y):=width(x);
1613@y
1614  pack_direction:=math_direction;
1615  y:=vpack(y,natural); width(y):=width(x);
1616@z
1617%-------------------------
1618@x [36] m.759
1619x:=vpack(x,natural); shift_amount(x):=shift_down;
1620@y
1621pack_direction:=math_direction;
1622x:=vpack(x,natural); shift_amount(x):=shift_down;
1623@z
1624%-------------------------
1625@x [38] m.814
1626@!internal_right_box_width:integer; {running \.{\\localrightbox} width}
1627@!temp_no_whatsits:integer; {used when closing group}
1628
1629@ @<Set init...@>=
1630@y
1631@!internal_right_box_width:integer; {running \.{\\localrightbox} width}
1632@!paragraph_dir:integer; {main direction of paragraph}
1633@!line_break_dir:integer; {current direction within paragraph}
1634@!break_c_htdp:quarterword; {height-depth entry in |char_info|}
1635@!temp_no_whatsits:integer; {used when closing group}
1636@!temp_no_dirs:integer; {used when closing group}
1637@!temporary_dir:integer;
1638@!dir_ptr,@!dir_tmp,@!dir_rover:pointer;
1639
1640@ @<Set init...@>=
1641temp_no_whatsits:=0; temp_no_dirs:=0; temporary_dir:=0;
1642dir_ptr:=null; dir_tmp:=null; dir_rover:=null;
1643@z
1644%-------------------------
1645@x [39] m.816
1646link(tail):=new_param_glue(par_fill_skip_code);
1647@y
1648final_par_glue:=new_param_glue(par_fill_skip_code);
1649link(tail):=final_par_glue;
1650@z
1651%-------------------------
1652@x [38] m.816
1653init_cur_lang:=prev_graf mod @'200000;
1654init_l_hyf:=prev_graf div @'20000000;
1655init_r_hyf:=(prev_graf div @'200000) mod @'100;
1656@y
1657init_cur_lang:=prev_graf mod @'200000;
1658init_l_hyf:=prev_graf div @'20000000;
1659init_r_hyf:=(prev_graf div @'200000) mod @'100;
1660paragraph_dir:=local_par_dir(link(head));
1661line_break_dir:=paragraph_dir;
1662@<DIR: Initialize |dir_ptr| for |line_break|@>;
1663@z
1664%-------------------------
1665@x [39] m.821
1666@!pass_number:halfword; {the number of passive nodes allocated on this pass}
1667@y
1668@!pass_number:halfword; {the number of passive nodes allocated on this pass}
1669@!final_par_glue:pointer;
1670@z
1671%-------------------------
1672@x [38] m.841
1673@<Subtract the width of node |v|...@>=
1674if is_char_node(v) then
1675  begin f:=font(v);
1676  break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v)));
1677  end
1678else  case type(v) of
1679  ligature_node: begin f:=font(lig_char(v));@/
1680    break_width[1]:=@|break_width[1]-
1681      char_width(f)(char_info(f)(character(lig_char(v))));
1682    end;
1683  hlist_node,vlist_node,rule_node,kern_node:
1684    break_width[1]:=break_width[1]-width(v);
1685@y
1686@<Subtract the width of node |v|...@>=
1687if is_char_node(v) then
1688  begin f:=font(v);
1689  if is_rotated(line_break_dir) then begin
1690    break_c_htdp:=height_depth(char_info(f)(character(v)));
1691    break_width[1]:=break_width[1]-char_height(f)(break_c_htdp)
1692                                  -char_depth(f)(break_c_htdp);
1693    end
1694  else
1695    break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v)));
1696  end
1697else  case type(v) of
1698  ligature_node: begin f:=font(lig_char(v));@/
1699   if is_rotated(line_break_dir) then begin
1700     break_c_htdp:=height_depth(char_info(f)(character(lig_char(v))));
1701     break_width[1]:=break_width[1]-char_height(f)(break_c_htdp)
1702                                   -char_depth(f)(break_c_htdp);
1703     end
1704   else
1705     break_width[1]:=@|break_width[1]-
1706       char_width(f)(char_info(f)(character(lig_char(v))));
1707   end;
1708  hlist_node,vlist_node:
1709    if not (dir_orthogonal(dir_primary[box_dir(v)])(dir_primary[line_break_dir]))
1710      then break_width[1]:=break_width[1]-width(v)
1711    else
1712      break_width[1]:=break_width[1]-(depth(v)+height(v));
1713  rule_node,kern_node:
1714    break_width[1]:=break_width[1]-width(v);
1715@z
1716%-------------------------
1717@x [38] m.842
1718@ @<Add the width of node |s| to |b...@>=
1719if is_char_node(s) then
1720  begin f:=font(s);
1721  break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s)));
1722  end
1723else  case type(s) of
1724  ligature_node: begin f:=font(lig_char(s));
1725    break_width[1]:=break_width[1]+
1726      char_width(f)(char_info(f)(character(lig_char(s))));
1727    end;
1728  hlist_node,vlist_node,rule_node,kern_node:
1729    break_width[1]:=break_width[1]+width(s);
1730@y
1731@ @<Add the width of node |s| to |b...@>=
1732if is_char_node(s) then
1733  begin f:=font(s);
1734  if is_rotated(line_break_dir) then begin
1735    break_c_htdp:=height_depth(char_info(f)(character(s)));
1736    break_width[1]:=break_width[1]+char_height(f)(break_c_htdp)
1737                                  +char_depth(f)(break_c_htdp);
1738    end
1739  else
1740    break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s)));
1741  end
1742else  case type(s) of
1743  ligature_node: begin f:=font(lig_char(s));
1744   if is_rotated(line_break_dir) then begin
1745     break_c_htdp:=height_depth(char_info(f)(character(lig_char(s))));
1746     break_width[1]:=break_width[1]+char_height(f)(break_c_htdp)
1747                                   +char_depth(f)(break_c_htdp);
1748     end
1749   else
1750     break_width[1]:=break_width[1]+
1751       char_width(f)(char_info(f)(character(lig_char(s))));
1752   end;
1753  hlist_node,vlist_node:
1754    if not (dir_orthogonal(dir_primary[box_dir(s)])(dir_primary[line_break_dir]))
1755      then break_width[1]:=break_width[1]+width(s)
1756    else
1757      break_width[1]:=break_width[1]+(depth(s)+height(s));
1758  rule_node,kern_node:
1759    break_width[1]:=break_width[1]+width(s);
1760@z
1761%-------------------------
1762@x [38] m.844
1763passive_right_box_width(q):=internal_right_box_width;
1764@y
1765passive_right_box_width(q):=internal_right_box_width;
1766@z
1767%-------------------------
1768@x [38] m.866
1769hlist_node,vlist_node,rule_node: act_width:=act_width+width(cur_p);
1770@y
1771hlist_node,vlist_node:
1772if not (dir_orthogonal(dir_primary[box_dir(cur_p)])(dir_primary[line_break_dir]))
1773then act_width:=act_width+width(cur_p)
1774else act_width:=act_width+(depth(cur_p)+height(cur_p));
1775rule_node: act_width:=act_width+width(cur_p);
1776@z
1777%-------------------------
1778@x [38] m.866
1779  act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
1780@y
1781  if is_rotated(line_break_dir) then begin
1782    break_c_htdp:=height_depth(char_info(f)(character(lig_char(cur_p))));
1783    act_width:=act_width+char_height(f)(break_c_htdp)
1784                        +char_depth(f)(break_c_htdp);
1785    end
1786  else
1787    act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
1788@z
1789%-------------------------
1790@x [38] m.867
1791act_width:=act_width+char_width(f)(char_info(f)(character(cur_p)));
1792@y
1793if is_rotated(line_break_dir) then begin
1794    break_c_htdp:=height_depth(char_info(f)(character(cur_p)));
1795    act_width:=act_width+char_height(f)(break_c_htdp)
1796                        +char_depth(f)(break_c_htdp);
1797  end
1798else
1799  act_width:=act_width+char_width(f)(char_info(f)(character(cur_p)));
1800@z
1801%-------------------------
1802@x [38] m.870
1803@ @<Add the width of node |s| to |disc_width|@>=
1804if is_char_node(s) then
1805  begin f:=font(s);
1806  disc_width:=disc_width+char_width(f)(char_info(f)(character(s)));
1807  end
1808else  case type(s) of
1809  ligature_node: begin f:=font(lig_char(s));
1810    disc_width:=disc_width+
1811      char_width(f)(char_info(f)(character(lig_char(s))));
1812    end;
1813  hlist_node,vlist_node,rule_node,kern_node:
1814    disc_width:=disc_width+width(s);
1815@y
1816@ @<Add the width of node |s| to |disc_width|@>=
1817if is_char_node(s) then
1818  begin f:=font(s);
1819  if is_rotated(line_break_dir) then begin
1820      break_c_htdp:=height_depth(char_info(f)(character(s)));
1821      disc_width:=disc_width+char_height(f)(break_c_htdp)
1822                            +char_depth(f)(break_c_htdp);
1823    end
1824  else
1825    disc_width:=disc_width+char_width(f)(char_info(f)(character(s)));
1826  end
1827else  case type(s) of
1828  ligature_node: begin f:=font(lig_char(s));
1829    if is_rotated(line_break_dir) then begin
1830        break_c_htdp:=height_depth(char_info(f)(character(lig_char(s))));
1831        disc_width:=disc_width+char_height(f)(break_c_htdp)
1832                              +char_depth(f)(break_c_htdp);
1833      end
1834    else
1835      disc_width:=disc_width+
1836        char_width(f)(char_info(f)(character(lig_char(s))));
1837    end;
1838  hlist_node,vlist_node:
1839   if not (dir_orthogonal(dir_primary[box_dir(s)])(dir_primary[line_break_dir]))
1840    then disc_width:=disc_width+width(s)
1841    else disc_width:=disc_width+(depth(s)+height(s));
1842  rule_node,kern_node:
1843    disc_width:=disc_width+width(s);
1844@z
1845%-------------------------
1846@x [38] m.871
1847@ @<Add the width of node |s| to |act_width|@>=
1848if is_char_node(s) then
1849  begin f:=font(s);
1850  act_width:=act_width+char_width(f)(char_info(f)(character(s)));
1851  end
1852else  case type(s) of
1853  ligature_node: begin f:=font(lig_char(s));
1854    act_width:=act_width+
1855      char_width(f)(char_info(f)(character(lig_char(s))));
1856    end;
1857  hlist_node,vlist_node,rule_node,kern_node:
1858    act_width:=act_width+width(s);
1859@y
1860@ @<Add the width of node |s| to |act_width|@>=
1861if is_char_node(s) then
1862  begin f:=font(s);
1863  if is_rotated(line_break_dir) then begin
1864      break_c_htdp:=height_depth(char_info(f)(character(s)));
1865      act_width:=act_width+char_height(f)(break_c_htdp)
1866                          +char_depth(f)(break_c_htdp);
1867    end
1868  else
1869    act_width:=act_width+char_width(f)(char_info(f)(character(s)));
1870  end
1871else  case type(s) of
1872  ligature_node: begin f:=font(lig_char(s));
1873    if is_rotated(line_break_dir) then begin
1874        break_c_htdp:=height_depth(char_info(f)(character(lig_char(s))));
1875        act_width:=act_width+char_height(f)(break_c_htdp)
1876                            +char_depth(f)(break_c_htdp);
1877      end
1878    else
1879      act_width:=act_width+
1880        char_width(f)(char_info(f)(character(lig_char(s))));
1881    end;
1882  hlist_node,vlist_node:
1883   if not (dir_orthogonal(dir_primary[box_dir(s)])(dir_primary[line_break_dir]))
1884    then act_width:=act_width+width(s)
1885    else act_width:=act_width+(depth(s)+height(s));
1886  rule_node,kern_node:
1887    act_width:=act_width+width(s);
1888@z
1889%-------------------------
1890@x [39] m.877
1891@ The total number of lines that will be set by |post_line_break|
1892is |best_line-prev_graf-1|. The last breakpoint is specified by
1893|break_node(best_bet)|, and this passive node points to the other breakpoints
1894via the |prev_break| links. The finishing-up phase starts by linking the
1895relevant passive nodes in forward order, changing |prev_break| to
1896|next_break|. (The |next_break| fields actually reside in the same memory
1897space as the |prev_break| fields did, but we give them a new name because
1898of their new significance.) Then the lines are justified, one by one.
1899
1900@d next_break==prev_break {new name for |prev_break| after links are reversed}
1901
1902@<Declare subprocedures for |line_break|@>=
1903procedure post_line_break(@!final_widow_penalty:integer);
1904label done,done1;
1905var q,@!r,@!s:pointer; {temporary registers for list manipulation}
1906@!disc_break:boolean; {was the current break at a discretionary node?}
1907@!post_disc_break:boolean; {and did it have a nonempty post-break part?}
1908@!cur_width:scaled; {width of line number |cur_line|}
1909@!cur_indent:scaled; {left margin of line number |cur_line|}
1910@!t:quarterword; {used for replacement counts in discretionary nodes}
1911@!pen:integer; {use when calculating penalties between lines}
1912@!cur_line: halfword; {the current line number being justified}
1913begin @<Reverse the links of the relevant passive nodes, setting |cur_p| to the
1914  first breakpoint@>;
1915cur_line:=prev_graf+1;
1916repeat @<Justify the line ending at breakpoint |cur_p|, and append it to the
1917  current vertical list, together with associated penalties and other
1918  insertions@>;
1919incr(cur_line); cur_p:=next_break(cur_p);
1920if cur_p<>null then if not post_disc_break then
1921  @<Prune unwanted nodes at the beginning of the next line@>;
1922until cur_p=null;
1923if (cur_line<>best_line)or(link(temp_head)<>null) then
1924  confusion("line breaking");
1925@:this can't happen line breaking}{\quad line breaking@>
1926prev_graf:=best_line-1;
1927end;
1928@y
1929@ The total number of lines that will be set by |post_line_break|
1930is |best_line-prev_graf-1|. The last breakpoint is specified by
1931|break_node(best_bet)|, and this passive node points to the other breakpoints
1932via the |prev_break| links. The finishing-up phase starts by linking the
1933relevant passive nodes in forward order, changing |prev_break| to
1934|next_break|. (The |next_break| fields actually reside in the same memory
1935space as the |prev_break| fields did, but we give them a new name because
1936of their new significance.) Then the lines are justified, one by one.
1937
1938The |post_line_break| must also keep an dir stack, so that it can
1939output end direction instructions at the ends of lines
1940and begin direction instructions at the beginnings of lines.
1941
1942@d next_break==prev_break {new name for |prev_break| after links are reversed}
1943
1944@<Declare subprocedures for |line_break|@>=
1945procedure post_line_break(@!final_widow_penalty:integer);
1946label done,done1;
1947var q,@!r,@!s:pointer; {temporary registers for list manipulation}
1948@!disc_break:boolean; {was the current break at a discretionary node?}
1949@!post_disc_break:boolean; {and did it have a nonempty post-break part?}
1950@!cur_width:scaled; {width of line number |cur_line|}
1951@!cur_indent:scaled; {left margin of line number |cur_line|}
1952@!t:quarterword; {used for replacement counts in discretionary nodes}
1953@!pen:integer; {use when calculating penalties between lines}
1954@!cur_line: halfword; {the current line number being justified}
1955begin dir_ptr:=dir_save;
1956@<Reverse the links of the relevant passive nodes, setting |cur_p| to the
1957  first breakpoint@>;
1958cur_line:=prev_graf+1;
1959repeat @<Justify the line ending at breakpoint |cur_p|, and append it to the
1960  current vertical list, together with associated penalties and other
1961  insertions@>;
1962incr(cur_line); cur_p:=next_break(cur_p);
1963if cur_p<>null then if not post_disc_break then
1964  @<Prune unwanted nodes at the beginning of the next line@>;
1965until cur_p=null;
1966if (cur_line<>best_line)or(link(temp_head)<>null) then
1967  confusion("line breaking");
1968@:this can't happen line breaking}{\quad line breaking@>
1969prev_graf:=best_line-1; dir_save:=dir_ptr;
1970end;
1971@z
1972%-------------------------
1973@x [39] m.880
1974@<Justify the line ending at breakpoint |cur_p|, and append it...@>=
1975@<Modify the end of the line to reflect the nature of the break and to include
1976  \.{\\rightskip}; also set the proper value of |disc_break|@>;
1977@<Put the \(l)\.{\\leftskip} glue at the left and detach this line@>;
1978@y
1979@<Justify the line ending at breakpoint |cur_p|, and append it...@>=
1980@<DIR: Insert dir nodes at the beginning of the current line@>;
1981@<DIR: Adjust the dir stack based on dir nodes in this line@>;
1982@<Modify the end of the line to reflect the nature of the break and to include
1983  \.{\\rightskip}; also set the proper value of |disc_break|@>;
1984@<Put the \(l)\.{\\leftskip} glue at the left and detach this line@>;
1985@z
1986%-------------------------
1987@x [39] m.881
1988    if passive_right_box(cur_p)<>null then begin
1989      r:=temp_head;
1990      while link(r)<>q do r:=link(r);
1991      s:=copy_node_list(passive_right_box(cur_p));
1992      link(r):=s;
1993      link(s):=q;
1994      end;
1995    delete_glue_ref(glue_ptr(q));
1996    glue_ptr(q):=right_skip;
1997    subtype(q):=right_skip_code+1; add_glue_ref(right_skip);
1998    goto done;
1999    end
2000  else  begin if type(q)=disc_node then
2001      @<Change discretionary to compulsory and set
2002        |disc_break:=true|@>
2003    else if (type(q)=math_node)or(type(q)=kern_node) then width(q):=0;
2004    end
2005else  begin q:=temp_head;
2006  while link(q)<>null do q:=link(q);
2007  end;
2008@y
2009     if passive_right_box(cur_p)<>null then begin
2010      r:=temp_head;
2011      while link(r)<>q do r:=link(r);
2012      @<DIR: Insert dir nodes at the end of the current line@>;
2013      s:=copy_node_list(passive_right_box(cur_p));
2014      link(r):=s;
2015      link(s):=q;
2016      end
2017     else begin
2018      r:=temp_head;
2019      while link(r)<>q do r:=link(r);
2020      @<DIR: Insert dir nodes at the end of the current line@>;
2021      end;
2022    delete_glue_ref(glue_ptr(q));
2023    glue_ptr(q):=right_skip;
2024    subtype(q):=right_skip_code+1; add_glue_ref(right_skip);
2025    goto done;
2026    end
2027  else  begin if type(q)=disc_node then
2028      @<Change discretionary to compulsory and set
2029        |disc_break:=true|@>
2030    else if (type(q)=math_node)or(type(q)=kern_node) then width(q):=0;
2031    end
2032else  begin q:=temp_head;
2033  while link(q)<>null do q:=link(q);
2034  end;
2035r:=q;
2036@<DIR: Insert dir nodes at the end of the current line@>;
2037@z
2038%-------------------------
2039@x [39] m.888
2040append_to_vlist(just_box);
2041if adjust_head<>adjust_tail then
2042  begin link(tail):=link(adjust_head); tail:=adjust_tail;
2043   end;
2044adjust_tail:=null
2045@y
2046append_to_vlist(just_box);
2047if adjust_head<>adjust_tail then
2048  begin link(tail):=link(adjust_head); tail:=adjust_tail;
2049   end;
2050adjust_tail:=null
2051@z
2052%-------------------------
2053@x [39] m.888
2054adjust_tail:=adjust_head; just_box:=hpack(q,cur_width,exactly);
2055@y
2056adjust_tail:=adjust_head;
2057pack_direction:=paragraph_dir;
2058just_box:=hpack(q,cur_width,exactly);
2059@z
2060%-------------------------
2061@x [44] m.977
2062@p function vsplit(@!n:eight_bits; @!h:scaled):pointer;
2063  {extracts a page of height |h| from box |n|}
2064label exit,done;
2065var v:pointer; {the box to be split}
2066p:pointer; {runs through the vlist}
2067q:pointer; {points to where the break occurs}
2068begin v:=box(n);
2069if split_first_mark<>null then
2070  begin delete_token_ref(split_first_mark); split_first_mark:=null;
2071  delete_token_ref(split_bot_mark); split_bot_mark:=null;
2072  end;
2073@<Dispense with trivial cases of void or bad boxes@>;
2074q:=vert_break(list_ptr(v),h,split_max_depth);
2075@<Look at all the marks in nodes before the break, and set the final
2076  link to |null| at the break@>;
2077q:=prune_page_top(q); p:=list_ptr(v); free_node(v,box_node_size);
2078@y
2079@p function vsplit(@!n:eight_bits; @!h:scaled):pointer;
2080  {extracts a page of height |h| from box |n|}
2081label exit,done;
2082var v:pointer; {the box to be split}
2083vdir:integer; {the direction of the box to be split}
2084p:pointer; {runs through the vlist}
2085q:pointer; {points to where the break occurs}
2086begin v:=box(n); vdir:=box_dir(v);
2087if split_first_mark<>null then
2088  begin delete_token_ref(split_first_mark); split_first_mark:=null;
2089  delete_token_ref(split_bot_mark); split_bot_mark:=null;
2090  end;
2091@<Dispense with trivial cases of void or bad boxes@>;
2092q:=vert_break(list_ptr(v),h,split_max_depth);
2093@<Look at all the marks in nodes before the break, and set the final
2094  link to |null| at the break@>;
2095q:=prune_page_top(q); p:=list_ptr(v); free_node(v,box_node_size);
2096pack_direction:=vdir;
2097@z
2098%-------------------------
2099@x [45] m.1001
2100if width(temp_ptr)>height(p) then width(temp_ptr):=width(temp_ptr)-height(p)
2101else width(temp_ptr):=0;
2102@y
2103if (type(p)=hlist_node) and (is_mirrored(body_direction)) then begin
2104  if width(temp_ptr)>depth(p) then width(temp_ptr):=width(temp_ptr)-depth(p)
2105  else width(temp_ptr):=0;
2106  end
2107else begin
2108  if width(temp_ptr)>height(p) then width(temp_ptr):=width(temp_ptr)-height(p)
2109  else width(temp_ptr):=0;
2110  end;
2111@z
2112%-------------------------
2113@x [45] m.1002
2114begin page_total:=page_total+page_depth+height(p);
2115page_depth:=depth(p);
2116@y
2117begin
2118if (type(p)=hlist_node) and (is_mirrored(body_direction)) then begin
2119  page_total:=page_total+page_depth+depth(p);
2120  page_depth:=height(p);
2121  end
2122else begin
2123  page_total:=page_total+page_depth+height(p);
2124  page_depth:=depth(p);
2125  end;
2126@z
2127%-------------------------
2128@x [45] m.1017
2129set_equiv(box_base+255,
2130          vpackage(link(page_head),best_size,exactly,page_max_depth));
2131@y
2132pack_direction:=body_direction;
2133set_equiv(box_base+255,
2134          vpackage(link(page_head),best_size,exactly,page_max_depth));
2135@z
2136%-------------------------
2137@x [45] m.1021
2138temp_ptr:=list_ptr(box(n));
2139free_node(box(n),box_node_size);
2140@y
2141temp_ptr:=list_ptr(box(n));
2142free_node(box(n),box_node_size);
2143pack_direction:=body_direction;
2144@z
2145%-------------------------
2146@x [47] m.1063
2147non_math(left_brace): begin
2148  new_save_level(simple_group);
2149  eq_word_define(int_base+no_local_whatsits_code,0);
2150  end;
2151any_mode(begin_group): begin
2152  new_save_level(semi_simple_group);
2153  eq_word_define(int_base+no_local_whatsits_code,0);
2154  end;
2155any_mode(end_group):
2156  if cur_group=semi_simple_group then begin
2157    temp_no_whatsits:=no_local_whatsits;
2158    unsave;
2159    if temp_no_whatsits<>0 then
2160      if abs(mode)=hmode then @<LOCAL: Add local paragraph node@>;
2161    end
2162  else off_save;
2163@y
2164non_math(left_brace): begin
2165  new_save_level(simple_group);
2166  eq_word_define(int_base+no_local_whatsits_code,0);
2167  eq_word_define(int_base+no_local_dirs_code,0);
2168  end;
2169any_mode(begin_group): begin
2170  new_save_level(semi_simple_group);
2171  eq_word_define(int_base+no_local_whatsits_code,0);
2172  eq_word_define(int_base+no_local_dirs_code,0);
2173  end;
2174any_mode(end_group):
2175  if cur_group=semi_simple_group then begin
2176    temp_no_whatsits:=no_local_whatsits;
2177    temp_no_dirs:=no_local_dirs;
2178    temporary_dir:=text_direction;
2179    if dir_level(text_dir_ptr)=cur_level then
2180      @<DIR: Remove from |text_dir_ptr|@>;
2181    unsave;
2182    if abs(mode)=hmode then begin
2183      if temp_no_dirs<>0 then begin
2184        @<DIR: Add local dir node@>;
2185        dir_dir(tail):=temporary_dir-64;
2186        end;
2187      if temp_no_whatsits<>0 then
2188        @<LOCAL: Add local paragraph node@>;
2189      end
2190    end
2191  else off_save;
2192@z
2193%-------------------------
2194@x [47] m.1068
2195simple_group: begin
2196  temp_no_whatsits:=no_local_whatsits;
2197  unsave;
2198  if temp_no_whatsits<>0 then
2199    if abs(mode)=hmode then @<LOCAL: Add local paragraph node@>;
2200  end;
2201@y
2202simple_group: begin
2203  temp_no_whatsits:=no_local_whatsits;
2204  temp_no_dirs:=no_local_dirs;
2205  temporary_dir:=text_direction;
2206  if dir_level(text_dir_ptr)=cur_level then
2207    @<DIR: Remove from |text_dir_ptr|@>;
2208  unsave;
2209  if abs(mode)=hmode then begin
2210    if temp_no_dirs<>0 then begin
2211      @<DIR: Add local dir node@>;
2212      dir_dir(tail):=temporary_dir-64;
2213      end;
2214    if temp_no_whatsits<>0 then
2215      @<LOCAL: Add local paragraph node@>;
2216    end
2217  end;
2218@z
2219%-------------------------
2220@x [47] m.1083
2221begin k:=cur_chr-vtop_code; saved(0):=box_context;
2222if k=hmode then
2223  if (box_context<box_flag)and(abs(mode)=vmode) then
2224    scan_spec(adjusted_hbox_group,true)
2225  else scan_spec(hbox_group,true)
2226else  begin if k=vmode then scan_spec(vbox_group,true)
2227  else  begin scan_spec(vtop_group,true); k:=vmode;
2228    end;
2229  normal_paragraph;
2230  end;
2231push_nest; mode:=-k;
2232@y
2233begin k:=cur_chr-vtop_code; saved(0):=box_context;
2234case abs(mode) of
2235vmode: spec_direction:=body_direction;
2236hmode: spec_direction:=text_direction;
2237mmode: spec_direction:=math_direction;
2238end;
2239if k=hmode then
2240  if (box_context<box_flag)and(abs(mode)=vmode) then
2241    scan_spec(adjusted_hbox_group,true)
2242  else scan_spec(hbox_group,true)
2243else  begin if k=vmode then scan_spec(vbox_group,true)
2244  else  begin scan_spec(vtop_group,true); k:=vmode;
2245    end;
2246  normal_paragraph;
2247  end;
2248push_nest; mode:=-k;
2249@z
2250%-------------------------
2251@x [47] m.1086
2252procedure package(@!c:small_number);
2253var h:scaled; {height of box}
2254@!p:pointer; {first node in a box}
2255@!d:scaled; {max depth}
2256begin d:=box_max_depth; unsave; save_ptr:=save_ptr-3;
2257if mode=-hmode then cur_box:=hpack(link(head),saved(2),saved(1))
2258else  begin cur_box:=vpackage(link(head),saved(2),saved(1),d);
2259  if c=vtop_code then @<Readjust the height and depth of |cur_box|,
2260    for \.{\\vtop}@>;
2261  end;
2262pop_nest; box_end(saved(0));
2263end;
2264@y
2265procedure package(@!c:small_number);
2266var h:scaled; {height of box}
2267@!p:pointer; {first node in a box}
2268@!d:scaled; {max depth}
2269begin d:=box_max_depth; unsave; save_ptr:=save_ptr-5;
2270pack_direction:=saved(3);
2271if mode=-hmode then cur_box:=hpack(link(head),saved(2),saved(1))
2272else  begin cur_box:=vpackage(link(head),saved(2),saved(1),d);
2273  if c=vtop_code then @<Readjust the height and depth of |cur_box|,
2274    for \.{\\vtop}@>;
2275  end;
2276if saved(4)<>null then
2277  @<DIR: Adjust back |text_dir_ptr| for |scan_spec|@>;
2278pop_nest; box_end(saved(0));
2279end;
2280@z
2281%-------------------------
2282@x [47] m.1091
2283procedure new_graf(@!indented:boolean);
2284begin prev_graf:=0;
2285if (mode=vmode)or(head<>tail) then
2286  tail_append(new_param_glue(par_skip_code));
2287push_nest; mode:=hmode; space_factor:=1000; set_cur_lang; clang:=cur_lang;
2288prev_graf:=(norm_min(left_hyphen_min)*@'100+norm_min(right_hyphen_min))
2289             *@'200000+cur_lang;
2290@<LOCAL: Add local paragraph node@>;
2291if indented then begin
2292  tail:=new_null_box; link(link(head)):=tail; width(tail):=par_indent;@+
2293  end;
2294@y
2295procedure new_graf(@!indented:boolean);
2296var p,q,dir_graf_tmp:pointer;
2297begin prev_graf:=0;
2298if (mode=vmode)or(head<>tail) then
2299  tail_append(new_param_glue(par_skip_code));
2300push_nest; mode:=hmode; space_factor:=1000; set_cur_lang; clang:=cur_lang;
2301prev_graf:=(norm_min(left_hyphen_min)*@'100+norm_min(right_hyphen_min))
2302             *@'200000+cur_lang;
2303@<LOCAL: Add local paragraph node@>;
2304if indented then begin
2305  p:=new_null_box; box_dir(p):=par_direction;
2306  width(p):=par_indent;@+
2307  tail_append(p);
2308  end;
2309q:=tail;
2310dir_rover:=text_dir_ptr;
2311while dir_rover<>null do
2312  begin
2313  if (link(dir_rover)<>null) or (dir_dir(dir_rover)<>par_direction) then
2314    begin
2315    dir_graf_tmp:=new_dir(dir_dir(dir_rover));
2316    link(dir_graf_tmp):=link(q); link(q):=dir_graf_tmp;
2317    end;
2318  dir_rover:=link(dir_rover);
2319  end;
2320q:=head;
2321while link(q)<>null do q:=link(q);
2322tail:=q;
2323@z
2324%-------------------------
2325@x [47] m.1096
2326procedure end_graf;
2327begin if mode=hmode then
2328  begin if (head=tail) or (link(head)=tail) then pop_nest
2329        {null paragraphs are ignored, all contain a |local_paragraph| node}
2330  else line_break(widow_penalty);
2331  normal_paragraph;
2332  error_count:=0;
2333  end;
2334end;
2335@y
2336procedure end_graf;
2337begin if mode=hmode then
2338  begin if (head=tail) or (link(head)=tail) then pop_nest
2339        {null paragraphs are ignored, all contain a |local_paragraph| node}
2340  else line_break(widow_penalty);
2341  if dir_save<>null then
2342    begin flush_node_list(dir_save); dir_save:=null;
2343    end;
2344  normal_paragraph;
2345  error_count:=0;
2346  end;
2347end;
2348@z
2349%-------------------------
2350@x [48] m.1136
2351procedure push_math(@!c:group_code);
2352begin push_nest; mode:=-mmode; incompleat_noad:=null; new_save_level(c);
2353end;
2354@y
2355procedure push_math(@!c:group_code);
2356begin
2357if math_direction<>text_direction then dir_math_save:=true;
2358push_nest; mode:=-mmode; incompleat_noad:=null;
2359@<DIR: |new_save_level| math@>;
2360end;
2361@z
2362%-------------------------
2363@x [48] m.1174
2364begin unsave; p:=fin_mlist(null);
2365@y
2366begin @<DIR: |unsave| math@>; p:=fin_mlist(null);
2367@z
2368%-------------------------
2369@x [48] m.1186
2370math_group: begin unsave; decr(save_ptr);@/
2371@y
2372math_group: begin @<DIR: |unsave| math@>; decr(save_ptr);@/
2373@z
2374%-------------------------
2375@x [48] m.1191
2376  else  begin p:=fin_mlist(p); unsave; {end of |math_left_group|}
2377@y
2378  else  begin p:=fin_mlist(p);
2379    @<DIR: |unsave| math@>; {end of |math_left_group|}
2380@z
2381%-------------------------
2382@x [48] m.1194
2383procedure after_math;
2384var l:boolean; {`\.{\\leqno}' instead of `\.{\\eqno}'}
2385@!danger:boolean; {not enough symbol fonts are present}
2386@!m:integer; {|mmode| or |-mmode|}
2387@!p:pointer; {the formula}
2388@!a:pointer; {box containing equation number}
2389@<Local variables for finishing a displayed formula@>@;
2390begin danger:=false;
2391@<Check that the necessary fonts for math symbols are present;
2392  if not, flush the current math lists and set |danger:=true|@>;
2393m:=mode; l:=false; p:=fin_mlist(null); {this pops the nest}
2394if mode=-m then {end of equation number}
2395  begin @<Check that another \.\$ follows@>;
2396  cur_mlist:=p; cur_style:=text_style; mlist_penalties:=false;
2397  mlist_to_hlist; a:=hpack(link(temp_head),natural);
2398  unsave; decr(save_ptr); {now |cur_group=math_shift_group|}
2399  if saved(0)=1 then l:=true;
2400@y
2401procedure after_math;
2402var l:boolean; {`\.{\\leqno}' instead of `\.{\\eqno}'}
2403@!danger:boolean; {not enough symbol fonts are present}
2404@!m:integer; {|mmode| or |-mmode|}
2405@!p:pointer; {the formula}
2406@!a:pointer; {box containing equation number}
2407@<Local variables for finishing a displayed formula@>@;
2408begin danger:=false;
2409@<Check that the necessary fonts for math symbols are present;
2410  if not, flush the current math lists and set |danger:=true|@>;
2411m:=mode; l:=false; p:=fin_mlist(null); {this pops the nest}
2412if mode=-m then {end of equation number}
2413  begin @<Check that another \.\$ follows@>;
2414  cur_mlist:=p; cur_style:=text_style; mlist_penalties:=false;
2415  mlist_to_hlist; a:=hpack(link(temp_head),natural);
2416  @<DIR: |unsave| math@>;
2417  decr(save_ptr); {now |cur_group=math_shift_group|}
2418  if saved(0)=1 then l:=true;
2419@z
2420%-------------------------
2421@x [48] m.1196
2422@<Finish math in text@>=
2423begin tail_append(new_math(math_surround,before));
2424cur_mlist:=p; cur_style:=text_style; mlist_penalties:=(mode>0); mlist_to_hlist;
2425link(tail):=link(temp_head);
2426while link(tail)<>null do tail:=link(tail);
2427tail_append(new_math(math_surround,after));
2428space_factor:=1000; unsave;
2429end
2430@y
2431@<Finish math in text@> =
2432begin tail_append(new_math(math_surround,before));
2433if dir_math_save then
2434  @<Append a begin direction to the tail of the current list@>;
2435cur_mlist:=p; cur_style:=text_style; mlist_penalties:=(mode>0); mlist_to_hlist;
2436link(tail):=link(temp_head);
2437while link(tail)<>null do tail:=link(tail);
2438if dir_math_save then
2439  @<Append an end direction to the tail of the current list@>;
2440dir_math_save:=false;
2441tail_append(new_math(math_surround,after));
2442space_factor:=1000;
2443@<DIR: |unsave| math@>;
2444end
2445@z
2446%-------------------------
2447@x [48] m.1200
2448procedure resume_after_display;
2449begin if cur_group<>math_shift_group then confusion("display");
2450@:this can't happen display}{\quad display@>
2451unsave; prev_graf:=prev_graf+3;
2452@y
2453procedure resume_after_display;
2454begin if cur_group<>math_shift_group then confusion("display");
2455@:this can't happen display}{\quad display@>
2456@<DIR: |unsave| math@>;
2457prev_graf:=prev_graf+3;
2458@z
2459%-------------------------
2460@x [49] m.1210
2461any_mode(assign_int),
2462@y
2463any_mode(assign_int),
2464any_mode(assign_dir),
2465@z
2466%-------------------------
2467@x [49] m.1228
2468assign_dimen: begin p:=cur_chr; scan_optional_equals;
2469  scan_normal_dimen; word_define(p,cur_val);
2470  end;
2471@y
2472assign_dir: begin
2473  @<DIR: Assign direction codes@>
2474  end;
2475assign_dimen: begin p:=cur_chr; scan_optional_equals;
2476  scan_normal_dimen; word_define(p,cur_val);
2477  end;
2478@z
2479%-------------------------
2480@x [49] m.1257
2481@!flushable_string:str_number; {string not yet referenced}
2482@y
2483@!natural_dir:integer;{the natural direction of the font}
2484@!flushable_string:str_number; {string not yet referenced}
2485@z
2486%-------------------------
2487@x [49] m.1257
2488if scan_keyword("offset") then begin
2489  scan_int;
2490  offset:=cur_val;
2491  if (cur_val<0) then begin
2492    print_err("Illegal offset has been changed to 0");
2493    help1("The offset must be bigger than 0."); int_error(cur_val);
2494    offset:=0;
2495    end
2496  end
2497else offset:=0;
2498name_in_progress:=false;
2499@<If this font has already been loaded, set |f| to the internal
2500  font number and |goto common_ending|@>;
2501f:=read_font_info(u,cur_name,cur_area,s,offset);
2502@y
2503if scan_keyword("offset") then begin
2504  scan_int;
2505  offset:=cur_val;
2506  if (cur_val<0) then begin
2507    print_err("Illegal offset has been changed to 0");
2508    help1("The offset must be bigger than 0."); int_error(cur_val);
2509    offset:=0;
2510    end
2511  end
2512else offset:=0;
2513if scan_keyword("naturaldir") then begin
2514  scan_dir;
2515  natural_dir:=cur_val;
2516  end
2517else natural_dir:=-1;
2518name_in_progress:=false;
2519@<If this font has already been loaded, set |f| to the internal
2520  font number and |goto common_ending|@>;
2521f:=read_font_info(u,cur_name,cur_area,s,offset,natural_dir);
2522@z
2523%-------------------------
2524@x [51] m.1337
2525if (loc<limit)and(cat_code(buffer[loc])<>escape) then start_input;
2526  {\.{\\input} assumed}
2527@y
2528if (loc<limit)and(cat_code(buffer[loc])<>escape) then start_input;
2529  {\.{\\input} assumed}
2530@<DIR: Initialize |text_dir_ptr|@>;
2531@z
2532%-------------------------
2533@x [53] m.1341
2534@d language_node=4 {|subtype| in whatsits that change the current language}
2535@y
2536@d language_node=4 {|subtype| in whatsits that change the current language}
2537@d dir_node_size=4 {number of words in change direction node}
2538@d dir_dir(#)==info(#+1) {keep the direction to be taken}
2539@d dir_level(#)==link(#+1) {the save level at which the direction was defined}
2540@d dir_dvi_ptr(#)==info(#+2) {for reflecting dvi output}
2541@d dir_dvi_h(#)==info(#+3) {for reflecting dvi output}
2542@z
2543%-------------------------
2544@x [53] m.1342
2545@!write_open:array[0..17] of boolean;
2546@y
2547@!write_open:array[0..17] of boolean;
2548@!neg_wd:scaled;
2549@!pos_wd:scaled;
2550@!neg_ht:scaled;
2551@!dvi_direction:integer;
2552@!dir_primary:array[0..31] of 0..31;
2553@!dir_secondary:array[0..31] of 0..31;
2554@!dir_tertiary:array[0..31] of 0..31;
2555@!dir_rearrange:array[0..3] of 0..31;
2556@!dir_names:array[0..3] of str_number;
2557@!text_dir_ptr:pointer;
2558@!text_dir_tmp:pointer;
2559@z
2560%-------------------------
2561@x [53] m.1343
2562for k:=0 to 17 do write_open[k]:=false;
2563@y
2564for k:=0 to 17 do write_open[k]:=false;
2565set_new_eqtb_int(dir_base+page_direction_code,0);
2566set_new_eqtb_int(dir_base+body_direction_code,0);
2567set_new_eqtb_int(dir_base+par_direction_code,0);
2568set_new_eqtb_int(dir_base+text_direction_code,0);
2569set_new_eqtb_int(dir_base+math_direction_code,0);
2570pack_direction:=-1;
2571set_new_eqtb_sc(dimen_base+page_height_code,55380984); {29.7cm}
2572set_new_eqtb_sc(dimen_base+page_width_code,39158276); {21cm}
2573set_new_eqtb_sc(dimen_base+page_bottom_offset_code,page_height-9472573);
2574                {-2 inches}
2575set_new_eqtb_sc(dimen_base+page_right_offset_code,page_width-9472573);
2576                {-2 inches}
2577for k:= 0 to 7 do begin
2578  dir_primary  [k   ]:=dir_T;
2579  dir_primary  [k+ 8]:=dir_L;
2580  dir_primary  [k+16]:=dir_B;
2581  dir_primary  [k+24]:=dir_R;
2582  end;
2583for k:= 0 to 3 do begin
2584  dir_secondary[k   ]:=dir_L;
2585  dir_secondary[k+ 4]:=dir_R;
2586  dir_secondary[k+ 8]:=dir_T;
2587  dir_secondary[k+12]:=dir_B;
2588
2589  dir_secondary[k+16]:=dir_L;
2590  dir_secondary[k+20]:=dir_R;
2591  dir_secondary[k+24]:=dir_T;
2592  dir_secondary[k+28]:=dir_B;
2593  end;
2594for k:=0 to 7 do begin
2595  dir_tertiary[k*4  ]:=dir_T;
2596  dir_tertiary[k*4+1]:=dir_L;
2597  dir_tertiary[k*4+2]:=dir_B;
2598  dir_tertiary[k*4+3]:=dir_R;
2599  end;
2600dir_rearrange[0]:=0;
2601dir_rearrange[1]:=0;
2602dir_rearrange[2]:=1;
2603dir_rearrange[3]:=1;
2604dir_names[0]:="T";
2605dir_names[1]:="L";
2606dir_names[2]:="B";
2607dir_names[3]:="R";
2608@z
2609%-------------------------
2610@x [53] m.1344
2611@d local_par_node=6 {|subtype| in whatsits for local paragraph node}
2612@y
2613@d local_par_node=6 {|subtype| in whatsits for local paragraph node}
2614@d dir_node=7 {|subtype| in whatsits for change direction node}
2615@z
2616%-------------------------
2617@x [53] m.1344
2618primitive("localinterlinepenalty",assign_int,local_inter_line_penalty_code);@/
2619primitive("localbrokenpenalty",assign_int,local_broken_penalty_code);@/
2620@y
2621primitive("localinterlinepenalty",assign_int,local_inter_line_penalty_code);@/
2622primitive("localbrokenpenalty",assign_int,local_broken_penalty_code);@/
2623primitive("pagedir",assign_dir,dir_base+page_direction_code);@/
2624primitive("bodydir",assign_dir,dir_base+body_direction_code);@/
2625primitive("pardir",assign_dir,dir_base+par_direction_code);@/
2626primitive("textdir",assign_dir,dir_base+text_direction_code);@/
2627primitive("mathdir",assign_dir,dir_base+math_direction_code);@/
2628primitive("pageheight",assign_dimen,dimen_base+page_height_code);@/
2629primitive("pagewidth",assign_dimen,dimen_base+page_width_code);@/
2630{
2631|primitive("pagerightoffset",assign_dimen,dimen_base+page_right_offset_code);|
2632|primitive("pagebottomoffset",assign_dimen,dimen_base+page_bottom_offset_code);|
2633}
2634@z
2635%-------------------------
2636@x [53] m.1346
2637  set_language_code:print_esc("setlanguage");
2638  othercases print("[unknown extension!]")
2639  endcases;
2640@y
2641  set_language_code:print_esc("setlanguage");
2642  othercases print("[unknown extension!]")
2643  endcases;
2644@z
2645%-------------------------
2646@x [53] m.1348
2647set_language_code:@<Implement \.{\\setlanguage}@>;
2648@y
2649set_language_code:@<Implement \.{\\setlanguage}@>;
2650@z
2651%-------------------------
2652@x [53] m.1356
2653language_node:begin print_esc("setlanguage");
2654  print_int(what_lang(p)); print(" (hyphenmin ");
2655  print_int(what_lhm(p)); print_char(",");
2656  print_int(what_rhm(p)); print_char(")");
2657  end;
2658@y
2659language_node:begin print_esc("setlanguage");
2660  print_int(what_lang(p)); print(" (hyphenmin ");
2661  print_int(what_lhm(p)); print_char(",");
2662  print_int(what_rhm(p)); print_char(")");
2663  end;
2664dir_node:
2665  if dir_dir(p)<0 then begin
2666    print_esc("enddir"); print(" "); print_dir(dir_dir(p)+64);
2667    end
2668  else begin
2669    print_esc("begindir"); print(" "); print_dir(dir_dir(p));
2670    end;
2671@z
2672%-------------------------
2673@x [53] m.1357
2674close_node,language_node: begin r:=get_node(small_node_size);
2675  words:=small_node_size;
2676  end;
2677@y
2678close_node,language_node: begin r:=get_node(small_node_size);
2679  words:=small_node_size;
2680  end;
2681dir_node: begin r:=get_node(dir_node_size);
2682  words:=dir_node_size;
2683  end;
2684@z
2685%-------------------------
2686@x [53] m.1358
2687close_node,language_node: free_node(p,small_node_size);
2688@y
2689close_node,language_node: free_node(p,small_node_size);
2690dir_node: free_node(p,dir_node_size);
2691@z
2692%-------------------------
2693@x [53] m.1360
2694@ @<Incorporate a whatsit node into an hbox@>=do_nothing
2695@y
2696@ @<Incorporate a whatsit node into an hbox@>=
2697begin
2698if subtype(p)=dir_node then
2699  begin
2700  @<DIR: Adjust the dir stack for the |hpack| routine@>;
2701  end;
2702end
2703@z
2704%-------------------------
2705@x [53] m.1362
2706@<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>=@+
2707adv_past(cur_p) else @<LOCAL: Advance past a |local_paragraph| node@>
2708@y
2709@<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>=@+
2710adv_past(cur_p) else @<LOCAL: Advance past a |local_paragraph| node@>
2711else @<DIR: Adjust the dir stack for the |line_break| routine@>
2712@z
2713%-------------------------
2714@x [53] m.1366
2715@ @<Output the whatsit node |p| in an hlist@>=
2716out_what(p)
2717@y
2718@ @<Output the whatsit node |p| in an hlist@>=
2719if subtype(p)<>dir_node then out_what(p)
2720else @<Output a reflection instruction if the direction has changed@>
2721@z
2722%-------------------------
2723@x
2724@d local_par_size==7
2725@y
2726@d local_par_dir(#)==mem[#+7].int
2727@d local_par_size==8
2728@z
2729%-------------------------
2730@x
2731make_local_par_node:=p;
2732@y
2733local_par_dir(p):=par_direction;
2734make_local_par_node:=p;
2735@z
2736%-------------------------
2737@x
2738@ @<LOCAL: local paragraph node@>=
2739((type(q)=whatsit_node) and (subtype(q)=local_par_node))
2740
2741@y
2742@ @<LOCAL: local paragraph node@>=
2743((type(q)=whatsit_node) and (subtype(q)=local_par_node))
2744
2745@ @<DIR: Assign direction codes@>=
2746case cur_chr of
2747dir_base+page_direction_code: begin
2748  if its_all_over then begin
2749    scan_dir;
2750    eq_word_define(dir_base+page_direction_code,cur_val);
2751    end;
2752  end;
2753dir_base+body_direction_code: begin
2754  if its_all_over then begin
2755    scan_dir;
2756    eq_word_define(dir_base+body_direction_code,cur_val);
2757    end;
2758  end;
2759dir_base+par_direction_code: begin
2760  scan_dir;
2761  eq_word_define(dir_base+par_direction_code,cur_val);
2762  end;
2763dir_base+text_direction_code: begin scan_dir;
2764  if (no_local_dirs>0) and (abs(mode)=hmode) then begin
2765    @<DIR: Add local dir node@>;
2766    dir_dir(tail):=dir_dir(tail)-64;
2767    end;
2768  if dir_level(text_dir_ptr)=cur_level then
2769    @<DIR: Remove from |text_dir_ptr|@>;
2770  eq_word_define(dir_base+text_direction_code,cur_val);
2771  @<DIR: Add to |text_dir_ptr|@>;
2772  if abs(mode)=hmode then
2773    begin
2774    @<DIR: Add local dir node@>;
2775    dir_level(tail):=cur_level;
2776    end;
2777  eq_word_define(int_base+no_local_dirs_code,no_local_dirs+1);
2778  eq_word_define(int_base+level_local_dir_code,cur_level);
2779  end;
2780dir_base+math_direction_code: begin scan_dir;
2781  eq_word_define(dir_base+math_direction_code,cur_val);
2782  end;
2783end;
2784
2785@
2786@d push_dir(#)==
2787begin dir_tmp:=new_dir(#);
2788link(dir_tmp):=dir_ptr; dir_ptr:=dir_tmp;
2789dir_ptr:=dir_tmp;
2790end
2791
2792@d push_dir_node(#)==
2793begin dir_tmp:=get_node(dir_node_size);
2794type(dir_tmp):=whatsit_node; subtype(dir_tmp):=dir_node;
2795dir_dir(dir_tmp):=dir_dir(#);
2796dir_level(dir_tmp):=dir_level(#);
2797dir_dvi_h(dir_tmp):=dir_dvi_h(#);
2798dir_dvi_ptr(dir_tmp):=dir_dvi_ptr(#);
2799link(dir_tmp):=dir_ptr; dir_ptr:=dir_tmp;
2800end
2801
2802@d pop_dir_node==
2803begin dir_tmp:=dir_ptr;
2804dir_ptr:=link(dir_tmp);
2805free_node(dir_tmp,dir_node_size);
2806end
2807
2808@ @<DIR: Declare |new_dir|@>=
2809function new_dir(s:small_number): pointer;
2810var p:pointer; {the new node}
2811begin p:=get_node(dir_node_size); type(p):=whatsit_node;
2812subtype(p):=dir_node; dir_dir(p):=s;
2813dir_dvi_h(p):=0; dir_dvi_ptr(p):=-1;
2814dir_level(p):=cur_level; new_dir:=p;
2815end
2816
2817@ @<Append a begin direction to the tail of the current list@>=
2818tail_append(new_dir(math_direction))
2819
2820@ @<Append an end direction to the tail of the current list@>=
2821tail_append(new_dir(math_direction-64))
2822
2823@ @<DIR: Add local dir node@>=
2824tail_append(new_dir(text_direction))
2825
2826@ @<DIR: Adjust the dir stack for the |line_break| routine@>=
2827if subtype(cur_p)=dir_node then
2828begin
2829if dir_dir(cur_p)>=0 then begin
2830  line_break_dir:=dir_dir(cur_p);
2831  push_dir_node(cur_p);
2832  end
2833else begin
2834  pop_dir_node;
2835  line_break_dir:=dir_dir(dir_ptr);
2836  end
2837end
2838
2839@ @<DIR: Adjust the dir stack for the |hpack| routine@>=
2840begin
2841if dir_dir(p)>=0 then begin
2842  hpack_dir:=dir_dir(p);
2843  push_dir_node(p);
2844  end
2845else begin
2846  pop_dir_node;
2847  hpack_dir:=dir_dir(dir_ptr);
2848  end
2849end
2850
2851@ @<DIR: Insert dir nodes at the beginning of the current line@>=
2852begin
2853dir_rover:=dir_ptr;
2854while dir_rover<>null do
2855  begin
2856  dir_tmp:=new_dir(dir_dir(dir_rover)); link(dir_tmp):=link(temp_head);
2857  link(temp_head):=dir_tmp; dir_rover:=link(dir_rover);
2858  end
2859end
2860
2861@ @<DIR: Adjust the dir stack based on dir nodes in this line@>=
2862begin flush_node_list(dir_ptr); dir_ptr:=null;
2863q:=link(temp_head);
2864while q<>cur_break(cur_p) do
2865  begin if not is_char_node(q) then
2866    if type(q)=whatsit_node then
2867      if subtype(q)=dir_node then begin
2868        if dir_dir(q)>=0 then begin
2869          push_dir_node(q)
2870          end
2871        else if dir_ptr<>null then
2872          if dir_dir(dir_ptr)=(dir_dir(q)+64) then begin
2873            pop_dir_node;
2874            end;
2875        end;
2876  q:=link(q);
2877  end
2878end
2879
2880@ @<DIR: Insert dir nodes at the end of the current line@>=
2881if dir_ptr<>null then
2882  begin
2883  if link(r)=q then begin
2884    dir_rover:=dir_ptr;
2885    while dir_rover<>null do
2886      begin
2887      dir_tmp:=new_dir(dir_dir(dir_rover)-64);
2888      link(dir_tmp):=q;
2889      link(r):=dir_tmp;
2890      r:=dir_tmp;
2891      dir_rover:=link(dir_rover);
2892      end;
2893    end
2894  else if r=final_par_glue then begin
2895    s:=temp_head;
2896    while link(s)<>r do
2897      s:=link(s);
2898    dir_rover:=dir_ptr;
2899    while dir_rover<>null do
2900      begin
2901      dir_tmp:=new_dir(dir_dir(dir_rover)-64);
2902      link(dir_tmp):=q;
2903      link(s):=dir_tmp;
2904      s:=dir_tmp;
2905      dir_rover:=link(dir_rover);
2906      end;
2907    end
2908  else begin
2909    dir_rover:=dir_ptr;
2910    s:=link(q);
2911    while dir_rover<>null do
2912      begin
2913      dir_tmp:=new_dir(dir_dir(dir_rover)-64);
2914      link(dir_tmp):=s;
2915      link(q):=dir_tmp;
2916      q:=dir_tmp;
2917      dir_rover:=link(dir_rover);
2918      end;
2919    r:=q;
2920    end
2921  end
2922
2923@ @<DIR: Reset |dir_ptr|@>=
2924begin
2925 while dir_ptr<>null do
2926  pop_dir_node
2927end
2928
2929@ @<DIR: |unsave| math@>=
2930begin
2931unsave;
2932decr(save_ptr);
2933flush_node_list(text_dir_ptr);
2934text_dir_ptr:=saved(0);
2935end
2936
2937@ @<DIR: |new_save_level| math@>=
2938begin
2939saved(0):=text_dir_ptr;
2940text_dir_ptr:=new_dir(math_direction);
2941incr(save_ptr);
2942new_save_level(c);
2943eq_word_define(dir_base+body_direction_code,math_direction);
2944eq_word_define(dir_base+par_direction_code,math_direction);
2945eq_word_define(dir_base+text_direction_code,math_direction);
2946eq_word_define(int_base+level_local_dir_code,cur_level);
2947end
2948
2949@ @<DIR: Adjust |text_dir_ptr| for |scan_spec|@>=
2950begin
2951if spec_direction<>-1 then begin
2952  saved(3):=text_dir_ptr;
2953  text_dir_ptr:=new_dir(spec_direction);
2954  end
2955else saved(3):=null;
2956end
2957
2958@ @<DIR: Adjust back |text_dir_ptr| for |scan_spec|@>=
2959begin
2960flush_node_list(text_dir_ptr);
2961text_dir_ptr:=saved(4);
2962end
2963
2964@ @<DIR: Add to |text_dir_ptr|@>=
2965begin
2966text_dir_tmp:=new_dir(text_direction);
2967link(text_dir_tmp):=text_dir_ptr;
2968text_dir_ptr:=text_dir_tmp;
2969end
2970
2971@ @<DIR: Remove from |text_dir_ptr|@>=
2972begin
2973text_dir_tmp:=link(text_dir_ptr);
2974free_node(text_dir_ptr,dir_node_size);
2975text_dir_ptr:=text_dir_tmp;
2976end
2977
2978@ @<DIR: Initialize |text_dir_ptr|@>=
2979begin
2980text_dir_ptr:=new_dir(0);
2981end
2982
2983@ @<DIR: Initialize |dir_ptr| for |ship_out|@>=
2984begin dir_ptr:=null; push_dir(dvi_direction);
2985dir_dvi_ptr(dir_ptr):=dvi_ptr;
2986end
2987
2988@ @<DIR: Initialize |dir_ptr| for |hpack|@>=
2989begin dir_ptr:=null; push_dir(hpack_dir) end
2990
2991@ @<DIR: Initialize |dir_ptr| for |line_break|@>=
2992begin dir_ptr:=null; push_dir(paragraph_dir); end
2993
2994@ @<Output a reflection instruction if the direction has changed@>=
2995begin
2996if dir_dir(p)>=0 then
2997  begin synch_h; synch_v;
2998  push_dir_node(p);
2999  if dir_opposite(dir_secondary[dir_dir(dir_ptr)])(dir_secondary[dvi_direction])
3000  then begin
3001    if (dir_secondary[dvi_direction]=0) or
3002       (dir_secondary[dvi_direction]=2) then
3003      dvi_out(down4)
3004    else
3005      dvi_out(right4);
3006    dir_dvi_ptr(dir_ptr):=dvi_ptr;
3007    dir_dvi_h(dir_ptr):=dvi_h;
3008    dvi_four(0);
3009    cur_h:=0; dvi_h:=0;
3010    end
3011  else begin
3012    dir_dvi_ptr(dir_ptr):=dvi_ptr;
3013    dir_dvi_h(dir_ptr):=dvi_h;
3014    end;
3015  dvi_direction:=dir_dir(dir_ptr);
3016  end
3017else begin
3018  dvi_dir_h:=dir_dvi_h(dir_ptr);
3019  dvi_dir_ptr:=dir_dvi_ptr(dir_ptr);
3020  pop_dir_node;
3021  synch_h; synch_v;
3022  dvi_direction:=dir_dir(dir_ptr);
3023 if dir_opposite(dir_secondary[dir_dir(p)+64])(dir_secondary[dvi_direction])
3024  then begin
3025    dvi_temp_ptr:=dvi_ptr;
3026    dvi_ptr:=dvi_dir_ptr;
3027    if (dir_secondary[dvi_direction]=0) or
3028       (dir_secondary[dvi_direction]=1) then
3029      dvi_four(dvi_h)
3030    else
3031      dvi_four(-dvi_h);
3032    dvi_ptr:=dvi_temp_ptr;
3033    if (dir_secondary[dvi_direction]=0) or
3034       (dir_secondary[dvi_direction]=2) then
3035      dvi_out(down4)
3036    else
3037      dvi_out(right4);
3038    if (dir_secondary[dvi_direction]=0) or
3039       (dir_secondary[dvi_direction]=1) then
3040      dvi_four(dvi_h)
3041    else
3042      dvi_four(-dvi_h);
3043    end;
3044    cur_h:=dvi_dir_h+dvi_h; dvi_h:=cur_h;
3045  end
3046end
3047@z
3048