% This is etex.ch in text format, as of October 26, 1996. % WEB change file containing code for various features extending TeX; % to be applied to tex.web (Version 3.14159) in order to define the % e-TeX program. % e-TeX is copyright (C) 1994,96 by the NTS team; all rights are reserved. % Copying of this file is authorized only if (1) you are a member of the % NTS team, or if (2) you make absolutely no changes to your copy. % (Programs such as PATCHWEB, TIE, or WEBMERGE allow the application of % several change files to tex.web; the master files tex.web and etex.ch % should stay intact.) % See etex_gen.tex for hints on how to install this program. % And see etripman.tex for details about how to validate it. % The TeX program is copyright (C) 1982 by D. E. Knuth. % TeX is a trademark of the American Mathematical Society. % e-TeX and NTS are trademarks of the NTS group. % All line numbers refer to TEX.WEB 3.14159 as of March 21, 1995. @x limbo l.1 - this is e-TeX % This program is copyright (C) 1982 by D. E. Knuth; all rights are reserved. % Copying of this file is authorized only if (1) you are D. E. Knuth, or if % (2) you make absolutely no changes to your copy. (The WEB system provides % for alterations via an auxiliary file; the master file should stay intact.) % See Appendix H of the WEB manual for hints on how to install this program. % And see Appendix A of the TRIP manual for details about how to validate it. % TeX is a trademark of the American Mathematical Society. % METAFONT is a trademark of Addison-Wesley Publishing Company. @y % e-TeX is copyright (C) 1994,96 by the NTS team; all rights are reserved. % Copying of this file is authorized only if (1) you are a member of the % NTS team, or if (2) you make absolutely no changes to your copy. % (Programs such as PATCHWEB, TIE, or WEBMERGE allow the application of % several change files to tex.web; the master files tex.web and etex.ch % should stay intact.) % See etex_gen.tex for hints on how to install this program. % And see etripman.tex for details about how to validate it. % e-TeX and NTS are trademarks of the NTS group. % TeX is a trademark of the American Mathematical Society. % METAFONT is a trademark of Addison-Wesley Publishing Company. % This program is directly derived from Donald E. Knuth's TeX; % the change history which follows and the reward offered for finders of % bugs refer specifically to TeX; they should not be taken as referring % to e-TeX, although the change history is relevant in that it % demonstrates the evolutionary path followed. This program is not TeX; % that name is reserved strictly for the program which is the creation % and sole responsibility of Professor Knuth. @z %--------------------------------------- @x limbo l.50 - e-TeX history % Although considerable effort has been expended to make the TeX program % correct and reliable, no warranty is implied; the author disclaims any % obligation or liability for damages, including but not limited to % special, indirect, or consequential damages arising out of or in % connection with the use or performance of this software. This work has % been a ``labor of love'' and the author hopes that users enjoy it. @y % A preliminary version of TeX--XeT was released in April 1992. % TeX--XeT version 1.0 was released in June 1992, % version 1.1 prevented arith overflow in glue computation (Oct 1992). % A preliminary e-TeX version 0.95 was operational in March 1994. % Version 1.0beta was released in May 1995. % Version 1.01beta fixed bugs in just_copy and every_eof (December 1995). % Version 1.02beta allowed 256 mark classes (March 1996). % Version 1.1 changed \group{type,level} -> \currentgroup{type,level}, % first public release (October 1996). % Although considerable effort has been expended to make the e-TeX program % correct and reliable, no warranty is implied; the authors disclaim any % obligation or liability for damages, including but not limited to % special, indirect, or consequential damages arising out of or in % connection with the use or performance of this software. This work has % been a ``labor of love'' and the authors hope that users enjoy it. @z %--------------------------------------- @x limbo l.61 - e-TeX logo, TeXXeT \let\mc=\ninerm % medium caps for names like SAIL @y \let\mc=\ninerm % medium caps for names like SAIL \def\eTeX{$\varepsilon$-\TeX} \font\revrm=xbmc10 % for right-to-left text % to generate xbmc10 (i.e., reflected cmbx10) use a file % xbmc10.mf containing: %+++++++++++++++++++++++++++++++++++++++++++++++++ % if unknown cmbase: input cmbase fi % extra_endchar := extra_endchar & % "currentpicture:=currentpicture " & % "reflectedabout((.5[l,r],0),(.5[l,r],1));"; % input cmbx10 %+++++++++++++++++++++++++++++++++++++++++++++++++ \ifx\beginL\undefined % this is TeX \def\XeT{X\kern-.125em\lower.5ex\hbox{E}\kern-.1667emT} \def\TeXeT{\TeX-\hbox{\revrm \XeT}} % for TeX-XeT \def\TeXXeT{\TeX-\hbox{\revrm -\XeT}} % for TeX--XeT \else % this is TeX--XeT (or TeX-XeT) \ifx\TeXXeTstate\undefined \else % this is e-TeX \TeXXeTstate=1 \fi \def\TeXeT{\TeX-{\revrm\beginR\TeX\endR}} % for TeX-XeT \def\TeXXeT{\TeX-{\revrm\beginR\TeX-\endR}} % for TeX--XeT \fi @z %--------------------------------------- @x limbo l.64 - bug fix (print only changed modules) \def\pct!{{\char`\%}} % percent sign in ordinary text @y \def\pct!{{\char`\%}} % percent sign in ordinary text \def\grp{\.{\char'173...\char'175}} @z %--------------------------------------- @x limbo l.80 - e-TeX basic \def\title{\TeX82} @y \def\title{\eTeX} % system dependent redefinitions of \title should come later % and should use: % \toks0=\expandafter{\title} % \edef\title{...\the\toks0...} \let\maybe=\iffalse % print only changed modules @z %--------------------------------------- @x [1] m.1 l.91 - this is e-TeX This is \TeX, a document compiler intended to produce typesetting of high @y This is \eTeX, a program derived from and extending the capabilities of \TeX, a document compiler intended to produce typesetting of high @z %--------------------------------------- @x [1] m.2 l.179 - e-TeX basic If this program is changed, the resulting system should not be called @y This program contains code for various features extending \TeX, therefore this program is called `\eTeX' and not @z %--------------------------------------- @x [1] m.2 l.185 - e-TeX basic November 1984]. @y November 1984]. A similar test suite called the ``\.{e-TRIP} test'' is available for helping to determine whether a particular implementation deserves to be known as `\eTeX'. @z %--------------------------------------- @x [1] m.2 l.187 - e-TeX basic @d banner=='This is TeX, Version 3.14159' {printed when \TeX\ starts} @y @d banner=='This is TeX, Version 3.14159' {printed when \TeX\ starts} @# @d eTeX_version_string=='3.14159-1.1' {current \eTeX\ version} @d eTeX_version=1 { \.{\\eTeXversion} } @d eTeX_revision==".1" { \.{\\eTeXrevision} } @# @d eTeX_banner=='This is e-TeX, Version ',eTeX_version_string {printed when \eTeX\ starts} @# @d TEX==ETEX {change program name into |ETEX|} @# @d TeXXeT_code=0 {the \TeXXeT\ feature is optional} @# @d eTeX_states=1 {number of \eTeX\ state variables in |eqtb|} @z %--------------------------------------- @x [5] m.61 l.1556 - e-TeX basic wterm(banner); @y wterm(eTeX_banner); @z %--------------------------------------- @x [10] m.147 l.3069 - e-TeX TeXXeT the amount of surrounding space inserted by \.{\\mathsurround}. @y the amount of surrounding space inserted by \.{\\mathsurround}. In addition a |math_node| with |subtype>after| and |width=0| will be (ab)used to record a regular |math_node| reinserted after being discarded at a line break or one of the text direction primitives ( \.{\\beginL}, \.{\\endL}, \.{\\beginR}, and \.{\\endR} ). @z %--------------------------------------- @x [10] m.147 l.3073 - e-TeX TeXXeT @d after=1 {|subtype| for math node that winds up a formula} @y @d after=1 {|subtype| for math node that winds up a formula} @# @d M_code=2 @d begin_M_code=M_code+before {|subtype| for \.{\\beginM} node} @d end_M_code=M_code+after {|subtype| for \.{\\endM} node} @d L_code=4 @d begin_L_code=L_code+begin_M_code {|subtype| for \.{\\beginL} node} @d end_L_code=L_code+end_M_code {|subtype| for \.{\\endL} node} @d R_code=L_code+L_code @d begin_R_code=R_code+begin_M_code {|subtype| for \.{\\beginR} node} @d end_R_code=R_code+end_M_code {|subtype| for \.{\\endR} node} @# @d end_LR(#)==odd(subtype(#)) @d end_LR_type(#)==(L_code*(subtype(#) div L_code)+end_M_code) @d begin_LR_type(#)==(#-after+before) @z %--------------------------------------- @x [12] m.175 l.3546 - e-TeX TeXXeT math_node: print_char("$"); @y math_node: if subtype(p)>=L_code then print("[]") else print_char("$"); @z %--------------------------------------- @x [12] m.184 l.3713 - e-TeX TeXXeT begin print(", shifted "); print_scaled(shift_amount(p)); end; @y begin print(", shifted "); print_scaled(shift_amount(p)); end; if eTeX_ex then @; @z %--------------------------------------- @x [12] m.192 l.3811 - e-TeX TeXXeT begin print_esc("math"); @y if subtype(p)>after then begin if end_LR(p) then print_esc("end") else print_esc("begin"); if subtype(p)>R_code then print_char("R") else if subtype(p)>L_code then print_char("L") else print_char("M"); end else begin print_esc("math"); @z %--------------------------------------- @x [12] m.196 l.3844 - e-TeX marks begin print_esc("mark"); print_mark(mark_ptr(p)); @y begin print_esc("mark"); if subtype(p)>min_quarterword then begin print_char("s"); print_int(qo(subtype(p))); end; print_mark(mark_ptr(p)); @z %--------------------------------------- @x [15] m.208 l.4091 - e-TeX TeXXeT @d valign=33 {vertical table alignment ( \.{\\valign} )} @y @d valign=33 {vertical table alignment ( \.{\\valign} )} {or text direction directives ( \.{\\beginL}, etc.~)} @z %--------------------------------------- @x [15] m.208 l.4107 - e-TeX middle @d left_right=49 {variable delimiter ( \.{\\left}, \.{\\right} )} @y @d left_right=49 {variable delimiter ( \.{\\left}, \.{\\right} )} {or \.{\\middle}} @z %--------------------------------------- @x [15] m.209 l.4151 - e-TeX basic \.{\\insertpenalties} )} @y \.{\\insertpenalties} )} {or \.{\\interactionmode}} @z %--------------------------------------- @x [15] m.209 l.4163 - e-TeX protected @d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} @y @d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} {or \.{\\protected}} @z %--------------------------------------- @x [15] m.209 l.4166 - e-TeX read_line @d read_to_cs=96 {read into a control sequence ( \.{\\read} )} @y @d read_to_cs=96 {read into a control sequence ( \.{\\read} )} {or \.{\\readline}} @z %--------------------------------------- @x [15] m.210 l.4181 - e-TeX scan_tokens @d input=max_command+4 {input a source file ( \.{\\input}, \.{\\endinput} )} @y @d input=max_command+4 {input a source file ( \.{\\input}, \.{\\endinput} )} {or \.{\\scantokens}} @z %--------------------------------------- @x [15] m.210 l.4186 - e-TeX unexpanded @d the=max_command+9 {expand an internal quantity ( \.{\\the} )} @y @d the=max_command+9 {expand an internal quantity ( \.{\\the} )} {or \.{\\unexpanded}, \.{\\detokenize}} @z %--------------------------------------- @x [16] m.212 l.4289 - e-TeX basic user's output routine. @y user's output routine. A seventh quantity, |eTeX_aux|, is used by the extended features \eTeX. In vertical modes it is known as |LR_save| and holds the LR stack when a paragraph is interrupted by a displayed formula. In display math mode it is known as |LR_box| and holds a pointer to a prototype box for the display. In math mode it is known as |delim_ptr| and points to the most recent |left_noad| or |middle_noad| of a |math_left_group|. @z %--------------------------------------- @x [16] m.212 l.4304 - e-TeX basic @!head_field,@!tail_field: pointer; @y @!head_field,@!tail_field: pointer; @!eTeX_aux_field: pointer; @z %--------------------------------------- @x [16] m.213 l.4311 - e-TeX basic @d tail==cur_list.tail_field {final node on current list} @y @d tail==cur_list.tail_field {final node on current list} @d eTeX_aux==cur_list.eTeX_aux_field {auxiliary data for \eTeX} @d LR_save==eTeX_aux {LR stack when a paragraph is interrupted} @d LR_box==eTeX_aux {prototype box for display} @d delim_ptr==eTeX_aux {most recent left or right noad of a math left group} @z %--------------------------------------- @x [16] m.215 l.4342 - e-TeX basic mode:=vmode; head:=contrib_head; tail:=contrib_head; @y mode:=vmode; head:=contrib_head; tail:=contrib_head; eTeX_aux:=null; @z %--------------------------------------- @x [16] m.216 l.4358 push_nest - e-TeX basic incr(nest_ptr); head:=get_avail; tail:=head; prev_graf:=0; mode_line:=line; @y incr(nest_ptr); head:=get_avail; tail:=head; prev_graf:=0; mode_line:=line; eTeX_aux:=null; @z %--------------------------------------- @x [17] m.230 l.4720 - e-TeX basic @d err_help_loc=local_base+9 {points to token list for \.{\\errhelp}} @d toks_base=local_base+10 {table of 256 token list registers} @y @d every_eof_loc=local_base+9 {points to token list for \.{\\everyeof}} @d err_help_loc=local_base+10 {points to token list for \.{\\errhelp}} @d toks_base=local_base+11 {table of 256 token list registers} @z %--------------------------------------- @x [17] m.231 l.4787 - e-TeX basic othercases print_esc("errhelp") @y @/@@/ othercases print_esc("errhelp") @z %--------------------------------------- @x [17] m.236 l.4955 - e-TeX basic @d count_base=int_base+int_pars {256 user \.{\\count} registers} @y @d tracing_assigns_code=int_pars {show assignments} @d tracing_groups_code=int_pars+1 {show save/restore groups} @d tracing_ifs_code=int_pars+2 {show conditionals} @d tracing_scan_tokens_code=int_pars+3 {show pseudo file open and close} @d pre_display_direction_code=int_pars+4 {text direction preceding a display} @d eTeX_state_code=int_pars+5 {\eTeX\ state variables} @d count_base=int_base+eTeX_state_code+eTeX_states {256 user \.{\\count} registers} @z %--------------------------------------- @x [17] m.236 l.5016 - e-TeX basic @d error_context_lines==int_par(error_context_lines_code) @y @d error_context_lines==int_par(error_context_lines_code) @d tracing_assigns==int_par(tracing_assigns_code) @d tracing_groups==int_par(tracing_groups_code) @d tracing_ifs==int_par(tracing_ifs_code) @d tracing_scan_tokens==int_par(tracing_scan_tokens_code) @d pre_display_direction==int_par(pre_display_direction_code) @z %--------------------------------------- @x [17] m.237 l.5081 print_param - e-TeX basic othercases print("[unknown integer parameter!]") @y @/@@/ othercases print("[unknown integer parameter!]") @z %--------------------------------------- @x [18] m.264 l.5612 primitive - e-TeX basic @!j:small_number; {index into |buffer|} @y @!j:0..buf_size; {index into |buffer|} @z %--------------------------------------- @x [18] m.264 l.5616 primitive - e-TeX basic {we will move |s| into the (empty) |buffer|} for j:=0 to l-1 do buffer[j]:=so(str_pool[k+j]); cur_val:=id_lookup(0,l); {|no_new_control_sequence| is |false|} @y {we will move |s| into the (possibly non-empty) |buffer|} if first+l>buf_size+1 then overflow("buffer size",buf_size); @:TeX capacity exceeded buffer size}{\quad buffer size@> for j:=0 to l-1 do buffer[first+j]:=so(str_pool[k+j]); cur_val:=id_lookup(first,l); {|no_new_control_sequence| is |false|} @z %--------------------------------------- @x [18] m.266 l.5741 - e-TeX cond expand_after: print_esc("expandafter"); @y expand_after: if chr_code=0 then print_esc("expandafter") @; @z %--------------------------------------- @x [18] m.266 l.5747 - e-TeX marks mark: print_esc("mark"); @y mark: begin print_esc("mark"); if chr_code>0 then print_char("s"); end; @z %--------------------------------------- @x [18] m.266 l.5758 - e-TeX read_line read_to_cs: print_esc("read"); @y read_to_cs: if chr_code=0 then print_esc("read") @; @z %--------------------------------------- @x [18] m.266 l.5763 - e-TeX unexpanded the: print_esc("the"); @y the: if chr_code=0 then print_esc("the") @; @z %--------------------------------------- @x [18] m.266 l.5766 - e-TeX TeXXeT valign: print_esc("valign"); @y valign: if chr_code=0 then print_esc("valign")@/ @; @z %--------------------------------------- @x [19] m.268 l.5820 - e-TeX tracing the entries for that group. @y the entries for that group. Furthermore, in extended \eTeX\ mode, |save_stack[p-1]| contains the source line number at which the current level of grouping was entered. @z %--------------------------------------- @x [19] m.268 l.5830 - e-TeX basic @d level_boundary=3 {|save_type| corresponding to beginning of group} @y @d level_boundary=3 {|save_type| corresponding to beginning of group} @p@t\4@>@ @z %--------------------------------------- @x [19] m.274 l.5916 new_save_level - e-TeX tracing begin check_full_save_stack; @y begin check_full_save_stack; if eTeX_ex then begin saved(0):=line; incr(save_ptr); end; @z %--------------------------------------- @x [19] m.274 l.5923 new_save_level - e-TeX tracing cur_boundary:=save_ptr; incr(cur_level); incr(save_ptr); cur_group:=c; @y cur_boundary:=save_ptr; cur_group:=c; @!stat if tracing_groups>0 then group_trace(false);@+tats@;@/ incr(cur_level); incr(save_ptr); @z %--------------------------------------- @x [19] m.277 l.5967 eq_define - e-TeX tracing begin if eq_level(p)=cur_level then eq_destroy(eqtb[p]) else if cur_level>level_one then eq_save(p,eq_level(p)); eq_level(p):=cur_level; eq_type(p):=t; equiv(p):=e; @y begin @!stat if tracing_assigns>0 then restore_trace(p,"changing"); tats@;@/ begin if eq_level(p)=cur_level then eq_destroy(eqtb[p]) else if cur_level>level_one then eq_save(p,eq_level(p)); eq_level(p):=cur_level; eq_type(p):=t; equiv(p):=e; end; @!stat if tracing_assigns>0 then restore_trace(p,"into"); tats@;@/ @z %--------------------------------------- @x [19] m.278 l.5980 eq_word_define - e-TeX tracing eqtb[p].int:=w; @y @!stat if tracing_assigns>0 then restore_trace(p,"changing"); tats@;@/ eqtb[p].int:=w; @!stat if tracing_assigns>0 then restore_trace(p,"into"); tats@;@/ @z %--------------------------------------- @x [19] m.279 l.5990 geq_define - e-TeX tracing begin eq_destroy(eqtb[p]); eq_level(p):=level_one; eq_type(p):=t; equiv(p):=e; @y begin @!stat if tracing_assigns>0 then restore_trace(p,"globally changing"); tats@;@/ begin eq_destroy(eqtb[p]); eq_level(p):=level_one; eq_type(p):=t; equiv(p):=e; end; @!stat if tracing_assigns>0 then restore_trace(p,"into"); tats@;@/ @z %--------------------------------------- @x [19] m.279 l.5995 geq_word_define - e-TeX tracing begin eqtb[p].int:=w; xeq_level[p]:=level_one; @y begin @!stat if tracing_assigns>0 then restore_trace(p,"globally changing"); tats@;@/ begin eqtb[p].int:=w; xeq_level[p]:=level_one; end; @!stat if tracing_assigns>0 then restore_trace(p,"into"); tats@;@/ @z %--------------------------------------- @x [19] m.281 l.6012 - e-TeX tracing @p@t\4@>@@;@/ @y @p @z %--------------------------------------- @x [19] m.282 l.6041 - e-TeX tracing done: cur_group:=save_level(save_ptr); cur_boundary:=save_index(save_ptr) @y done: @!stat if tracing_groups>0 then group_trace(true);@+tats@;@/ cur_group:=save_level(save_ptr); cur_boundary:=save_index(save_ptr); if eTeX_ex then decr(save_ptr) @z %--------------------------------------- @x [19] m.284 l.6067 - e-TeX tracing @ @= @y @ @= @z %--------------------------------------- @x [20] m.289 l.6155 - e-TeX protected @d end_match_token=@'7000 {$2^8\cdot|end_match|$} @y @d end_match_token=@'7000 {$2^8\cdot|end_match|$} @d protected_token=@'7001 {$2^8\cdot|end_match|+1$} @z %--------------------------------------- @x [20] m.294 l.6280 - e-TeX protected end_match: print("->"); @y end_match: if c=0 then print("->"); @z %--------------------------------------- @x [20] m.296 l.6301 print_meaning - e-TeX marks else if cur_cmd=top_bot_mark then begin print_char(":"); print_ln; @y else if (cur_cmd=top_bot_mark)and(cur_chr0 then if cur_cmd>=if_test then if cur_cmd<=fi_or_else then begin print(": "); if cur_cmd=fi_or_else then begin print_cmd_chr(if_test,cur_if); print_char(" "); n:=0; l:=if_line; end else begin n:=1; l:=line; end; p:=cond_ptr; while p<>null do begin incr(n); p:=link(p); end; print_int(n); if l<>0 then begin print(" on line "); print_int(l); end; end; print_char("}"); @z %--------------------------------------- @x [22] m.303 l.6475 show_context - e-TeX scan_tokens the terminal, under control of the procedure |read_toks|.) @y the terminal, under control of the procedure |read_toks|.) Finally |18<=name<=19| indicates that we are reading a pseudo file created by the \.{\\scantokens} command. @z %--------------------------------------- @x [22] m.304 l.6538 - e-TeX every_eof @!line_stack : array[1..max_in_open] of integer; @y @!line_stack : array[1..max_in_open] of integer; @!eof_seen : array[1..max_in_open] of boolean; {has eof been seen?} @z %--------------------------------------- @x [22] m.307 l.6692 - e-TeX basic @d mark_text=14 {|token_type| code for \.{\\topmark}, etc.} @d write_text=15 {|token_type| code for \.{\\write}} @y @d every_eof_text=14 {|token_type| code for \.{\\everyeof}} @d mark_text=15 {|token_type| code for \.{\\topmark}, etc.} @d write_text=16 {|token_type| code for \.{\\write}} @z %--------------------------------------- @x [22] m.311 l.6749 show_context - e-TeX scan_tokens if (name>17) or (base_ptr=0) then bottom_line:=true; @y if (name>19) or (base_ptr=0) then bottom_line:=true; @z %--------------------------------------- @x [22] m.313 l.6794 - e-TeX scan_tokens else begin print_nl("l."); print_int(line); @y else if index<>in_open then {input from a pseudo file} begin print_nl("l."); print_int(line_stack[index+1]); end else begin print_nl("l."); print_int(line); @z %--------------------------------------- @x [22] m.314 l.6814 - e-TeX basic every_cr_text: print_nl(" "); @y every_cr_text: print_nl(" "); every_eof_text: print_nl(" "); @z %--------------------------------------- @x [23] m.328 l.7037 begin_file_reading - e-TeX every_eof incr(in_open); push_input; index:=in_open; @y incr(in_open); push_input; index:=in_open; eof_seen[index]:=false; @z %--------------------------------------- @x [23] m.329 l.7047 end_file_reading - e-TeX scan_tokens if name>17 then a_close(cur_file); {forget it} @y if (name=18)or(name=19) then pseudo_close else if name>17 then a_close(cur_file); {forget it} @z %--------------------------------------- @x [24] m.362 l.7538 - e-TeX scan_tokens, every_eof if not force_eof then @y if not force_eof then if name<=19 then begin if pseudo_input then {not end of file} firm_up_the_line {this sets |limit|} else if (every_eof<>null)and not eof_seen[index] then begin limit:=first-1; eof_seen[index]:=true; {fake one empty line} begin_token_list(every_eof,every_eof_text); goto restart; end else force_eof:=true; end else @z %--------------------------------------- @x [24] m.362 l.7541 - e-TeX every_eof else force_eof:=true; @y else if (every_eof<>null)and not eof_seen[index] then begin limit:=first-1; eof_seen[index]:=true; {fake one empty line} begin_token_list(every_eof,every_eof_text); goto restart; end else force_eof:=true; @z %--------------------------------------- @x [24] m.362 l.7544 - e-TeX scan_tokens begin print_char(")"); decr(open_parens); update_terminal; {show user that file has been read} @y begin if name>=19 then begin print_char(")"); decr(open_parens); update_terminal; {show user that file has been read} end; @z %--------------------------------------- @x [25] m.366 l.7630 - e-TeX basic @t\4@>@@;@/ @y @t\4@>@@;@/ @t\4@>@@;@/ @z %--------------------------------------- @x [25] m.366 l.7637 expand - e-TeX cond procedure expand; @y procedure expand; label reswitch; @z %--------------------------------------- @x [25] m.366 l.7648 expand - e-TeX cond if cur_cmd @y reswitch: if cur_cmd @z %--------------------------------------- @x [25] m.367 l.7659 - e-TeX cond expand_after:@; @y expand_after:if cur_chr=0 then @ else @; @z %--------------------------------------- @x [25] m.377 l.7779 - e-TeX scan_tokens input: if chr_code=0 then print_esc("input")@+else print_esc("endinput"); @y input: if chr_code=0 then print_esc("input") @/@@/ else print_esc("endinput"); @z %--------------------------------------- @x [25] m.378 l.7782 - e-TeX scan_tokens if cur_chr>0 then force_eof:=true @y if cur_chr=1 then force_eof:=true @/@@/ @z %--------------------------------------- @x [25] m.382 l.7835 - e-TeX marks array by symbolic names |top_mark|, etc. The value of |top_mark| is either @y array by symbolic names |top_mark|, etc.\ (depending on a local or global variable |0<=mark_class<=255|). The value of |top_mark| is either @z %--------------------------------------- @x [25] m.382 l.7838 - e-TeX marks @d top_mark_code=0 {the mark in effect at the previous page break} @y @d marks_code==5 {add this for \.{\\topmarks} etc.} @d cur_mark==cur_marks[mark_class] @# @d top_mark_code=0 {the mark in effect at the previous page break} @z %--------------------------------------- @x [25] m.382 l.7850 - e-TeX marks @!cur_mark:array[top_mark_code..split_bot_mark_code] of pointer; @y @!mark_class:eight_bits; {a mark class} @!cur_marks:array[0..255,top_mark_code..split_bot_mark_code] of pointer; @z %--------------------------------------- @x [25] m.383 l.7854 - e-TeX marks top_mark:=null; first_mark:=null; bot_mark:=null; split_first_mark:=null; split_bot_mark:=null; @y for mark_class:=0 to 255 do begin top_mark:=null; first_mark:=null; bot_mark:=null; split_first_mark:=null; split_bot_mark:=null; end; @z %--------------------------------------- @x [25] m.385 l.7870 - e-TeX marks top_bot_mark: case chr_code of @y top_bot_mark: begin case (chr_code mod marks_code) of @z %--------------------------------------- @x [25] m.385 l.7876 - e-TeX marks endcases; @y endcases; if chr_code>=marks_code then print_char("s"); end; @z %--------------------------------------- @x [25] m.386 l.7882 - e-TeX marks begin if cur_mark[cur_chr]<>null then begin_token_list(cur_mark[cur_chr],mark_text); @y begin if cur_chr>=marks_code then begin t:=cur_chr mod marks_code; scan_eight_bit_int; cur_chr:=t; mark_class:=cur_val; end else mark_class:=0; begin if cur_mark[cur_chr]<>null then begin_token_list(cur_mark[cur_chr],mark_text); end; @z %--------------------------------------- @x [25] m.389 l.7945 macro_call - e-TeX protected if info(r)<>end_match_token then @y if info(r)=protected_token then r:=link(r); if info(r)<>end_match_token then @z %--------------------------------------- @x [26] m.416 l.8390 - e-TeX last_node_type |glue_val|, |input_line_no_code|, or |badness_code|. @d input_line_no_code=glue_val+1 {code for \.{\\inputlineno}} @d badness_code=glue_val+2 {code for \.{\\badness}} @y |glue_val|, |last_node_type_code|, |input_line_no_code|, |badness_code|, |eTeX_version_code|, |group_level_code|, or |group_type_code|. @d last_node_type_code=glue_val+1 {code for \.{\\lastnodetype}} @d input_line_no_code=glue_val+2 {code for \.{\\inputlineno}} @d badness_code=glue_val+3 {code for \.{\\badness}} @z %--------------------------------------- @x [26] m.417 l.8425 - e-TeX interaction_mode @+else print_esc("insertpenalties"); @y @/@@/ @+else print_esc("insertpenalties"); @z %--------------------------------------- @x [26] m.417 l.8434 - e-TeX basic othercases print_esc("badness") @y @/@@/ othercases print_esc("badness") @z %--------------------------------------- @x [26] m.419 l.8457 - e-TeX interaction_mode begin if m=0 then cur_val:=dead_cycles@+else cur_val:=insert_penalties; @y begin if m=0 then cur_val:=dead_cycles @/@@/ else cur_val:=insert_penalties; @z %--------------------------------------- @x [26] m.424 l.8493 - e-TeX TeXXeT implemented. The reference count for \.{\\lastskip} will be updated later. @y implemented. The reference count for \.{\\lastskip} will be updated later. A final \.{\\endM} node is temporarily removed. @z %--------------------------------------- @x [26] m.424 l.8499 - e-TeX last_node_type if cur_chr>glue_val then begin if cur_chr=input_line_no_code then cur_val:=line @y if cur_chr>last_node_type_code then begin if cur_chr=input_line_no_code then cur_val:=line @/@@/ @z %--------------------------------------- @x [26] m.424 l.8505 - e-TeX last_node_type cur_val_level:=cur_chr; @y if cur_chr=last_node_type_code then begin cur_val:=int_val; if (tail=head)or(mode=0) then cur_val:=-1; end else cur_val_level:=cur_chr; @z %--------------------------------------- @x [26] m.424 l.8507 - e-TeX TeXXeT case cur_chr of @y begin if (type(tail)=math_node)and(subtype(tail)=end_M_code) then remove_end_M; case cur_chr of @z %--------------------------------------- @x [26] m.424 l.8513 - e-TeX last_node_type end; @y end; last_node_type_code: if (type(tail)<>math_node)or(subtype(tail)<>end_M_code) then if type(tail)<=unset_node then cur_val:=type(tail)+1 else cur_val:=unset_node+2; @z %--------------------------------------- @x [26] m.424 l.8514 - e-TeX TeXXeT end {there are no other cases} @y end; {there are no other cases} if LR_temp<>null then insert_end_M; end @z %--------------------------------------- @x [26] m.424 l.8519 - e-TeX last_node_type glue_val: if last_glue<>max_halfword then cur_val:=last_glue; @y glue_val: if last_glue<>max_halfword then cur_val:=last_glue; last_node_type_code: cur_val:=last_node_type; @z %--------------------------------------- @x [27] m.464 l.9129 - e-TeX basic @p function str_toks(@!b:pool_pointer):pointer; @y @p @t\4@>@@;@/ function str_toks(@!b:pool_pointer):pointer; @z %--------------------------------------- @x [27] m.465 l.9154 the_toks - e-TeX unexpanded @p function the_toks:pointer; @y @p function the_toks:pointer; label exit; @z %--------------------------------------- @x [27] m.465 l.9158 the_toks - e-TeX unexpanded begin get_x_token; scan_something_internal(tok_val,false); @y @!c:small_number; {value of |cur_chr|} begin @;@/ get_x_token; scan_something_internal(tok_val,false); @z %--------------------------------------- @x [27] m.465 l.9172 the_toks - e-TeX unexpanded end; @y exit:end; @z %--------------------------------------- @x [27] m.469 l.9223 - e-TeX basic othercases print_esc("jobname") @y @/@@/ othercases print_esc("jobname") @z %--------------------------------------- @x [27] m.470 l.9232 conv_toks - e-TeX basic @!c:number_code..job_name_code; {desired type of conversion} @y @!c:small_number; {desired type of conversion} @z %--------------------------------------- @x [27] m.471 l.9249 - e-TeX basic end {there are no other cases} @y @/@@/ end {there are no other cases} @z %--------------------------------------- @x [27] m.472 l.9265 - e-TeX basic end {there are no other cases} @y @/@@/ end {there are no other cases} @z %--------------------------------------- @x [27] m.478 l.9374 - e-TeX protected if cur_cmd<=max_command then goto done2; @y if cur_cmd>=call then if info(link(cur_chr))=protected_token then begin cur_cmd:=relax; cur_chr:=no_expand_flag; end; if cur_cmd<=max_command then goto done2; @z %--------------------------------------- @x [27] m.482 l.9422 read_toks - e-TeX read_line @p procedure read_toks(@!n:integer;@!r:pointer); @y @p procedure read_toks(@!n:integer;@!r:pointer;@!j:halfword); @z %--------------------------------------- @x [27] m.483 l.9448 - e-TeX read_line loop@+ begin get_token; @y @;@/ loop@+ begin get_token; @z %--------------------------------------- @x [27] m.486 l.9489 - e-TeX read_line print_err("File ended within "); print_esc("read"); @y print_err("File ended within "); print_cmd_chr(read_to_cs,j); @.File ended within \\readline@> @z %--------------------------------------- @x [28] m.487 l.9500 - e-TeX cond @d if_char_code=0 { `\.{\\if}' } @y @d unless_code=32 {amount added for `\.{\\unless}' prefix} @# @d if_char_code=0 { `\.{\\if}' } @z %--------------------------------------- @x [28] m.488 l.9555 - e-TeX cond if_test: case chr_code of @y if_test: begin if chr_code>=unless_code then print_esc("unless"); case chr_code mod unless_code of @z %--------------------------------------- @x [28] m.488 l.9572 - e-TeX cond othercases print_esc("if") endcases; @y @/@@/ othercases print_esc("if") endcases; end; @z %--------------------------------------- @x [28] m.494 l.9646 pass_text - e-TeX tracing done: scanner_status:=save_scanner_status; @y done: scanner_status:=save_scanner_status; if tracing_ifs>0 then show_cur_cmd_chr; @z %--------------------------------------- @x [28] m.498 l.9699 conditional - e-TeX cond begin @;@+save_cond_ptr:=cond_ptr;this_if:=cur_chr;@/ @; @y @!is_unless:boolean; {was this if preceded by `\.{\\unless}' ?} begin if tracing_ifs>0 then if tracing_commands<=1 then show_cur_cmd_chr; @;@+save_cond_ptr:=cond_ptr; is_unless:=(cur_chr>=unless_code); this_if:=cur_chr mod unless_code;@/ @; if is_unless then b:=not b; @z %--------------------------------------- @x [28] m.501 l.9742 - e-TeX cond if_false_code: b:=false; @y if_false_code: b:=false; @/@@/ @z %--------------------------------------- @x [28] m.510 l.9871 - e-TeX cond if cur_chr>if_limit then @y begin if tracing_ifs>0 then if tracing_commands<=1 then show_cur_cmd_chr; if cur_chr>if_limit then @z %--------------------------------------- @x [28] m.510 l.9882 - e-TeX cond end @y end; end @z %--------------------------------------- @x [29] m.536 l.10324 - e-TeX basic begin wlog(banner); @y begin wlog(eTeX_banner); @z %--------------------------------------- @x [29] m.536 l.10331 - e-TeX basic end @y wlog_cr; wlog('entering '); if eTeX_ex then wlog('extended') else wlog('compatibility'); wlog(' mode'); end @z %--------------------------------------- @x [32] m.616 l.12238 - e-TeX TeXXeT this is essentially the depth of |push| commands in the \.{DVI} output. @y this is essentially the depth of |push| commands in the \.{DVI} output. For mixed direction text (\TeXXeT) the current text direction is called |cur_dir|. As the box being shipped out will never be used again and soon be recycled, we can simply reverse any R-text (i.e., right-to-left) segments of hlist nodes as well as complete hlist nodes embedded in such segments. Moreover this can be done iteratively rather than recursively. There are, however, two complications related to leaders that require some additional bookkeeping: (1)~One and the same hlist node might be used more than once (but never inside both L- and R-text); and (2)~leader boxes inside hlists must be aligned with respect to the left edge of the original hlist. A math node is changed into a kern node whenever the text direction remains the same, it is replaced by an |edge_node| if the text direction changes; the subtype of an an |hlist_node| inside R-text is changed to |reversed| once its hlist has been reversed. @!@^data structure assumptions@> @z %--------------------------------------- @x [32] m.616 l.12240 - e-TeX TeXXeT @d synch_h==if cur_h<>dvi_h then @y @d reversed=min_quarterword+1 {subtype for an |hlist_node| whose hlist has been reversed} @d dlist=min_quarterword+2 {subtype for an |hlist_node| from display math mode} @d left_to_right=0 @d right_to_left=1 @d reflected==1-cur_dir {the opposite of |cur_dir|} @# @d synch_h==if cur_h<>dvi_h then @z %--------------------------------------- @x [32] m.619 l.12300 hlist_out - e-TeX add_glue @!g_order: glue_ord; {applicable order of infinity for glue} @y @z %--------------------------------------- @x [32] m.619 l.12308 hlist_out - e-TeX TeXXeT @!edge:scaled; {left edge of sub-box, or right edge of leader space} @y @!edge:scaled; {right edge of sub-box or leader space} @!prev_p:pointer; {one step behind |p|} @z %--------------------------------------- @x [32] m.619 l.12309 hlist_out - e-TeX add_glue @!glue_temp:real; {glue value before rounding} begin this_box:=temp_ptr; g_order:=glue_order(this_box); @y begin this_box:=temp_ptr; @z %--------------------------------------- @x [32] m.619 l.12315 hlist_out - e-TeX TeXXeT save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; left_edge:=cur_h; @y save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; prev_p:=this_box+list_offset; if eTeX_ex then begin @; if subtype(this_box)=dlist then if cur_dir=right_to_left then begin cur_dir:=left_to_right; cur_h:=cur_h-width(this_box); end else subtype(this_box):=min_quarterword; if (cur_dir=right_to_left)and(subtype(this_box)<>reversed) then @; end; left_edge:=cur_h; @z %--------------------------------------- @x [32] m.619 l.12318 hlist_out - e-TeX TeXXeT prune_movements(save_loc); @y if eTeX_ex then begin @; if subtype(this_box)=dlist then cur_dir:=right_to_left; end; prune_movements(save_loc); @z %--------------------------------------- @x [32] m.620 l.12337 - e-TeX TeXXeT p:=link(p); @y prev_p:=p; p:=link(p); @z %--------------------------------------- @x [32] m.622 l.12362 - e-TeX TeXXeT kern_node,math_node:cur_h:=cur_h+width(p); @y kern_node:cur_h:=cur_h+width(p); math_node:begin if eTeX_ex then @; cur_h:=cur_h+width(p); end; @z %--------------------------------------- @x [32] m.622 l.12364 - e-TeX TeXXeT othercases do_nothing @y @/@@; othercases do_nothing @z %--------------------------------------- @x [32] m.622 l.12369 - e-TeX TeXXeT next_p:p:=link(p); @y next_p:prev_p:=p; p:=link(p); @z %--------------------------------------- @x [32] m.623 l.12376 - e-TeX TeXXeT temp_ptr:=p; edge:=cur_h; @y temp_ptr:=p; edge:=cur_h+width(p); if cur_dir=right_to_left then cur_h:=edge; @z %--------------------------------------- @x [32] m.623 l.12379 - e-TeX TeXXeT cur_h:=edge+width(p); cur_v:=base_line; @y cur_h:=edge; cur_v:=base_line; @z %--------------------------------------- @x [32] m.625 l.12401 - e-TeX add_glue begin if g_sign=stretching then begin if stretch_order(g)=g_order then begin vet_glue(float(glue_set(this_box))*stretch(g)); @^real multiplication@> rule_wd:=rule_wd+round(glue_temp); end; end else if shrink_order(g)=g_order then begin vet_glue(float(glue_set(this_box))*shrink(g)); rule_wd:=rule_wd-round(glue_temp); end; end; @y add_glue(rule_wd); @z %--------------------------------------- @x [32] m.626 l.12428 - e-TeX TeXXeT edge:=cur_h+rule_wd; lx:=0; @y if cur_dir=right_to_left then cur_h:=cur_h-10; edge:=cur_h+rule_wd; lx:=0; @z %--------------------------------------- @x [32] m.626 l.12434 - e-TeX TeXXeT cur_h:=edge-10; goto next_p; @y if cur_dir=right_to_left then cur_h:=edge else cur_h:=edge-10; goto next_p; @z %--------------------------------------- @x [32] m.628 l.12473 - e-TeX TeXXeT synch_h; save_h:=dvi_h; temp_ptr:=leader_box; @y synch_h; save_h:=dvi_h; temp_ptr:=leader_box; if cur_dir=right_to_left then cur_h:=cur_h+leader_wd; @z %--------------------------------------- @x [32] m.629 l.12489 vlist_out - e-TeX add_glue @!g_order: glue_ord; {applicable order of infinity for glue} @y @z %--------------------------------------- @x [32] m.629 l.12498 vlist_out - e-TeX add_glue @!glue_temp:real; {glue value before rounding} begin this_box:=temp_ptr; g_order:=glue_order(this_box); @y begin this_box:=temp_ptr; @z %--------------------------------------- @x [32] m.632 l.12544 - e-TeX TeXXeT cur_h:=left_edge+shift_amount(p); {shift the box right} @y if cur_dir=right_to_left then cur_h:=left_edge-shift_amount(p) else cur_h:=left_edge+shift_amount(p); {shift the box right} @z %--------------------------------------- @x [32] m.633 l.12556 - e-TeX TeXXeT begin synch_h; synch_v; dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd); @y begin if cur_dir=right_to_left then cur_h:=cur_h-rule_wd; synch_h; synch_v; dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd); cur_h:=left_edge; @z %--------------------------------------- @x [32] m.634 l.12564 - e-TeX add_glue begin if g_sign=stretching then begin if stretch_order(g)=g_order then begin vet_glue(float(glue_set(this_box))*stretch(g)); @^real multiplication@> rule_ht:=rule_ht+round(glue_temp); end; end else if shrink_order(g)=g_order then begin vet_glue(float(glue_set(this_box))*shrink(g)); rule_ht:=rule_ht-round(glue_temp); end; end; @y add_glue(rule_ht); @z %--------------------------------------- @x [32] m.637 l.12619 - e-TeX TeXXeT begin cur_h:=left_edge+shift_amount(leader_box); synch_h; save_h:=dvi_h;@/ @y begin if cur_dir=right_to_left then cur_h:=left_edge-shift_amount(leader_box) else cur_h:=left_edge+shift_amount(leader_box); synch_h; save_h:=dvi_h;@/ @z %--------------------------------------- @x [32] m.638 l.12656 ship_out - e-TeX TeXXeT @; @y @; if eTeX_ex then @; @z %--------------------------------------- @x [33] m.649 l.12876 hpack - e-TeX TeXXeT h:=0; @; @y h:=0; @; if TeXXeT_en then @; @z %--------------------------------------- @x [33] m.649 l.12886 hpack - e-TeX TeXXeT exit: hpack:=r; @y exit: if TeXXeT_en then @; hpack:=r; @z %--------------------------------------- @x [33] m.651 l.12910 - e-TeX TeXXeT kern_node,math_node: x:=x+width(p); @y kern_node: x:=x+width(p); math_node: begin x:=x+width(p); if TeXXeT_en then @; end; @z %--------------------------------------- @x [34] m.687 l.13480 - e-TeX middle \TeX's \.{\\left} and \.{\\right}. The |nucleus| of such noads is @y \TeX's \.{\\left} and \.{\\right} as well as \eTeX's \.{\\middle}. The |nucleus| of such noads is @z %--------------------------------------- @x [34] m.687 l.13497 - e-TeX middle @d delimiter==nucleus {|delimiter| field in left and right noads} @y @d delimiter==nucleus {|delimiter| field in left and right noads} @d middle_noad==1 {|subtype| of right noad representing \.{\\middle}} @z %--------------------------------------- @x [34] m.696 l.13670 - e-TeX middle right_noad: begin print_esc("right"); print_delimiter(nucleus(p)); end; end; if subtype(p)<>normal then if subtype(p)=limits then print_esc("limits") else print_esc("nolimits"); if type(p)normal then if subtype(p)=limits then print_esc("limits") else print_esc("nolimits"); print_subsidiary_data(nucleus(p),"."); end; @z %--------------------------------------- @x [36] m.727 l.14268 - e-TeX middle done_with_noad: r:=q; r_type:=type(r); @y done_with_noad: r:=q; r_type:=type(r); if r_type=right_noad then begin r_type:=left_noad; cur_style:=style; @; end; @z %--------------------------------------- @x [36] m.760 l.14929 - e-TeX middle r_type:=t; @y if type(q)=right_noad then t:=open_noad; r_type:=t; @z %--------------------------------------- @x [36] m.762 l.14970 make_left_right - e-TeX middle begin if style; @z %--------------------------------------- @x [37] m.807 l.15834 - e-TeX TeXXeT begin type(q):=hlist_node; width(q):=width(p); @y begin type(q):=hlist_node; width(q):=width(p); if nest[nest_ptr-1].mode_field=mmode then subtype(q):=dlist; {for |ship_out|} @z %--------------------------------------- @x [37] m.808 l.15852 - e-TeX TeXXeT n:=span_count(r); t:=width(s); w:=t; u:=hold_head; @y n:=span_count(r); t:=width(s); w:=t; u:=hold_head; subtype(r):=min_quarterword; {for |ship_out|} @z %--------------------------------------- @x [39] m.866 l.17030 - e-TeX TeXXeT math_node: begin auto_breaking:=(subtype(cur_p)=after); kern_break; @y math_node: begin if subtype(cur_p); @z %--------------------------------------- @x [39] m.880 l.17276 - e-TeX TeXXeT @; @y if TeXXeT_en then @; @; if TeXXeT_en then @; @z %--------------------------------------- @x [39] m.881 l.17299 - e-TeX TeXXeT else if (type(q)=math_node)or(type(q)=kern_node) then width(q):=0; @y else if type(q)=kern_node then width(q):=0 else if type(q)=math_node then begin width(q):=0; if TeXXeT_en then @; end; @z %--------------------------------------- @x [44] m.977 l.18998 vsplit - e-TeX marks begin v:=box(n); @y @!mark_class:eight_bits; begin v:=box(n); for mark_class:=0 to 255 do @z %--------------------------------------- @x [44] m.979 l.19032 - e-TeX marks else loop@+begin if type(p)=mark_node then @y else loop@+begin if type(p)=mark_node then begin mark_class:=qo(subtype(p)); @z %--------------------------------------- @x [44] m.979 l.19042 - e-TeX marks end; @y end; end; @z %--------------------------------------- @x [45] m.982 l.19167 - e-TeX last_node_type The variables |last_penalty| and |last_kern| are similar. And @y The variables |last_penalty|, |last_kern|, and |last_node_type| are similar. And @z %--------------------------------------- @x [45] m.982 l.19180 - e-TeX last_node_type @!last_kern:scaled; {used to implement \.{\\lastkern}} @y @!last_kern:scaled; {used to implement \.{\\lastkern}} @!last_node_type:integer; {used to implement \.{\\lastnodetype}} @z %--------------------------------------- @x [45] m.991 l.19317 - e-TeX last_node_type last_glue:=max_halfword; last_penalty:=0; last_kern:=0; @y last_glue:=max_halfword; last_penalty:=0; last_kern:=0; last_node_type:=-1; @z %--------------------------------------- @x [45] m.996 l.19384 - e-TeX last_node_type last_penalty:=0; last_kern:=0; @y last_penalty:=0; last_kern:=0; last_node_type:=type(p)+1; @z %--------------------------------------- @x [45] m.1012 l.19660 fire_up - e-TeX marks begin @; @y @!mark_class:eight_bits; begin @; for mark_class:=0 to 255 do @z %--------------------------------------- @x [45] m.1012 l.19669 fire_up - e-TeX marks if (top_mark<>null)and(first_mark=null) then @y for mark_class:=0 to 255 do if (top_mark<>null)and(first_mark=null) then @z %--------------------------------------- @x [45] m.1016 l.19725 - e-TeX marks begin if first_mark=null then @y begin mark_class:=qo(subtype(p)); if first_mark=null then @z %--------------------------------------- @x [46] m.1030 l.19973 - e-TeX basic @p @t\4@>@@; @y @p @t\4@>@ @t\4@>@@; @z %--------------------------------------- @x [47] m.1080 l.20901 - e-TeX TeXXeT since |head| is a one-word node. @y since |head| is a one-word node. A final \.{\\endM} node is temporarily removed. @z %--------------------------------------- @x [47] m.1080 l.20914 - e-TeX TeXXeT if (type(tail)=hlist_node)or(type(tail)=vlist_node) then @; @y begin if (type(tail)=math_node)and(subtype(tail)=end_M_code) then remove_end_M; if (type(tail)=hlist_node)or(type(tail)=vlist_node) then @; if LR_temp<>null then insert_end_M; end; @z %--------------------------------------- @x [47] m.1096 l.21119 - e-TeX TeXXeT else line_break(widow_penalty); @y else line_break(widow_penalty); if LR_save<>null then begin flush_list(LR_save); LR_save:=null; end; @z %--------------------------------------- @x [47] m.1101 l.21175 make_mark - e-TeX marks begin p:=scan_toks(false,true); p:=get_node(small_node_size); type(p):=mark_node; subtype(p):=0; {the |subtype| is not used} @y @!c:eight_bits; {the mark class} begin if cur_chr=0 then c:=0 else begin scan_eight_bit_int; c:=cur_val; end; p:=scan_toks(false,true); p:=get_node(small_node_size); type(p):=mark_node; subtype(p):=qi(c); @z %--------------------------------------- @x [47] m.1105 l.21203 - e-TeX TeXXeT will be deleted, if present. @y will be deleted, if present. A final \.{\\endM} node is temporarily removed. @z %--------------------------------------- @x [47] m.1105 l.21213 delete_last - e-TeX TeXXeT else begin if not is_char_node(tail) then if type(tail)=cur_chr then @y else begin if not is_char_node(tail) then begin if (type(tail)=math_node)and(subtype(tail)=end_M_code) then remove_end_M; if type(tail)=cur_chr then @z %--------------------------------------- @x [47] m.1105 l.21224 delete_last - e-TeX TeXXeT end; @y if LR_temp<>null then insert_end_M; end; end; @z %--------------------------------------- @x [47] m.1130 l.21562 - e-TeX TeXXeT vmode+halign,hmode+valign:init_align; @y vmode+halign:init_align; hmode+valign:@@; init_align; @z %--------------------------------------- @x [48] m.1138 l.21629 init_math - e-TeX TeXXeT procedure init_math; label reswitch,found,not_found,done; var w:scaled; {new or partial |pre_display_size|} @y @t\4@>@@; procedure init_math; label reswitch,found,not_found,done; var w:scaled; {new or partial |pre_display_size|} @!j:pointer; {prototype box for display} @!x:integer; {new |pre_display_direction|} @z %--------------------------------------- @x [48] m.1145 l.21687 - e-TeX TeXXeT begin if head=tail then {`\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}'} begin pop_nest; w:=-max_dimen; end @y begin j:=null; w:=-max_dimen; if head=tail then {`\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}'} @ @z %--------------------------------------- @x [48] m.1145 l.21700 - e-TeX TeXXeT eq_word_define(dimen_base+pre_display_size_code,w); @y eq_word_define(dimen_base+pre_display_size_code,w); LR_box:=j; if eTeX_ex then eq_word_define(int_base+pre_display_direction_code,x); @z %--------------------------------------- @x [48] m.1146 l.21708 - e-TeX TeXXeT v:=shift_amount(just_box)+2*quad(cur_font); w:=-max_dimen; p:=list_ptr(just_box); @y @; @z %--------------------------------------- @x [48] m.1146 l.21723 - e-TeX TeXXeT done: @y done: @ @z %--------------------------------------- @x [48] m.1147 l.21734 - e-TeX TeXXeT kern_node,math_node: d:=width(p); @y kern_node: d:=width(p); @t\4@>@@; @z %--------------------------------------- @x [48] m.1185 l.22243 - e-TeX middle if type(q)<>left_noad then confusion("right"); @:this can't happen right}{\quad right@> info(numerator(incompleat_noad)):=link(q); link(q):=incompleat_noad; link(incompleat_noad):=p; @y if (type(q)<>left_noad)or(delim_ptr=null) then confusion("right"); @:this can't happen right}{\quad right@> info(numerator(incompleat_noad)):=link(delim_ptr); link(delim_ptr):=incompleat_noad; link(incompleat_noad):=p; @z %--------------------------------------- @x [48] m.1189 l.22288 - e-TeX middle else print_esc("right"); @y @/@@/ else print_esc("right"); @z %--------------------------------------- @x [48] m.1191 l.22297 math_left_right - e-TeX middle begin t:=cur_chr; if (t=right_noad)and(cur_group<>math_left_group) then @y @!q:pointer; {resulting mlist} begin t:=cur_chr; if (t<>left_noad)and(cur_group<>math_left_group) then @z %--------------------------------------- @x [48] m.1191 l.22302 math_left_right - e-TeX middle if t=left_noad then begin push_math(math_left_group); link(head):=p; tail:=p; end else begin p:=fin_mlist(p); unsave; {end of |math_left_group|} @y if t=middle_noad then begin type(p):=right_noad; subtype(p):=middle_noad; end; if t=left_noad then q:=p else begin q:=fin_mlist(p); unsave; {end of |math_left_group|} end; if t<>right_noad then begin push_math(math_left_group); link(head):=q; tail:=p; delim_ptr:=p; end else begin @z %--------------------------------------- @x [48] m.1191 l.22308 math_left_right - e-TeX middle info(nucleus(tail)):=p; @y info(nucleus(tail)):=q; @z %--------------------------------------- @x [48] m.1192 l.22316 - e-TeX middle print_err("Extra "); print_esc("right"); @.Extra \\right.@> help1("I'm ignoring a \right that had no matching \left."); @y print_err("Extra "); if t=middle_noad then begin print_esc("middle"); @.Extra \\middle.@> help1("I'm ignoring a \middle that had no matching \left."); end else begin print_esc("right"); @.Extra \\right.@> help1("I'm ignoring a \right that had no matching \left."); end; @z %--------------------------------------- @x [48] m.1194 l.22331 after_math - e-TeX TeXXeT procedure after_math; @y @t\4@>@@; procedure after_math; @z %--------------------------------------- @x [48] m.1194 l.22338 after_math - e-TeX TeXXeT begin danger:=false; @y begin danger:=false; @; @z %--------------------------------------- @x [48] m.1194 l.22345 after_math - e-TeX TeXXeT mlist_to_hlist; a:=hpack(link(temp_head),natural); @y mlist_to_hlist; a:=hpack(link(temp_head),natural); subtype(a):=dlist; @z %--------------------------------------- @x [48] m.1194 l.22348 after_math - e-TeX TeXXeT danger:=false; @y danger:=false; @; @z %--------------------------------------- @x [48] m.1199 l.22435 - e-TeX TeXXeT w:=width(b); z:=display_width; s:=display_indent; @y w:=width(b); z:=display_width; s:=display_indent; if pre_display_direction<0 then s:=-s-z; @z %--------------------------------------- @x [48] m.1199 l.22450 - e-TeX TeXXeT resume_after_display @y @; resume_after_display @z %--------------------------------------- @x [48] m.1202 l.22492 - e-TeX TeXXeT d:=half(z-w); @y subtype(b):=dlist; d:=half(z-w); @z %--------------------------------------- @x [48] m.1203 l.22513 - e-TeX TeXXeT begin shift_amount(a):=s; append_to_vlist(a); @y begin app_display(j,a,0); @z %--------------------------------------- @x [48] m.1204 l.22528 - e-TeX TeXXeT shift_amount(b):=s+d; append_to_vlist(b) @y app_display(j,b,d) @z %--------------------------------------- @x [48] m.1205 l.22533 - e-TeX TeXXeT shift_amount(a):=s+z-width(a); append_to_vlist(a); @y app_display(j,a,z-width(a)); @z %--------------------------------------- @x [48] m.1206 l.22552 - e-TeX TeXXeT pop_nest; @y flush_node_list(LR_box); pop_nest; @z %--------------------------------------- @x [49] m.1208 l.22577 - e-TeX protected control sequence can be defined to be `\.{\\long}' or `\.{\\outer}', and it might or might not be expanded. The prefixes `\.{\\global}', `\.{\\long}', @y control sequence can be defined to be `\.{\\long}', `\.{\\protected}', or `\.{\\outer}', and it might or might not be expanded. The prefixes `\.{\\global}', `\.{\\long}', `\.{\\protected}', @z %--------------------------------------- @x [49] m.1209 l.22603 - e-TeX protected else print_esc("global"); @y @/@@/ else print_esc("global"); @z %--------------------------------------- @x [49] m.1211 l.22665 prefixed_command - e-TeX tracing @; @y @; if tracing_commands>2 then if eTeX_ex then show_cur_cmd_chr; @z %--------------------------------------- @x [49] m.1213 l.22686 - e-TeX protected if (cur_cmd<>def)and(a mod 4<>0) then @y if a>=8 then begin j:=protected_token; a:=a-8; end else j:=0; if (cur_cmd<>def)and((a mod 4<>0)or(j<>0)) then @z %--------------------------------------- @x [49] m.1218 l.22749 - e-TeX protected q:=scan_toks(true,e); define(p,call+(a mod 4),def_ref); @y q:=scan_toks(true,e); if j<>0 then begin q:=get_avail; info(q):=j; link(q):=link(def_ref); link(def_ref):=q; end; define(p,call+(a mod 4),def_ref); @z %--------------------------------------- @x [49] m.1225 l.22853 - e-TeX read_line read_to_cs: begin scan_int; n:=cur_val; @y read_to_cs: begin j:=cur_chr; scan_int; n:=cur_val; @z %--------------------------------------- @x [49] m.1225 l.22861 - e-TeX read_line p:=cur_cs; read_toks(n,p); define(p,call,cur_val); @y p:=cur_cs; read_toks(n,p,j); define(p,call,cur_val); @z %--------------------------------------- @x [49] m.1246 l.23179 alter_integer - e-TeX interaction_mode var c:0..1; {0 for \.{\\deadcycles}, 1 for \.{\\insertpenalties}} begin c:=cur_chr; scan_optional_equals; scan_int; if c=0 then dead_cycles:=cur_val @y var c:small_number; {0 for \.{\\deadcycles}, 1 for \.{\\insertpenalties}, etc.} begin c:=cur_chr; scan_optional_equals; scan_int; if c=0 then dead_cycles:=cur_val @/@@/ @z %--------------------------------------- @x [49] m.1292 l.23581 - e-TeX show_levels show_lists:print_esc("showlists"); @y show_lists:print_esc("showlists"); @@;@/ @z %--------------------------------------- @x [49] m.1293 l.23594 show_whatever - e-TeX show_levels othercases @@;@/ othercases @0 then print_char(" "); print("macro"); @z %--------------------------------------- @x [50] m.1307 l.23779 - e-TeX basic dump_int(@$);@/ @y dump_int(@$);@/ @@/ @z %--------------------------------------- @x [50] m.1308 l.23794 - e-TeX basic if x<>@$ then goto bad_fmt; {check that strings are the same} @y if x<>@$ then goto bad_fmt; {check that strings are the same} @/@@/ @z %--------------------------------------- @x [51] m.1335 l.24301 final_cleanup - e-TeX marks var c:small_number; {0 for \.{\\end}, 1 for \.{\\dump}} @y var c:small_number; {0 for \.{\\end}, 1 for \.{\\dump}} @!mark_class:eight_bits; {a mark class} @z %--------------------------------------- @x [51] m.1335 l.24313 final_cleanup - tracing print_int(cur_level-level_one); print_char(")"); @y print_int(cur_level-level_one); print_char(")"); if eTeX_ex then show_save_groups; @z %--------------------------------------- @x [51] m.1335 l.24336 final_cleanup - e-TeX marks if cur_mark[c]<>null then delete_token_ref(cur_mark[c]); @y for mark_class:=0 to 255 do if cur_mark[c]<>null then delete_token_ref(cur_mark[c]); @z %--------------------------------------- @x [51] m.1336 l.24345 ] m.1336 l.24340 init_prim - e-TeX basic begin no_new_control_sequence:=false; @y begin no_new_control_sequence:=false; first:=0; @z %--------------------------------------- @x [51] m.1337 l.24360 - e-TeX basic if (format_ident=0)or(buffer[loc]="&") then @y @@;@/ if (format_ident=0)or(buffer[loc]="&") then @z %--------------------------------------- @x [51] m.1337 l.24368 - e-TeX basic end; @y end; wterm('entering '); if eTeX_ex then wterm('extended') else wterm('compatibility'); wterm_ln(' mode'); @z %--------------------------------------- @x [54] m.1379 l.24903 - e-TeX additions @* \[54] System-dependent changes. @y @* \[53a] The extended features of \eTeX. The program has two modes of operation: (1)~In \TeX\ compatibility mode it fully deserves the name \TeX\ and there are neither extended features nor additional primitive commands. There are, however, a few modifications that would be legitimate in any implementation of \TeX\ such as, e.g., preventing arithmetic overflow in the glue to \.{DVI} unit conversion during |ship_out|. (2)~In extended mode there are additional primitive commands and the extended features of \eTeX\ are available. The distinction between these two modes of operation initially takes place when a `virgin' \.{INITEX} starts without reading a format file. Later on the values of all \eTeX\ state variables are inherited when \.{VIRTEX} (or \.{INITEX}) reads a format file. The code below is designed to work for cases where `$|init|\ldots|tini|$' is a run-time switch. @= @!init if (buffer[loc]="*")and(format_ident=" (INITEX)") then begin no_new_control_sequence:=false; @@; incr(loc); eTeX_mode:=1; {enter extended mode} end; tini@;@/ if not no_new_control_sequence then {just entered extended mode ?} no_new_control_sequence:=true@+else @ The \eTeX\ features available in extended mode are grouped into two categories: (1)~Some of them are permanently enabled and have no semantic effect as long as none of the additional primitives are executed. (2)~The remaining \eTeX\ features are optional and can be individually enabled and disabled. For each optional feature there is an \eTeX\ state variable named \.{\\...state}; the feature is enabled, resp.\ disabled by assigning a positive, resp.\ non-positive value to that integer. @d eTeX_state_base=int_base+eTeX_state_code @d eTeX_state(#)==eqtb[eTeX_state_base+#].int {an \eTeX\ state variable} @# @d eTeX_version_code=glue_val+4 {code for \.{\\eTeXversion}} @d eTeX_revision_code=6 {command code for \.{\\eTeXrevision}} @= primitive("lastnodetype",last_item,last_node_type_code); @!@:last_node_type_}{\.{\\lastnodetype} primitive@> primitive("eTeXversion",last_item,eTeX_version_code); @!@:eTeX_version_}{\.{\\eTeXversion} primitive@> primitive("eTeXrevision",convert,eTeX_revision_code);@/ @!@:eTeX_revision_}{\.{\\eTeXrevision} primitive@> @ @= last_node_type_code: print_esc("lastnodetype"); eTeX_version_code: print_esc("eTeXversion"); @ @= else if cur_chr=eTeX_version_code then cur_val:=eTeX_version @ @= eTeX_revision_code: print_esc("eTeXrevision"); @ @= eTeX_revision_code: do_nothing; @ @= eTeX_revision_code: print(eTeX_revision); @ @d eTeX_ex==(eTeX_mode=1) {is this extended mode?} @= @!eTeX_mode: 0..1; {identifies compatibility and extended mode} @ @= eTeX_mode:=0; {initially we are in compatibility mode} @ @= dump_int(eTeX_mode); for j:=0 to eTeX_states-1 do eTeX_state(j):=0; {disable all enhancements} @ @= undump(0)(1)(eTeX_mode); @ The |eTeX_enabled| function simply returns its first argument as result. This argument is |true| if an optional \eTeX\ feature is currently enabled; otherwise, if the argument is |false|, the function gives an error message. @= function eTeX_enabled(@!b:boolean;@!j:quarterword;@!k:halfword):boolean; begin if not b then begin print_err("Improper "); print_cmd_chr(j,k); help1("Sorry, this optional e-TeX feature has been disabled."); error; end; eTeX_enabled:=b; end; @ @= procedure@?scan_eight_bit_int; forward;@t\2@> @ First we implement the additional \eTeX\ parameters in the table of equivalents. @= primitive("everyeof",assign_toks,every_eof_loc); @!@:every_eof_}{\.{\\everyeof} primitive@> primitive("tracingassigns",assign_int,int_base+tracing_assigns_code);@/ @!@:tracing_assigns_}{\.{\\tracingassigns} primitive@> primitive("tracinggroups",assign_int,int_base+tracing_groups_code);@/ @!@:tracing_groups_}{\.{\\tracinggroups} primitive@> primitive("tracingifs",assign_int,int_base+tracing_ifs_code);@/ @!@:tracing_ifs_}{\.{\\tracingifs} primitive@> primitive("tracingscantokens",assign_int,int_base+tracing_scan_tokens_code);@/ @!@:tracing_scan_tokens_}{\.{\\tracingscantokens} primitive@> primitive("predisplaydirection", assign_int,int_base+pre_display_direction_code);@/ @!@:pre_display_direction_}{\.{\\predisplaydirection} primitive@> @ @d every_eof==equiv(every_eof_loc) @= every_eof_loc: print_esc("everyeof"); @ @= tracing_assigns_code:print_esc("tracingassigns"); tracing_groups_code:print_esc("tracinggroups"); tracing_ifs_code:print_esc("tracingifs"); tracing_scan_tokens_code:print_esc("tracingscantokens"); pre_display_direction_code:print_esc("predisplaydirection"); @ The |print_group| procedure prints the current level of grouping and the name corresponding to |cur_group|. @= procedure print_group(@!e:boolean); label exit; begin print_int(cur_level); print(": "); case cur_group of bottom_level: begin print("bottom level"); return; end; simple_group,semi_simple_group: begin if cur_group=semi_simple_group then print("semi "); print("simple"); end; hbox_group,adjusted_hbox_group: begin if cur_group=adjusted_hbox_group then print("adjusted "); print("hbox"); end; vbox_group: print("vbox"); vtop_group: print("vtop"); align_group,no_align_group: begin if cur_group=no_align_group then print("no "); print("align"); end; output_group: print("output"); disc_group: print("disc"); insert_group: print("insert"); vcenter_group: print("vcenter"); math_group,math_choice_group,math_shift_group,math_left_group: begin print("math"); if cur_group=math_choice_group then print(" choice") else if cur_group=math_shift_group then print(" shift") else if cur_group=math_left_group then print(" left"); end; end; {there are no other cases} print(" group"); if saved(-1)<>0 then begin if e then print(" entered at line ") else print(" at line "); print_int(saved(-1)); end; exit:end; @ The |group_trace| procedure is called when a new level of grouping begins (|e=false|) or ends (|e=true|) with |saved(-1)| containing the line number. @= @!stat procedure group_trace(@!e:boolean); begin begin_diagnostic; print_char("{"); if e then print("leaving ") else print("entering "); print_group(e); print_char("}"); end_diagnostic(false); end; tats @ The \.{\\currentgrouplevel} and \.{\\currentgrouptype} commands return the current level of grouping and the type of the current group respectively. @d group_level_code=glue_val+5 {code for \.{\\currentgrouplevel}} @d group_type_code=glue_val+6 {code for \.{\\currentgrouptype}} @= primitive("currentgrouplevel",last_item,group_level_code); @!@:current_group_level_}{\.{\\currentgrouplevel} primitive@> primitive("currentgrouptype",last_item,group_type_code); @!@:current_group_type_}{\.{\\currentgrouptype} primitive@> @ @= group_level_code: print_esc("currentgrouplevel"); group_type_code: print_esc("currentgrouptype"); @ @= else if cur_chr=group_level_code then cur_val:=cur_level-level_one else if cur_chr=group_type_code then cur_val:=cur_group @ The \.{\\showgroups} command displays all currently active grouping levels. @d show_groups=4 { \.{\\showgroups} } @= primitive("showgroups",xray,show_groups); @!@:show_groups_}{\.{\\showgroups} primitive@> @ @= show_groups:print_esc("showgroups"); @ @= show_groups: begin begin_diagnostic; show_save_groups; end; @ The modifications of \TeX\ required for the display produced by the |show_save_groups| procedure were first discussed by Donald~E. Knuth in {\sl TUGboat\/} {\bf 11}, 165--170 and 499--511, 1990. @^Knuth, Donald Ervin@> In order to understand a group type we also have to know its mode. Since unrestricted horizontal modes are not associated with grouping, they are skipped when traversing the semantic nest. @= procedure show_save_groups; label found1,found2,found,done; var p:0..nest_size; {index into |nest|} @!m:-mmode..mmode; {mode} @!v:0..save_size; {saved value of |save_ptr|} @!l:quarterword; {saved value of |cur_level|} @!c:group_code; {saved value of |cur_group|} @!a:-1..1; {to keep track of alignments} @!i:integer; @!j:quarterword; @!s:str_number; begin p:=nest_ptr; nest[p]:=cur_list; {put the top level into the array} v:=save_ptr; l:=cur_level; c:=cur_group; save_ptr:=cur_boundary; decr(cur_level);@/ a:=1; print_nl(""); print_ln; loop@+begin print_nl("### "); print_group(true); if cur_group=bottom_level then goto done; repeat m:=nest[p].mode_field; if p>0 then decr(p) else m:=vmode; until m<>hmode; print(" ("); case cur_group of simple_group: begin incr(p); goto found2; end; hbox_group,adjusted_hbox_group: s:="hbox"; vbox_group: s:="vbox"; vtop_group: s:="vtop"; align_group: if a=0 then begin if m=-vmode then s:="halign" else s:="valign"; a:=1; goto found1; end else begin if a=1 then print("align entry") else print_esc("cr"); if p>=a then p:=p-a; a:=0; goto found; end; no_align_group: begin incr(p); a:=-1; print_esc("noalign"); goto found2; end; output_group: begin print_esc("output"); goto found; end; math_group: goto found2; disc_group,math_choice_group: begin if cur_group=disc_group then print_esc("discretionary") else print_esc("mathchoice"); for i:=1 to 3 do if i<=saved(-2) then print("{}"); goto found2; end; insert_group: begin if saved(-2)=255 then print_esc("vadjust") else begin print_esc("insert"); print_int(saved(-2)); end; goto found2; end; vcenter_group: begin s:="vcenter"; goto found1; end; semi_simple_group: begin incr(p); print_esc("begingroup"); goto found; end; math_shift_group: begin if m=mmode then print_char("$") else if nest[p].mode_field=mmode then begin print_cmd_chr(eq_no,saved(-2)); goto found; end; print_char("$"); goto found; end; math_left_group: begin if type(nest[p+1].eTeX_aux_field)=left_noad then print_esc("left") else print_esc("middle"); goto found; end; end; {there are no other cases} @; found1: print_esc(s); @; found2: print_char("{"); found: print_char(")"); decr(cur_level); cur_group:=save_level(save_ptr); save_ptr:=save_index(save_ptr) end; done: save_ptr:=v; cur_level:=l; cur_group:=c; end; @ @= if saved(-2)<>0 then begin print_char(" "); if saved(-3)=exactly then print("to") else print("spread"); print_scaled(saved(-2)); print("pt"); end @ @= i:=saved(-4); if i<>0 then if i0 then print_cmd_chr(j,0) else print_cmd_chr(j,1); print_scaled(abs(i)); print("pt"); end else if i255 then begin print_esc("global"); i:=i-256; end; print_esc("setbox"); print_int(i); print_char("="); end else print_cmd_chr(leader_ship,i-(leader_flag-a_leaders)) @ The |scan_general_text| procedure is much like |scan_toks(false,false)|, but will be invoked via |expand|, i.e., recursively. @^recursion@> @= procedure@?scan_general_text; forward;@t\2@> @ The token list (balanced text) created by |scan_general_text| begins at |link(temp_head)| and ends at |cur_val|. (If |cur_val=temp_head|, the list is empty.) @= procedure scan_general_text; label found; var s:normal..absorbing; {to save |scanner_status|} @!w:pointer; {to save |warning_index|} @!d:pointer; {to save |def_ref|} @!p:pointer; {tail of the token list being built} @!q:pointer; {new node being added to the token list via |store_new_token|} @!unbalance:halfword; {number of unmatched left braces} begin s:=scanner_status; w:=warning_index; d:=def_ref; scanner_status:=absorbing; warning_index:=cur_cs; def_ref:=get_avail; token_ref_count(def_ref):=null; p:=def_ref; scan_left_brace; {remove the compulsory left brace} unbalance:=1; loop@+ begin get_token; if cur_tok= primitive("showtokens",xray,show_tokens); @!@:show_tokens_}{\.{\\showtokens} primitive@> @ @= show_tokens:print_esc("showtokens"); @ The \.{\\unexpanded} primitive prevents expansion of tokens much as the result from \.{\\the} applied to a token variable. The \.{\\detokenize} primitive converts a token list into a list of character tokens much as if the token list were written to a file. We use the fact that the command modifiers for \.{\\unexpanded} and \.{\\detokenize} are odd whereas those for \.{\\the} and \.{\\showthe} are even. @= primitive("unexpanded",the,1);@/ @!@:unexpanded_}{\.{\\unexpanded} primitive@> primitive("detokenize",the,show_tokens);@/ @!@:detokenize_}{\.{\\detokenize} primitive@> @ @= else if chr_code=1 then print_esc("unexpanded") else print_esc("detokenize") @ @= if odd(cur_chr) then begin c:=cur_chr; scan_general_text; if c=1 then the_toks:=cur_val else begin old_setting:=selector; selector:=new_string; b:=pool_ptr; p:=get_avail; link(p):=link(temp_head); token_show(p); flush_list(p); selector:=old_setting; the_toks:=str_toks(b); end; return; end @ The \.{\\interactionmode} primitive allows to query and set the interaction mode. @= primitive("interactionmode",set_page_int,2); @!@:interaction_mode_}{\.{\\interactionmode} primitive@> @ @= else if chr_code=2 then print_esc("interactionmode") @ @= else if m=2 then cur_val:=interaction @ @= procedure@?new_interaction; forward;@t\2@> @ @= else if c=2 then begin if (cur_valerror_stop_mode) then begin print_err("Bad interaction mode"); @.Bad interaction mode@> help2("Modes are 0=batch, 1=nonstop, 2=scroll, and")@/ ("3=errorstop. Proceed, and I'll ignore this case."); int_error(cur_val); end else begin cur_chr:=cur_val; new_interaction; end; end @ The |middle| feature of \eTeX\ allows one ore several \.{\\middle} delimiters to appear between \.{\\left} and \.{\\right}. @= primitive("middle",left_right,middle_noad); @!@:middle_}{\.{\\middle} primitive@> @ @= else if chr_code=middle_noad then print_esc("middle") @ In constructions such as $$\vbox{\halign{\.{#}\hfil\cr {}\\vbox to \\vsize\{\cr \hskip 25pt \\vskip 0pt plus 0.0001fil\cr \hskip 25pt ...\cr \hskip 25pt \\vfil\\penalty-200\\vfilneg\cr \hskip 25pt ...\}\cr}}$$ the stretch components of \.{\\vfil} and \.{\\vfilneg} compensate; in standard \TeX\ they may get modified in order to prevent arithmetic overflow during |ship_out| when each of them is multiplied by a large |glue_set| value. In \eTeX\ the conversion from stretch or shrink components of glue to \.{DVI} units is performed by the |do_glue| function defined below. In extended mode the |do_glue| function adds up the relevant stretch (or shrink) components of consecutive glue nodes and converts the glue nodes into equivalent kern nodes; during this process glue specifications may be recycled. The accumulated stretch or shrink is then multiplied by |glue_set(this_box)| and returned as result. Since one and the same box may be used several times inside leaders the result is also added to the width of the first or only kern node; the subtype of the glue node(s) remains unchanged. The consecutive glue nodes may be separated by insert, mark, adjust, kern, and penalty nodes. @d add_glue(#)==#:=#+do_glue(this_box,p) @# @d add_stretch_shrink== {accumulate stretch or shrink amount} if g_sign=stretching then begin if stretch_order(g)=g_order then s:=s+stretch(g); end else begin if shrink_order(g)=g_order then s:=s-shrink(g); end @= function do_glue(@!this_box,@!p:pointer):scaled; label continue, next_p, done; var q:pointer; {list traverser} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @!s:scaled; {accumulated stretch or shrink} @!glue_temp:real; {glue value before rounding} begin g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); s:=0; add_stretch_shrink; if not eTeX_ex or(subtype(p)>=a_leaders) then goto done; q:=p; continue: type(q):=kern_node; width(q):=width(g); fast_delete_glue_ref(g); next_p: q:=link(q); if (q<>null) and not is_char_node(q) then case type(q) of ins_node,mark_node,adjust_node,kern_node,penalty_node: goto next_p; glue_node: if subtype(q)0 then begin vet_glue(float(glue_set(this_box))*s); s:=round(glue_temp); @^real multiplication@> if type(p)=kern_node then width(p):=width(p)+s; end; do_glue:=s; end; @ The optional |TeXXeT| feature of \eTeX\ contains the code for mixed left-to-right and right-to-left typesetting. This code is inspired by but different from \TeXeT\ as presented by Donald~E. Knuth and Pierre MacKay in {\sl TUGboat\/} {\bf 8}, 14--25, 1987. @^Knuth, Donald Ervin@> @^MacKay, Pierre@> In order to avoid confusion with \TeXeT\ the present implementation of mixed direction typesetting is called \TeXXeT. It differs from \TeXeT\ in several important aspects: (1)~Right-to-left text is reversed explicitely by the |ship_out| routine and is written to a normal \.{DVI} file without any |begin_reflect| or |end_reflect| commands; (2)~a |math_node| is (ab)used instead of a |whatsit_node| to record the \.{\\beginL}, \.{\\endL}, \.{\\beginR}, and \.{\\endR} text direction primitives in order to keep the influence on the line breaking algorithm for pure left-to-right text as small as possible; (3)~right-to-left text interrupted by a displayed equation is automatically resumed after that equation; and (4)~the |valign| command code with a non-zero command modifier is (ab)used for the text direction primitives. Nevertheless there is a subtle difference between \TeX\ and \TeXXeT\ that may influence the line breaking algorithm for pure left-to-right text. When a paragraph containing math mode material is broken into lines \TeX\ may generate lines where math mode material is not enclosed by properly nested \.{\\mathon} and \.{\\mathoff} nodes. Unboxing such lines as part of a new paragraph may have the effect that hyphenation is attempted for `words' originating from math mode or that hyphenation is inhibited for words originating from horizontal mode. In \TeXXeT\ additional \.{\\beginM}, resp.\ \.{\\endM} math nodes are supplied at the start, resp.\ end of lines such that math mode material inside a horizontal list always starts with either \.{\\mathon} or \.{\\beginM} and ends with \.{\\mathoff} or \.{\\endM}. These additional nodes are transparent to operations such as \.{\\unskip}, \.{\\lastpenalty}, or \.{\\lastbox} but they do have the effect that hyphenation is never attempted for `words' originating from math mode and is never inhibited for words originating from horizontal mode. @d TeXXeT_state==eTeX_state(TeXXeT_code) @d TeXXeT_en==(TeXXeT_state>0) {is \TeXXeT\ enabled?} @= eTeX_state_code+TeXXeT_code:print_esc("TeXXeTstate"); @ @= primitive("TeXXeTstate",assign_int,eTeX_state_base+TeXXeT_code); @!@:TeXXeT_state_}{\.{\\TeXXeT_state} primitive@> primitive("beginL",valign,begin_L_code); @!@:beginL_}{\.{\\beginL} primitive@> primitive("endL",valign,end_L_code); @!@:endL_}{\.{\\endL} primitive@> primitive("beginR",valign,begin_R_code); @!@:beginR_}{\.{\\beginR} primitive@> primitive("endR",valign,end_R_code); @!@:endR_}{\.{\\endR} primitive@> @ @= else case chr_code of begin_L_code: print_esc("beginL"); end_L_code: print_esc("endL"); begin_R_code: print_esc("beginR"); othercases print_esc("endR") endcases @ @= if cur_chr>0 then begin if eTeX_enabled(TeXXeT_en,cur_cmd,cur_chr) then @.Improper \\beginL@> @.Improper \\endL@> @.Improper \\beginR@> @.Improper \\endR@> tail_append(new_math(0,cur_chr)); end else @ An hbox with subtype dlist will never be reversed, even when embedded in right-to-left text. @= if (type(p)=hlist_node)and(subtype(p)=dlist) then print(", display") @ A number of routines are based on a stack of one-word nodes whose |info| fields contain |end_M_code|, |end_L_code|, or |end_R_code|. The top of the stack is pointed to by |LR_ptr|. When the stack manipulation macros of this section are used below, variable |LR_ptr| might be the global variable declared here for |hpack| and |ship_out|, or might be local to |post_line_break|. @d put_LR(#)==begin temp_ptr:=get_avail; info(temp_ptr):=#; link(temp_ptr):=LR_ptr; LR_ptr:=temp_ptr; end @# @d push_LR(#)==put_LR(end_LR_type(#)) @# @d pop_LR==begin temp_ptr:=LR_ptr; LR_ptr:=link(temp_ptr); free_avail(temp_ptr); end @= @!LR_temp:pointer; {holds a temporarily removed \.{\\endM} node} @!LR_ptr:pointer; {stack of LR codes for |hpack|, |ship_out|, and |init_math|} @!LR_problems:integer; {counts missing begins and ends} @!cur_dir:small_number; {current text direction} @ @= LR_temp:=null; LR_ptr:=null; LR_problems:=0; cur_dir:=left_to_right; @ @= begin q:=link(temp_head); if LR_ptr<>null then begin temp_ptr:=LR_ptr; r:=q; repeat s:=new_math(0,begin_LR_type(info(temp_ptr))); link(s):=r; r:=s; temp_ptr:=link(temp_ptr); until temp_ptr=null; link(temp_head):=r; end; while q<>cur_break(cur_p) do begin if not is_char_node(q) then if type(q)=math_node then @; q:=link(q); end; end @ @= if end_LR(q) then begin if LR_ptr<>null then if info(LR_ptr)=end_LR_type(q) then pop_LR; end else push_LR(q) @ We use the fact that |q| now points to the node with \.{\\rightskip} glue. @= if LR_ptr<>null then begin s:=temp_head; r:=link(s); while r<>q do begin s:=r; r:=link(s); end; r:=LR_ptr; while r<>null do begin temp_ptr:=new_math(0,info(r)); link(s):=temp_ptr; s:=temp_ptr; r:=link(r); end; link(s):=q; end @ Special \.{\\beginM} and \.{\\endM} nodes are inserted in cases where math nodes are discarded during line breaking or end up in different lines. When the current lists ends with an \.{\\endM} node that node is temporarily removed and later reinserted when the last node is to be inspected or removed. A final \.{\\endM} preceded by a |char_node| will not be removed. @= procedure remove_end_M; var @!p:pointer; {runs through the current list} begin p:=head; while link(p)<>tail do p:=link(p); if not is_char_node(p) then begin LR_temp:=tail; link(p):=null; tail:=p; end; end; @ @= procedure insert_end_M; label done; var @!p:pointer; {runs through the current list} begin if not is_char_node(tail) then if (type(tail)=math_node)and(subtype(tail)=begin_M_code) then begin free_node(LR_temp,small_node_size); p:=head; while link(p)<>tail do p:=link(p); free_node(tail,small_node_size); link(p):=null; tail:=p; goto done; end; link(tail):=LR_temp; tail:=LR_temp; done: LR_temp:=null; end; @ @= put_LR(before) {this will never match} @ @= if end_LR(p) then if info(LR_ptr)=end_LR_type(p) then pop_LR else begin incr(LR_problems); type(p):=kern_node; subtype(p):=explicit; end else push_LR(p) @ @= begin if info(LR_ptr)<>before then begin while link(q)<>null do q:=link(q); repeat temp_ptr:=q; q:=new_math(0,info(LR_ptr)); link(temp_ptr):=q; LR_problems:=LR_problems+10000; pop_LR; until info(LR_ptr)=before; end; if LR_problems>0 then begin @; goto common_ending; end; pop_LR; if LR_ptr<>null then confusion("LR1"); @:this can't happen LR1}{\quad LR1@> end @ @= begin print_ln; print_nl("\endL or \endR problem (");@/ print_int(LR_problems div 10000); print(" missing, ");@/ print_int(LR_problems mod 10000); print(" extra");@/ LR_problems:=0; end @ Breaking a paragraph into lines while \TeXXeT\ is disabled may result in lines whith unpaired math nodes. Such hlists are silently accepted in the absence of text direction directives. @d LR_dir(#)==(subtype(#) div R_code) {text direction of a `math node'} @= begin if end_LR(p) then if info(LR_ptr)=end_LR_type(p) then pop_LR else begin if subtype(p)>L_code then incr(LR_problems); end else begin push_LR(p); if LR_dir(p)<>cur_dir then @; end; type(p):=kern_node; end @ @= begin while info(LR_ptr)<>before do begin if info(LR_ptr)>L_code then LR_problems:=LR_problems+10000; pop_LR; end; pop_LR; end @ @d edge_node=style_node {a |style_node| does not occur in hlists} @d edge_node_size=style_node_size {number of words in an edge node} @d edge_dist(#)==depth(#) {new |left_edge| position relative to |cur_h| (after |width| has been taken into account)} @= function new_edge(@!s:small_number;@!w:scaled):pointer; {create an edge node} var p:pointer; {the new node} begin p:=get_node(edge_node_size); type(p):=edge_node; subtype(p):=s; width(p):=w; edge_dist(p):=0; {the |edge_dist| field will be set later} new_edge:=p; end; @ @= edge_node: begin cur_h:=cur_h+width(p); left_edge:=cur_h+edge_dist(p); cur_dir:=subtype(p); end; @ We detach the hlist, start a new one consisting of just one kern node, append the reversed list, and set the width of the kern node. @= begin save_h:=cur_h; temp_ptr:=p; p:=new_kern(0); link(prev_p):=p; cur_h:=0; link(p):=reverse(this_box,null); width(p):=-cur_h; cur_h:=save_h; subtype(this_box):=reversed; end @ We detach the remainder of the hlist, replace the math node by an edge node, and append the reversed hlist segment to it; the tail of the reversed segment is another edge node and the remainder of the original list is attached to it. @= begin save_h:=cur_h; temp_ptr:=link(p); rule_wd:=width(p); free_node(p,small_node_size); cur_dir:=reflected; p:=new_edge(cur_dir,rule_wd); link(prev_p):=p; cur_h:=cur_h-left_edge+rule_wd; link(p):=reverse(this_box,new_edge(reflected,0)); edge_dist(p):=cur_h; cur_dir:=reflected; cur_h:=save_h; goto reswitch; end @ The |reverse| function defined here is responsible to reverse the nodes of an hlist (segment). The first parameter |this_box| is the enclosing hlist node, the second parameter |t| is to become the tail of the reversed list, and the global variable |temp_ptr| is the head of the list to be reversed. We remove nodes from the original list and add them to the head of the new one. @= function reverse(@!this_box,@!t:pointer):pointer; label reswitch,next_p,done; var l:pointer; {the new list} @!p:pointer; {the current node} @!q:pointer; {the next node} @!g_sign: normal..shrinking; {selects type of glue} @!m,@!n:halfword; {count of unmatched math nodes} begin g_sign:=glue_sign(this_box); l:=t; p:=temp_ptr; m:=min_halfword; n:=min_halfword; loop@+ begin while p<>null do @; if (t=null)and(m=min_halfword)and(n=min_halfword) then goto done; p:=new_math(0,info(LR_ptr)); LR_problems:=LR_problems+10000; {manufacture one missing math node} end; done:reverse:=l; end; @ @= reswitch: if is_char_node(p) then repeat f:=font(p); c:=character(p); cur_h:=cur_h+char_width(f)(char_info(f)(c)); q:=link(p); link(p):=l; l:=p; p:=q; until not is_char_node(p) else @ @ @= begin q:=link(p); case type(p) of hlist_node,vlist_node,rule_node,kern_node: rule_wd:=width(p); @t\4@>@@; edge_node: confusion("LR2"); @:this can't happen LR2}{\quad LR2@> othercases goto next_p endcases;@/ cur_h:=cur_h+rule_wd; next_p: link(p):=l; if type(p)=kern_node then if (rule_wd=0)or(l=null) then begin free_node(p,small_node_size); p:=l; end; l:=p; p:=q; end @ Here we have to remember that |add_glue| may have converted the glue node into a kern node. If this is not the case we try to covert the glue node into a rule node. @= glue_node: begin g:=glue_ptr(p); rule_wd:=width(g); if g_sign<>normal then add_glue(rule_wd); if subtype(p)>=a_leaders then begin temp_ptr:=leader_ptr(p); if type(temp_ptr)=rule_node then begin delete_glue_ref(g); free_node(p,small_node_size); p:=temp_ptr; width(p):=rule_wd; end; end; end; @ A ligature node is replaced by a char node. @= ligature_node: begin flush_node_list(lig_ptr(p)); temp_ptr:=p; p:=get_avail; mem[p]:=mem[lig_char(temp_ptr)]; link(p):=q; free_node(temp_ptr,small_node_size); goto reswitch; end; @ Math nodes in an inner reflected segment are modified, those at the outer level are changed into kern nodes. @= math_node: begin rule_wd:=width(p); if end_LR(p) then if info(LR_ptr)<>end_LR_type(p) then begin type(p):=kern_node; incr(LR_problems); end else begin pop_LR; if n>min_halfword then begin decr(n); decr(subtype(p)); {change |after| into |before|} end else begin type(p):=kern_node; if m>min_halfword then decr(m) else @; end; end else begin push_LR(p); if (n>min_halfword)or(LR_dir(p)<>cur_dir) then begin incr(n); incr(subtype(p)); {change |before| into |after|} end else begin type(p):=kern_node; incr(m); end; end; end; @ Finally we have found the end of the hlist segment to be reversed; the final math node is released and the remaining list attached to the edge node terminating the reversed segment. @= begin free_node(p,small_node_size); link(t):=q; width(t):=rule_wd; edge_dist(t):=-cur_h-rule_wd; goto done; end @ @= begin if LR_problems>0 then begin @; print_char(")"); print_ln; end; if (LR_ptr<>null)or(cur_dir<>left_to_right) then confusion("LR3"); @:this can't happen LR3}{\quad LR3@> end @ Some special actions are required for displayed equation in paragraphs with mixed direction texts. First of all we have to set the text direction preceding the display. @= if LR_save=null then x:=0 else if info(LR_save)>=R_code then x:=-1@+else x:=1 @ @= begin pop_nest; @; end @ When calculating the natural width, |w|, of the final line preceding the display, we may have to copy all or part of its hlist. We copy, however, only those parts of the original list that are relevant for the computation of |pre_display_size|. @^data structure assumptions@> @= procedure just_copy(@!p,@!h,@!t:pointer); label found,not_found; var @!r:pointer; {current node being fabricated for new list} @!words:0..5; {number of words remaining to be copied} begin while p<>null do begin words:=1; {this setting occurs in more branches than any other} if is_char_node(p) then r:=get_avail else case type(p) of hlist_node,vlist_node: begin r:=get_node(box_node_size); mem[r+6]:=mem[p+6]; mem[r+5]:=mem[p+5]; {copy the last two words} words:=5; list_ptr(r):=null; {this affects |mem[r+5]|} end; rule_node: begin r:=get_node(rule_node_size); words:=rule_node_size; end; ligature_node: begin r:=get_avail; {only |font| and |character| are needed} mem[r]:=mem[lig_char(p)]; goto found; end; kern_node,math_node: begin r:=get_node(small_node_size); words:=small_node_size; end; glue_node: begin r:=get_node(small_node_size); add_glue_ref(glue_ptr(p)); glue_ptr(r):=glue_ptr(p); leader_ptr(r):=null; end; whatsit_node:@; othercases goto not_found endcases; while words>0 do begin decr(words); mem[r+words]:=mem[p+words]; end; found: link(h):=r; h:=r; not_found: p:=link(p); end; link(h):=t; end; @ When the final line ends with R-text, the value |w| refers to the line reflected with respect to the left edge of the enclosing vertical list. @= if eTeX_ex then @; v:=shift_amount(just_box); @; if x>=0 then begin p:=list_ptr(just_box); link(temp_head):=null; end else begin v:=-v-width(just_box); p:=new_math(0,begin_L_code); link(temp_head):=p; just_copy(list_ptr(just_box),p,new_math(0,end_L_code)); cur_dir:=right_to_left; end; v:=v+2*quad(cur_font); if TeXXeT_en then @ @ @= if TeXXeT_en then begin while LR_ptr<>null do pop_LR; if LR_problems<>0 then begin w:=max_dimen; LR_problems:=0; end; end; cur_dir:=left_to_right; flush_node_list(link(temp_head)) @ In the presence of text direction directives we assume that any LR problems have been fixed by the |hpack| routine. If the final line contains, however, text direction directives while \TeXXeT\ is disabled, then we set |w:=max_dimen|. @= math_node: begin d:=width(p); if TeXXeT_en then @ else if subtype(p)>=L_code then begin w:=max_dimen; goto done; end; end; edge_node: begin d:=width(p); cur_dir:=subtype(p); end; @ @= if end_LR(p) then begin if info(LR_ptr)=end_LR_type(p) then pop_LR else if subtype(p)>L_code then begin w:=max_dimen; goto done; end end else begin push_LR(p); if LR_dir(p)<>cur_dir then begin just_reverse(p); p:=temp_head; end; end @ @= procedure just_reverse(@!p:pointer); label found,done; var l:pointer; {the new list} @!t:pointer; {tail of reversed segment} @!q:pointer; {the next node} @!m,@!n:halfword; {count of unmatched math nodes} begin m:=min_halfword; n:=min_halfword; if link(temp_head)=null then begin just_copy(link(p),temp_head,null); q:=link(temp_head); end else begin q:=link(p); link(p):=null; flush_node_list(link(temp_head)); end; t:=new_edge(cur_dir,0); l:=t; cur_dir:=reflected; while q<>null do if is_char_node(q) then repeat p:=q; q:=link(p); link(p):=l; l:=p; until not is_char_node(q) else begin p:=q; q:=link(p); if type(p)=math_node then @; link(p):=l; l:=p; end; goto done; found:width(t):=width(p); link(t):=q; free_node(p,small_node_size); done:link(temp_head):=l; end; @ @= if end_LR(p) then if info(LR_ptr)<>end_LR_type(p) then begin type(p):=kern_node; incr(LR_problems); end else begin pop_LR; if n>min_halfword then begin decr(n); decr(subtype(p)); {change |after| into |before|} end else begin if m>min_halfword then decr(m)@+else goto found; type(p):=kern_node; end; end else begin push_LR(p); if (n>min_halfword)or(LR_dir(p)<>cur_dir) then begin incr(n); incr(subtype(p)); {change |before| into |after|} end else begin type(p):=kern_node; incr(m); end; end @ The prototype box is an hlist node with the width, glue set, and shift amount of |just_box|, i.e., the last line preceding the display. Its hlist reflects the current \.{\\leftskip} and \.{\\rightskip}. @= begin if right_skip=zero_glue then j:=new_kern(0) else j:=new_param_glue(right_skip_code); if left_skip=zero_glue then p:=new_kern(0) else p:=new_param_glue(left_skip_code); link(p):=j; j:=new_null_box; width(j):=width(just_box); shift_amount(j):=shift_amount(just_box); list_ptr(j):=p; glue_order(j):=glue_order(just_box); glue_sign(j):=glue_sign(just_box); glue_set(j):=glue_set(just_box); end @ At the end of a displayed equation we retrieve the prototype box. @= @!j:pointer; {prototype box} @ @= if mode=mmode then j:=LR_box @ @= flush_node_list(j) @ The |app_display| procedure used to append the displayed equation and\slash or equation number to the current vertical list has three parameters: the prototype box, the hbox to be appended, and the displacement of the hbox in the display line. @= procedure app_display(@!j,@!b:pointer;@!d:scaled); var z:scaled; {width of the line} @!s:scaled; {move the line right this much} @!e:scaled; {distance from right edge of box to end of line} @!x:integer; {|pre_display_direction|} @!p,@!q,@!r,@!t,@!u:pointer; {for list manipulation} begin s:=display_indent; x:=pre_display_direction; if x=0 then shift_amount(b):=s+d else begin z:=display_width; p:=b; @; @; end; append_to_vlist(b); end; @ Here we construct the hlist for the display, starting with node |p| and ending with node |q|. We also set |d| and |e| to the amount of kerning to be added before and after the hlist (adjusted for the prototype box). @= if x>0 then e:=z-d-width(p) else begin e:=d; d:=z-e-width(p); end; if j<>null then begin b:=copy_node_list(j); height(b):=height(p); depth(b):=depth(p); s:=s-shift_amount(b); d:=d+s; e:=e+width(b)-z-s; end; if subtype(p)=dlist then q:=p {display or equation number} else begin {display and equation number} r:=list_ptr(p); free_node(p,box_node_size); if r=null then confusion("LR4"); if x>0 then begin p:=r; repeat q:=r; r:=link(r); {find tail of list} until r=null; end else begin p:=null; q:=r; repeat t:=link(r); link(r):=p; p:=r; r:=t; {reverse list} until r=null; end; end @ In the presence of a prototype box we use its shift amount and width to adjust the values of kerning and add these values to the glue nodes inserted to cancel the \.{\\leftskip} and \.{\\rightskip}. If there is no prototype box (because the display is preceded by an empty paragraph), or if the skip parameters are zero, we just add kerns. The |cancel_glue| macro creates and links a glue node that is, together with another glue node, equivalent to a given amount of kerning. We can use |j| as temporary pointer, since all we need is |j<>null|. @d cancel_glue(#)==j:=new_skip_param(#); cancel_glue_cont @d cancel_glue_cont(#)==link(#):=j; cancel_glue_cont_cont @d cancel_glue_cont_cont(#)==link(j):=#; cancel_glue_end @d cancel_glue_end(#)==j:=glue_ptr(#); cancel_glue_end_end @d cancel_glue_end_end(#)== stretch_order(temp_ptr):=stretch_order(j); shrink_order(temp_ptr):=shrink_order(j); width(temp_ptr):=#-width(j); stretch(temp_ptr):=-stretch(j); shrink(temp_ptr):=-shrink(j) @= if j=null then begin r:=new_kern(0); t:=new_kern(0); {the widths will be set later} end else begin r:=list_ptr(b); t:=link(r); end; u:=new_math(0,end_M_code); if type(t)=glue_node then {|t| is \.{\\rightskip} glue} begin cancel_glue(right_skip_code)(q)(u)(t)(e); link(u):=t; end else begin width(t):=e; link(t):=u; link(q):=t; end; u:=new_math(0,begin_M_code); if type(r)=glue_node then {|r| is \.{\\leftskip} glue} begin cancel_glue(left_skip_code)(u)(p)(r)(d); link(r):=u; end else begin width(r):=d; link(r):=p; link(u):=r; if j=null then begin b:=hpack(u,natural); shift_amount(b):=s; end else list_ptr(b):=u; end @ The |scan_tokens| feature of \eTeX\ defines the \.{\\scantokens} primitive. @= primitive("scantokens",input,2); @!@:scan_tokens_}{\.{\\scantokens} primitive@> @ @= else if chr_code=2 then print_esc("scantokens") @ @= else if cur_chr=2 then pseudo_start @ The global variable |pseudo_files| is used to maintain a stack of pseudo files. The |info| field of each pseudo file points to a linked list of variable size nodes representing lines not yet processed: the |info| field of the first word contains the size of this node, all the following words contain ASCII codes. @= @!pseudo_files:pointer; {stack of pseudo files} @ @= pseudo_files:=null; @ The |pseudo_start| procedure initiates reading from a pseudo file. @= procedure@?pseudo_start; forward;@t\2@> @ @= procedure pseudo_start; var old_setting:0..max_selector; {holds |selector| setting} @!s:str_number; {string to be converted into a pseudo file} @!l,@!m:pool_pointer; {indices into |str_pool|} @!p,@!q,@!r:pointer; {for list construction} @!w: four_quarters; {four ASCII codes} @!nl,@!sz:integer; begin scan_general_text; old_setting:=selector; selector:=new_string; token_show(temp_head); selector:=old_setting; flush_list(link(temp_head)); str_room(1); s:=make_string; @; flush_string; @; end; @ @= str_pool[pool_ptr]:=si(" "); l:=str_start[s]; nl:=si(new_line_char); p:=get_avail; q:=p; while lnl) do incr(l); sz:=(l-m+7)div 4; if sz=1 then sz:=2; r:=get_node(sz); link(q):=r; q:=r; info(q):=hi(sz); while sz>2 do begin decr(sz); incr(r); w.b0:=qi(so(str_pool[m])); w.b1:=qi(so(str_pool[m+1])); w.b2:=qi(so(str_pool[m+2])); w.b3:=qi(so(str_pool[m+3])); mem[r].qqqq:=w; m:=m+4; end; w.b0:=qi(" "); w.b1:=qi(" "); w.b2:=qi(" "); w.b3:=qi(" "); if l>m then begin w.b0:=qi(so(str_pool[m])); if l>m+1 then begin w.b1:=qi(so(str_pool[m+1])); if l>m+2 then begin w.b2:=qi(so(str_pool[m+2])); if l>m+3 then w.b3:=qi(so(str_pool[m+3])); end; end; end; mem[r+1].qqqq:=w; if str_pool[l]=nl then incr(l); end; info(p):=link(p); link(p):=pseudo_files; pseudo_files:=p @ @= begin_file_reading; {set up |cur_file| and new level of input} line:=0; limit:=start; loc:=limit+1; {force line read} if tracing_scan_tokens>0 then begin if term_offset>max_print_line-3 then print_ln else if (term_offset>0)or(file_offset>0) then print_char(" "); name:=19; print("( "); incr(open_parens); update_terminal; end else name:=18 @ Here we read a line from the current pseudo file into |buffer|. @= function pseudo_input: boolean; {inputs the next line or returns |false|} var p:pointer; {current line from pseudo file} @!sz:integer; {size of node |p|} @!w:four_quarters; {four ASCII codes} @!r:pointer; {loop index} begin last:=first; {cf.\ Matthew 19\thinspace:\thinspace30} p:=info(pseudo_files); if p=null then pseudo_input:=false else begin info(pseudo_files):=link(p); sz:=ho(info(p)); if 4*sz-3>=buf_size-last then @; last:=first; for r:=p+1 to p+sz-1 do begin w:=mem[r].qqqq; buffer[last]:=w.b0; buffer[last+1]:=w.b1; buffer[last+2]:=w.b2; buffer[last+3]:=w.b3; last:=last+4; end; if last>=max_buf_stack then max_buf_stack:=last+1; while (last>first)and(buffer[last-1]=" ") do decr(last); free_node(p,sz); pseudo_input:=true; end; end; @ When we are done with a pseudo file we `close' it. @= procedure pseudo_close; {close the top level pseudo file} var p,@!q: pointer; begin p:=link(pseudo_files); q:=info(pseudo_files); free_avail(pseudo_files); pseudo_files:=p; while q<>null do begin p:=q; q:=link(p); free_node(p,ho(info(p))); end; end; @ @= while pseudo_files<>null do pseudo_close; {flush pseudo files} @ @= primitive("readline",read_to_cs,1);@/ @!@:read_line_}{\.{\\readline} primitive@> @ @= else print_esc("readline") @ @= if j=1 then begin while loc<=limit do {current line not yet finished} begin cur_chr:=buffer[loc]; incr(loc); if cur_chr=" " then cur_tok:=space_token @+else cur_tok:=cur_chr+other_token; store_new_token(cur_tok); end; goto done; end @ The |cond| feature of \eTeX\ defines additional conditionals as well as the \.{\\unless} prefix. @d if_def_code=17 { `\.{\\ifdefined}' } @d if_cs_code=18 { `\.{\\ifcsname}' } @= primitive("unless",expand_after,1);@/ @!@:unless_}{\.{\\unless} primitive@> primitive("ifdefined",if_test,if_def_code); @!@:if_defined_}{\.{\\ifdefined} primitive@> primitive("ifcsname",if_test,if_cs_code); @!@:if_cs_name_}{\.{\\ifcsname} primitive@> @ @= else print_esc("unless") @ @= if_def_code:print_esc("ifdefined"); if_cs_code:print_esc("ifcsname"); @ The result of a boolean condition is reversed when the conditional is preceded by \.{\\unless}. @= begin get_token; if (cur_cmd=if_test)and(cur_chr<>if_case_code) then begin cur_chr:=cur_chr+unless_code; goto reswitch; end; print_err("You can't use `"); print_esc("unless"); print("' before `"); @.You can't use \\unless...@> print_cmd_chr(cur_cmd,cur_chr); print_char("'"); help1("Continue, and I'll forget that it ever happened."); back_error; end @ The conditional \.{\\ifdefined} tests if a control sequence is defined. We need to reset |scanner_status|, since \.{\\outer} control sequences are allowed, but we might be scanning a macro definition or preamble. @= if_def_code:begin save_scanner_status:=scanner_status; scanner_status:=normal; get_next; b:=(cur_cmd<>undefined_cs); scanner_status:=save_scanner_status; end; @ The conditional \.{\\ifcsname} is equivalent to \.{\{\\expandafter} \.{\}\\expandafter} \.{\\ifdefined} \.{\\csname}, except that no new control sequence will be entered into the hash table (once all tokens preceding the mandatory \.{\\endcsname} have been expanded). @= if_cs_code:begin n:=get_avail; p:=n; {head of the list of characters} repeat get_x_token; if cur_cs=0 then store_new_token(cur_tok); until cur_cs<>0; if cur_cmd<>end_cs_name then @; @; flush_list(n); b:=(eq_type(cur_cs)<>undefined_cs); end; @ @= m:=first; p:=link(n); while p<>null do begin if m>=max_buf_stack then begin max_buf_stack:=m+1; if max_buf_stack=buf_size then overflow("buffer size",buf_size); @:TeX capacity exceeded buffer size}{\quad buffer size@> end; buffer[m]:=info(p) mod @'400; incr(m); p:=link(p); end; if m>first+1 then cur_cs:=id_lookup(first,m-first) {|no_new_control_sequence| is |true|} else if m=first then cur_cs:=null_cs {the list is empty} else cur_cs:=single_base+buffer[first] {the list has length one} @ The |protected| feature of \eTeX\ defines the \.{\\protected} prefix command for macro definitions. Such macros are protected against expansions when lists of expanded tokens are built, e.g., for \.{\\edef} or during \.{\\write}. @= primitive("protected",prefix,8); @!@:protected_}{\.{\\protected} primitive@> @ @= else if chr_code=8 then print_esc("protected") @ \eTeX\ supports 256~classes of marks where \.{\\marks0} is a synonym for \.{\\mark}. Similarly there are 256~classes of topmarks etc. @= primitive("marks",mark,marks_code); @!@:marks_}{\.{\\marks} primitive@> primitive("topmarks",top_bot_mark,top_mark_code+marks_code); @!@:top_marks_}{\.{\\topmarks} primitive@> primitive("firstmarks",top_bot_mark,first_mark_code+marks_code); @!@:first_marks_}{\.{\\firstmarks} primitive@> primitive("botmarks",top_bot_mark,bot_mark_code+marks_code); @!@:bot_marks_}{\.{\\botmarks} primitive@> primitive("splitfirstmarks",top_bot_mark,split_first_mark_code+marks_code); @!@:split_first_marks_}{\.{\\splitfirstmarks} primitive@> primitive("splitbotmarks",top_bot_mark,split_bot_mark_code+marks_code); @!@:split_bot_marks_}{\.{\\splitbotmarks} primitive@> @ We have to declare |mark_class| as local variable for |initialize|. @= @!mark_class:eight_bits; {a mark class} @* \[54] System-dependent changes. @z %---------------------------------------