@x @d banner=='This is TeX, Version 1.3' {printed when \TeX\ starts} @y @d banner=='This is TeX 1.3 for Cedar 6.0' {printed when \TeX\ starts} @z @x @f type==true {but `|type|' will not be treated as a reserved word} @y @f type==true {but `|type|' will not be treated as a reserved word} @d write_ln==writeln {since our Tangle doesn't strip out "_"} @d read_ln==readln {since our Tangle doesn't strip out "_"} @z @x procedure initialize; {this procedure gets things started properly} @y @@/ procedure initialize; {this procedure gets things started properly} @z @x @d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging} @d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging} @y @d debug== @d gubed== @z @x @d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering usage statistics} @d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering usage statistics} @y @d stat== @d tats== @z @x @!init @@;@+tini @y if start_like_initex then begin @ end; @z @x @!mem_max=30000; {greatest index in \TeX's internal |mem| array; @y @!mem_max=65000; {greatest index in \TeX's internal |mem| array; @z @x @!buf_size=500; {maximum number of characters simultaneously present in @y @!buf_size=7500; {maximum number of characters simultaneously present in @z @x @!error_line=72; {width of context lines on terminal error messages} @!half_error_line=42; {width of first lines of contexts in terminal error messages; should be between 30 and |error_line-15|} @!max_print_line=79; {width of longest text lines output; should be at least 60} @y @!error_line=64; {width of context lines on terminal error messages} @!half_error_line=32; {width of first lines of contexts in terminal error messages; should be between 30 and |error_line-15|} @!max_print_line=30000; {width of longest text lines output; should be at least 60} @z @x @!font_max=75; {maximum internal font number; must not exceed |max_quarterword| and must be at most |font_base+256|} @!font_mem_size=20000; {number of words of |font_info| for all fonts} @y @!font_max=100; {maximum internal font number; must not exceed |max_quarterword| and must be at most |font_base+256|} @!font_mem_size=25000; {number of words of |font_info| for all fonts} @z @x @!max_strings=3000; {maximum number of strings; must not exceed |max_halfword|} @!string_vacancies=8000; {the minimum number of characters that should be available for the user's control sequences and font names, after \TeX's own error messages are stored} @!pool_size=32000; {maximum number of characters in strings, including all error messages and help texts, and the names of all fonts and control sequences; must exceed |string_vacancies| by the total length of \TeX's own strings, which is currently about 23000} @y @!max_strings=4400; {maximum number of strings; must not exceed |max_halfword|} @!string_vacancies=15000; {the minimum number of characters that should be available for the user's control sequences and font names, after \TeX's own error messages are stored} @!pool_size=48000; {maximum number of characters in strings, including all error messages and help texts, and the names of all fonts and control sequences; must exceed |string_vacancies| by the total length of \TeX's own strings, which is currently about 23000} @z @x @!file_name_size=40; {file names shouldn't be longer than this} @y @!file_name_size=127; {file names shouldn't be longer than this} @z @x @!pool_name='TeXformats:TEX.POOL '; @y @z @x @d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX}; must not be less than |mem_min|} @d mem_top==30000 {largest index in the |mem| array dumped by \.{INITEX}; must be substantially larger than |mem_bot| and not greater than |mem_max|} @y @d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX}; must not be less than |mem_min|} @d mem_top==65000 {largest index in the |mem| array dumped by \.{INITEX}; must be substantially larger than |mem_bot| and not greater than |mem_max|} @z @x @d hash_size=2100 {maximum number of control sequences; it should be at most about |(mem_max-mem_min)/10|, but 2100 is already quite generous} @d hash_prime=1777 {a prime number equal to about 85\% of |hash_size|} @y @d hash_size=2500 {maximum number of control sequences; it should be at most about |(mem_max-mem_min)/10|, but 2100 is already quite generous} @d hash_prime=2129 {a prime number equal to about 85\% of |hash_size|} @z @x @d last_text_char=127 {ordinal number of the largest element of |text_char|} @y @d last_text_char=255 {ordinal number of the largest element of |text_char|} @z @x for i:=1 to @'37 do xchr[i]:=' '; @y for i:=1 to @'37 do xchr[i]:=chr(i); @z @x @d reset_OK(#)==erstat(#)=0 @d rewrite_OK(#)==erstat(#)=0 @p function a_open_in(var f:alpha_file):boolean; {open a text file for input} begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f); end; @# function a_open_out(var f:alpha_file):boolean; {open a text file for output} begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f); end; @# function b_open_in(var f:byte_file):boolean; {open a binary file for input} begin reset(f,name_of_file,'/O'); b_open_in:=reset_OK(f); end; @# function b_open_out(var f:byte_file):boolean; {open a binary file for output} begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f); end; @# function w_open_in(var f:word_file):boolean; {open a word file for input} begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f); end; @# function w_open_out(var f:word_file):boolean; {open a word file for output} begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f); end; @y @p function a_open_in(var f:alpha_file):boolean; external; {open a text file for input} @# function a_open_out(var f:alpha_file):boolean; external; {open a text file for output} @# function b_open_in(var f:byte_file):boolean; external; {open a binary file for input} @# function b_open_out(var f:byte_file):boolean; external; {open a binary file for output} @# function w_open_in(var f:word_file):boolean; external; {open a word file for input} @# function w_open_out(var f:word_file):boolean; external; {open a word file for output} @z @x @p procedure a_close(var f:alpha_file); {close a text file} begin close(f); end; @# procedure b_close(var f:byte_file); {close a binary file} begin close(f); end; @# procedure w_close(var f:word_file); {close a word file} begin close(f); end; @y @p procedure a_close(var f:alpha_file); external; {close a text file} @# procedure b_close(var f:byte_file); external; {close a binary file} @# procedure w_close(var f:word_file); external; {close a word file} @z @x @d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input} @d t_open_out==rewrite(term_out,'TTY:','/O') {open the terminal for text output} @y @d t_open_in==reset_term_in(term_in) {open the terminal for text input} @d t_open_out==rewrite_term_out(term_out) {open the terminal for text output} @z @x @d clear_terminal == break_in(term_in,true) {clear the terminal input buffer} @y @d clear_terminal == {clear the terminal input buffer} @z @x begin t_open_in; @y const cmd_blank = 0; cmd_ok = 1; cmd_overflow = -1; var cmd_status:integer; begin t_open_in; cmd_status:=stuff_on_cmd_line; if cmd_status=cmd_overflow then overflow("buffer size",buf_size); if cmd_status=cmd_ok then begin init_terminal:=true; return end; @z @x name_of_file:=pool_name; {we needn't set |name_length|} @y set_pool_name; @z @x if interaction=error_stop_mode then @; @y if interaction=error_stop_mode then begin set_normal_priority; @; end; @z @x exit:end; @y exit: set_background_priority; end; @z @x print(" at line "); print_int(line); @y print(" near character "); print_int(line); @z @x @!nonnegative_integer=0..@'17777777777; {$0\L x<2^{31}$} @y @!nonnegative_integer=integer; {$0\L x<2^{31}$} @z @x @d max_halfword==65535 {largest allowable value in a |halfword|} @y @d max_halfword==65515 {largest allowable value in a |halfword|} @z @x @d qi(#)==#+min_quarterword {to put an |eight_bits| item into a quarterword} @d qo(#)==#-min_quarterword {to take an |eight_bits| item out of a quarterword} @d hi(#)==#+min_halfword {to put a sixteen-bit item into a halfword} @d ho(#)==#-min_halfword {to take a sixteen-bit item from a halfword} @y @d qi(#)==# {to put an |eight_bits| item into a quarterword} @d qo(#)==# {to take an |eight_bits| item out of a quarterword} @d hi(#)==# {to put a sixteen-bit item into a halfword} @d ho(#)==# {to take a sixteen-bit item from a halfword} @z @x @!two_choices = 1..2; {used when there are two variants in a record} @!four_choices = 1..4; {used when there are four variants in a record} @!two_halves = packed record@;@/ @!rh:halfword; case two_choices of 1: (@!lh:halfword); 2: (@!b0:quarterword; @!b1:quarterword); end; @!four_quarters = packed record@;@/ @!b0:quarterword; @!b1:quarterword; @!b2:quarterword; @!b3:quarterword; end; @!memory_word = record@;@/ case four_choices of 1: (@!int:integer); 2: (@!gr:glue_ratio); 3: (@!hh:two_halves); 4: (@!qqqq:four_quarters); end; @y @!two_choices = (c1of2, c2of2); {used when there are two variants in a record} @!four_choices = (c1of4, c2of4, c3of4, c4of4); {used when there are four variants in a record} @!two_halves = packed record@;@/ @!rh:halfword; case two_choices of c1of2: (@!lh:halfword); c2of2: (@!b0:quarterword; @!b1:quarterword); end; @!four_quarters = packed record@;@/ @!b0:quarterword; @!b1:quarterword; @!b2:quarterword; @!b3:quarterword; end; @!memory_word = record@;@/ case four_choices of c1of4: (@!int:integer); c2of4: (@!gr:glue_ratio); c3of4: (@!hh:two_halves); c4of4: (@!qqqq:four_quarters); end; @z @x print(" entered at line "); print_int(abs(nest[p].ml_field)); @y print(" entered in line at c. "); print_int(abs(nest[p].ml_field)); @z @x begin time:=12*60; {minutes since midnight} day:=4; {fourth day of the month} month:=7; {seventh month of the year} year:=1776; {Anno Domini} end; @y begin read_the_clock(time,day,month,year); end; @z @x @!mag_set:integer; {if nonzero, this magnification should be used henceforth} @y @!mag_set:integer; {if nonzero, this magnification should be used henceforth} @!use_press_format:boolean; {the user has requested that Press format be used} @z @x @p procedure prepare_mag; begin if (mag_set>0)and(mag<>mag_set) then @y @p procedure prepare_mag; var @!user_wants_press:boolean; begin user_wants_press:=profile_asks_for_press; if (mag_set>0)and(mag<>mag_set) then @z @x if (mag<=0)or(mag>32768) then @y if (mag_set>0)and(use_press_format<>user_wants_press) then begin print_err("Tardy attempt to select Press print file format is being ignored"); error; user_wants_press:=use_press_format; end; if (mag<=0)or(mag>32768) then @z @x mag_set:=mag; @y mag_set:=mag; use_press_format:=user_wants_press; @z @x else begin print_nl("l."); print_int(line); @y else begin print_nl("c."); print_int(line+(loc-start)); @z @x print("; all text was ignored after line "); print_int(skip_line); @y print("; all text was ignored after line at c. "); print_int(skip_line); @z @x begin incr(line); first:=start; @y begin line:=file_get_pos(cur_file); first:=start; @z @x @!num,@!denom:1..65536; {conversion ratio for the scanned units} @y @!num,@!denom:integer; {conversion ratio for the scanned units} @z @x @d TEX_area=="TeXinputs:" @.TeXinputs@> @d TEX_font_area=="TeXfonts:" @.TeXfonts@> @y @= @!TEX_area:str_number; @.TeXinputs@> @!TEX_font_area:str_number; @.TeXfonts@> @z @x else begin if (c=">")or(c=":") then begin area_delimiter:=pool_ptr; ext_delimiter:=0; end else if (c=".")and(ext_delimiter=0) then ext_delimiter:=pool_ptr; @y else begin if (c=">")or(c="/")or(c="]") then area_delimiter:=pool_ptr else if (c=".") then ext_delimiter:=pool_ptr; @z @x @ A messier routine is also needed, since format file names must be scanned before \TeX's string mechanism has been initialized. We shall use the global variable |TEX_format_default| to supply the text for default system areas and extensions related to format files. @^system dependencies@> @d format_default_length=20 {length of the |TEX_format_default| string} @d format_area_length=11 {length of its area part} @d format_ext_length=4 {length of its `\.{.fmt}' part} @= @!TEX_format_default:packed array[1..format_default_length] of char; @ @= TEX_format_default:='TeXformats:PLAIN.fmt'; @.TeXformats@> @.PLAIN@> @^system dependencies@> @ @= if format_default_length>file_name_size then bad:=31; @y @ This module is a dummy. The default name of the format file is dealt with directly in Cedar. @ So is this one. @ This one too. @z @x @p procedure pack_buffered_name(@!n:small_number;@!a,@!b:integer); var k:integer; {number of positions filled in |name_of_file|} @!c: ASCII_code; {character being packed} @!j:integer; {index into |buffer| or |TEX_format_default|} begin if n+b-a+1+format_ext_length>file_name_size then b:=a+file_name_size-n-1-format_ext_length; k:=0; for j:=1 to n do append_to_name(xord[TEX_format_default[j]]); for j:=a to b do append_to_name(buffer[j]); for j:=format_default_length-format_ext_length+1 to format_default_length do append_to_name(xord[TEX_format_default[j]]); if k<=file_name_size then name_length:=k@+else name_length:=file_name_size; for k:=name_length+1 to file_name_size do name_of_file[k]:=' '; end; @y @p procedure pack_buffered_name(@!a,@!b:integer); external; procedure pack_default_area(@!a,@!b:integer); external; procedure pack_all_default; external; @z @x pack_buffered_name(0,loc,j-1); {try first without the system file area} @y pack_buffered_name(loc,j-1); {try first without the system file area} @z @x pack_buffered_name(format_area_length,loc,j-1); @y pack_default_area(loc,j-1); @z @x wterm_ln('Sorry, I can''t find that format;',' will try PLAIN.'); @y wterm_ln('Sorry, I can''t find that format;',' will try your default.'); @z @x pack_buffered_name(format_default_length-format_ext_length,1,0); @y pack_all_default; @z @x wterm_ln('I can''t find the PLAIN format file!'); @y wterm_ln('I can''t find your default format file!'); @z @x function a_make_name_string(var f:alpha_file):str_number; begin a_make_name_string:=make_name_string; end; function b_make_name_string(var f:byte_file):str_number; begin b_make_name_string:=make_name_string; end; function w_make_name_string(var f:word_file):str_number; begin w_make_name_string:=make_name_string; end; @y function a_make_name_string(var f:alpha_file):str_number; external; function b_make_name_string(var f:byte_file):str_number; external; function w_make_name_string(var f:word_file):str_number; external; function press_make_name_string:str_number; external; @z @x @d ensure_dvi_open==if output_file_name=0 then @y @d ensure_press_open==if output_file_name=0 then begin if job_name=0 then open_log_file; pack_job_name(".press"); while not press_open_out do prompt_file_name("file name for output",".press"); output_file_name:=press_make_name_string; end; @d ensure_dvi_open==if output_file_name=0 then @z @x first:=limit+1; loc:=start; line:=1; @y first:=limit+1; loc:=start; line:=1; @z @x @!skew_char:array[internal_font_number] of integer; {current \.{\\skewchar} values} @y @!skew_char:array[internal_font_number] of integer; {current \.{\\skewchar} values} @!font_family:array[internal_font_number] of str_number; {the Press family name} @!font_face:array[internal_font_number] of eight_bits; {the Press face code} @!font_pype_code:array[internal_font_number] of cedar_nat; {once font_used is true, holds the SirPress pyping font code} @z @x @!f:internal_font_number; {the new font's number} @y @!i,@!fam_len:halfword; {new temporaries} @!f:internal_font_number; {the new font's number} @z @x begin g:=null_font;@/ @y procedure read_the_tfm_header; @; begin g:=null_font;@/ @z @x @; @y read_the_tfm_header; @z @x @ Only the first two words of the header are needed by \TeX82. @= begin if lh<2 then abort; store_four_quarters(font_check[f]); fget; read_sixteen(z); {this rejects a negative design size} fget; z:=z*@'400+fbyte; fget; z:=(z*@'20)+(fbyte div@'20); if z2 do begin fget;fget;fget;fget;decr(lh); {ignore the rest of the header} end; font_dsize[f]:=z; if s<>-1000 then if s>=0 then z:=s else z:=xn_over_d(z,-s,1000); font_size[f]:=z; end @y @ Normally, \TeX82 only needs to read the first two words of the header. But we must read more, in order to handle Press output. @= begin if lh<18 then abort; store_four_quarters(font_check[f]); fget; read_sixteen(z); {this rejects a negative design size} fget; z:=z*@'400+fbyte; fget; z:=(z*@'20)+(fbyte div@'20); if z18 do begin fget;fget;fget;fget;decr(lh); {ignore the rest of the header} end; font_dsize[f]:=z; if s<>-1000 then if s>=0 then z:=s else z:=xn_over_d(z,-s,1000); font_size[f]:=z; end @z @x @p procedure write_dvi(@!a,@!b:dvi_index); var k:dvi_index; begin for k:=a to b do write(dvi_file,dvi_buf[k]); end; @y @p procedure write_dvi(@!a,@!b:dvi_index); external; @z @x @!cur_s:integer; {current depth of output box nesting} @y @!cur_s:integer; {current depth of output box nesting} @!press_h_ok:boolean; {while pyping, tells if SirPress has the correct x-coordinate} @z @x cur_s:=-1; ensure_dvi_open; @y cur_s:=-1; prepare_mag; {now the Press/DVI die is cast} if use_press_format then begin ensure_press_open; if total_pages=0 then do_nothing; {nothing special needs to be done before the first page} end else begin ensure_dvi_open; @z @x pool_ptr:=str_start[str_ptr]; {flush the current string} end @y pool_ptr:=str_start[str_ptr]; {flush the current string} end; end @z @x @p procedure@?vlist_out; forward; {|hlist_out| and |vlist_out| are mutually recursive} @y @p procedure@?vlist_out; forward; {|hlist_out| and |vlist_out| are mutually recursive} procedure@?hlist_press_out; forward; procedure@?vlist_press_out; forward; @z @x @ The recursive procedures |hlist_out| and |vlist_out| each have local variables |save_h| and |save_v| to hold the values of |dvi_h| and |dvi_v| just before entering a new level of recursion. In effect, the values of |save_h| and |save_v| on \TeX's run-time stack correspond to the values of |h| and |v| that a \.{DVI}-reading program will push onto its coordinate stack. @d move_past=13 {go to this label when advancing past glue or a rule} @d fin_rule=14 {go to this label to finish processing a rule} @d next_p=15 {go to this label when finished with node |p|} @p @t\4@>@@t@>@/ procedure hlist_out; {output an |hlist_node| box} label reswitch, move_past, fin_rule, next_p; var base_line: scaled; {the baseline coordinate for this box} @!left_edge: scaled; {the left coordinate for this box} @!save_h,@!save_v: scaled; {what |dvi_h| and |dvi_v| should pop to} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @!p:pointer; {current position in the hlist} @!save_loc:integer; {\.{DVI} byte location upon entry} @!leader_box:pointer; {the leader box being replicated} @!leader_wd:scaled; {width of leader box being replicated} @!lx:scaled; {extra space between leader boxes} @!outer_doing_leaders:boolean; {were we doing leaders?} @!edge:scaled; {left edge of sub-box, or right edge of leader space} begin this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); incr(cur_s); if cur_s>0 then dvi_out(push); if cur_s>max_push then max_push:=cur_s; save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; left_edge:=cur_h; while p<>null do @; prune_movements(save_loc); if cur_s>0 then dvi_pop(save_loc); decr(cur_s); end; @ We ought to give special care to the efficiency of one part of |hlist_out|, since it belongs to \TeX's inner loop. When a |char_node| is encountered, we save a little time by processing several nodes in succession until reaching a non-|char_node|. The program uses the fact that |set_char_0=0|. @^inner loop@> @= reswitch: if is_char_node(p) then begin synch_h; synch_v; repeat f:=font(p); c:=character(p); if f<>dvi_f then @; if c @ @= begin if not font_used[f] then begin dvi_font_def(f); font_used[f]:=true; end; if f<=64+font_base then dvi_out(f-font_base-1+fnt_num_0) else begin dvi_out(fnt1); dvi_out(f-font_base-1); end; dvi_f:=f; end @ @= begin case type(p) of hlist_node,vlist_node:@; rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); goto fin_rule; end; whatsit_node: @; glue_node: @; kern_node,math_node:cur_h:=cur_h+width(p); ligature_node: @; othercases do_nothing endcases;@/ goto next_p; fin_rule: @; move_past: cur_h:=cur_h+rule_wd; next_p:p:=link(p); end @ @= if list_ptr(p)=null then cur_h:=cur_h+width(p) else begin save_h:=dvi_h; save_v:=dvi_v; cur_v:=base_line+shift_amount(p); {shift the box down} temp_ptr:=p; edge:=cur_h; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_h:=save_h; dvi_v:=save_v; cur_h:=edge+width(p); cur_v:=base_line; end @ @= if is_running(rule_ht) then rule_ht:=height(this_box); if is_running(rule_dp) then rule_dp:=depth(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} begin synch_h; cur_v:=base_line+rule_dp; synch_v; dvi_out(set_rule); dvi_four(rule_ht); dvi_four(rule_wd); cur_v:=base_line; dvi_h:=dvi_h+rule_wd; end @ @= begin g:=glue_ptr(p); rule_wd:=width(g); if g_sign<>normal then begin if g_sign=stretching then begin if stretch_order(g)=g_order then rule_wd:=rule_wd+round(float(glue_set(this_box))*stretch(g)); @^real multiplication@> end else begin if shrink_order(g)=g_order then rule_wd:=rule_wd-round(float(glue_set(this_box))*shrink(g)); end; end; if subtype(p)>=a_leaders then @; goto move_past; end @ @= begin leader_box:=leader_ptr(p); if type(leader_box)=rule_node then begin rule_ht:=height(leader_box); rule_dp:=depth(leader_box); goto fin_rule; end; leader_wd:=width(leader_box); if (leader_wd>0)and(rule_wd>0) then begin edge:=cur_h+rule_wd; lx:=0; @; while cur_h+leader_wd<=edge do @; cur_h:=edge; goto next_p; end; end @ The calculations related to leaders require a bit of care. First, in the case of |a_leaders| (aligned leaders), we want to move |cur_h| to |left_edge| plus the smallest multiple of |leader_wd| for which the result is not less than the current value of |cur_h|; i.e., |cur_h| should become $|left_edge|+|leader_wd|\times\lceil (|cur_h|-|left_edge|)/|leader_wd|\rceil$. The program here should work in all cases even though some implementations of \PASCAL\ give nonstandard results for the |div| operation precisely, and even when |cur_h| is less than |left_edge|. In the case of |c_leaders| (centered leaders), we want to increase |cur_h| by half of the excess space not occupied by the leaders; and in the case of case of |x_leaders| (expanded leaders) we increase |cur_h| by $1/(q+1)$ of this excess space, where $q$ is the number of times the leader box will be replicated. Slight inaccuracies in the division might accumulate; half of this rounding error is placed at each end of the leaders. @= if subtype(p)=a_leaders then begin save_h:=cur_h; cur_h:=left_edge+leader_wd*((cur_h-left_edge)@!div leader_wd); if cur_h= begin cur_v:=base_line+shift_amount(leader_box); synch_v; save_v:=dvi_v;@/ synch_h; save_h:=dvi_h; temp_ptr:=leader_box; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then vlist_out@+else hlist_out; doing_leaders:=outer_doing_leaders; dvi_v:=save_v; dvi_h:=save_h; cur_v:=save_v; cur_h:=save_h+leader_wd+lx; end @ The |vlist_out| routine is similar to |hlist_out|, but a bit simpler. @p procedure vlist_out; {output a |vlist_node| box} label move_past, fin_rule, next_p; var left_edge: scaled; {the left coordinate for this box} @!top_edge: scaled; {the top coordinate for this box} @!save_h,@!save_v: scaled; {what |dvi_h| and |dvi_v| should pop to} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @!p:pointer; {current position in the vlist} @!save_loc:integer; {\.{DVI} byte location upon entry} @!leader_box:pointer; {the leader box being replicated} @!leader_ht:scaled; {height of leader box being replicated} @!lx:scaled; {extra space between leader boxes} @!outer_doing_leaders:boolean; {were we doing leaders?} @!edge:scaled; {bottom boundary of leader space} begin this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); incr(cur_s); if cur_s>0 then dvi_out(push); if cur_s>max_push then max_push:=cur_s; save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; cur_v:=cur_v-height(this_box); top_edge:=cur_v; while p<>null do @; prune_movements(save_loc); if cur_s>0 then dvi_pop(save_loc); decr(cur_s); end; @ @= begin if is_char_node(p) then confusion("vlistout") @:this can't happen vlistout}{\quad vlistout@> else @; next_p:p:=link(p); end @ @= begin case type(p) of hlist_node,vlist_node:@; rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); goto fin_rule; end; whatsit_node: @; glue_node: @; kern_node:cur_v:=cur_v+width(p); othercases do_nothing endcases;@/ goto next_p; fin_rule: @; move_past: cur_v:=cur_v+rule_ht; end @ The |synch_v| here allows the \.{DVI} output to use one-byte commands for adjusting |v| in most cases, since the baselineskip distance will usually be constant. @= if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) else begin cur_v:=cur_v+height(p); synch_v; save_h:=dvi_h; save_v:=dvi_v; cur_h:=left_edge+shift_amount(p); {shift the box right} temp_ptr:=p; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_h:=save_h; dvi_v:=save_v; cur_v:=save_v+depth(p); cur_h:=left_edge; end @ @= if is_running(rule_wd) then rule_wd:=width(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} cur_v:=cur_v+rule_ht; if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} begin synch_h; synch_v; dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd); end; goto next_p @ @= begin g:=glue_ptr(p); rule_ht:=width(g); if g_sign<>normal then begin if g_sign=stretching then begin if stretch_order(g)=g_order then rule_ht:=rule_ht+round(float(glue_set(this_box))*stretch(g)); @^real multiplication@> end else begin if shrink_order(g)=g_order then rule_ht:=rule_ht-round(float(glue_set(this_box))*shrink(g)); end; end; if subtype(p)>=a_leaders then @; goto move_past; end @ @= begin leader_box:=leader_ptr(p); if type(leader_box)=rule_node then begin rule_wd:=width(leader_box); rule_dp:=0; goto fin_rule; end; leader_ht:=height(leader_box)+depth(leader_box); if (leader_ht>0)and(rule_ht>0) then begin edge:=cur_v+rule_ht; lx:=0; @; while cur_v+leader_ht<=edge do @; cur_v:=edge; goto next_p; end; end @ @= if subtype(p)=a_leaders then begin save_v:=cur_v; cur_v:=top_edge+leader_ht*((cur_v-top_edge)@!div leader_ht); if cur_v= begin cur_h:=left_edge+shift_amount(leader_box); synch_h; save_h:=dvi_h;@/ cur_v:=cur_v+height(leader_box); synch_v; save_v:=dvi_v; temp_ptr:=leader_box; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then vlist_out@+else hlist_out; doing_leaders:=outer_doing_leaders; dvi_v:=save_v; dvi_h:=save_h; cur_h:=save_h; cur_v:=save_v-height(leader_box)+leader_ht+lx; end @y @ The recursive procedures |hlist_out| and |vlist_out| each have local variables |save_h| and |save_v| to hold the values of |dvi_h| and |dvi_v| just before entering a new level of recursion. In effect, the values of |save_h| and |save_v| on \TeX's run-time stack correspond to the values of |h| and |v| that a \.{DVI}-reading program will push onto its coordinate stack. @d move_past=13 {go to this label when advancing past glue or a rule} @d fin_rule=14 {go to this label to finish processing a rule} @d next_p=15 {go to this label when finished with node |p|} @p @t\4@>@@t@>@/ procedure hlist_out; {output an |hlist_node| box} label reswitch, move_past, fin_rule, next_p; var base_line: scaled; {the baseline coordinate for this box} @!left_edge: scaled; {the left coordinate for this box} @!save_h,@!save_v: scaled; {what |dvi_h| and |dvi_v| should pop to} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @!p:pointer; {current position in the hlist} @!save_loc:integer; {\.{DVI} byte location upon entry} @!leader_box:pointer; {the leader box being replicated} @!leader_wd:scaled; {width of leader box being replicated} @!lx:scaled; {extra space between leader boxes} @!outer_doing_leaders:boolean; {were we doing leaders?} @!edge:scaled; {left edge of sub-box, or right edge of leader space} begin this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); incr(cur_s); if cur_s>0 then dvi_out(push); if cur_s>max_push then max_push:=cur_s; save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; left_edge:=cur_h; while p<>null do @; prune_movements(save_loc); if cur_s>0 then dvi_pop(save_loc); decr(cur_s); end; @ We ought to give special care to the efficiency of one part of |hlist_out|, since it belongs to \TeX's inner loop. When a |char_node| is encountered, we save a little time by processing several nodes in succession until reaching a non-|char_node|. The program uses the fact that |set_char_0=0|. @^inner loop@> @= reswitch: if is_char_node(p) then begin synch_h; synch_v; repeat f:=font(p); c:=character(p); if f<>dvi_f then @; if c @ @= begin if not font_used[f] then begin dvi_font_def(f); font_used[f]:=true; end; if f<=64+font_base then dvi_out(f-font_base-1+fnt_num_0) else begin dvi_out(fnt1); dvi_out(f-font_base-1); end; dvi_f:=f; end @ @= begin case type(p) of hlist_node,vlist_node:@; rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); goto fin_rule; end; whatsit_node: @; glue_node: @; kern_node,math_node:cur_h:=cur_h+width(p); ligature_node: @; othercases do_nothing endcases;@/ goto next_p; fin_rule: @; move_past: cur_h:=cur_h+rule_wd; next_p:p:=link(p); end @ @= if list_ptr(p)=null then cur_h:=cur_h+width(p) else begin save_h:=dvi_h; save_v:=dvi_v; cur_v:=base_line+shift_amount(p); {shift the box down} temp_ptr:=p; edge:=cur_h; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_h:=save_h; dvi_v:=save_v; cur_h:=edge+width(p); cur_v:=base_line; end @ @= if is_running(rule_ht) then rule_ht:=height(this_box); if is_running(rule_dp) then rule_dp:=depth(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} begin synch_h; cur_v:=base_line+rule_dp; synch_v; dvi_out(set_rule); dvi_four(rule_ht); dvi_four(rule_wd); cur_v:=base_line; dvi_h:=dvi_h+rule_wd; end @ @= begin g:=glue_ptr(p); rule_wd:=width(g); if g_sign<>normal then begin if g_sign=stretching then begin if stretch_order(g)=g_order then rule_wd:=rule_wd+round(float(glue_set(this_box))*stretch(g)); @^real multiplication@> end else begin if shrink_order(g)=g_order then rule_wd:=rule_wd-round(float(glue_set(this_box))*shrink(g)); end; end; if subtype(p)>=a_leaders then @; goto move_past; end @ @= begin leader_box:=leader_ptr(p); if type(leader_box)=rule_node then begin rule_ht:=height(leader_box); rule_dp:=depth(leader_box); goto fin_rule; end; leader_wd:=width(leader_box); if (leader_wd>0)and(rule_wd>0) then begin edge:=cur_h+rule_wd; lx:=0; @; while cur_h+leader_wd<=edge do @; cur_h:=edge; goto next_p; end; end @ The calculations related to leaders require a bit of care. First, in the case of |a_leaders| (aligned leaders), we want to move |cur_h| to |left_edge| plus the smallest multiple of |leader_wd| for which the result is not less than the current value of |cur_h|; i.e., |cur_h| should become $|left_edge|+|leader_wd|\times\lceil (|cur_h|-|left_edge|)/|leader_wd|\rceil$. The program here should work in all cases even though some implementations of \PASCAL\ give nonstandard results for the |div| operation precisely, and even when |cur_h| is less than |left_edge|. In the case of |c_leaders| (centered leaders), we want to increase |cur_h| by half of the excess space not occupied by the leaders; and in the case of case of |x_leaders| (expanded leaders) we increase |cur_h| by $1/(q+1)$ of this excess space, where $q$ is the number of times the leader box will be replicated. Slight inaccuracies in the division might accumulate; half of this rounding error is placed at each end of the leaders. @= if subtype(p)=a_leaders then begin save_h:=cur_h; cur_h:=left_edge+leader_wd*((cur_h-left_edge)@!div leader_wd); if cur_h= begin cur_v:=base_line+shift_amount(leader_box); synch_v; save_v:=dvi_v;@/ synch_h; save_h:=dvi_h; temp_ptr:=leader_box; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then vlist_out@+else hlist_out; doing_leaders:=outer_doing_leaders; dvi_v:=save_v; dvi_h:=save_h; cur_v:=save_v; cur_h:=save_h+leader_wd+lx; end @ The |vlist_out| routine is similar to |hlist_out|, but a bit simpler. @p procedure vlist_out; {output a |vlist_node| box} label move_past, fin_rule, next_p; var left_edge: scaled; {the left coordinate for this box} @!top_edge: scaled; {the top coordinate for this box} @!save_h,@!save_v: scaled; {what |dvi_h| and |dvi_v| should pop to} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @!p:pointer; {current position in the vlist} @!save_loc:integer; {\.{DVI} byte location upon entry} @!leader_box:pointer; {the leader box being replicated} @!leader_ht:scaled; {height of leader box being replicated} @!lx:scaled; {extra space between leader boxes} @!outer_doing_leaders:boolean; {were we doing leaders?} @!edge:scaled; {bottom boundary of leader space} begin this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); incr(cur_s); if cur_s>0 then dvi_out(push); if cur_s>max_push then max_push:=cur_s; save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; cur_v:=cur_v-height(this_box); top_edge:=cur_v; while p<>null do @; prune_movements(save_loc); if cur_s>0 then dvi_pop(save_loc); decr(cur_s); end; @ @= begin if is_char_node(p) then confusion("vlistout") @:this can't happen vlistout}{\quad vlistout@> else @; next_p:p:=link(p); end @ @= begin case type(p) of hlist_node,vlist_node:@; rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); goto fin_rule; end; whatsit_node: @; glue_node: @; kern_node:cur_v:=cur_v+width(p); othercases do_nothing endcases;@/ goto next_p; fin_rule: @; move_past: cur_v:=cur_v+rule_ht; end @ The |synch_v| here allows the \.{DVI} output to use one-byte commands for adjusting |v| in most cases, since the baselineskip distance will usually be constant. @= if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) else begin cur_v:=cur_v+height(p); synch_v; save_h:=dvi_h; save_v:=dvi_v; cur_h:=left_edge+shift_amount(p); {shift the box right} temp_ptr:=p; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_h:=save_h; dvi_v:=save_v; cur_v:=save_v+depth(p); cur_h:=left_edge; end @ @= if is_running(rule_wd) then rule_wd:=width(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} cur_v:=cur_v+rule_ht; if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} begin synch_h; synch_v; dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd); end; goto next_p @ @= begin g:=glue_ptr(p); rule_ht:=width(g); if g_sign<>normal then begin if g_sign=stretching then begin if stretch_order(g)=g_order then rule_ht:=rule_ht+round(float(glue_set(this_box))*stretch(g)); @^real multiplication@> end else begin if shrink_order(g)=g_order then rule_ht:=rule_ht-round(float(glue_set(this_box))*shrink(g)); end; end; if subtype(p)>=a_leaders then @; goto move_past; end @ @= begin leader_box:=leader_ptr(p); if type(leader_box)=rule_node then begin rule_wd:=width(leader_box); rule_dp:=0; goto fin_rule; end; leader_ht:=height(leader_box)+depth(leader_box); if (leader_ht>0)and(rule_ht>0) then begin edge:=cur_v+rule_ht; lx:=0; @; while cur_v+leader_ht<=edge do @; cur_v:=edge; goto next_p; end; end @ @= if subtype(p)=a_leaders then begin save_v:=cur_v; cur_v:=top_edge+leader_ht*((cur_v-top_edge)@!div leader_ht); if cur_v= begin cur_h:=left_edge+shift_amount(leader_box); synch_h; save_h:=dvi_h;@/ cur_v:=cur_v+height(leader_box); synch_v; save_v:=dvi_v; temp_ptr:=leader_box; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then vlist_out@+else hlist_out; doing_leaders:=outer_doing_leaders; dvi_v:=save_v; dvi_h:=save_h; cur_h:=save_h; cur_v:=save_v-height(leader_box)+leader_ht+lx; end @z @x @p procedure ship_out(@!p:pointer); {output the box |p|} @y @p @t\4@>@@t@>@/ procedure ship_out(@!p:pointer); {output the box |p|} @z @x page_loc:=dvi_offset+dvi_ptr; dvi_out(bop); for k:=0 to 9 do dvi_four(count(k)); dvi_four(last_bop); last_bop:=page_loc; cur_v:=height(p)+v_offset; temp_ptr:=p; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_out(eop); incr(total_pages); done: @y if use_press_format then begin cur_v:=height(p)+v_offset; temp_ptr:=p; if type(p)=vlist_node then vlist_press_out@+else hlist_press_out; press_write_page; incr(total_pages); end else begin page_loc:=dvi_offset+dvi_ptr; dvi_out(bop); for k:=0 to 9 do dvi_four(count(k)); dvi_four(last_bop); last_bop:=page_loc; cur_v:=height(p)+v_offset; temp_ptr:=p; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_out(eop); incr(total_pages); end; done: @z @x else begin dvi_out(post); {beginning of the postamble} @y else if use_press_format then begin print_nl("Output written on "); print(output_file_name); @.Output written on x@> print(" ("); print_int(total_pages); print(" page"); if total_pages<>1 then print_char("s"); print(")."); press_close_file; end else begin dvi_out(post); {beginning of the postamble} @z @x begin if pack_begin_line>0 then print(") in paragraph at lines ") else print(") in alignment at lines "); @y begin if pack_begin_line>0 then print(") in paragraph at cc. ") else print(") in alignment at cc. "); @z @x else print(") detected at line "); @y else print(") detected at c. "); @z @x begin print(") in alignment at lines "); @y begin print(") in alignment at cc. "); @z @x else print(") detected at line "); @y else print(") detected at c. "); @z @x @!rule_save:scaled; {temporary storage for |overfull_rule|} @y @!rule_save:scaled; {temporary storage for |overfull_rule|} procedure fin_align_inner; begin @; end; @z @x @; @y fin_align_inner; @z @x var @@; begin pack_begin_line:=mode_line; {this is for over/underfull box messages} @; @y var @@; procedure line_break_inner; begin @; end; begin pack_begin_line:=mode_line; {this is for over/underfull box messages} line_break_inner; @z @x label exit,done,done1,continue,deactivate; @y label exit,done1,continue,deactivate; @z @x @@; @y @@; procedure try_break_inner; label done; begin @; end; @z @x ((old_l<>easy_line)or(r=last_active)) then @; @y ((old_l<>easy_line)or(r=last_active)) then try_break_inner; @z @x dump_int(skew_char[k]);@/ @y dump_int(skew_char[k]);@/ dump_int(font_family[k]); dump_int(font_face[k]);@/ @z @x undump_int(skew_char[k]);@/ @y undump_int(skew_char[k]);@/ undump(0)(str_ptr)(font_family[k]); undump(0)(255)(font_face[k]);@/ @z @x @!ready_already:integer; {a sacrifice of purity for economy} @y @!start_like_initex:boolean; {otherwise, we start up like TeX} @z @x @p begin @!{|start_here|} @y @p procedure the_real_tex; begin @!{|start_here|} @z @x if ready_already=314159 then goto start_of_TEX; @y set_background_priority; @z @x @!init if not get_strings_started then goto final_end; init_prim; {call |primitive| for each primitive} tini@/ @y if start_like_initex then begin if not get_strings_started then goto final_end; init_prim; {call |primitive| for each primitive} end; @z @x ready_already:=314159; @y @z @x final_end: ready_already:=0; @y final_end: set_normal_priority; @z @x end. @y end; begin end. @z @x begin @; @y begin @; for k := 1 to in_open do begin a_close(input_file[k]); print_char(")"); end; @z @x print(log_name); print_char("."); @y print(log_name); print_char("."); print_char(carriage_return); @z @x begin print(" on line "); print_int(if_line); @y begin print(" on line at c. "); print_int(if_line); @z @x if (locescape) then start_input; @y read_profile_for_directories; if (locescape) then start_input; @z @x itself will get a new section number. @^system dependencies@> @y itself will get a new section number. @^system dependencies@> @ @= @ @ @ @ @ The actual work of writing the Press file is done by the SirPress package in Cedar. The following procedures provide access to this package from Pascal. The final function is a little different: its job it to provide access to our procedures from Cedar. @= function get_pype_code(f: internal_font_number; at_size_in_hnm:integer): cedar_nat; external; procedure press_set_font(c: cedar_nat); external; procedure press_show_char(c: quarterword); external; procedure press_set_x(x: scaled); external; procedure press_set_y(y: scaled); external; procedure press_show_rule(xstart, ystart, xlen, ylen: scaled); external; procedure flush_pype; external; procedure press_write_page; external; procedure press_close_file; external; @ The procedure hlist_press_out is very similar to hlist_out. Note that hlist_press_out makes no use of dvi_h, dvi_v, or cur_s. Instead, we make use of the global booleans press_h_ok; if we are pyping, this boolean tells us that there is no need to do a PipePosition before the next PipeChar. We shall first add a macro definition for the number of micas in 11 inches, since Press has it's vertical axis running up instead of down. Also, a macro for the number of hectonanometers (meters*e^-7) in 11 inches, since sometimes we will be computing in them. They correspond to SirPress.unit=100. In addition, the origin of the DVI page is actually shifted by one inch in both h and v. We also add macros for these distances. @d page_height_in_mica==27940 {micas in 11 inches} @d page_height_in_hnm==2794000 {hnm in 11 inches} @d h_marg_in_mica==2540 @d h_marg_in_hnm==254000 @d v_marg_in_mica==2540 @d v_marg_in_hnm==254000 @= procedure hlist_press_out; {output an |hlist_node| box} label reswitch, move_past, fin_rule, next_p; var base_line: scaled; {the baseline coordinate for this box} @!base_in_mica: scaled; {baseline in micas} @!left_edge: scaled; {the left coordinate for this box} @!save_h,@!save_v: scaled; {still used in leaders calculations} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @!p:pointer; {current position in the hlist} @!leader_box:pointer; {the leader box being replicated} @!leader_wd:scaled; {width of leader box being replicated} @!lx:scaled; {extra space between leader boxes} @!outer_doing_leaders:boolean; {were we doing leaders?} @!edge:scaled; {left edge of sub-box, or right edge of leader space} begin this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); base_line:=cur_v; left_edge:=cur_h; base_in_mica:=page_height_in_mica - v_marg_in_mica - x_over_n(xn_over_d(base_line, mag, 18647),100); while p<>null do @; end; @ @= reswitch: if is_char_node(p) then begin press_set_y(base_in_mica); f:=font(p); if f<>dvi_f then @; press_set_x(h_marg_in_mica + x_over_n(xn_over_d(cur_h, mag, 18647),100)); repeat c:=character(p); press_show_char(c); cur_h:=cur_h+char_width(f)(char_info(f)(c)); p:=link(p); until (not is_char_node(p))or(font(p)<>dvi_f); end else @ @ @= begin if not font_used[f] then begin font_pype_code[f]:=get_pype_code(f, xn_over_d(font_size[f],mag,18647)); font_used[f]:=true; end; press_set_font(font_pype_code[f]); dvi_f:=f; end @ @= begin case type(p) of hlist_node,vlist_node:@; rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); goto fin_rule; end; whatsit_node: @; glue_node: @; kern_node,math_node:cur_h:=cur_h+width(p); ligature_node: @; othercases do_nothing endcases;@/ goto next_p; fin_rule: @; move_past: cur_h:=cur_h+rule_wd; next_p:p:=link(p); end @ @= if list_ptr(p)=null then cur_h:=cur_h+width(p) else begin cur_v:=base_line+shift_amount(p); {shift the box down} temp_ptr:=p; edge:=cur_h; if type(p)=vlist_node then vlist_press_out@+else hlist_press_out; cur_h:=edge+width(p); cur_v:=base_line; end @ @= if is_running(rule_ht) then rule_ht:=height(this_box); if is_running(rule_dp) then rule_dp:=depth(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} begin press_show_rule(h_marg_in_hnm + xn_over_d(cur_h,mag,18647), page_height_in_hnm - v_marg_in_hnm - xn_over_d(base_line+rule_dp,mag,18647), xn_over_d(rule_wd,mag,18647), xn_over_d(rule_ht,mag,18647)); cur_v:=base_line; end @ @= begin g:=glue_ptr(p); rule_wd:=width(g); if g_sign<>normal then begin if g_sign=stretching then begin if stretch_order(g)=g_order then rule_wd:=rule_wd+round(float(glue_set(this_box))*stretch(g)); @^real multiplication@> end else begin if shrink_order(g)=g_order then rule_wd:=rule_wd-round(float(glue_set(this_box))*shrink(g)); end; end; if subtype(p)>=a_leaders then @; goto move_past; end @ @= begin leader_box:=leader_ptr(p); if type(leader_box)=rule_node then begin rule_ht:=height(leader_box); rule_dp:=depth(leader_box); goto fin_rule; end; leader_wd:=width(leader_box); if (leader_wd>0)and(rule_wd>0) then begin edge:=cur_h+rule_wd; lx:=0; @; while cur_h+leader_wd<=edge do @; cur_h:=edge; goto next_p; end; end @ @= begin cur_v:=base_line+shift_amount(leader_box); save_v:=cur_v;@/ save_h:=cur_h; temp_ptr:=leader_box; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then vlist_press_out@+else hlist_press_out; doing_leaders:=outer_doing_leaders; cur_v:=save_v; cur_h:=save_h+leader_wd+lx; end @ @= procedure vlist_press_out; {output a |vlist_node| box} label move_past, fin_rule, next_p; var left_edge: scaled; {the left coordinate for this box} @!top_edge: scaled; {the top coordinate for this box} @!save_h,@!save_v: scaled; {what |dvi_h| and |dvi_v| should pop to} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @!p:pointer; {current position in the vlist} @!leader_box:pointer; {the leader box being replicated} @!leader_ht:scaled; {height of leader box being replicated} @!lx:scaled; {extra space between leader boxes} @!outer_doing_leaders:boolean; {were we doing leaders?} @!edge:scaled; {bottom boundary of leader space} begin this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); left_edge:=cur_h; cur_v:=cur_v-height(this_box); top_edge:=cur_v; while p<>null do @; end; @ @= begin if is_char_node(p) then confusion("vlistout") @:this can't happen vlistout}{\quad vlistout@> else @; next_p:p:=link(p); end @ @= begin case type(p) of hlist_node,vlist_node:@; rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); goto fin_rule; end; whatsit_node: @; glue_node: @; kern_node:cur_v:=cur_v+width(p); othercases do_nothing endcases;@/ goto next_p; fin_rule: @; move_past: cur_v:=cur_v+rule_ht; end @ @= if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) else begin cur_v:=cur_v+height(p); save_v:=cur_v; cur_h:=left_edge+shift_amount(p); {shift the box right} temp_ptr:=p; if type(p)=vlist_node then vlist_press_out@+else hlist_press_out; cur_v:=save_v+depth(p); cur_h:=left_edge; end @ @= if is_running(rule_wd) then rule_wd:=width(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} cur_v:=cur_v+rule_ht; if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} begin press_show_rule(h_marg_in_hnm + xn_over_d(cur_h,mag,18647), page_height_in_hnm - v_marg_in_hnm - xn_over_d(cur_v,mag,18647), xn_over_d(rule_wd,mag,18647), xn_over_d(rule_ht,mag,18647)); end; goto next_p @ @= begin g:=glue_ptr(p); rule_ht:=width(g); if g_sign<>normal then begin if g_sign=stretching then begin if stretch_order(g)=g_order then rule_ht:=rule_ht+round(float(glue_set(this_box))*stretch(g)); @^real multiplication@> end else begin if shrink_order(g)=g_order then rule_ht:=rule_ht-round(float(glue_set(this_box))*shrink(g)); end; end; if subtype(p)>=a_leaders then @; goto move_past; end @ @= begin leader_box:=leader_ptr(p); if type(leader_box)=rule_node then begin rule_wd:=width(leader_box); rule_dp:=0; goto fin_rule; end; leader_ht:=height(leader_box)+depth(leader_box); if (leader_ht>0)and(rule_ht>0) then begin edge:=cur_v+rule_ht; lx:=0; @; while cur_v+leader_ht<=edge do @; cur_v:=edge; goto next_p; end; end @ @= begin cur_h:=left_edge+shift_amount(leader_box); save_h:=cur_h;@/ cur_v:=cur_v+height(leader_box); save_v:=cur_v; temp_ptr:=leader_box; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then vlist_press_out@+else hlist_press_out; doing_leaders:=outer_doing_leaders; cur_h:=save_h; cur_v:=save_v-height(leader_box)+leader_ht+lx; end @ @= procedure press_out_what(@!p:pointer); begin case subtype(p) of open_node,write_node,close_node:out_what(p); special_node:do_nothing; {specials not implemented for Press output} othercases confusion("ext4") @:this can't happen ext4}{\quad ext4@> endcases; end; @ @= press_out_what(p) @ @= press_out_what(p) @ We want to refer to the type of SirPress font codes from with Pascal, so we do the following. @= @!cedar_nat=0..32767; @ Here, finally, are the external procedure declarations. @= procedure reset_term_in(var f: alpha_file); external; {set up for input from terminal} procedure rewrite_term_out(var f: alpha_file); external; {set up for output to terminal} function profile_asks_for_press: boolean; external; function press_open_out: boolean; external; procedure read_the_clock(var ttime,dday,mmonth,yyear:integer); external; function file_get_pos(var f: alpha_file):integer; external; {return character count} procedure set_pool_name; external; procedure read_profile_for_directories; external; procedure set_normal_priority; external; procedure set_background_priority; external; function stuff_on_cmd_line:integer; external; @z %^file: TeX.changes Written by Michael Plass, September 27, 1985 9:12:40 am PDT. Modified by Lyle Ramshaw, February 5, 1984 5:38 pm Last changed by Pavel on May 23, 1985 1:13:13 pm PDT December 3, 1984: Pavel changed hi_mem_base back to 13000 from 25000, since the lower half of memory didn't seem to need more room and the upper half certainly did. The removed change was marked UNUSED and commented out, in case anybody wants to put it back the way it was. I also changed the banner line for version 1.2. December 3, 1984: Pavel changed that part back because it appears that the earlier referred to statistics have lied to us. Therefore, the hi-mem-base has been moved back to it's old value of 25000 and the mem_max change from 58000 to 65000. Sigh. December 14, 1984: Pavel upgraded to version 1.3. This involved changing the banner and removing the hi_mem_base changes altogether. December 28, 1984: Pavel finished the upgrade to 1.3. This involved setting mem_bot and mem_top to always be equal to mem_min and mem_max respectively since they must be so for IniTeX and we don't have a separate version. This does mean that the format file length will go up by about 35000 words, but it doesn't seem to be able to be helped. Sigh. February 4, 1985: Pavel added a fix so that TeX would close all of its input files when it ends. February 12, 1985: Pavel removed the call to ``register_tex_commands'' in the main program. Command registration is now done differently. September 27, 1985: Michael added a missing semicolon before press_close_file call. 006776: Add "Cedar" to the banner line. 009786: Define macros for read_ln and write_ln that expand without the underscores. 010090: Add external procedure declarations for things implemented in Cedar 012024: Turn on debug code. 012201: Turn on statistics code. 013080: Only initialize the table entries if we are to start_like_initex. 015849: TRIP: Set mem_max for the trip test. @x @!mem_max=30000; {greatest index in \TeX's internal |mem| array, @y @!mem_max=3000; {greatest index in \TeX's internal |mem| array, @z 015849: Set mem_max to a reasonable production value. If you change this, be sure to change mem_top, below. 015959: Up the buf_size, so that long input lines don't cause errors. 016162: TRIP: Set error_line, half_error_line, max_print_line for the trip test. @x @!error_line=72; {width of context lines on terminal error messages} @!half_error_line=42; {width of first lines of contexts in terminal error messages, should be between 30 and |error_line-15|} @!max_print_line=79; {width of longest text lines output, should be at least 60} @y @!error_line=64; {width of context lines on terminal error messages} @!half_error_line=32; {width of first lines of contexts in terminal error messages, should be between 30 and |error_line-15|} @!max_print_line=72; {width of longest text lines output, should be at least 60} @z 016162: Set error_line and half_error_line small, but max_print_line very large. 016613: Up the font_max and font_mem_size for LaTeX and other greedy users. 016943: Up the max_strings, string_vacancies, and pool_size for LaTeX and other greedy folk. 017775: Up the file_name_size to 127, enough for FS including version numbers. 017839: Delete pool name, since that initialization will be done by an external proc. 000000: Set mem_bot and mem_top to mem_min and mem_max respectively. 018878: Up the hash_size and hash_prime for greedy users. 025470: Allow for eight-bit characters 030172: Set up the character-code mapping to be the identity for now. 034917: Replace Pascal-H extended file routines with external calls. 036219: Also make close-operations external. 041190: Terminal files are also external. 042174: Remove break_in from clear_terminal 045051: Read the tail of the command line as the first line of input 054024: This is where to change if you want to print the extended character set to the terminal. 054715: Set up pool_name properly, filling out with blanks. 075294: Set process priority back up to normal for error handling interactions 075593: But set it back down to background when the interaction is over 076701: In Cedar, character counts are more useful than line numbers. My basic plan is to store character counts of the beginning of the lines in Knuth's "line" variables. To avoid confusion with zero, which Knuth uses as a special flag, I shall actually store (charPos+1) instead. This works out wonderfully, since the Position button in Tioga starts counting characters from one instead of from zero anyway. 085725: Eliminate big subrange of INT. 096364: Make max_halfword a little smaller to allow more effiencient index arithmetic. 097561: Make life easy on the compiler, given that min_halfword=min_quarterword=0 098142: Change tag fields in variant records to enumerated types. 178496: Fix up character count versus line number 216323: Fix up fix_date_and_time 252194: Add flag that chooses Press output format 252400: Set flag by inquiring of the user profile 252865: Complain about a tardy attempt to change the output format 253126: Irrevocably decide on the output format 282012: Report error locations by character count rather than line number. In this particular case, I adjust the value of line in order to indicate the exact character at which the error happened. 294981: Change message from "line" to "character" 309157: Set "line" to character count rather than line number. Remember that we want to store (charPos+1) in "line", but the offset of plus one comes for free, since Pascal has read the first character of the new line behind our backs. 361891: Eliminate large subrange of INT. 402772: Default file directories 403170: Adjust parsing of file names. 405257: We shall generate format file names in Cedar, working from the default name in the user profile. Hence, we here replace three modules by dummies (to keep the numbering the same). 406537: Pack_buffered_name in Pascal is replaced by three external relatives. 407921: Change first call on pack_buffered_name to a call on an external. 408066: Change second call on pack_buffered_name to a call on an external. 408247: Change message to indicate that PLAIN isn't necessarily the default format file. 408415: Change third call on pack_buffered_name to a call on an external. 408538: Change another message to indicate that PLAIN isn't necessarily the default format file. 409289: Report full names of open files by calls to system dependent externals. 413111: Open either press or DVI as appropriate. 417246: No change here, since it happens that 1 is correct value of (charPos+1) at the start of a file. 431785: Add arrays for Press font parameters. 438943: Add two new local variables to read_font_info 439273: Declare inner procedure for reading header, to make read_font_info shorter. 440837: Call the new inner procedure. 443721: Change old header-reading code into body of the new inner procedure. 482739: Make write_dvi external also. 498097: Add new global variable for use by hlist_press_out; 498257: Ship_out must firm up the selection between Press and DVI, and then initialize the appropriate one. 498873: Close off new block that the 498257 change opened inside ship_out. 499328: Declare hlist_press_out and vlist_press_out. 499418: Perform the identity change on the output code, to warn us of any future changes. If something changes here, the corresponding change should be made to the Press analogues of hlist_out and vlist_out, which appear at the end of this change file. 512274: Here is where we shall stick the procedures that do Press output, right before ship_out. 513940: Ship out page in either Press or DVI format. 515424: Close off print format output file, either Press or DVI 527348: Change first half of illfull hbox error message from "line" to "character" 527520: Change the other half of the hbox message. 533523: Change first half of illfull vbox message as well. 533630: Change the other half of the vbox message. 636439: Declare the new procedure fin_align_inner. 637074: Invoke the new procedure fin_align_inner. 649303: Declare inner procedure line_break_inner, and call it. 664669: Remove a label from try_break, since it now appears in try_break_inner. 664949: Declare the new procedure try_break_inner. 669277: Call the new procedure try_break_inner; 941047: Dump the Press font information to the format file. 941943: Undump the Press font information from the format file. 947272: Replace ready_already by the new boolean initing 947551: Wrap up the main code into a procedure body. 947687: Delete test on ready_already; instead, set process priority down to background. 948004: Only intialize strings and primitives if we are to start_like_initex; else, reading the format will take care of these initializations. 948115: Delete set of ready_already. 948429: Delete set of ready_already; instead, set process priority back up to normal. 948458: End the new procedure the_real_tex, and put in a null main body. 953085: Close all of the input files at the end. 953422: Add a final carriage-return to the terminal output. 951454: Fix up one last (line number)_(character position) point. 953143: Read the default directories from the user profile; strings must be started by now, and we can't wait any longer since the next line might call start_input 971877: All the new modules go here, so that other modules would not be renumbered. Most of our new modules are concerned with Press output; the final one declares as external the procedures that are implemented directly in Cedar. Κ ˜J™J™˜>Jšœ˜Jšœ˜Jšœ,˜,Jšœ ˜ Jšœ9˜9Jšœ˜Jšœ˜Jšœ-˜-Jšœ!˜!Jšœ>˜>Jšœ˜Jšœ˜Jšœ,˜,Jšœ˜Jšœ9˜9Jšœ˜Jšœ˜Jšœ-˜-Jšœ˜Jšœ>˜>Jšœ˜—šœ˜Jšœ:˜:Jšœ˜Jšœ˜Jšœ9˜9Jšœ˜Jšœ˜Jšœ7˜7Jšœ ˜ Jšœ˜Jšœ8˜8Jšœ!˜!Jšœ˜Jšœ7˜7Jšœ˜Jšœ˜Jšœ8˜8Jšœ˜—Jšœ˜—šœ,™,šœ˜Jšœ;˜;J˜J˜J˜J˜9J˜J˜J˜J˜7J˜J˜—šœ˜JšœE˜EJ˜J˜CJ˜J˜A—Jšœ˜—šœ)™)šœ˜JšœM˜MJ˜P—šœ˜JšœG˜GJ˜M—Jšœ˜—šœ+™+šœ˜JšœM˜M—šœ˜Jšœ7˜7—Jšœ˜—šœD™Dšœ˜Jšœ˜—šœ˜˜J˜ J˜—J˜J˜J˜J˜AJ˜@—Jšœ˜—Kšœ`™`šœ;™;šœ˜Jšœ7˜7—šœ˜J˜—Jšœ˜—šœN™Nšœ˜JšœG˜G—šœ˜Jšœi˜i—Jšœ˜—šœG™Gšœ˜Jšœ ˜ —šœ˜Jšœ#˜#—Jšœ˜—šœŸ™Ÿšœ˜Jšœ&˜&—šœ˜Jšœ-˜-—Jšœ˜—šœ&™&šœ˜Jšœ8˜8—šœ˜Jšœ/˜/—Jšœ˜—šœV™Všœ˜Jšœ@˜@—šœ˜Jšœ@˜@—Jšœ˜—šœQ™Qšœ˜Jšœ―˜―—šœ˜Jšœυ˜υ—Jšœ˜—šœA™Ašœ˜JšœD˜DJ˜FJ˜ J˜J˜J˜J˜*J˜J˜#J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜—šœ˜Jšœ˜Jšœ0˜0J˜.J˜1J˜ J˜J˜Jšœ˜Jšœ.˜.J˜J˜#J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜J˜ J˜—Jšœ˜—šœ1™1šœ˜Jšœ?˜?—šœ˜JšœE˜E—Jšœ˜—šœ ™ šœ˜Jšœ+˜+J˜!J˜%J˜J˜—šœ˜J˜*J˜—Jšœ˜—šœ1™1šœ˜JšœM˜M—šœ˜JšœM˜MJ˜N—Jšœ˜—šœ1™1šœ˜Jšœ˜J˜*—šœ˜Jšœ˜J˜J˜/J˜$—Jšœ˜—šœB™Bšœ˜Jšœ˜—šœ˜J˜:J˜VJ˜J˜%J˜Jšœ˜—Jšœ˜—šœ/™/šœ˜Jšœ ˜ —šœ˜Jšœ ˜ J˜#—Jšœ˜—šœΖ™Ζšœ˜Jšœ,˜,—šœ˜Jšœ8˜8—Jšœ˜—šœ1™1šœ˜JšœF˜F—šœ˜JšœL˜L—Jšœ˜—šœμ™μšœ˜Jšœ˜—šœ˜Jšœ1˜1—Jšœ˜—šœ(™(šœ˜Jšœ@˜@—šœ˜Jšœ?˜?—Jšœ˜—šœ ™ šœ˜Jšœ˜J˜ J˜J˜ —šœ˜Jšœ ˜ Jšœ˜J˜ Jšœ˜J˜ —Jšœ˜—šœ%™%šœ˜Jšœ¦˜¦—šœ˜Jšœy˜y—Jšœ˜—šœ»™»šœ˜J˜…—šœ˜J˜ƒ—Jšœ˜—šœM™Mšœ˜JšœΖ˜Ζ—šœ˜Jšœ;˜;Jšœ7˜7J˜%—Jšœ˜—šœI™Išœ˜JšœI˜I—šœ˜JšœG˜G—Jšœ˜—šœJ™Jšœ˜Jšœ1˜1—šœ˜Jšœ˜—Jšœ˜—šœX™Xšœ˜JšœC˜C—šœ˜JšœJ˜J—Jšœ˜—šœI™Išœ˜Jšœ@˜@—šœ˜Jšœ˜—Jšœ˜—šœ`™`šœ˜Jšœ3˜3—šœ˜Jšœ6˜6—Jšœ˜—šœO™Ošœ˜JšœΎ˜Ύ—šœ˜JšœC˜CJšœB˜BJšœB˜BJšœ5˜5—Jšœ˜—šœ0™0šœ˜J˜.—šœ˜J˜0J˜)J˜J˜J˜6J˜+J˜J˜J˜.—Jšœ˜—šœg™gšœ˜Jšœ$˜$—šœ˜Jšœ$˜$—Jšœ˜—šœ-™-šœ˜Jšœ3˜3J˜!—šœ˜Jšœ3˜3J˜!J˜8J˜J˜6J˜J˜:J˜?—Jšœ˜—šœ5™5šœ˜Jšœ1˜1—šœ˜J˜)Jšœ1˜1—Jšœ˜—šœS™Sšœ˜Jšœ˜—šœ˜˜Jšœ˜—Jšœ˜—Jšœ˜—šœ&™&šœ˜Jšœ˜—šœ˜J˜—Jšœ˜—šœL™Lšœ˜Jšœς˜ς—šœ˜Jšœ­˜­—Jšœ˜—šœ%™%šœ˜Jšœ*˜*J˜J˜2J˜—šœ˜Jšœ4˜4—Jšœ˜—šœ;™;šœ˜Jšœ6˜6—šœ˜Jšœ6˜6J˜T—Jšœ˜—šœk™kšœ˜Jšœ˜—šœ˜J˜ J˜-J˜J˜J˜J˜J˜HJ˜J˜Jšœ˜Jšœ˜—Jšœ˜—šœJ™Jšœ˜J˜:J˜—šœ˜J˜:J˜J˜—Jšœ˜—šœ4™4šœ˜JšœK˜KJšœ ˜ —šœ˜JšœK˜KJšœ ˜ J˜$J˜$—Jšœ˜—šœύ™ύšœ˜Jšœ c˜ c—šœ˜Jšœ c˜ c—Jšœ˜—šœ`™`šœ˜Jšœ8˜8—šœ˜J˜6Jšœ5˜5—Jšœ˜—šœ4™4šœ˜Jšœύ˜ύ—šœ˜JšœΫ˜Ϋ—Jšœ˜—šœ?™?šœ˜Jšœ7˜7—šœ˜JšœΉ˜Ή—Jšœ˜—šœR™Ršœ˜JšœE˜EJ˜+—šœ˜JšœC˜CJ˜)—Jšœ˜—šœ2™2šœ˜Jšœ$˜$—šœ˜Jšœ"˜"—Jšœ˜—šœ:™:šœ˜Jšœ,˜,—šœ˜Jšœ*˜*—Jšœ˜—šœ2™2šœ˜Jšœ$˜$—šœ˜Jšœ"˜"—Jšœ˜—šœ2™2šœ˜Jšœ;˜;—šœ˜Jšœ;˜;˜J˜J˜™>šœ˜Jšœ+˜+J˜KJ˜%—šœ˜Jšœ+˜+˜J˜J˜%J˜—J˜KJ˜—Jšœ˜—šœO™Ošœ˜Jšœ*˜*—šœ˜Jšœ%˜%—Jšœ˜—šœ2™2šœ˜Jšœ+˜+—šœ˜Jšœ+˜+˜J˜ J˜J˜JJ˜——Jšœ˜—šœ/™/šœ˜Jšœ0˜0J˜:J˜—šœ˜Jšœ0˜0J˜—Jšœ˜—šœ;™;šœ˜Jšœ˜—šœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœ˜—šœ?™?šœ˜Jšœ˜—šœ˜Jšœ˜Jšœ#˜#Jšœ˜—Jšœ˜—šœ8™8šœ˜Jšœ<˜<—šœ˜Jšœ>˜>—Jšœ˜—šœ4™4šœ˜Jšœ˜—šœ˜Jšœ˜Jšœ˜—Jšœ˜—šœX™Xšœ˜Jšœ/˜/—šœ˜Jšœ˜—Jšœ˜—šœ™šœ˜Jšœn˜n—šœ˜Jšœ˜Jšœ8˜8Jšœ2˜2Jšœ˜—Jšœ˜—šœ$™$šœ˜Jšœ˜—Jšœ˜Jšœ˜—šœV™Všœ˜Jšœ˜—šœ˜Jšœ˜—Jšœ˜—šœH™Hšœ˜Jšœ˜—šœ˜J˜J˜J˜—Jšœ˜—šœ0™0šœ˜Jšœ ˜ —šœ˜Jšœ ˜ ˜˜J˜J˜—J˜——Jšœ˜—šœ;™;šœ˜Jšœ%˜%—šœ˜JšœB˜B—Jšœ˜—šœA™Ašœ˜Jšœ1˜1—šœ˜Jšœ7˜7—Jšœ˜—šœ€™€šœ˜JšœB˜B—šœ˜J˜JšœB˜B—Jšœ˜—šœθ™θšœ˜Jšœ%˜%J˜—šœ˜Jšœ=˜=Jšœπ\˜π\J˜J˜J˜:J˜JšœM˜MJšœ5˜5Jšœ!˜!Jšœ8˜8Jšœ ˜ J˜3J˜+J˜HJ˜TJ˜"J˜1J˜(J˜,J˜-—Jšœ˜—K™K™K™K™—…—πΰ+G