summaryrefslogtreecommitdiff
path: root/language/xettex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /language/xettex
Initial commit
Diffstat (limited to 'language/xettex')
-rw-r--r--language/xettex/cxet.ch2098
-rw-r--r--language/xettex/waits-xe.ch1979
2 files changed, 4077 insertions, 0 deletions
diff --git a/language/xettex/cxet.ch b/language/xettex/cxet.ch
new file mode 100644
index 0000000000..f8df0b4463
--- /dev/null
+++ b/language/xettex/cxet.ch
@@ -0,0 +1,2098 @@
+% Change file for TeX-XeT in C, derived from ctex.ch developed
+% by Tim Morgan, UC Irvine ICS Department
+% and adapted for TeX-Xet by Pierre MacKay, University of Washington
+
+% Modification History: (TeX-XeT.ch)
+% (4 /17/88) PAM revised to match revisions in ctex.ch
+% (2 /13/88) PAM Successfully compiled from TeX 2.9
+%
+% Modification History: (ctex.ch)
+%
+% (5 /28/86) ETM Started with TeX 2.0
+% (7 /3/87) ETM Brought up to TeX 2.2
+% (9 /26/87) ETM Brought up to TeX 2.3
+% (10/1/87) ETM Brought up to TeX 2.5
+% (12/21/87) ETM Brought up to TeX 2.7
+% (1 /14/88) ETM Brought up to TeX 2.9
+% (2 /20/88) PAM Revised format and module numbers
+% (3 /1 /88) ETM Eliminated some unused variables and unnecesary tests
+
+% NOTE: the module numbers in this change file refer to the published
+% text in TeX, the Program, Volume B. 1986
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [0] WEAVE: only print changes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x Tell WEAVE to print only the changes:
+ \def\?##1]{\hbox to 1in{\hfil##1.\ }}
+ }
+@y
+ \def\?##1]{\hbox{Changes to \hbox to 1em{\hfil##1}.\ }}
+ }
+\let\maybe=\iffalse
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1.2] banner line
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d banner=='This is TeX, Version 2.9' {printed when \TeX\ starts}
+@y
+@d banner=='This is TeX-XeT, C Version 2.9' {printed when \TeX\ starts}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1.4] program header
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+Actually the heading shown here is not quite normal: The |program| line
+does not mention any |output| file, because \ph\ would ask the \TeX\ user
+to specify a file name if |output| were specified here.
+@^system dependencies@>
+
+@d mtype==t@&y@&p@&e {this is a \.{WEB} coding trick:}
+@f mtype==type {`\&{mtype}' will be equivalent to `\&{type}'}
+@f type==true {but `|type|' will not be treated as a reserved word}
+
+@p @t\4@>@<Compiler directives@>@/
+program TEX; {all file names are defined dynamically}
+label @<Labels in the outer block@>@/
+@y
+
+@d mtype==t@&y@&p@&e {this is a \.{WEB} coding trick:}
+@d standard_input==i@&n@&p@&u@&t {and another}
+@f mtype==type {`\&{mtype}' will be equivalent to `\&{type}'}
+@f type==true {but `|type|' will not be treated as a reserved word}
+
+@p @t\4@>@<Compiler directives@>@/
+program TEXXET; {all file names are defined dynamically}
+@z
+
+@x
+@<Labels in the out...@>=
+start_of_TEX@t\hskip-2pt@>, end_of_TEX@t\hskip-2pt@>,@,final_end;
+ {key control points}
+@y
+@<Labels in the outer block@>=
+start_of_TEX@t\hskip-2pt@>, end_of_TEX@t\hskip-2pt@>,@,final_end;
+ {key control points}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1.7] debug..gubed, stat..tats
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Here we change these WEB symbols, which are used much as #ifdef's
+% in C, into something which will get translated into actual #ifdef's.
+@x
+@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
+@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
+@y
+@d debug==ifdef('DEBUG')
+@d gubed==endif('DEBUG')
+@z
+@x
+@d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering
+ usage statistics}
+@d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering
+ usage statistics}
+@y
+@d stat==ifdef('STAT')
+@d tats==endif('STAT')
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1.8] init..tini
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
+@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
+@y
+@d init==ifdef('INITEX')
+@d tini==endif('INITEX')
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1.9] compiler directives
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead}
+@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging}
+@y
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1.11] compile-time constants, use logical names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% doubled mem_max for C since UCI people are memory hogs
+% made dvi_buf_size=2*8192 for better BSD Unix I/O performance
+% enlarged various other datastructures
+@x
+@!mem_max=30000; {greatest index in \TeX's internal |mem| array;
+ must be strictly less than |max_halfword|;
+ must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
+@!mem_min=0; {smallest index in \TeX's internal |mem| array;
+ must be |min_halfword| or more;
+ must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
+@!buf_size=500; {maximum number of characters simultaneously present in
+ current lines of open files and in control sequences between
+ \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
+@!error_line=72; {width of context lines on terminal error messages}
+@!half_error_line=42; {width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|}
+@!max_print_line=79; {width of longest text lines output; should be at least 60}
+@!stack_size=200; {maximum number of simultaneous input sources}
+@!max_in_open=6; {maximum number of input files and error insertions that
+ can be going on simultaneously}
+@!font_max=75; {maximum internal font number; must not exceed |max_quarterword|
+ and must be at most |font_base+256|}
+@!font_mem_size=20000; {number of words of |font_info| for all fonts}
+@!param_size=60; {maximum number of simultaneous macro parameters}
+@!nest_size=40; {maximum number of semantic levels simultaneously active}
+@!max_strings=3000; {maximum number of strings; must not exceed |max_halfword|}
+@!string_vacancies=8000; {the minimum number of characters that should be
+ available for the user's control sequences and font names,
+ after \TeX's own error messages are stored}
+@!pool_size=32000; {maximum number of characters in strings, including all
+ error messages and help texts, and the names of all fonts and
+ control sequences; must exceed |string_vacancies| by the total
+ length of \TeX's own strings, which is currently about 23000}
+@!save_size=600; {space for saving values outside of current group; must be
+ at most |max_halfword|}
+@!trie_size=8000; {space for hyphenation patterns; should be larger for
+ \.{INITEX} than it is in production versions of \TeX}
+@!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8}
+@!file_name_size=40; {file names shouldn't be longer than this}
+@!pool_name='TeXformats:TEX.POOL ';
+ {string of length |file_name_size|; tells where the string pool appears}
+@y
+@!mem_max=65530; {greatest index in \TeX's internal |mem| array;
+ must be strictly less than |max_halfword|;
+ must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
+@!mem_min=0; {smallest index in \TeX's internal |mem| array;
+ must be |min_halfword| or more;
+ must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
+@!buf_size=500; {maximum number of characters simultaneously present in
+ current lines of open files and in control sequences between
+ \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
+@!error_line=79; {width of context lines on terminal error messages}
+@!half_error_line=50; {width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|}
+@!max_print_line=79; {width of longest text lines output; should be at least 60}
+@!stack_size=200; {maximum number of simultaneous input sources}
+@!max_in_open=15; {maximum number of input files and error insertions that
+ can be going on simultaneously}
+@!font_max=120; {maximum internal font number; must not exceed |max_quarterword|
+ and must be at most |font_base+256|}
+@!font_mem_size=36000; {number of words of |font_info| for all fonts}
+@!param_size=60; {maximum number of simultaneous macro parameters}
+@!nest_size=40; {maximum number of semantic levels simultaneously active}
+@!max_strings=4400; {maximum number of strings; must not exceed |max_halfword|}
+@!string_vacancies=15000; {the minimum number of characters that should be
+ available for the user's control sequences and font names,
+ after \TeX's own error messages are stored}
+@!pool_size=45000; {maximum number of characters in strings, including all
+ error messages and help texts, and the names of all fonts and
+ control sequences; must exceed |string_vacancies| by the total
+ length of \TeX's own strings, which is currently about 23000}
+@!save_size=2000; {space for saving values outside of current group; must be
+ at most |max_halfword|}
+@!trie_size=8000; {space for hyphenation patterns; should be larger for
+ \.{INITEX} than it is in production versions of \TeX}
+@!dvi_buf_size=16384; {size of the output buffer; must be a multiple of 8}
+@!file_name_size=1024; {file names can't be longer than this in 4.2BSD}
+@!pool_name='tex.pool';
+ {string of length |file_name_size|; tells where the string pool appears}
+@!mem_top=65530; {largest index in the |mem| array dumped by \.{INITEX};
+ must be substantially larger than |mem_bot|
+ and not greater than |mem_max|}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1.12] sensitive compile-time constants
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% For C we change mem_base and hi_mem_base to reflect our use of
+% 0-origin vs pc's use of negative-origin. Despite the fact that
+% these are "sensitive" constants, we're going to make mem_top a
+% #define in the C code for readability and ease of modification
+% (it's up above). Beware!
+@x
+@d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX};
+ must not be less than |mem_min|}
+@d mem_top==30000 {largest index in the |mem| array dumped by \.{INITEX};
+ must be substantially larger than |mem_bot|
+ and not greater than |mem_max|}
+@d font_base=0 {smallest internal font number; must not be less
+ than |min_quarterword|}
+@d hash_size=2100 {maximum number of control sequences; it should be at most
+ about |(mem_max-mem_min)/10|, but 2100 is already quite generous}
+@d hash_prime=1777 {a prime number equal to about 85\% of |hash_size|}
+@d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions}
+@y
+@d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX};
+ must not be less than |mem_min|}
+@d font_base=0 {smallest internal font number; must not be less
+ than |min_quarterword|}
+@d hash_size=3000 {maximum number of control sequences; it should be at most
+ about |(mem_max-mem_min)/10|, but 3000 is already quite generous}
+@d hash_prime=2551 {a prime number equal to about 85\% of |hash_size|}
+@d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1.16] Use C macros for incr()/decr()
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% By not defining these, they slip through into the C code, where we
+% may be able to generate more efficient code.
+@x
+@d incr(#) == #:=#+1 {increase a variable by unity}
+@d decr(#) == #:=#-1 {decrease a variable by unity}
+@y
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [1.18] Use 8-bit characters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Unix really deals in 8-bit characters
+@x
+@ Characters of text that have been converted to \TeX's internal form
+are said to be of type |ASCII_code|, which is a subrange of the integers.
+
+@<Types...@>=
+@!ASCII_code=0..127; {seven-bit numbers}
+
+@ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
+@y
+@ Characters of text that have been converted to \TeX's internal form
+are said to be of type |ASCII_code|, which is a subrange of the integers.
+
+@<Types...@>=
+@!ASCII_code=0..255; {eight-bit numbers}
+
+@ The original \PASCAL\ compiler was designed in the late 60s, when six-bit
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [2.23] all characters are legal
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Unlike the standard Unix TeX distribution, we allow all characters
+% as legal input, to support SAIL and MIT input files on occasion.
+@x
+@^character set dependencies@>
+@^system dependencies@>
+
+@<Set init...@>=
+for i:=1 to @'37 do xchr[i]:=' ';
+@y
+@^character set dependencies@>
+@^system dependencies@>
+
+The code shown here is intended to be used on systems
+where any ASCII character may appear in the input.
+
+@<Set initial values...@>=
+for i:=1 to @'37 do xchr[i]:=chr(i);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3.25] file types
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+The program actually makes use also of a third kind of file, called a
+|word_file|, when dumping and reloading base information for its own
+initialization. We shall define a word file later; but it will be possible
+for us to specify simple operations on word files before they are defined.
+
+@y
+I/O in C is done using standard I/O. We will define the path numbers
+in an include file for C which are used in searching for files to be
+read. We'll define all the file types in C also.
+@z
+
+@x
+@!alpha_file=packed file of text_char; {files that contain textual data}
+@!byte_file=packed file of eight_bits; {files that contain binary data}
+@y
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3.26] add real_name_of_file array
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+is crucial for our purposes. We shall assume that |name_of_file| is a variable
+of an appropriate type such that the \PASCAL\ run-time system being used to
+implement \TeX\ can open a file whose external name is specified by
+|name_of_file|.
+@^system dependencies@>
+
+@<Glob...@>=
+@!name_of_file:packed array[1..file_name_size] of char;@;@/
+ {on some systems this may be a \&{record} variable}
+@!name_length:0..file_name_size;@/{this many characters are actually
+ relevant in |name_of_file| (the rest are blank)}
+@y
+is crucial for our purposes. We shall assume that |name_of_file| is a variable
+of an appropriate type such that the \PASCAL\ run-time system being used to
+implement \TeX\ can open a file whose external name is specified by
+|name_of_file|.
+The Berkeley {\mc UNIX} version uses search paths to look for files to open.
+We use |real_name_of_file| to hold the |name_of_file| with a directory
+name from the path in front of it.
+@^system dependencies@>
+
+@<Glob...@>=
+@!name_of_file,@!real_name_of_file:packed array[1..file_name_size] of char;
+@;@/
+@!name_length:0..file_name_size;@/{this many characters are actually
+ relevant in |name_of_file| (the rest are blank)}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3.27] file opening
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ The \ph\ compiler with which the present version of \TeX\ was prepared has
+extended the rules of \PASCAL\ in a very convenient way. To open file~|f|,
+we can write
+$$\vbox{\halign{#\hfil\qquad&#\hfil\cr
+|reset(f,@t\\{name}@>,'/O')|&for input;\cr
+|rewrite(f,@t\\{name}@>,'/O')|&for output.\cr}}$$
+The `\\{name}' parameter, which is of type `{\bf packed array
+$[\langle\\{any}\rangle]$ of \\{char}}', stands for the name of
+the external file that is being opened for input or output.
+Blank spaces that might appear in \\{name} are ignored.
+
+The `\.{/O}' parameter tells the operating system not to issue its own
+error messages if something goes wrong. If a file of the specified name
+cannot be found, or if such a file cannot be opened for some other reason
+(e.g., someone may already be trying to write the same file), we will have
+|@!erstat(f)<>0| after an unsuccessful |reset| or |rewrite|. This allows
+\TeX\ to undertake appropriate corrective action.
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+
+\TeX's file-opening procedures return |false| if no file identified by
+|name_of_file| could be opened.
+
+@d reset_OK(#)==erstat(#)=0
+@d rewrite_OK(#)==erstat(#)=0
+
+@p function a_open_in(var f:alpha_file):boolean;
+ {open a text file for input}
+begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f);
+end;
+@#
+function a_open_out(var f:alpha_file):boolean;
+ {open a text file for output}
+begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f);
+end;
+@#
+function b_open_in(var f:byte_file):boolean;
+ {open a binary file for input}
+begin reset(f,name_of_file,'/O'); b_open_in:=reset_OK(f);
+end;
+@#
+function b_open_out(var f:byte_file):boolean;
+ {open a binary file for output}
+begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f);
+end;
+@#
+function w_open_in(var f:word_file):boolean;
+ {open a word file for input}
+begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f);
+end;
+@#
+function w_open_out(var f:word_file):boolean;
+ {open a word file for output}
+begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f);
+end;
+@y
+@ All of the file opening functions will be defined as macros in C.
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3.28] reserve file closure for C routines
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ Files can be closed with the \ph\ routine `|close(f)|', which
+@^system dependencies@>
+should be used when all input or output with respect to |f| has been completed.
+This makes |f| available to be opened again, if desired; and if |f| was used for
+output, the |close| operation makes the corresponding external file appear
+on the user's area, ready to be read.
+
+These procedures should not generate error messages if a file is
+being closed before it has been successfully opened.
+
+@p procedure a_close(var f:alpha_file); {close a text file}
+begin close(f);
+end;
+@#
+procedure b_close(var f:byte_file); {close a binary file}
+begin close(f);
+end;
+@#
+procedure w_close(var f:word_file); {close a word file}
+begin close(f);
+end;
+@y
+@ And all file closing as well.
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3.31] Make input_ln an external C routine
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
+ {inputs the next line or returns |false|}
+var last_nonblank:0..buf_size; {|last| with trailing blanks removed}
+begin if bypass_eoln then if not eof(f) then get(f);
+ {input the first character of the line into |f^|}
+last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
+if eof(f) then input_ln:=false
+else begin last_nonblank:=first;
+ while not eoln(f) do
+ begin if last>=max_buf_stack then
+ begin max_buf_stack:=last+1;
+ if max_buf_stack=buf_size then
+ overflow("buffer size",buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+ end;
+ buffer[last]:=xord[f^]; get(f); incr(last);
+ if buffer[last-1]<>" " then last_nonblank:=last;
+ end;
+ last:=last_nonblank; input_ln:=true;
+ end;
+end;
+@y
+We'll get inputln from an external C module, coded for efficiency
+directly in C.
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3.32] term_in/out are input,output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ The user's terminal acts essentially like other files of text, except
+that it is used both for input and for output. When the terminal is
+considered an input file, the file variable is called |term_in|, and when it
+is considered an output file the file variable is |term_out|.
+@^system dependencies@>
+
+@<Glob...@>=
+@!term_in:alpha_file; {the terminal as an input file}
+@!term_out:alpha_file; {the terminal as an output file}
+@y
+@ The user's terminal acts essentially like other files of text, except
+that it is used both for input and for output. When the terminal is
+considered an input file, the file is called |term_in|, and when it
+is considered an output file the file is |term_out|.
+For Berkeley {\mc UNIX} we use |standard_input| and |output| for these
+files, as were declared in the program header. The former name
+|standard_input| was defined using a web trick so that ``input'' is
+produced in the Pascal file. In C, ``input'' and ``output'' will
+be defined as ``stdin'' and ``stdout,'' respectively.
+
+@d term_in==standard_input {the terminal as an input file}
+@d term_out==output {the terminal as an output file}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3.33] don't need to open terminal files
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ Here is how to open the terminal files
+in \ph. The `\.{/I}' switch suppresses the first |get|.
+@^system dependencies@>
+
+@d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input}
+@d t_open_out==rewrite(term_out,'TTY:','/O') {open the terminal for text output}
+@y
+@ Here is how to open the terminal files. |t_open_out| does nothing.
+|t_open_in|, on the other hand, does the work of "rescanning", or getting
+any command line arguments the user has provided. It's coded in C
+externally.
+
+@d t_open_out == {output already open for text output}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3.34] flushing output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+these operations can be specified in \ph:
+@^system dependencies@>
+
+@d update_terminal == break(term_out) {empty the terminal output buffer}
+@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer}
+@d wake_up_terminal == do_nothing {cancel the user's cancellation of output}
+@y
+these operations can be specified with {\mc UNIX}. |update_terminal|
+does an fflush, since that's easy. |wake_up_terminal| and |clear_terminal|
+are specified in external C routines, if desired. We call fflush()
+termflush() here, and fix it with a macro in C, so we can cast it to (void)
+to keep lint quiet.
+@^system dependencies@>
+
+@d update_terminal == termflush(output)
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [3.37] rescanning the command line
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ The following program does the required initialization
+without retrieving a possible command line.
+It should be clear how to modify this routine to deal with command lines,
+if the system permits them.
+@^system dependencies@>
+
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+begin t_open_in;
+loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
+@.**@>
+ if not input_ln(term_in,true) then {this shouldn't happen}
+ begin write_ln(term_out);
+ write(term_out,'! End of file on the terminal... why?');
+@.End of file on the terminal@>
+ init_terminal:=false; return;
+ end;
+ loc:=first;
+ while (loc<last)and(buffer[loc]=" ") do incr(loc);
+ if loc<last then
+ begin init_terminal:=true;
+ return; {return unless the line was all blank}
+ end;
+ write_ln(term_out,'Please type the name of your input file.');
+ end;
+exit:end;
+@y
+@ The following program does the required initialization.
+Iff anything has been specified on the command line, then |t_open_in|
+will return with last > first.
+@^system dependencies@>
+
+@p
+function init_terminal:boolean; {gets the terminal input started}
+label exit;
+
+var
+ i, j : integer;
+
+begin
+ t_open_in;
+ if last > first then begin
+ loc := first;
+ while (loc < last) and (buffer[loc]=' ') do
+ incr(loc);
+ if loc < last then begin
+ init_terminal := true;
+ goto exit;
+ end;
+ end;
+ loop@+begin
+ wake_up_terminal; write(term_out, '**'); update_terminal;
+@.**@>
+ if not input_ln(term_in,true) then begin {this shouldn't happen}
+ write_ln(term_out);
+ write(term_out, '! End of file on the terminal... why?');
+@.End of file on the terminal@>
+ init_terminal:=false;
+ return;
+ end;
+
+ loc:=first;
+ while (loc<last)and(buffer[loc]=" ") do
+ incr(loc);
+
+ if loc<last then begin
+ init_terminal:=true;
+ return; {return unless the line was all blank}
+ end;
+ write_ln(term_out, 'Please type the name of your input file.');
+ end;
+exit:
+end;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [4.51] a_open_in of pool file needs path specifier
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+name_of_file:=pool_name; {we needn't set |name_length|}
+if a_open_in(pool_file) then
+@y
+vstrcpy(name_of_file+1, pool_name); {this is how you copy strings in C}
+if a_open_in(pool_file,pool_path_spec) then
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [4.51,52,53] make TEX.POOL lowercase in messages; fix reading it
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+else bad_pool('! I can''t read TEX.POOL.')
+@y
+else begin
+ {Like |bad_pool|, but must not close file if we never opened it}
+ wake_up_terminal; write_ln(term_out, '! I can''t read tex.pool.');
+ get_strings_started:= false; return;
+end
+@z
+@x
+begin if eof(pool_file) then bad_pool('! TEX.POOL has no check sum.');
+@.TEX.POOL has no check sum@>
+read(pool_file,m,n); {read two digits of string length}
+@y
+begin if eof(pool_file) then bad_pool('! tex.pool has no check sum.');
+@.TEX.POOL has no check sum@>
+read(pool_file,m); read(pool_file,n); {read two digits of string length}
+@z
+@x
+ bad_pool('! TEX.POOL line doesn''t begin with two digits.');
+@y
+ bad_pool('! tex.pool line doesn''t begin with two digits.');
+@z
+@x
+ bad_pool('! TEX.POOL check sum doesn''t have nine digits.');
+@y
+ bad_pool('! tex.pool check sum doesn''t have nine digits.');
+@z
+@x
+done: if a<>@$ then bad_pool('! TEX.POOL doesn''t match; TANGLE me again.');
+@y
+done: if a<>@$ then bad_pool('! tex.pool doesn''t match; tangle me again.');
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [6.81] Eliminate nonlocal goto
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Pastel can handle nonlocal goto, but the Unix Vax asm/linker don't
+% automatically use the long-range jump instruction that it requires.
+% Plus, it's nicer just to do an exit with the appropriate status code
+% under Unix. We call it "uexit" because there's a WEB symbol called
+% "exit" already. We use a C macro to change uexit() back to exit().
+@x
+@<Error hand...@>=
+procedure jump_out;
+begin goto end_of_TEX;
+end;
+@y
+@d do_final_end==begin
+ update_terminal;
+ ready_already:=0;
+ if (history <> spotless) and (history <> warning_issued) then
+ uexit(1)
+ else
+ uexit(0);
+ end
+@<Error hand...@>=
+procedure jump_out;
+begin
+close_files_and_terminate;
+do_final_end;
+end;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [6.84] switch-to-editor option
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+line ready to be edited. But such an extension requires some system
+wizardry, so the present implementation simply types out what file should be
+edited and the relevant line number.
+@^system dependencies@>
+
+There is a secret `\.D' option available when the debugging routines have
+not been commented out.
+@^debugging@>
+@y
+line ready to be edited.
+We do this by calling the external procedure |calledit| with a pointer to
+the filename, its length, and the line number.
+However, here we just set up the variables that will be used as arguments,
+since we don't want to do the switch-to-editor until after TeX has closed
+its files.
+@^system dependencies@>
+
+There is a secret `\.D' option available when the debugging routines have
+not been commented out.
+@^debugging@>
+@d edit_file==input_stack[base_ptr]
+@z
+@x
+"E": if base_ptr>0 then
+ begin print_nl("You want to edit file ");
+@.You want to edit file x@>
+ print(input_stack[base_ptr].name_field);
+ print(" at line "); print_int(line);
+ interaction:=scroll_mode; jump_out;
+@y
+"E": if base_ptr>0 then
+ begin
+ edit_name_start:=str_start[edit_file.name_field];
+ edit_name_length:=str_start[edit_file.name_field+1] -
+ str_start[edit_file.name_field];
+ edit_line:=line;
+ jump_out;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [7.109] Handle definition of glue_ratio in an include file as a typedef
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@!glue_ratio=real; {one-word representation of a glue expansion factor}
+@y
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [8.112] Efficiency!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `|x+0|' and `|x-0|', if these
+macros are simplified in the obvious way when |min_quarterword=0|.
+@^inner loop@>@^system dependencies@>
+
+@d qi(#)==#+min_quarterword
+ {to put an |eight_bits| item into a quarterword}
+@d qo(#)==#-min_quarterword
+ {to take an |eight_bits| item out of a quarterword}
+@d hi(#)==#+min_halfword
+ {to put a sixteen-bit item into a halfword}
+@d ho(#)==#-min_halfword
+ {to take a sixteen-bit item from a halfword}
+@y
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `|x+0|' and `|x-0|', if these
+macros are simplified in the obvious way when |min_quarterword=0|.
+So they have been simplified here in the obvious way.
+@^inner loop@>@^system dependencies@>
+
+@d qi(#)==# {to put an |eight_bits| item into a quarterword}
+@d qo(#)==# {to take an |eight_bits| item from a quarterword}
+@d hi(#)==# {to put a sixteen-bit item into a halfword}
+@d ho(#)==# {to take a sixteen-bit item from a halfword}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [8.113] Again, these are defined in an include file, coded by hand in C
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@!quarterword = min_quarterword..max_quarterword; {1/4 of a word}
+@!halfword=min_halfword..max_halfword; {1/2 of a word}
+@!two_choices = 1..2; {used when there are two variants in a record}
+@!four_choices = 1..4; {used when there are four variants in a record}
+@!two_halves = packed record@;@/
+ @!rh:halfword;
+ case two_choices of
+ 1: (@!lh:halfword);
+ 2: (@!b0:quarterword; @!b1:quarterword);
+ end;
+@!four_quarters = packed record@;@/
+ @!b0:quarterword;
+ @!b1:quarterword;
+ @!b2:quarterword;
+ @!b3:quarterword;
+ end;
+@!memory_word = record@;@/
+ case four_choices of
+ 1: (@!int:integer);
+ 2: (@!gr:glue_ratio);
+ 3: (@!hh:two_halves);
+ 4: (@!qqqq:four_quarters);
+ end;
+@!word_file = file of memory_word;
+@y
+@!two_choices = 1..2; {used when there are two variants in a record}
+@!four_choices = 1..4; {used when there are four variants in a record}
+@=#include "memory.h";@>
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [9.116] Change mem to zmem
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% We do this so that we can define mem to be a register pointer to the
+% memory array for speed.
+@x
+@!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area}
+@y
+@!zmem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [9.127] Fix casting problem in C
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% There are several of these. They come from the rules C uses for
+% comparing signed and unsigned quantities. Just doing the comparison
+% can result in incorrect evaluation wrt the way Pascal would do it.
+@x
+if r>p+1 then @<Allocate from the top of node |p| and |goto found|@>;
+@y
+if r>toint(p+1) then @<Allocate from the top of node |p| and |goto found|@>;
+@z
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [10.161] make room for a new creation procedure (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+\TeX's other algorithms intact.
+@^system dependencies@>
+@y
+\TeX's other algorithms intact.
+@^system dependencies@>
+@p@<Declare functions needed for special kinds of nodes@>
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [11.165] fix the word "free" so that it doesn't conflict with the C routine
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+been included. (You may want to decrease the size of |mem| while you
+@^debugging@>
+are debugging.)
+@y
+been included. (You may want to decrease the size of |mem| while you
+@^debugging@>
+are debugging.)
+
+@d free==free_arr
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [12.186] glue_ratio fix
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+floating point underflow on the author's computer.
+@^system dependencies@>
+@^dirty \PASCAL@>
+
+@<Display the value of |glue_set(p)|@>=
+g:=float(glue_set(p));
+if (g<>float_constant(0))and(glue_sign(p)<>normal) then
+ begin print(", glue set ");
+ if glue_sign(p)=shrinking then print("- ");
+ if abs(mem[p+glue_offset].int)<@'4000000 then print("?.?")
+ else if abs(g)>float_constant(20000) then
+ begin if g>float_constant(0) then print_char(">")
+ else print("< -");
+ print_glue(20000*unity,glue_order(p),0);
+ end
+ else print_glue(round(unity*g),glue_order(p),0);
+@^real multiplication@>
+ end
+@y
+floating point underflow on the author's computer.
+@^system dependencies@>
+@^dirty \PASCAL@>
+
+@<Display the value of |glue_set(p)|@>=
+g:=float(glue_set(p));
+if (g<>float_constant(0))and(glue_sign(p)<>normal) then
+ begin print(", glue set ");
+ if glue_sign(p)=shrinking then print("- ");
+ { The Unix "pc" folks removed this restriction with a remark that
+ invalid bit patterns were vanishingly improbable, so we follow
+ their example without really understanding it.
+ |if abs(mem[p+glue_offset].int)<@'4000000 then print('?.?')|
+ |else| }
+ if fabs(g)>float_constant(20000) then
+ begin if g>float_constant(0) then print_char(">")
+ else print("< -");
+ print_glue(20000*unity,glue_order(p),0);
+ end
+ else print_glue(round(unity*g),glue_order(p),0);
+@^real multiplication@>
+ end
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [15.208,209] New command code (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d max_non_prefixed_command=69 {largest command code that can't be \.{\\global}}
+
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+@d toks_register=70 {token list register ( \.{\\toks} )}
+@d assign_toks=71 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)}
+@d assign_int=72 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)}
+@d assign_dimen=73 {user-defined length ( \.{\\hsize}, etc.~)}
+@d assign_glue=74 {user-defined glue ( \.{\\baselineskip}, etc.~)}
+@d assign_mu_glue=75 {user-defined muglue ( \.{\\thinmuskip}, etc.~)}
+@d assign_font_dimen=76 {user-defined font dimension ( \.{\\fontdimen} )}
+@d assign_font_int=77 {user-defined font integer ( \.{\\hyphenchar},
+ \.{\\skewchar} )}
+@d set_aux=78 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )}
+@d set_prev_graf=79 {specify state info ( \.{\\prevgraf} )}
+@d set_page_dimen=80 {specify state info ( \.{\\pagegoal}, etc.~)}
+@d set_page_int=81 {specify state info ( \.{\\deadcycles},
+ \.{\\insertpenalties} )}
+@d set_box_dimen=82 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )}
+@d set_shape=83 {specify fancy paragraph shape ( \.{\\parshape} )}
+@d def_code=84 {define a character code ( \.{\\catcode}, etc.~)}
+@d def_family=85 {declare math fonts ( \.{\\textfont}, etc.~)}
+@d set_font=86 {set current font ( font identifiers )}
+@d def_font=87 {define a font file ( \.{\\font} )}
+@d register=88 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
+@d max_internal=88 {the largest code that can follow \.{\\the}}
+@d advance=89 {advance a register or parameter ( \.{\\advance} )}
+@d multiply=90 {multiply a register or parameter ( \.{\\multiply} )}
+@d divide=91 {divide a register or parameter ( \.{\\divide} )}
+@d prefix=92 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
+@d let=93 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
+@d shorthand_def=94 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
+@d read_to_cs=95 {read into a control sequence ( \.{\\read} )}
+@d def=96 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
+@d set_box=97 {set a box ( \.{\\setbox} )}
+@d hyph_data=98 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
+@d set_interaction=99 {define level of interaction ( \.{\\batchmode}, etc.~)}
+@d max_command=99 {the largest command code seen at |big_switch|}
+@y
+@d LR=70 {text direction ( \.{\\beginL}, \.{\\beginR}, \.{\\endL}, \.{\\endR} )}
+@d max_non_prefixed_command=70 {largest command code that can't be \.{\\global}}
+
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+@d toks_register=71 {token list register ( \.{\\toks} )}
+@d assign_toks=72 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)}
+@d assign_int=73 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)}
+@d assign_dimen=74 {user-defined length ( \.{\\hsize}, etc.~)}
+@d assign_glue=75 {user-defined glue ( \.{\\baselineskip}, etc.~)}
+@d assign_mu_glue=76 {user-defined muglue ( \.{\\thinmuskip}, etc.~)}
+@d assign_font_dimen=77 {user-defined font dimension ( \.{\\fontdimen} )}
+@d assign_font_int=78 {user-defined font integer ( \.{\\hyphenchar},
+ \.{\\skewchar} )}
+@d set_aux=79 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )}
+@d set_prev_graf=80 {specify state info ( \.{\\prevgraf} )}
+@d set_page_dimen=81 {specify state info ( \.{\\pagegoal}, etc.~)}
+@d set_page_int=82 {specify state info ( \.{\\deadcycles},
+ \.{\\insertpenalties} )}
+@d set_box_dimen=83 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )}
+@d set_shape=84 {specify fancy paragraph shape ( \.{\\parshape} )}
+@d def_code=85 {define a character code ( \.{\\catcode}, etc.~)}
+@d def_family=86 {declare math fonts ( \.{\\textfont}, etc.~)}
+@d set_font=87 {set current font ( font identifiers )}
+@d def_font=88 {define a font file ( \.{\\font} )}
+@d register=89 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
+@d max_internal=89 {the largest code that can follow \.{\\the}}
+@d advance=90 {advance a register or parameter ( \.{\\advance} )}
+@d multiply=91 {multiply a register or parameter ( \.{\\multiply} )}
+@d divide=92 {divide a register or parameter ( \.{\\divide} )}
+@d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
+@d let=94 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
+@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
+@d read_to_cs=96 {read into a control sequence ( \.{\\read} )}
+@d def=97 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
+@d set_box=98 {set a box ( \.{\\setbox} )}
+@d hyph_data=99 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
+@d set_interaction=100 {define level of interaction ( \.{\\batchmode}, etc.~)}
+@d max_command=100 {the largest command code seen at |big_switch|}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [17.241] fix_date_and_time
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ The following procedure, which is called just before \TeX\ initializes its
+input and output, establishes the initial values of the date and time.
+@^system dependencies@>
+Since standard \PASCAL\ cannot provide such information, something special
+is needed. The program here simply specifies July 4, 1776, at noon; but
+users probably want a better approximation to the truth.
+
+@p procedure fix_date_and_time;
+begin time:=12*60; {minutes since midnight}
+day:=4; {fourth day of the month}
+month:=7; {seventh month of the year}
+year:=1776; {Anno Domini}
+end;
+@y
+@ The following procedure, which is called just before \TeX\ initializes its
+input and output, establishes the initial values of the date and time.
+It calls a macro-defined |date_and_time| routine. |date_and_time|
+("dateandtime") in turn is a C macro, which calls |get_date_and_time|, passing
+it the addresses of the day, month, etc., so they can be set by the
+routine. |get_date_and_time| also sets up interrupt catching if that
+is conditionally compiled in the C code.
+@^system dependencies@>
+
+@d fix_date_and_time==date_and_time(time,day,month,year)
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [17.253] Change eqtb to zeqtb
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@!eqtb:array[active_base..eqtb_size] of memory_word;
+@y
+@!zeqtb:array[active_base..eqtb_size] of memory_word;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [23.331] use a different for loop index, local to tex_body
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+first:=buf_size; repeat buffer[first]:=0; decr(first); until first=0;
+@y
+bufindx:=buf_size; repeat buffer[bufindx]:=0; decr(bufindx); until bufindx=0;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.513] area and extension rules
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ The file names we shall deal with for illustrative purposes have the
+following structure: If the name contains `\.>' or `\.:', the file area
+consists of all characters up to and including the final such character;
+otherwise the file area is null. If the remaining file name contains
+`\..', the file extension consists of all such characters from the first
+remaining `\..' to the end, otherwise the file extension is null.
+@^system dependencies@>
+
+We can scan such file names easily by using two global variables that keep track
+of the occurrences of area and extension delimiters:
+
+@<Glob...@>=
+@!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any}
+@!ext_delimiter:pool_pointer; {the relevant `\..', if any}
+@y
+@ The file names we shall deal with for illustrative purposes have the
+following structure: If the name contains `\./', the file area
+consists of all characters up to and including the final such character;
+otherwise the file area is null. If the remaining file name contains
+`\..', the file extension consists of all such characters from the first
+remaining `\..' to the end, otherwise the file extension is null.
+@^system dependencies@>
+
+We can scan such file names easily by using two global variables that keep
+track of the occurrences of area and extension delimiters:
+
+@<Glob...@>=
+@!area_delimiter:pool_pointer; {the most recent `\./', if any}
+@!ext_delimiter:pool_pointer; {the most recent `\..', if any}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.514] TEX area directories
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d TEX_area=="TeXinputs:"
+@.TeXinputs@>
+@d TEX_font_area=="TeXfonts:"
+@.TeXfonts@>
+@y
+We'll handle the path stuff in an external C module.
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.516] more_name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+else begin if (c=">")or(c=":") then
+@y
+else begin if (c="/") then
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.520] default format
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d format_default_length=20 {length of the |TEX_format_default| string}
+@d format_area_length=11 {length of its area part}
+@d format_ext_length=4 {length of its `\.{.fmt}' part}
+@y
+Under Berkeley {\mc UNIX} we don't give the area part, instead depending
+on the path searching that will happen during file opening. This doesn't
+really matter, since we change TEXformatdefault to a char * anyway.
+
+@d format_default_length=9 {length of the |TEX_format_default| string}
+@d format_area_length=0 {length of its area part}
+@d format_ext_length=4 {length of its `\.{.fmt}' part}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.521] plain format location
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@!TEX_format_default:packed array[1..format_default_length] of char;
+
+@ @<Set init...@>=
+TEX_format_default:='TeXformats:plain.fmt';
+@y
+@!TEX_format_default:c_char_pointer;
+
+@ @<Set init...@>=
+TEX_format_default := ' plain.fmt';
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.524] format file opening: only try once, with path search
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+ pack_buffered_name(0,loc,j-1); {try first without the system file area}
+ if w_open_in(fmt_file) then goto found;
+ pack_buffered_name(format_area_length,loc,j-1);
+ {now try the system format file area}
+ if w_open_in(fmt_file) then goto found;
+@y
+ pack_buffered_name(0,loc,j-1);
+ if w_open_in(fmt_file) then goto found;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.525] make_name_string
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+which simply makes a \TeX\ string from the value of |name_of_file|, should
+ideally be changed to deduce the full name of file~|f|, which is the file
+most recently opened, if it is possible to do this in a \PASCAL\ program.
+@^system dependencies@>
+
+This routine might be called after string memory has overflowed, hence
+we dare not use `|str_room|'.
+
+@p function make_name_string:str_number;
+var k:1..file_name_size; {index into |name_of_file|}
+begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings) then
+ make_name_string:="?"
+else begin for k:=1 to name_length do append_char(xord[name_of_file[k]]);
+ make_name_string:=make_string;
+ end;
+end;
+function a_make_name_string(var f:alpha_file):str_number;
+begin a_make_name_string:=make_name_string;
+end;
+function b_make_name_string(var f:byte_file):str_number;
+begin b_make_name_string:=make_name_string;
+end;
+function w_make_name_string(var f:word_file):str_number;
+begin w_make_name_string:=make_name_string;
+end;
+@y
+which simply makes a \TeX\ string from the value of |name_of_file|, should
+ideally be changed to deduce the full name of file~|f|, if it is
+possible to do this in a \PASCAL\ program.
+
+With the Berkeley {\mc UNIX} version, we know that |real_name_of_file|
+contains |name_of_file| prepended with the directory name that was found
+by path searching.
+
+If |real_name_of_file| starts with |'./'|, we don't use that part of the
+name, since {\mc UNIX} users understand that.
+@^system dependencies@>
+
+@p function make_name_string:str_number;
+var k,@!kstart:1..file_name_size; {index into |name_of_file|}
+begin
+k:=1;
+while (k<file_name_size) and (xord[real_name_of_file[k]]<>" ") do
+ incr(k);
+name_length:=k-1; {the real |name_length|}
+str_room(name_length);
+if (xord[real_name_of_file[1]]=".") and (xord[real_name_of_file[2]]="/") then
+ kstart:=3
+else
+ kstart:=1;
+for k:=kstart to name_length do append_char(xord[real_name_of_file[k]]);
+make_name_string:=make_string;
+end;
+function a_make_name_string(f:alpha_file):str_number;
+begin a_make_name_string:=make_name_string;
+end;
+function b_make_name_string(f:byte_file):str_number;
+begin b_make_name_string:=make_name_string;
+end;
+init function w_make_name_string(f:word_file):str_number;
+begin w_make_name_string:=make_name_string;
+end;@+tini@/
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.534] Adjust for C string conventions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+@x
+@!months:packed array [1..36] of char; {abbreviations of month names}
+@y
+@!months:c_char_pointer;
+@z
+
+@x
+months:='JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC';
+@y
+months := ' JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC';
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.537] a_open_in of \input file needs path selector
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+ if a_open_in(cur_file) then goto done;
+ if cur_area="" then
+ begin pack_file_name(cur_name,TEX_area,cur_ext);
+ if a_open_in(cur_file) then goto done;
+ end;
+@y
+ if a_open_in(cur_file,input_path_spec) then goto done;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [29.537] get rid of return of name to string pool
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% This was in the Pastel changefile. I don't know what it does.
+@x
+if name=str_ptr-1 then {we can conserve string pool space now}
+ begin flush_string; name:=cur_name;
+ end;
+@y
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [30.563] Fix TFM file opening
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+file_opened:=false;
+if aire="" then pack_file_name(nom,TEX_font_area,".tfm")
+else pack_file_name(nom,aire,".tfm");
+if not b_open_in(tfm_file) then abort;
+file_opened:=true
+@y
+file_opened:=false;
+pack_file_name(nom,aire,".tfm");
+if not b_open_in(tfm_file) then abort;
+file_opened:=true
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [30.564] reading the tfm file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% As a special case, whenever we open a tfm file, we read its first
+% byte into "tfm_temp" right away. TeX looks at "fbyte" before calling
+% "fget", so it ends up seeing every byte. This is Pascal-like I/O.
+@x
+@d fget==get(tfm_file)
+@d fbyte==tfm_file^
+@y
+@d fget==tfm_temp:=getc(tfm_file)
+@d fbyte==tfm_temp
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [31.585-586] new DVI opcodes (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+\yskip\noindent Commands 250--255 are undefined at the present time.
+
+@ @d set_char_0=0 {typeset character 0 and move right}
+@y
+\yskip\hang|begin_reflect| 250. Begin a (possibly recursive) reflected segment.
+
+\yskip\hang|end_reflect| 251. End a (possibly recursive) reflected segment.
+
+\yskip\noindent Commands 250--255 are undefined in normal \.{DVI} files,
+but 250 and 251 are permitted in the special `\.{DVI-IVD}' files
+produced by this variant of \TeX.
+
+@ @d begin_reflect=250 {begin a reflected segment (not normally allowed)}
+@d end_reflect=251 {end a reflected segment (not normally allowed)}
+@d set_char_0=0 {typeset character 0 and move right}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [32.597] write_dvi
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
+|write_dvi(a,b)|. For best results, this procedure should be optimized to
+run as fast as possible on each particular system, since it is part of
+\TeX's inner loop. It is safe to assume that |a| and |b+1| will both be
+multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on
+many machines to use efficient methods to pack four bytes per word and to
+output an array of words with one system call.
+@^system dependencies@>
+@^inner loop@>
+@^defecation@>
+
+@p procedure write_dvi(@!a,@!b:dvi_index);
+var k:dvi_index;
+begin for k:=a to b do write(dvi_file,dvi_buf[k]);
+end;
+@y
+@ In C, we use a macro to call fwrite() or write() directly, writing all
+the bytes to be written in one shot. Much better even than writing four
+bytes at a time.
+@^system dependencies@>
+@^inner loop@>
+@^defecation@>
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [32.638] changes to ship_out (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+begin if tracing_output>0 then
+@y
+begin LR_ptr:=get_avail; info(LR_ptr):=0; {|begin_L_code| at outer level}
+if tracing_output>0 then
+@z
+@x (module 639)
+flush_node_list(p);
+@y
+flush_node_list(p); @<Flush the LR stack@>;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [33.649] hpack changes (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+begin r:=get_node(box_node_size); type(r):=hlist_node;
+@y
+@!LR_ptr,@!LR_tmp:pointer; {for LR stack maintenance}
+@!LR_problems:integer; {counts missing begins and ends}
+begin LR_ptr:=null; LR_problems:=0;
+r:=get_node(box_node_size); type(r):=hlist_node;
+@z
+@x (module 649, continued)
+exit: hpack:=r;
+@y
+exit: @<Check for LR anomalies at the end of |hpack|@>;
+hpack:=r;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [38.859] Fix a C casting/expression evaluation problem
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+if abs(fit_class-fitness(r))>1 then d:=d+adj_demerits
+@y
+if abs(toint(fit_class)-toint(fitness(r)))>1 then d:=d+adj_demerits
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [39.877] post_line_break stuff (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+begin @<Reverse the links of the relevant passive nodes, setting |cur_p| to the
+@y
+@!LR_ptr,@!LR_tmp:pointer; {for LR stack maintenance}
+begin LR_ptr:=null;
+ @<Reverse the links of the relevant passive nodes, setting |cur_p| to the
+@z
+@x (module 877, continued)
+prev_graf:=best_line-1;
+@y
+prev_graf:=best_line-1;
+@<Flush the LR stack@>;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [39.880] post_line_break stuff continued(TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x (module 880)
+@<Modify the end of the line to reflect the nature of the break and to include
+ \.{\\rightskip}; also set the proper value of |disc_break|@>;
+@y
+@<Insert LR nodes at the beginning of the current line@>;
+@<Adjust the LR stack based on LR nodes in this line@>;
+@<Modify the end of the line to reflect the nature of the break and to include
+ \.{\\rightskip}; also set the proper value of |disc_break|@>;
+@<Insert LR nodes at the end of the current line@>;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [43.944] Fix a C casting/expression evaluation problem
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+begin h:=abs(n+313*d+361*v) mod trie_op_hash_size;
+@y
+begin h:=abs(toint(n)+313*toint(d)+361*toint(v)) mod trie_op_hash_size;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [43.947] Fix a C casting/expression evaluation problem
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+begin h:=abs(trie_c[p]+1009*trie_o[p]+@|
+ 2718*trie_l[p]+3142*trie_r[p]) mod trie_size;
+@y
+begin h:=abs(toint(trie_c[p])+1009*toint(trie_o[p])+@|
+ 2718*toint(trie_l[p])+3142*toint(trie_r[p])) mod trie_size;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [47.1090] new horizontal command (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+ vmode+ex_space:@t@>@;@/
+@y
+ vmode+ex_space,vmode+LR:@t@>@;@/
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [48.1196] math in text is L-text (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+begin tail_append(new_math(math_surround,before));
+@y
+begin tail_append(new_math(math_surround,before));
+@<Append a |begin_L| to the tail of the current list@>;
+@z
+@x (module 1196, continued)
+tail_append(new_math(math_surround,after));
+@y
+@<Append an |end_L| to the tail of the current list@>;
+tail_append(new_math(math_surround,after));
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [49.1275] a_open_in of \read file needs path specifier
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+ if a_open_in(read_file[n]) then read_open[n]:=just_open;
+@y
+ if a_open_in(read_file[n],read_path_spec) then read_open[n]:=just_open;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [50.passim] Fix reading and writing fmt_file for C
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d dump_wd(#)==begin fmt_file^:=#; put(fmt_file);@+end
+@d dump_int(#)==begin fmt_file^.int:=#; put(fmt_file);@+end
+@d dump_hh(#)==begin fmt_file^.hh:=#; put(fmt_file);@+end
+@d dump_qqqq(#)==begin fmt_file^.qqqq:=#; put(fmt_file);@+end
+@y
+@d dump_wd(#)==put_fmt_word(#)
+@d dump_int(#)==put_fmt_int(#)
+@d dump_hh(#)==put_fmt_hh(#)
+@d dump_qqqq(#)==put_fmt_qqqq(#)
+@z
+
+@x
+@d undump_wd(#)==begin get(fmt_file); #:=fmt_file^;@+end
+@d undump_int(#)==begin get(fmt_file); #:=fmt_file^.int;@+end
+@d undump_hh(#)==begin get(fmt_file); #:=fmt_file^.hh;@+end
+@d undump_qqqq(#)==begin get(fmt_file); #:=fmt_file^.qqqq;@+end
+@y
+@d undump_wd(#)==get_fmt_word(#)
+@d undump_int(#)==get_fmt_int(#)
+@d undump_hh(#)==get_fmt_hh(#)
+@d undump_qqqq(#)==get_fmt_qqqq(#)
+@z
+
+@x
+x:=fmt_file^.int;
+@y
+get_fmt_int(x); {This is reading the first word of the fmt file}
+@z
+
+########################################################################
+% Make dumping/undumping more efficient in C
+########################################################################
+@x
+for k:=0 to str_ptr do dump_int(str_start[k]);
+k:=0;
+while k+4<pool_ptr do
+ begin dump_four_ASCII; k:=k+4;
+ end;
+k:=pool_ptr-4; dump_four_ASCII;
+@y
+dump_things(str_start[0], str_ptr+1);
+dump_things(str_pool[0], pool_ptr);
+@z
+
+@x
+for k:=0 to str_ptr do undump(0)(pool_ptr)(str_start[k]);
+k:=0;
+while k+4<pool_ptr do
+ begin undump_four_ASCII; k:=k+4;
+ end;
+k:=pool_ptr-4; undump_four_ASCII
+@y
+undump_things(str_start[0], str_ptr+1);
+undump_things(str_pool[0], pool_ptr);
+@z
+
+@x
+repeat for k:=p to q+1 do dump_wd(mem[k]);
+x:=x+q+2-p; var_used:=var_used+q-p;
+p:=q+node_size(q); q:=rlink(q);
+until q=rover;
+var_used:=var_used+lo_mem_max-p; dyn_used:=mem_end+1-hi_mem_min;@/
+for k:=p to lo_mem_max do dump_wd(mem[k]);
+x:=x+lo_mem_max+1-p;
+dump_int(hi_mem_min); dump_int(avail);
+for k:=hi_mem_min to mem_end do dump_wd(mem[k]);
+@y
+repeat
+ dump_things(mem[p], q+2-p);
+x:=x+q+2-p; var_used:=var_used+q-p;
+p:=q+node_size(q); q:=rlink(q);
+until q=rover;
+var_used:=var_used+lo_mem_max-p; dyn_used:=mem_end+1-hi_mem_min;@/
+dump_things(mem[p], lo_mem_max+1-p);
+x:=x+lo_mem_max+1-p;
+dump_int(hi_mem_min); dump_int(avail);
+dump_things(mem[hi_mem_min], mem_end+1-hi_mem_min);
+@z
+
+@x
+repeat for k:=p to q+1 do undump_wd(mem[k]);
+p:=q+node_size(q);
+if (p>lo_mem_max)or((q>=rlink(q))and(rlink(q)<>rover)) then goto bad_fmt;
+q:=rlink(q);
+until q=rover;
+for k:=p to lo_mem_max do undump_wd(mem[k]);
+@y
+repeat
+ undump_things(mem[p], q+2-p);
+p:=q+node_size(q);
+if (p>lo_mem_max)or((q>=rlink(q))and(rlink(q)<>rover)) then goto bad_fmt;
+q:=rlink(q);
+until q=rover;
+undump_things(mem[p], lo_mem_max+1-p);
+@z
+
+@x
+for k:=hi_mem_min to mem_end do undump_wd(mem[k]);
+@y
+undump_things(mem[hi_mem_min], mem_end+1-hi_mem_min);
+@z
+
+@x
+while k<l do
+ begin dump_wd(eqtb[k]); incr(k);
+ end;
+@y
+dump_things(eqtb[k], l-k);
+@z
+
+@x
+while k<l do
+ begin dump_wd(eqtb[k]); incr(k);
+ end;
+@y
+dump_things(eqtb[k], l-k);
+@z
+
+@x
+for j:=k to k+x-1 do undump_wd(eqtb[j]);
+@y
+undump_things(eqtb[k], x);
+@z
+
+@x
+for p:=hash_used+1 to undefined_control_sequence-1 do dump_hh(hash[p]);
+@y
+dump_things(hash[hash_used+1], undefined_control_sequence-1-hash_used);
+@z
+
+@x
+for p:=hash_used+1 to undefined_control_sequence-1 do undump_hh(hash[p]);
+@y
+undump_things(hash[hash_used+1], undefined_control_sequence-1-hash_used);
+@z
+
+@x
+for k:=0 to fmem_ptr-1 do dump_wd(font_info[k]);
+dump_int(font_ptr);
+for k:=null_font to font_ptr do
+ @<Dump the array info for internal font number |k|@>;
+@y
+@<Dump the array info for internal font number |k|@>;
+@z
+
+@x
+for k:=0 to fmem_ptr-1 do undump_wd(font_info[k]);
+undump_size(font_base)(font_max)('font max')(font_ptr);
+for k:=null_font to font_ptr do
+ @<Undump the array info for internal font number |k|@>
+@y
+@<Undump the array info for internal font number |k|@>;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [50.1322] Writing font info (almost at end of dump stuff)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ @<Dump the array info for internal font number |k|@>=
+begin dump_qqqq(font_check[k]);
+dump_int(font_size[k]);
+dump_int(font_dsize[k]);
+dump_int(font_params[k]);@/
+dump_int(hyphen_char[k]);
+dump_int(skew_char[k]);@/
+dump_int(font_name[k]);
+dump_int(font_area[k]);@/
+dump_int(font_bc[k]);
+dump_int(font_ec[k]);@/
+dump_int(char_base[k]);
+dump_int(width_base[k]);
+dump_int(height_base[k]);@/
+dump_int(depth_base[k]);
+dump_int(italic_base[k]);
+dump_int(lig_kern_base[k]);@/
+dump_int(kern_base[k]);
+dump_int(exten_base[k]);
+dump_int(param_base[k]);@/
+dump_int(font_glue[k]);@/
+print_nl("\font"); print_esc(font_id_text(k)); print_char("=");
+print_file_name(font_name[k],font_area[k],"");
+if font_size[k]<>font_dsize[k] then
+ begin print(" at "); print_scaled(font_size[k]); print("pt");
+ end;
+end
+@y
+@ @<Dump the array info for internal font number |k|@>=
+begin dump_things(font_info[0], fmem_ptr);
+dump_int(font_ptr);
+dump_things(font_check[null_font], font_ptr+1-null_font);
+dump_things(font_size[null_font], font_ptr+1-null_font);
+dump_things(font_dsize[null_font], font_ptr+1-null_font);
+dump_things(font_params[null_font], font_ptr+1-null_font);
+dump_things(hyphen_char[null_font], font_ptr+1-null_font);
+dump_things(skew_char[null_font], font_ptr+1-null_font);
+dump_things(font_name[null_font], font_ptr+1-null_font);
+dump_things(font_area[null_font], font_ptr+1-null_font);
+dump_things(font_bc[null_font], font_ptr+1-null_font);
+dump_things(font_ec[null_font], font_ptr+1-null_font);
+dump_things(char_base[null_font], font_ptr+1-null_font);
+dump_things(width_base[null_font], font_ptr+1-null_font);
+dump_things(height_base[null_font], font_ptr+1-null_font);
+dump_things(depth_base[null_font], font_ptr+1-null_font);
+dump_things(italic_base[null_font], font_ptr+1-null_font);
+dump_things(lig_kern_base[null_font], font_ptr+1-null_font);
+dump_things(kern_base[null_font], font_ptr+1-null_font);
+dump_things(exten_base[null_font], font_ptr+1-null_font);
+dump_things(param_base[null_font], font_ptr+1-null_font);
+dump_things(font_glue[null_font], font_ptr+1-null_font);
+for k:=null_font to font_ptr do begin
+ print_nl("\font"); print_esc(font_id_text(k)); print_char("=");
+ print_file_name(font_name[k],font_area[k],"");
+ if font_size[k]<>font_dsize[k] then begin
+ print(" at "); print_scaled(font_size[k]); print("pt");
+ end;
+end;
+end
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [50.1322] Reading font info for C (Nearly done with undump stuff)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ @<Undump the array info for internal font number |k|@>=
+begin undump_qqqq(font_check[k]);@/
+undump_int(font_size[k]);
+undump_int(font_dsize[k]);
+undump(min_halfword)(max_halfword)(font_params[k]);@/
+undump_int(hyphen_char[k]);
+undump_int(skew_char[k]);@/
+undump(0)(str_ptr)(font_name[k]);
+undump(0)(str_ptr)(font_area[k]);@/
+undump(0)(255)(font_bc[k]);
+undump(0)(255)(font_ec[k]);@/
+undump_int(char_base[k]);
+undump_int(width_base[k]);
+undump_int(height_base[k]);@/
+undump_int(depth_base[k]);
+undump_int(italic_base[k]);
+undump_int(lig_kern_base[k]);@/
+undump_int(kern_base[k]);
+undump_int(exten_base[k]);
+undump_int(param_base[k]);@/
+undump(min_halfword)(lo_mem_max)(font_glue[k]);
+end
+@y
+@ The way this is done in C, makes the reference to
+the internal font number meaningless, but putting the code
+here preserves the association with the WEB modules.
+
+@<Undump the array info for internal font number |k|@>=
+begin undump_things(font_info[0], fmem_ptr);
+undump_size(font_base)(font_max)('font max')(font_ptr);
+undump_things(font_check[null_font], font_ptr+1-null_font);
+undump_things(font_size[null_font], font_ptr+1-null_font);
+undump_things(font_dsize[null_font], font_ptr+1-null_font);
+undump_things(font_params[null_font], font_ptr+1-null_font);
+undump_things(hyphen_char[null_font], font_ptr+1-null_font);
+undump_things(skew_char[null_font], font_ptr+1-null_font);
+undump_things(font_name[null_font], font_ptr+1-null_font);
+undump_things(font_area[null_font], font_ptr+1-null_font);
+undump_things(font_bc[null_font], font_ptr+1-null_font);
+undump_things(font_ec[null_font], font_ptr+1-null_font);
+undump_things(char_base[null_font], font_ptr+1-null_font);
+undump_things(width_base[null_font], font_ptr+1-null_font);
+undump_things(height_base[null_font], font_ptr+1-null_font);
+undump_things(depth_base[null_font], font_ptr+1-null_font);
+undump_things(italic_base[null_font], font_ptr+1-null_font);
+undump_things(lig_kern_base[null_font], font_ptr+1-null_font);
+undump_things(kern_base[null_font], font_ptr+1-null_font);
+undump_things(exten_base[null_font], font_ptr+1-null_font);
+undump_things(param_base[null_font], font_ptr+1-null_font);
+undump_things(font_glue[null_font], font_ptr+1-null_font);
+end
+@z
+
+@x
+for k:=0 to trie_max do dump_hh(trie[k]);
+dump_int(trie_op_ptr);
+for k:=min_quarterword+1 to trie_op_ptr do
+ begin dump_int(hyf_distance[k]);
+ dump_int(hyf_num[k]);
+ dump_int(hyf_next[k]);
+ end;
+@y
+dump_things(trie[0], trie_max+1);
+dump_int(trie_op_ptr);
+dump_things(hyf_distance[min_quarterword+1], trie_op_ptr-min_quarterword);
+dump_things(hyf_num[min_quarterword+1], trie_op_ptr-min_quarterword);
+dump_things(hyf_next[min_quarterword+1], trie_op_ptr-min_quarterword);
+@z
+
+@x
+for k:=0 to trie_max do undump_hh(trie[k]);
+undump(min_quarterword)(max_quarterword)(trie_op_ptr);
+for k:=min_quarterword+1 to trie_op_ptr do
+ begin undump(0)(63)(hyf_distance[k]); {a |small_number|}
+ undump(0)(63)(hyf_num[k]);
+ undump(min_quarterword)(max_quarterword)(hyf_next[k]);
+ end
+@y
+undump_things(trie[0], trie_max+1);
+undump(min_quarterword)(max_quarterword)(trie_op_ptr);
+undump_things(hyf_distance[min_quarterword+1], trie_op_ptr-min_quarterword);
+undump_things(hyf_num[min_quarterword+1], trie_op_ptr-min_quarterword);
+undump_things(hyf_next[min_quarterword+1], trie_op_ptr-min_quarterword);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [51.1332] uexit() call depends on `history'; procedure-ize main prog;
+% Also, add call to set_paths
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@ Now this is really it: \TeX\ starts and ends here.
+
+The initial test involving |ready_already| should be deleted if the
+\PASCAL\ runtime system is smart enough to detect such a ``mistake.''
+@y
+@ Now this is really it: \TeX\ starts and ends here.
+
+Use the value of |history| to determine what exit-code to use. We use
+1 if |history <> spotless| and 0 otherwise.
+
+@z
+
+@x
+@p begin @!{|start_here|}
+history:=fatal_error_stop; {in case we quit during initialization}
+t_open_out; {open the terminal for output}
+if ready_already=314159 then goto start_of_TEX;
+@y
+@p procedure tex_body;
+label @<Labels in the outer block@>@/
+var bufindx:0..bufsize; {an index used in a for loop below}
+begin @!{|start_here|}
+history:=fatal_error_stop; {in case we quit during initialization}
+t_open_out; {open the terminal for output}
+if ready_already=314159 then goto start_of_TEX;
+set_paths; {get default file paths from the Unix environment}
+@z
+
+@x
+final_end: ready_already:=0;
+end.
+@y
+final_end: do_final_end;
+end {|tex_body|};
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [51.1333] omit call to wake_up_terminal on normal termination
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+wake_up_terminal; @<Finish the \.{DVI} file@>;
+@y
+@<Finish the \.{DVI} file@>;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [51.1333] print new line before termination; switch to editor if nec.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+ print(log_name); print_char(".");
+ end;
+ end;
+@y
+ print(log_name); print_char(".");
+ end;
+ end;
+print_ln;
+if (edit_name_start<>0) and (interaction>batch_mode) then
+ calledit(str_pool,edit_name_start,edit_name_length,edit_line);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [52.1338] Core-dump in debugging mode on 0 input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% In Unix, it's not possible to switch into the debugger while a program
+% is running. The best approximation is to do a core dump, then run
+% the debugger on it later.
+@x
+ begin goto breakpoint;@\ {go to every label at least once}
+ breakpoint: m:=0; @{'BREAKPOINT'@}@\
+ end
+@y
+ dump_core {Do something to cause a core dump}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [53.1341] whatsit processing (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d special_node=3 {|subtype| in whatsits that represent \.{\\special} things}
+@y
+@d special_node=3 {|subtype| in whatsits that represent \.{\\special} things}
+@d LR_node=4 {|subtype| in whatsits that represent \.{\\beginL}, etc.}
+@d LR_type(#)==mem[#+1].int {the sub-subtype}
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [53.1344] whatsit processing continued (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x
+@d immediate_code=4 {command modifier for \.{\\immediate}}
+
+@<Put each...@>=
+@y
+@d immediate_code=4 {command modifier for \.{\\immediate}}
+@d begin_L_code=0 {command modifier for \.{\\beginL}}
+@d begin_R_code=1 {command modifier for \.{\\beginR}}
+@d end_L_code=2 {command modifier for \.{\\endL}}
+@d end_R_code=3 {command modifier for \.{\\endR}}
+@d begin_LR(#)==(LR_type(#)<end_L_code)
+@d begin_LR_type(#)==(LR_type(#)-end_L_code)
+
+@<Put each...@>=
+primitive("beginL",LR,begin_L_code);@/
+@!@:begin_L_}{\.{\\beginL} primitive@>
+primitive("beginR",LR,begin_R_code);@/
+@!@:begin_R_}{\.{\\beginR} primitive@>
+primitive("endL",LR,end_L_code);@/
+@!@:end_L_}{\.{\\endL} primitive@>
+primitive("endR",LR,end_R_code);@/
+@!@:end_R_}{\.{\\endR} primitive@>
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [53.1346] whatsit processing continued (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x (module 1346)
+@ @<Cases of |print_cmd_chr|...@>=
+@y
+@ @<Cases of |print_cmd_chr|...@>=
+LR: case chr_code of
+begin_L_code: print_esc("beginL");
+begin_R_code: print_esc("beginR");
+end_L_code: print_esc("endL");
+othercases print_esc("endR")
+endcases;
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [53.1356] whatsit processing continued (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x (module 1356)
+othercases print("whatsit?")
+@y
+LR_node: case LR_type(p) of
+begin_L_code: print_esc("beginL");
+begin_R_code: print_esc("beginR");
+end_L_code: print_esc("endL");
+othercases print_esc("endR")
+endcases;
+othercases print("whatsit?")
+@z
+@x (module 1357)
+close_node: begin r:=get_node(small_node_size); words:=small_node_size;
+@y
+close_node,LR_node: begin r:=get_node(small_node_size); words:=small_node_size;
+@z
+@x (module 1358)
+close_node: free_node(p,small_node_size);
+@y
+close_node,LR_node: free_node(p,small_node_size);
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [53.1360] whatsit processing continued (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x (module 1360)
+@ @<Incorporate a whatsit node into an hbox@>=do_nothing
+@y
+@ @<Incorporate a whatsit node into an hbox@>=
+if subtype(p)=LR_node then @<Adjust the LR stack for the |hpack| routine@>
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [53.1366] whatsit processing continued (TeX-XeT extension)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x (module 1366)
+@ @<Output the whatsit node |p| in an hlist@>=
+out_what(p)
+@y
+@ @<Output the whatsit node |p| in an hlist@>=
+if subtype(p)<>LR_node then out_what(p)
+else @<Output a reflection instruction if the direction has changed@>
+@z
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% [54.1376] add TeX-XeT extensions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+@x Final system-dependent changes: [1376]
+This section should be replaced, if necessary, by changes to the program
+that are necessary to make \TeX\ work at a particular installation.
+It is usually best to design your change file so that all changes to
+previous sections preserve the section numbering; then everybody's version
+will be consistent with the published program. More extensive changes,
+which introduce new sections, can be inserted here; then only the index
+itself will get a new section number.
+@^system dependencies@>
+@y
+Now we do the main work required for mixed-direction texts.
+
+@<Cases of |main_control| that build...@>=
+hmode+LR: begin new_whatsit(LR_node,small_node_size); LR_type(tail):=cur_chr;
+ end;
+mmode+LR: report_illegal_case;
+
+@ @<Glob...@>=
+@!LR_ptr,@!LR_tmp:pointer; {stack of LR codes and temp for manipulation}
+
+@ @<Declare functions needed for special kinds of nodes@>=
+function new_LR(@!s:small_number): pointer;
+var p: pointer; {the new node}
+begin p:=get_node(small_node_size); type(p):=whatsit_node; subtype(p):=LR_node;
+LR_type(p):=s; new_LR:=p;
+end;
+
+@ @<Declare functions needed for special kinds of nodes@>=
+function safe_info(@!p:pointer): integer;
+begin if p=null then safe_info:=-1@+else safe_info:=info(p);
+end;
+
+@ @<Append a |begin_L| to the tail of the current list@>=
+tail_append(new_LR(begin_L_code))
+
+@ @<Append an |end_L| to the tail of the current list@>=
+tail_append(new_LR(end_L_code))
+
+@ A number of routines are based on a stack of one-word nodes whose |info|
+fields contain either |begin_L_code| or |begin_R_code|. The top of the
+stack is pointed to by |LR_ptr|, and an auxiliary variable |LR_tmp| is
+available for stack manipulation.
+
+@d push_LR(#)==begin LR_tmp:=get_avail; info(LR_tmp):=LR_type(#);
+ link(LR_tmp):=LR_ptr; LR_ptr:=LR_tmp;
+ end
+@d pop_LR==begin LR_tmp:=LR_ptr; LR_ptr:=link(LR_tmp); free_avail(LR_tmp);
+ end
+
+@<Flush the LR stack@>=while LR_ptr<>null do pop_LR
+
+@ @<Insert LR nodes at the beginning of the current line@>=
+while LR_ptr<>null do
+ begin LR_tmp:=new_LR(info(LR_ptr)); link(LR_tmp):=link(temp_head);
+ link(temp_head):=LR_tmp; pop_LR;
+ end
+
+@ @<Adjust the LR stack based on LR nodes in this line@>=
+q:=link(temp_head);
+while q<>cur_break(cur_p) do
+ begin if not is_char_node(q) then if type(q)=whatsit_node then
+ if subtype(q)=LR_node then
+ if begin_LR(q) then push_LR(q)
+ else if LR_ptr<>null then
+ if info(LR_ptr)=begin_LR_type(q) then pop_LR;
+ q:=link(q);
+ end
+
+@ We use the fact that |q| now points to the node with \.{\\rightskip} glue.
+
+@<Insert LR nodes at the end of the current line@>=
+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 LR_tmp:=new_LR(info(r)+end_L_code);
+ link(s):=LR_tmp; s:=LR_tmp; r:=link(r);
+ end;
+ link(s):=q;
+ end
+
+@ @<Adjust the LR stack for the |hpack| routine@>=
+if begin_LR(p) then push_LR(p)
+else if safe_info(LR_ptr)=begin_LR_type(p) then pop_LR
+else begin incr(LR_problems);
+ while link(q)<>p do q:=link(q);
+ link(q):=link(p); free_node(p,small_node_size); p:=q;
+ end
+
+@ @<Check for LR anomalies at the end of |hpack|@>=
+if LR_ptr<>null then
+ begin while link(q)<>null do q:=link(q);
+ repeat link(q):=new_LR(info(LR_ptr)+end_L_code); q:=link(q);
+ LR_problems:=LR_problems+10000; pop_LR;
+ until LR_ptr=null;
+ end;
+if LR_problems>0 then
+ 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; goto common_ending;
+ end
+
+@ @<Output a reflection instruction if the direction has changed@>=
+if begin_LR(p) then
+ begin if safe_info(LR_ptr)<>LR_type(p) then
+ begin synch_h; synch_v; dvi_out(begin_reflect);
+ end;
+ push_LR(p);
+ end
+else if safe_info(LR_ptr)=begin_LR_type(p) then
+ begin pop_LR;
+ if info(LR_ptr)+end_L_code<>LR_type(p) then
+ begin synch_h; synch_v; dvi_out(end_reflect);
+ end;
+ end
+else confusion("LR")
+@:this can't happen LR}{\quad LR@>
+
+@ Finally we get to a small addition that has nothing to do with LR nodes.
+
+Here is a temporary integer, used as a holder during reading and writing of
+TFM files, and a temporary |memory_word|, used in reading/writing format
+files.
+Also, the variables used to hold ``switch-to-editor'' information.
+@^<system dependencies@>
+
+@<Glob...@>=
+@!edit_name_start: pool_pointer;
+@!edit_name_length,@!edit_line,@!tfm_temp: integer;
+
+@ The |edit_name_start| will be set to point into |str_pool| somewhere after
+its beginning if \TeX\ is supposed to switch to an editor on exit.
+
+@<Set init...@>=
+edit_name_start:=0;
+@z
+
diff --git a/language/xettex/waits-xe.ch b/language/xettex/waits-xe.ch
new file mode 100644
index 0000000000..9cf606f28c
--- /dev/null
+++ b/language/xettex/waits-xe.ch
@@ -0,0 +1,1979 @@
+@x Tell WEAVE to print only the changes:
+ \def\?##1]{\hbox to 1in{\hfil##1.\ }}
+ }
+@y
+ \def\?##1]{\hbox{Changes to \hbox to 1em{\hfil##1}.\ }}
+ }
+\let\maybe=\iffalse
+@z
+
+@x WAITS's banner: [2]
+@d banner=='This is TeX, Version 2.0' {printed when \TeX\ starts}
+@y
+@d banner=='This is TeX-XeT, WAITS Version 2.0' {printed when \TeX\ starts}
+@z
+
+@x Switches for debugging and statistics: (7)
+@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
+@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
+@f debug==begin
+@f gubed==end
+@#
+@d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering
+ usage statistics}
+@d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering
+ usage statistics}
+@f stat==begin
+@f tats==end
+@y
+@d debug== {change this to `$\\{debug}\equiv\null$' when debugging}
+@d gubed== {change this to `$\\{gubed}\equiv\null$' when debugging}
+@f debug==begin
+@f gubed==end
+@#
+@d stat== {change this to `$\\{stat}\equiv\.{@@\{}$' when not
+ gathering usage statistics}
+@d tats== {change this to `$\\{tats}\equiv\.{@@\}}$' when not
+ gathering usage statistics}
+@f stat==begin
+@f tats==end
+@z
+
+@x The INITEX switch: (8)
+@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
+@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
+@y [In this case, no change is made]
+@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
+@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
+@z
+
+@x Compiler directives: (9)
+@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead}
+@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging}
+@y
+@{@&$C-,A+,D-,W+,H:0@}
+ {no range check, catch arithmetic overflow, no debug overhead, no heap}
+@!debug @{@&$C+,D:5,W+@}@+ gubed {but turn everything on when debugging}
+{the `|W+|' switch catches more syntax errors}
+{the `\ignorespaces|D:5|' avoids initial stop for the debugger}
+@z
+
+@x Compile-time constants: [11]
+@!mem_max=30000; {greatest index in \TeX's internal |mem| array;
+ must be strictly less than |max_halfword|;
+ must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
+@!mem_min=0; {smallest index in \TeX's internal |mem| array;
+ must be |min_halfword| or more;
+ must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
+@!buf_size=500; {maximum number of characters simultaneously present in
+ current lines of open files and in control sequences between
+ \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
+@!error_line=72; {width of context lines on terminal error messages}
+@!half_error_line=42; {width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|}
+@!max_print_line=79; {width of longest text lines output; should be at least 60}
+@!stack_size=200; {maximum number of simultaneous input sources}
+@!max_in_open=6; {maximum number of input files and error insertions that
+ can be going on simultaneously}
+@!font_max=75; {maximum internal font number; must not exceed |max_quarterword|
+ and must be at most |font_base+256|}
+@!font_mem_size=20000; {number of words of |font_info| for all fonts}
+@!param_size=60; {maximum number of simultaneous macro parameters}
+@!nest_size=40; {maximum number of semantic levels simultaneously active}
+@!max_strings=3000; {maximum number of strings; must not exceed |max_halfword|}
+@!string_vacancies=8000; {the minimum number of characters that should be
+ available for the user's control sequences and font names,
+ after \TeX's own error messages are stored}
+@!pool_size=32000; {maximum number of characters in strings, including all
+ error messages and help texts, and the names of all fonts and
+ control sequences; must exceed |string_vacancies| by the total
+ length of \TeX's own strings, which is currently about 23000}
+@!save_size=600; {space for saving values outside of current group; must be
+ at most |max_halfword|}
+@!trie_size=8000; {space for hyphenation patterns; should be larger for
+ \.{INITEX} than it is in production versions of \TeX}
+@!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8}
+@!file_name_size=40; {file names shouldn't be longer than this}
+@!pool_name='TeXformats:TEX.POOL ';
+ {string of length |file_name_size|; tells where the string pool appears}
+@.TeXformats@>
+@y
+@!mem_max=32000; {greatest index in \TeX's internal |mem| array;
+ must be strictly less than |max_halfword|;
+ must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
+@!mem_min=16000; {smallest index in \TeX's internal |mem| array;
+ must be |min_halfword| or more;
+ must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
+@!buf_size=500; {maximum number of characters simultaneously present in
+ current lines of open files and in control sequences between
+ \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
+@!error_line=80; {width of context lines on terminal error messages}
+@!half_error_line=50; {width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|}
+@!max_print_line=80; {width of longest text lines output; should be at least 60}
+@!stack_size=200; {maximum number of simultaneous input sources}
+@!max_in_open=6; {maximum number of input files and error insertions that
+ can be going on simultaneously}
+@!font_max=100;
+ {maximum internal font number; must not exceed |max_quarterword|}
+@!font_mem_size=23000; {number of words of |font_info| for all fonts}
+@!param_size=60; {maximum number of simultaneous macro parameters}
+@!nest_size=40; {maximum number of semantic levels simultaneously active}
+@!max_strings=3500; {maximum number of strings}
+@!string_vacancies=8000; {the minimum number of characters that should be
+ available for the user's control sequences and font names,
+ after \TeX's own error messages are stored}
+@!pool_size=40000; {maximum number of characters in strings, including all
+ error messages and help texts, and the names of all fonts and
+ control sequences; must exceed |string_vacancies| by the total
+ length of \TeX's own strings, which is currently about 22500}
+@!save_size=300; {space for saving values outside of current group; must be
+ at most |max_halfword|}
+@!trie_size=8000; {space for hyphenation patterns; should be larger for
+ \.{INITEX} than it is in production versions of \TeX}
+@!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8}
+@!file_name_size=23; {file names shouldn't be longer than this}
+@!pool_name='XET.POOL[XET,DEK] ';
+ {string of length |file_name_size|; tells where the string pool appears}
+@z
+
+@x TANGLE-time constants: (12)
+@d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX};
+ must not be less than |mem_min|}
+@d mem_top==30000 {largest index in the |mem| array dumped by \.{INITEX};
+ must be substantially larger than |mem_bot|
+ and not greater than |mem_max|}
+@d font_base=0 {smallest internal font number; must not be less
+ than |min_quarterword|}
+@d hash_size=2100 {maximum number of control sequences; it should be at most
+ about |(mem_max-mem_min)/10|, but 2100 is already quite generous}
+@d hash_prime=1777 {a prime number equal to about 85\% of |hash_size|}
+@d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions}
+@y
+@d mem_bot=16000 {smallest index in the |mem| array dumped by \.{INITEX};
+ must not be less than |mem_min|}
+@d mem_top==32000 {largest index in the |mem| array dumped by \.{INITEX};
+ must be substantially larger than |mem_bot|
+ and not greater than |mem_max|}
+@d font_base=0 {smallest internal font number; must not be less
+ than |min_quarterword|}
+@d hash_size=2500 {maximum number of control sequences; it should be at most
+ about |(mem_max-mem_min)/10|, but 2100 is already quite generous}
+@d hash_prime=2113 {a prime number equal to about 85\% of |hash_size|}
+@d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions}
+@z
+
+@x System-dependent character set changes: (23)
+@^character set dependencies@>
+@^system dependencies@>
+
+@<Set init...@>=
+for i:=1 to @'37 do xchr[i]:=' ';
+@y
+@^character set dependencies@>
+@^system dependencies@>
+
+The code shown here is intended to be used on the Stanford {\sc SAIL} system,
+and at other installations like CMU and ISI where essentially the same
+extended character set is used. The fact that {\mc SAIL} has |'}'| in the
+wrong place turns out to cause no difficulty in this case.
+
+@<Set initial values...@>=
+for i:=1 to @'37 do xchr[i]:=chr(i);
+xchr[@'30]:=chr(@'137);
+xchr[@'32]:=chr(@'33); {|not_equal| sign}
+xchr[@'33]:=chr(@'176);
+@z
+
+@x Opening files: (27)
+@d reset_OK(#)==erstat(#)=0
+@d rewrite_OK(#)==erstat(#)=0
+
+@p function a_open_in(var f:alpha_file):boolean;
+ {open a text file for input}
+begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f);
+end;
+@#
+function a_open_out(var f:alpha_file):boolean;
+ {open a text file for output}
+begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f);
+end;
+@#
+function b_open_in(var f:byte_file):boolean;
+ {open a binary file for input}
+begin reset(f,name_of_file,'/O'); b_open_in:=reset_OK(f);
+end;
+@#
+function b_open_out(var f:byte_file):boolean;
+ {open a binary file for output}
+begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f);
+end;
+@#
+function w_open_in(var f:word_file):boolean;
+ {open a word file for input}
+begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f);
+end;
+@#
+function w_open_out(var f:word_file):boolean;
+ {open a word file for output}
+begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f);
+end;
+@y
+@d reset_OK(#)==erstat(#) mod @'20000 = 0
+@d rewrite_OK(#)==erstat(#) mod @'20000 = 0
+
+@p function erstat(var f:file):integer; extern;@t/2@>
+@#
+function a_open_in(var f:alpha_file):boolean;
+ {open a text file for input}
+begin reset(f,name_of_file,'/E/O/N:9');
+ {the \.{/E} switch distinguishes |form_feed| from |carriage_return|;
+ the \.{/O} switch gives error control to us;
+ and the \.{/N:9} switch specifies 9 buffers, which
+ seems to work satisfactorily at {\mc SAIL}}
+a_open_in:=reset_OK(f);
+end;
+@#
+function a_open_out(var f:alpha_file):boolean;
+ {open a text file for output}
+begin rewrite(f,name_of_file,'/O/N:2'); a_open_out:=rewrite_OK(f);
+end; {two buffers seems adequate for text output files}
+@#
+function b_open_in(var f:byte_file):boolean;
+ {open a binary file for input}
+begin reset(f,name_of_file,'/B:8/O/N:2'); b_open_in:=reset_OK(f);
+end; {the \.{/B} switch is necessary to get byte packing}
+@#
+function b_open_out(var f:byte_file):boolean;
+ {open a binary file for output}
+begin rewrite(f,name_of_file,'/O/N:9/P:256'); b_open_out:=rewrite_OK(f);
+end; {here we use |ary_out| so the \.{/B} switch isn't appropriate}
+ {the \.{/P:256} sets file protection to `dump never'}
+@#
+function w_open_in(var f:word_file):boolean;
+ {open a word file for input}
+begin reset(f,name_of_file,'/O/N:9'); w_open_in:=reset_OK(f);
+end;
+@#
+function w_open_out(var f:word_file):boolean;
+ {open a word file for output}
+begin rewrite(f,name_of_file,'/O/N:9'); w_open_out:=rewrite_OK(f);
+end;
+@z
+
+@x New input_ln: (31)
+@ Input from text files is read one line at a time, using a routine called
+|input_ln|. This function is defined in terms of global variables called
+|buffer|, |first|, and |last| that will be described in detail later; for
+now, it suffices for us to know that |buffer| is an array of |ASCII_code|
+values, and that |first| and |last| are indices into this array
+representing the beginning and ending of a line of text.
+
+@<Glob...@>=
+@!buffer:array[0..buf_size] of ASCII_code; {lines of characters being read}
+@!first:0..buf_size; {the first unused position in |buffer|}
+@!last:0..buf_size; {end of the line just input to |buffer|}
+@!max_buf_stack:0..buf_size; {largest index used in |buffer|}
+@y
+@ Input from text files is read one line at a time, using a routine called
+|input_ln|. This function is defined in terms of global variables
+called |buffer|, |first|, and |last| that will be described in detail
+later; for now, it suffices for us to know that |buffer| is an array of
+|ASCII_code| values, and that |first| and |last| are indices into this
+array representing the beginning and ending of a line of text.
+
+We will read the lines first into an auxiliary buffer, in order to
+save the running time of procedure-call overhead. This uses a nice
+feature of \ph\ that Knuth chose not to mention in \TeX82.
+@^Knuth, Donald Ervin@>
+
+At {\mc SAIL} we want to recognize page marks (indicated by |form_feed|
+characters), and keep track of the current page number.
+
+@d form_feed=@'14 {ASCII code used at end of a page}
+
+@<Glob...@>=
+@!buffer:array[0..buf_size] of ASCII_code; {lines of characters being read}
+@!first:0..buf_size; {the first unused position in |buffer|}
+@!last:0..buf_size; {end of the line just input to |buffer|}
+@!max_buf_stack:0..buf_size; {largest index used in |buffer|}
+@!aux_buf:array[0..70] of text_char; {where the characters go first}
+@^system dependencies@>
+@z
+@x
+@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
+ {inputs the next line or returns |false|}
+var last_nonblank:0..buf_size; {|last| with trailing blanks removed}
+begin if bypass_eoln then if not eof(f) then get(f);
+ {input the first character of the line into |f^|}
+last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
+if eof(f) then input_ln:=false
+else begin last_nonblank:=first;
+ while not eoln(f) do
+ begin if last>=max_buf_stack then
+ begin max_buf_stack:=last+1;
+ if max_buf_stack=buf_size then
+ overflow("buffer size",buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+ end;
+ buffer[last]:=xord[f^]; get(f); incr(last);
+ if buffer[last-1]<>" " then last_nonblank:=last;
+ end;
+ last:=last_nonblank; input_ln:=true;
+ end;
+end;
+@y
+@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
+ {inputs the next line or returns |false|}
+label 1,done;
+var n: integer;
+@!k,@!m: 0..buf_size; {indices into |buffer|}
+begin if bypass_eoln then {input the first character of the line into |f^|}
+ begin if not eof(f) then get(f);
+ if not eof(f) then if f^=chr(@'12) then get(f); {skip past a |line_feed|}
+ end;
+last:=first;
+if eof(f) then input_ln:=false
+else begin read(f,aux_buf:n);
+ if buffer[first]=form_feed then {previous line was end-of-page}
+ begin incr(page); line:=1; {adjust line and page numbers}
+ end;
+1: if last+n>max_buf_stack then
+ if last+n>=buf_size then
+ begin max_buf_stack:=buf_size;
+ overflow("buffer size",buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+ end
+ else max_buf_stack:=last+n;
+ if n>0 then
+ begin m:=last;
+ if n=72 then last:=m+71@+else last:=m+n;
+ for k:=m to last-1 do buffer[k]:=xord[aux_buf[k-m]];
+ if n=72 then {there's more on this line}
+ begin read(f,aux_buf:n); goto 1;
+ end;
+ end
+ else if f^=chr(form_feed) then {end of page}
+ begin aux_buf[0]:=f^; n:=1; goto 1;
+ end;
+ loop@+ begin if last=first then goto done;
+ if buffer[last-1]<>" " then goto done;
+ decr(last);
+ end;
+done: input_ln:=true;
+ end;
+end;
+@^system dependencies@>
+@z
+
+@x Terminal I/O: (32)
+is considered an output file the file variable is |term_out|.
+@^system dependencies@>
+
+@<Glob...@>=
+@!term_in:alpha_file; {the terminal as an input file}
+@!term_out:alpha_file; {the terminal as an output file}
+
+@ Here is how to open the terminal files
+in \ph. The `\.{/I}' switch suppresses the first |get|.
+@^system dependencies@>
+
+@d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input}
+@d t_open_out==rewrite(term_out,'TTY:','/O') {open the terminal for text output}
+@y
+is considered an output file the file variable is |term_out|.
+On WAITS, this point is moot, since we use the built-in |TTY| file.
+@^system dependencies@>
+
+@d term_in==TTY {the terminal as an input file}
+@d term_out==TTY {the terminal as an output file}
+
+@ Here is how to open the terminal files on WAITS: we don't do anything,
+since |TTY| is always open. Note that |eoln(term_in)| is initially |true|.
+@^system dependencies@>
+
+@d t_open_in==do_nothing {open the terminal for text input}
+@d t_open_out==do_nothing {open the terminal for text output}
+@z
+
+@x Special terminal controls: (34)
+@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer}
+@d wake_up_terminal == do_nothing {cancel the user's cancellation of output}
+@y
+@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer}
+@d wake_up_terminal == begin if inskp0 then end
+ {cancel the user's cancellation of output}
+
+@<Error handling procedures@>=
+function inskp0:boolean; extern;
+@z
+
+@x Initializing the terminal: (37)
+@ The following program does the required initialization
+without retrieving a possible command line.
+It should be clear how to modify this routine to deal with command lines,
+if the system permits them.
+@^system dependencies@>
+
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+begin t_open_in;
+loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
+@.**@>
+ if not input_ln(term_in,true) then {this shouldn't happen}
+ begin write_ln(term_out);
+ write(term_out,'! End of file on the terminal... why?');
+@.End of file on the terminal@>
+ init_terminal:=false; return;
+ end;
+ loc:=first;
+ while (loc<last)and(buffer[loc]=" ") do incr(loc);
+ if loc<last then
+ begin init_terminal:=true;
+ return; {return unless the line was all blank}
+ end;
+ write_ln(term_out,'Please type the name of your input file.');
+ end;
+exit:end;
+@y
+@ The following program does the required initialization
+and accepts interrupts and also retrieves a possible command line, using
+new system routines due to David R. Fuchs.
+@^Fuchs, David Raymond@>
+
+@d pto_chr(#)==ptwr1w(0,ord(#)) {put a character in the line editor}
+
+@p procedure esci(var x:integer); extern; @t\2@>@;
+ {increments |x| each time the user types escape-I or break-I;
+ the program can change |x| whenever it wants to, but |x| had
+ better be a global variable}
+@#
+function rescan:boolean; extern; @t\2@>@;
+ {puts the command line into the terminal buffer,
+ or returns |false| if there was no command line}
+@#
+function tmp_in(f:string;var s:string):integer; extern;
+ @t\2@>@;
+ {reads \.{TMPCOR} file |f| into |s|, and returns its length
+ (|<=0| means error)}
+@#
+function cclsw: boolean; extern; @t\2@>@;
+ {was program started with \.{RUN} offset of 1 (i.e., from \.{SNAIL})?}
+@#
+procedure ptwr1w(pty,c:integer); extern; @t\2@>@;
+ {simulates typing of a character on a \.{PTY}}
+@#
+function init_terminal:boolean; {gets the terminal files started}
+label exit;
+var l:integer; {length returned by |tmp_in|}
+@!line_found:boolean; {have we scanned a line?}
+@!tmp_cor_buf:packed array[0..100] of char; {where |tmp_in| puts things}
+begin t_open_in;
+esci(interrupt);
+last:=first;
+if cclsw then {started by \.{TEX} monitor command}
+ begin l:=tmp_in('TEX',tmp_cor_buf);
+ loc:=1;
+ while (loc<l)and(tmp_cor_buf[loc]<>':=') do incr(loc);
+ incr(loc);
+ while loc<l do
+ begin if tmp_cor_buf[loc]>' ' then
+ begin buffer[last]:=xord[tmp_cor_buf[loc]]; incr(last);
+ end;
+ incr(loc);
+ end;
+ end
+else
+@!debug if false then@;@+gubed@;@/
+if rescan then
+ begin read_ln(term_in); {get first character into |term_in^|}
+ while (not eoln(term_in))and(term_in^<>';') do get(term_in);
+ if term_in^=';' then
+ begin get(term_in);
+ while not eoln(term_in) do
+ begin buffer[last]:=xord[term_in^]; incr(last); get(term_in);
+ end;
+ end;
+ end;
+line_found:=(last>first);
+loop@+ begin loc:=first;
+ while (loc<last)and(buffer[loc]=" ") do incr(loc);
+ if loc<last then
+ begin init_terminal:=true;
+ return; {return unless the line was all blank}
+ end;
+ if line_found then
+ write_ln(term_out,'Please type the name of your input file.');
+ wake_up_terminal; write(term_out,'**'); update_terminal;
+@.**@>
+ buffer[first]:=0; {|input_ln| may look at |buffer[first]|}
+ if not input_ln(term_in,true) then {this shouldn't happen}
+ begin write_ln(term_out);
+ write(term_out,'! End of file on the terminal... why?');
+@.End of file on the terminal@>
+ init_terminal:=false; return;
+ end;
+ line_found:=true;
+ end;
+exit:end;
+@^system dependencies@>
+@z
+
+@x Making special characters printable: (49)
+@<Character |k| cannot be printed@>=
+ (k<" ")or(k>"~")
+@y
+@<Character |k| cannot be printed@>=
+ (k=@'177)or(k in [0,@'11..@'15,@'33])
+@z
+
+@x Terminal input: (71)
+begin update_terminal; {Now the user sees the prompt for sure}
+@y
+begin update_terminal; {Now the user sees the prompt for sure}
+buffer[first]:=0; {makes sure |input_ln| doesn't find a |form_feed|}
+@z
+
+@x The `E' option: (84)
+line ready to be edited. But such an extension requires some system
+wizardry, so the present implementation simply types out what file should be
+edited and the relevant line number.
+@y
+line ready to be edited. The present implementation does this by loading
+the line editor with the appropriate call to the editor. We treat `\.T' the
+same as `\.E', because other programs on this system invoke the editor
+when the user says `\.T'.
+@z
+@x
+"E": if base_ptr>0 then
+ begin print_nl("You want to edit file ");
+@.You want to edit file x@>
+ print(input_stack[base_ptr].name_field);
+ print(" at line "); print_int(line);
+ interaction:=scroll_mode; jump_out;
+ end;
+@y
+"E","T": if base_ptr>0 then
+ begin selector:=new_string; pool_ptr:=str_start[str_ptr];
+ print("et "); print(input_stack[base_ptr].name_field);
+ print_char("/"); print_int(page); print("p/");
+ print_int(line); print_char("l"); print_char(carriage_return);
+ if str_ptr<max_strings then
+ begin pseudo_typein:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=pool_ptr;
+ end; {|make_string| not declared |forward|}
+ selector:=term_and_log; interaction:=scroll_mode; jump_out;
+ end;
+@z
+
+@x Changes for 36-bit machines: (110)
+The values defined here are recommended for most 32-bit computers.
+
+@d min_quarterword=0 {smallest allowable value in a |quarterword|}
+@d max_quarterword=255 {largest allowable value in a |quarterword|}
+@d min_halfword==0 {smallest allowable value in a |halfword|}
+@d max_halfword==65535 {largest allowable value in a |halfword|}
+@y
+The values defined here are recommended for most 36-bit computers.
+
+@d min_quarterword=0 {smallest allowable value in a |quarterword|}
+@d max_quarterword=511 {largest allowable value in a |quarterword|}
+@d min_halfword==0 {smallest allowable value in a |halfword|}
+@d max_halfword==262143 {largest allowable value in a |halfword|}
+@z
+
+@x Eliminating addition/subtraction of zero: (112)
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `|x+0|' and `|x-0|', if these
+macros are simplified in the obvious way when |min_quarterword=0|.
+@^inner loop@>@^system dependencies@>
+
+@d qi(#)==#+min_quarterword
+ {to put an |eight_bits| item into a quarterword}
+@d qo(#)==#-min_quarterword
+ {to take an |eight_bits| item out of a quarterword}
+@d hi(#)==#+min_halfword
+ {to put a sixteen-bit item into a halfword}
+@d ho(#)==#-min_halfword
+ {to take a sixteen-bit item from a halfword}
+@y
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `|x+0|' and `|x-0|', if these
+macros are simplified in the obvious way when |min_quarterword=0|.
+So they have been simplified here in the obvious way.
+@^inner loop@>@^system dependencies@>
+
+@d qi(#)==# {to put an |eight_bits| item into a quarterword}
+@d qo(#)==# {to take an |eight_bits| item from a quarterword}
+@d hi(#)==# {to put a sixteen-bit item into a halfword}
+@d ho(#)==# {to take a sixteen-bit item from a halfword}
+@z
+
+@x Kludge to get around Pascal bug (with large array lower bounds) (116)
+@!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area}
+@y
+@z
+
+@x make room for a new creation procedure [161]
+\TeX's other algorithms intact.
+@^system dependencies@>
+@y
+\TeX's other algorithms intact.
+@^system dependencies@>
+@p@<Declare functions needed for special kinds of nodes@>
+@z
+
+@x New command code [208-209]
+@d max_non_prefixed_command=69 {largest command code that can't be \.{\\global}}
+
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+@d toks_register=70 {token list register ( \.{\\toks} )}
+@d assign_toks=71 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)}
+@d assign_int=72 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)}
+@d assign_dimen=73 {user-defined length ( \.{\\hsize}, etc.~)}
+@d assign_glue=74 {user-defined glue ( \.{\\baselineskip}, etc.~)}
+@d assign_mu_glue=75 {user-defined muglue ( \.{\\thinmuskip}, etc.~)}
+@d assign_font_dimen=76 {user-defined font dimension ( \.{\\fontdimen} )}
+@d assign_font_int=77 {user-defined font integer ( \.{\\hyphenchar},
+ \.{\\skewchar} )}
+@d set_aux=78 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )}
+@d set_prev_graf=79 {specify state info ( \.{\\prevgraf} )}
+@d set_page_dimen=80 {specify state info ( \.{\\pagegoal}, etc.~)}
+@d set_page_int=81 {specify state info ( \.{\\deadcycles},
+ \.{\\insertpenalties} )}
+@d set_box_dimen=82 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )}
+@d set_shape=83 {specify fancy paragraph shape ( \.{\\parshape} )}
+@d def_code=84 {define a character code ( \.{\\catcode}, etc.~)}
+@d def_family=85 {declare math fonts ( \.{\\textfont}, etc.~)}
+@d set_font=86 {set current font ( font identifiers )}
+@d def_font=87 {define a font file ( \.{\\font} )}
+@d register=88 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
+@d max_internal=88 {the largest code that can follow \.{\\the}}
+@d advance=89 {advance a register or parameter ( \.{\\advance} )}
+@d multiply=90 {multiply a register or parameter ( \.{\\multiply} )}
+@d divide=91 {divide a register or parameter ( \.{\\divide} )}
+@d prefix=92 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
+@d let=93 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
+@d shorthand_def=94 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
+@d read_to_cs=95 {read into a control sequence ( \.{\\read} )}
+@d def=96 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
+@d set_box=97 {set a box ( \.{\\setbox} )}
+@d hyph_data=98 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
+@d set_interaction=99 {define level of interaction ( \.{\\batchmode}, etc.~)}
+@d max_command=99 {the largest command code seen at |big_switch|}
+@y
+@d LR=70 {text direction ( \.{\\beginL}, \.{\\beginR}, \.{\\endL}, \.{\\endR} )}
+@d max_non_prefixed_command=70 {largest command code that can't be \.{\\global}}
+
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+@d toks_register=71 {token list register ( \.{\\toks} )}
+@d assign_toks=72 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)}
+@d assign_int=73 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)}
+@d assign_dimen=74 {user-defined length ( \.{\\hsize}, etc.~)}
+@d assign_glue=75 {user-defined glue ( \.{\\baselineskip}, etc.~)}
+@d assign_mu_glue=76 {user-defined muglue ( \.{\\thinmuskip}, etc.~)}
+@d assign_font_dimen=77 {user-defined font dimension ( \.{\\fontdimen} )}
+@d assign_font_int=78 {user-defined font integer ( \.{\\hyphenchar},
+ \.{\\skewchar} )}
+@d set_aux=79 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )}
+@d set_prev_graf=80 {specify state info ( \.{\\prevgraf} )}
+@d set_page_dimen=81 {specify state info ( \.{\\pagegoal}, etc.~)}
+@d set_page_int=82 {specify state info ( \.{\\deadcycles},
+ \.{\\insertpenalties} )}
+@d set_box_dimen=83 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )}
+@d set_shape=84 {specify fancy paragraph shape ( \.{\\parshape} )}
+@d def_code=85 {define a character code ( \.{\\catcode}, etc.~)}
+@d def_family=86 {declare math fonts ( \.{\\textfont}, etc.~)}
+@d set_font=87 {set current font ( font identifiers )}
+@d def_font=88 {define a font file ( \.{\\font} )}
+@d register=89 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
+@d max_internal=89 {the largest code that can follow \.{\\the}}
+@d advance=90 {advance a register or parameter ( \.{\\advance} )}
+@d multiply=91 {multiply a register or parameter ( \.{\\multiply} )}
+@d divide=92 {divide a register or parameter ( \.{\\divide} )}
+@d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
+@d let=94 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
+@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
+@d read_to_cs=96 {read into a control sequence ( \.{\\read} )}
+@d def=97 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
+@d set_box=98 {set a box ( \.{\\setbox} )}
+@d hyph_data=99 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
+@d set_interaction=100 {define level of interaction ( \.{\\batchmode}, etc.~)}
+@d max_command=100 {the largest command code seen at |big_switch|}
+@z
+
+@x Special form_feed initialization: (232)
+cat_code("\"):=escape; cat_code("%"):=comment;
+@y
+cat_code("\"):=escape; cat_code("%"):=comment;
+cat_code(form_feed):=car_ret;
+@z
+
+@x Date and time: (241)
+Since standard \PASCAL\ cannot provide such information, something special
+is needed. The program here simply specifies July 4, 1776, at noon; but
+users probably want a better approximation to the truth.
+
+@p procedure fix_date_and_time;
+begin time:=12*60; {minutes since midnight}
+day:=4; {fourth day of the month}
+month:=7; {seventh month of the year}
+year:=1776; {Anno Domini}
+end;
+@y
+It uses a {\mc WAITS} monitor call that puts the date in the left 18 bits
+and the time in the right 18 bits.
+
+@p procedure fix_date_and_time;
+var t:integer; {accumulator}
+date:integer; {raw date}
+g:boolean; {garbage}
+begin call_i(@'400101,,t,t,g); {that's \.{ACCTIM}}
+date:=t div @'1000000;
+time:=(t mod @'1000000) div 60;
+day:=(date mod 31)+1;
+month:=((date div 31) mod 12)+1;
+year:=(date div (31*12))+1964;
+end;
+@z
+
+@x Page number maintenance: (304)
+If more information about the input state is needed, it can be
+included in small arrays like those shown here. For example,
+the current page or segment number in the input file might be
+put into a variable |@!page|, maintained for enclosing levels in
+`\ignorespaces|@!page_stack:array[1..max_in_open] of integer|\unskip'
+by analogy with |line_stack|.
+@y
+Similarly, we maintain a global variable |page| and a corresponding
+|page_stack|.
+@z
+@x
+@!line_stack : array[1..max_in_open] of integer;
+@y
+@!line_stack : array[1..max_in_open] of integer;
+@!page : integer; {current page number in the current source file}
+@!page_stack : array[1..max_in_open] of integer;
+@z
+
+@x Printing the page number: (313)
+else begin print_nl("l."); print_int(line);
+@y
+else begin if page>1 then
+ begin print_nl("p."); print_int(page); print(",l.");
+ end
+ else print_nl("l.");
+ print_int(line);
+@z
+
+@x More page number maintenance: (328)
+or |limit| or |line|.
+@y
+or |limit| or |line| or |page|.
+@z
+@x
+line_stack[index]:=line; start:=first; state:=mid_line;
+@y
+line_stack[index]:=line; start:=first; state:=mid_line;
+page_stack[index]:=page;
+@z
+@x
+begin first:=start; line:=line_stack[index];
+@y
+begin first:=start; page:=page_stack[index]; line:=line_stack[index];
+@z
+
+@x More page number printing: (336)
+ print("; all text was ignored after line "); print_int(skip_line);
+@y
+ print("; all text was ignored after line "); print_int(skip_line);
+ if skip_page>1 then
+ begin print(", p."); print_int(skip_page);
+ end;
+@z
+
+@x Pausing on input: (363)
+@ If the user has set the |pausing| parameter to some positive value,
+and if nonstop mode has not been selected, each line of input is displayed
+on the terminal and the transcript file, followed by `\.{=>}'.
+\TeX\ waits for a response. If the response is simply |carriage_return|, the
+line is accepted as it stands, otherwise the line typed is
+used instead of the line in the file.
+
+@p procedure firm_up_the_line;
+var k:0..buf_size; {an index into |buffer|}
+begin limit:=last;
+if pausing>0 then if interaction>nonstop_mode then
+ begin wake_up_terminal; print_ln;
+ if start<limit then for k:=start to limit-1 do print(buffer[k]);
+ first:=limit; prompt_input("=>"); {wait for user response}
+@.=>@>
+ if last>first then
+ begin for k:=first to last-1 do {move line down in buffer}
+ buffer[k+start-first]:=buffer[k];
+ limit:=start+last-first;
+ end;
+ end;
+end;
+@y
+@ If the user}
+@d wake_up_terminal == do_nothing {cancel the user's cancellation of output}
+@y
+@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer}
+@d wake_up_terminal == begin if inskp0 then end
+ {cancel the user's cancellation of output}
+
+@<Error handling procedures@>=
+function inskp0:boolean; extern;
+@z
+
+@x Initializing the terminal: (37)
+@ The following program does the required initialization
+without retrieving a possible command line.
+It should be clear how to modify this routine to deal with command lines,
+if the system permits them.
+@^system dependencies@>
+
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+begin t_open_in;
+loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
+@.**@>
+ if not input_ln(term_in,true) then {this shouldn't happen}
+ begin write_ln(term_out);
+ write(term_out,'! End of file on the terminal... why?');
+@.End of file on the terminal@>
+ init_terminal:=false; return;
+ end;
+ loc:=first;
+ while (loc<last)and(buffer[loc]=" ") do incr(loc);
+ if loc<last then
+ begin init_terminal:=true;
+ return; {return unless the line was all blank}
+ end;
+ write_ln(term_out,'Please type the name of your input file.');
+ end;
+exit:end;
+@y
+@ The following program does the required initialization
+and accepts interrupts and also retrieves a possible command line, using
+new system routines due to David R. Fuchs.
+@^Fuchs, David Raymond@>
+
+@d pto_chr(#)==ptwr1w(0,ord(#)) {put a character in the line editor}
+
+@p procedure esci(var x:integer); extern; @t\2@>@;
+ {increments |x| each time the user types escape-I or break-I;
+ the program can change |x| whenever it wants to, but |x| had
+ better be a global variable}
+@#
+function rescan:boolean; extern; @t\2@>@;
+ {puts the command line into the terminal buffer,
+ or returns |false| if there was no command line}
+@#
+function tmp_in(f:string;var s:string):integer; extern;
+ @t\2@>@;
+ {reads \.{TMPCOR} file |f| into |s|, and returns its length
+ (|<=0| means error)}
+@#
+function cclsw: boolean; extern; @t\2@>@;
+ {was program started with \.{RUN} offset of 1 (i.e., from \.{SNAIL})?}
+@#
+procedure ptwr1w(pty,c:integer); extern; @t\2@>@;
+ {simulates typing of a character on a \.{PTY}}
+@#
+function init_terminal:boolean; {gets the terminal files started}
+label exit;
+var l:integer; {length returned by |tmp_in|}
+@!line_found:boolean; {have we scanned a line?}
+@!tmp_cor_buf:packed array[0..100] of char; {where |tmp_in| puts things}
+begin t_open_in;
+esci(interrupt);
+last:=first;
+if cclsw then {started by \.{TEX} monitor command}
+ begin l:=tmp_in('TEX',tmp_cor_buf);
+ loc:=1;
+ while (loc<l)and(tmp_cor_buf[loc]<>':=') do incr(loc);
+ incr(loc);
+ while loc<l do
+ begin if tmp_cor_buf[loc]>' ' then
+ begin buffer[last]:=xord[tmp_cor_buf[loc]]; incr(last);
+ end;
+ incr(loc);
+ end;
+ end
+else
+@!debug if false then@;@+gubed@;@/
+if rescan then
+ begin read_ln(term_in); {get first character into |term_in^|}
+ while (not eoln(term_in))and(term_in^<>';') do get(term_in);
+ if term_in^=';' then
+ begin get(term_in);
+ while not eoln(term_in) do
+ begin buffer[last]:=xord[term_in^]; incr(last); get(term_in);
+ end;
+ end;
+ end;
+line_found:=(last>first);
+loop@+ begin loc:=first;
+ while (loc<last)and(buffer[loc]=" ") do incr(loc);
+ if loc<last then
+ begin init_terminal:=true;
+ return; {return unless the line was all blank}
+ end;
+ if line_found then
+ write_ln(term_out,'Please type the name of your input file.');
+ wake_up_terminal; write(term_out,'**'); update_terminal;
+@.**@>
+ buffer[first]:=0; {|input_ln| may look at |buffer[first]|}
+ if not input_ln(term_in,true) then {this shouldn't happen}
+ begin write_ln(term_out);
+ write(term_out,'! End of file on the terminal... why?');
+@.End of file on the terminal@>
+ init_terminal:=false; return;
+ end;
+ line_found:=true;
+ end;
+exit:end;
+@^system dependencies@>
+@z
+
+@x Making special characters printable: (49)
+@<Character |k| cannot be printed@>=
+ (k<" ")or(k>"~")
+@y
+@<Character |k| cannot be printed@>=
+ (k=@'177)or(k in [0,@'11..@'15,@'33])
+@z
+
+@x Terminal input: (71)
+begin update_terminal; {Now the user sees the prompt for sure}
+@y
+begin update_terminal; {Now the user sees the prompt for sure}
+buffer[first]:=0; {makes sure |input_ln| doesn't find a |form_feed|}
+@z
+
+@x The `E' option: (84)
+line ready to be edited. But such an extension requires some system
+wizardry, so the present implementation simply types out what file should be
+edited and the relevant line number.
+@y
+line ready to be edited. The present implementation does this by loading
+the line editor with the appropriate call to the editor. We treat `\.T' the
+same as `\.E', because other programs on this system invoke the editor
+when the user says `\.T'.
+@z
+@x
+"E": if base_ptr>0 then
+ begin print_nl("You want to edit file ");
+@.You want to edit file x@>
+ print(input_stack[base_ptr].name_field);
+ print(" at line "); print_int(line);
+ interaction:=scroll_mode; jump_out;
+ end;
+@y
+"E","T": if base_ptr>0 then
+ begin selector:=new_string; pool_ptr:=str_start[str_ptr];
+ print("et "); print(input_stack[base_ptr].name_field);
+ print_char("/"); print_int(page); print("p/");
+ print_int(line); print_char("l"); print_char(carriage_return);
+ if str_ptr<max_strings then
+ begin pseudo_typein:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=pool_ptr;
+ end; {|make_string| not declared |forward|}
+ selector:=term_and_log; interaction:=scroll_mode; jump_out;
+ end;
+@z
+
+@x Changes for 36-bit machines: (110)
+The values defined here are recommended for most 32-bit computers.
+
+@d min_quarterword=0 {smallest allowable value in a |quarterword|}
+@d max_quarterword=255 {largest allowable value in a |quarterword|}
+@d min_halfword==0 {smallest allowable value in a |halfword|}
+@d max_halfword==65535 {largest allowable value in a |halfword|}
+@y
+The values defined here are recommended for most 36-bit computers.
+
+@d min_quarterword=0 {smallest allowable value in a |quarterword|}
+@d max_quarterword=511 {largest allowable value in a |quarterword|}
+@d min_halfword==0 {smallest allowable value in a |halfword|}
+@d max_halfword==262143 {largest allowable value in a |halfword|}
+@z
+
+@x Eliminating addition/subtraction of zero: (112)
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `|x+0|' and `|x-0|', if these
+macros are simplified in the obvious way when |min_quarterword=0|.
+@^inner loop@>@^system dependencies@>
+
+@d qi(#)==#+min_quarterword
+ {to put an |eight_bits| item into a quarterword}
+@d qo(#)==#-min_quarterword
+ {to take an |eight_bits| item out of a quarterword}
+@d hi(#)==#+min_halfword
+ {to put a sixteen-bit item into a halfword}
+@d ho(#)==#-min_halfword
+ {to take a sixteen-bit item from a halfword}
+@y
+The inner loop of \TeX\ will run faster with respect to compilers
+that don't optimize expressions like `|x+0|' and `|x-0|', if these
+macros are simplified in the obvious way when |min_quarterword=0|.
+So they have been simplified here in the obvious way.
+@^inner loop@>@^system dependencies@>
+
+@d qi(#)==# {to put an |eight_bits| item into a quarterword}
+@d qo(#)==# {to take an |eight_bits| item from a quarterword}
+@d hi(#)==# {to put a sixteen-bit item into a halfword}
+@d ho(#)==# {to take a sixteen-bit item from a halfword}
+@z
+
+@x Kludge to get around Pascal bug (with large array lower bounds) (116)
+@!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area}
+@y
+@z
+
+@x make room for a new creation procedure [161]
+\TeX's other algorithms intact.
+@^system dependencies@>
+@y
+\TeX's other algorithms intact.
+@^system dependencies@>
+@p@<Declare functions needed for special kinds of nodes@>
+@z
+
+@x New command code [208-209]
+@d max_non_prefixed_command=69 {largest command code that can't be \.{\\global}}
+
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+@d toks_register=70 {token list register ( \.{\\toks} )}
+@d assign_toks=71 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)}
+@d assign_int=72 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)}
+@d assign_dimen=73 {user-defined length ( \.{\\hsize}, etc.~)}
+@d assign_glue=74 {user-defined glue ( \.{\\baselineskip}, etc.~)}
+@d assign_mu_glue=75 {user-defined muglue ( \.{\\thinmuskip}, etc.~)}
+@d assign_font_dimen=76 {user-defined font dimension ( \.{\\fontdimen} )}
+@d assign_font_int=77 {user-defined font integer ( \.{\\hyphenchar},
+ \.{\\skewchar} )}
+@d set_aux=78 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )}
+@d set_prev_graf=79 {specify state info ( \.{\\prevgraf} )}
+@d set_page_dimen=80 {specify state info ( \.{\\pagegoal}, etc.~)}
+@d set_page_int=81 {specify state info ( \.{\\deadcycles},
+ \.{\\insertpenalties} )}
+@d set_box_dimen=82 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )}
+@d set_shape=83 {specify fancy paragraph shape ( \.{\\parshape} )}
+@d def_code=84 {define a character code ( \.{\\catcode}, etc.~)}
+@d def_family=85 {declare math fonts ( \.{\\textfont}, etc.~)}
+@d set_font=86 {set current font ( font identifiers )}
+@d def_font=87 {define a font file ( \.{\\font} )}
+@d register=88 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
+@d max_internal=88 {the largest code that can follow \.{\\the}}
+@d advance=89 {advance a register or parameter ( \.{\\advance} )}
+@d multiply=90 {multiply a register or parameter ( \.{\\multiply} )}
+@d divide=91 {divide a register or parameter ( \.{\\divide} )}
+@d prefix=92 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
+@d let=93 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
+@d shorthand_def=94 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
+@d read_to_cs=95 {read into a control sequence ( \.{\\read} )}
+@d def=96 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
+@d set_box=97 {set a box ( \.{\\setbox} )}
+@d hyph_data=98 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
+@d set_interaction=99 {define level of interaction ( \.{\\batchmode}, etc.~)}
+@d max_command=99 {the largest command code seen at |big_switch|}
+@y
+@d LR=70 {text direction ( \.{\\beginL}, \.{\\beginR}, \.{\\endL}, \.{\\endR} )}
+@d max_non_prefixed_command=70 {largest command code that can't be \.{\\global}}
+
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+@d toks_register=71 {token list register ( \.{\\toks} )}
+@d assign_toks=72 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)}
+@d assign_int=73 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)}
+@d assign_dimen=74 {user-defined length ( \.{\\hsize}, etc.~)}
+@d assign_glue=75 {user-defined glue ( \.{\\baselineskip}, etc.~)}
+@d assign_mu_glue=76 {user-defined muglue ( \.{\\thinmuskip}, etc.~)}
+@d assign_font_dimen=77 {user-defined font dimension ( \.{\\fontdimen} )}
+@d assign_font_int=78 {user-defined font integer ( \.{\\hyphenchar},
+ \.{\\skewchar} )}
+@d set_aux=79 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )}
+@d set_prev_graf=80 {specify state info ( \.{\\prevgraf} )}
+@d set_page_dimen=81 {specify state info ( \.{\\pagegoal}, etc.~)}
+@d set_page_int=82 {specify state info ( \.{\\deadcycles},
+ \.{\\insertpenalties} )}
+@d set_box_dimen=83 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )}
+@d set_shape=84 {specify fancy paragraph shape ( \.{\\parshape} )}
+@d def_code=85 {define a character code ( \.{\\catcode}, etc.~)}
+@d def_family=86 {declare math fonts ( \.{\\textfont}, etc.~)}
+@d set_font=87 {set current font ( font identifiers )}
+@d def_font=88 {define a font file ( \.{\\font} )}
+@d register=89 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
+@d max_internal=89 {the largest code that can follow \.{\\the}}
+@d advance=90 {advance a register or parameter ( \.{\\advance} )}
+@d multiply=91 {multiply a register or parameter ( \.{\\multiply} )}
+@d divide=92 {divide a register or parameter ( \.{\\divide} )}
+@d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
+@d let=94 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
+@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
+@d read_to_cs=96 {read into a control sequence ( \.{\\read} )}
+@d def=97 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
+@d set_box=98 {set a box ( \.{\\setbox} )}
+@d hyph_data=99 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
+@d set_interaction=100 {define level of interaction ( \.{\\batchmode}, etc.~)}
+@d max_command=100 {the largest command code seen at |big_switch|}
+@z
+
+@x Special form_feed initialization: (232)
+cat_code("\"):=escape; cat_code("%"):=comment;
+@y
+cat_code("\"):=escape; cat_code("%"):=comment;
+cat_code(form_feed):=car_ret;
+@z
+
+@x Date and time: (241)
+Since standard \PASCAL\ cannot provide such information, something special
+is needed. The program here simply specifies July 4, 1776, at noon; but
+users probably want a better approximation to the truth.
+
+@p procedure fix_date_and_time;
+begin time:=12*60; {minutes since midnight}
+day:=4; {fourth day of the month}
+month:=7; {seventh month of the year}
+year:=1776; {Anno Domini}
+end;
+@y
+It uses a {\mc WAITS} monitor call that puts the date in the left 18 bits
+and the time in the right 18 bits.
+
+@p procedure fix_date_and_time;
+var t:integer; {accumulator}
+date:integer; {raw date}
+g:boolean; {garbage}
+begin call_i(@'400101,,t,t,g); {that's \.{ACCTIM}}
+date:=t div @'1000000;
+time:=(t mod @'1000000) div 60;
+day:=(date mod 31)+1;
+month:=((date div 31) mod 12)+1;
+year:=(date div (31*12))+1964;
+end;
+@z
+
+@x Page number maintenance: (304)
+If more information about the input state is needed, it can be
+included in small arrays like those shown here. For example,
+the current page or segment number in the input file might be
+put into a variable |@!page|, maintained for enclosing levels in
+`\ignorespaces|@!page_stack:array[1..max_in_open] of integer|\unskip'
+by analogy with |line_stack|.
+@y
+Similarly, we maintain a global variable |page| and a corresponding
+|page_stack|.
+@z
+@x
+@!line_stack : array[1..max_in_open] of integer;
+@y
+@!line_stack : array[1..max_in_open] of integer;
+@!page : integer; {current page number in the current source file}
+@!page_stack : array[1..max_in_open] of integer;
+@z
+
+@x Printing the page number: (313)
+else begin print_nl("l."); print_int(line);
+@y
+else begin if page>1 then
+ begin print_nl("p."); print_int(page); print(",l.");
+ end
+ else print_nl("l.");
+ print_int(line);
+@z
+
+@x More page number maintenance: (328)
+or |limit| or |line|.
+@y
+or |limit| or |line| or |page|.
+@z
+@x
+line_stack[index]:=line; start:=first; state:=mid_line;
+@y
+line_stack[index]:=line; start:=first; state:=mid_line;
+page_stack[index]:=page;
+@z
+@x
+begin first:=start; line:=line_stack[index];
+@y
+begin first:=start; page:=page_stack[index]; line:=line_stack[index];
+@z
+
+@x More page number printing: (336)
+ print("; all text was ignored after line "); print_int(skip_line);
+@y
+ print("; all text was ignored after line "); print_int(skip_line);
+ if skip_page>1 then
+ begin print(", p."); print_int(skip_page);
+ end;
+@z
+
+@x Pausing on input: (363)
+@ If the user has set the |pausing| parameter to some positive value,
+and if nonstop mode has not been selected, each line of input is displayed
+on the terminal and the transcript file, followed by `\.{=>}'.
+\TeX\ waits for a response. If the response is simply |carriage_return|, the
+line is accepted as it stands, otherwise the line typed is
+used instead of the line in the file.
+
+@p procedure firm_up_the_line;
+var k:0..buf_size; {an index into |buffer|}
+begin limit:=last;
+if pausing>0 then if interaction>nonstop_mode then
+ begin wake_up_terminal; print_ln;
+ if start<limit then for k:=start to limit-1 do print(buffer[k]);
+ first:=limit; prompt_input("=>"); {wait for user response}
+@.=>@>
+ if last>first then
+ begin for k:=first to last-1 do {move line down in buffer}
+ buffer[k+start-first]:=buffer[k];
+ limit:=start+last-first;
+ end;
+ end;
+end;
+@y
+@ If the user has set the |pausing| parameter to some positive value,
+and if nonstop mode has not been selected,
+each line of input is displayed in the transcript file, followed by `\.{=>}',
+and also put into the user's line-editor buffer.
+\TeX\ waits for the line to be edited, and the next line received is
+used instead of the line in the file.
+
+@p procedure firm_up_the_line;
+var k:0..buf_size; {an index into |buffer|}
+begin limit:=last;
+if pausing>0 then if interaction>nonstop_mode then
+ if buffer[start]<>form_feed then
+ begin wake_up_terminal; print_ln;
+ if start=limit then {empty line will be made nonempty so that it's visible}
+ begin buffer[start]:=" "; incr(limit);
+ end;
+ decr(selector); {inhibit terminal output temporarily}
+ for k:=start to limit-1 do
+ begin print_char(buffer[k]);
+ pto_chr(xchr[buffer[k]]);
+ end;
+ print("=>"); first:=start;
+ if not input_ln(term_in,true) then
+ fatal_error("End of file on the terminal!");
+@.End of file on the terminal@>
+ if last>first then for k:=first to last-1 do print_char(buffer[k]);
+ limit:=last; print_ln; incr(selector);
+ end;
+end;
+@z
+
+@x Reading the first line of a file: (485)
+@ The first line of a file must be treated specially, since |input_ln|
+must be told not to start with |get|.
+@^system dependencies@>
+
+@<Input the first line of |read_file[m]|@>=
+if input_ln(read_file[m],false) then read_open[m]:=normal
+else begin a_close(read_file[m]); read_open[m]:=closed;
+ end
+@y
+@ The first line of a file must be treated specially, since |input_ln|
+must be told not to |get|. Furthermore we want to omit the optional file
+directory page present at {\mc SAIL}.
+@^system dependencies@>
+
+@<Input the first line of |read_file[m]|@>=
+if not input_ln(read_file[m],false) then
+ begin a_close(read_file[m]); read_open[m]:=closed;
+ end
+else begin
+ if(last-start=29)and(buffer[start]="C")and(buffer[start+8]=@'26) then
+ begin while (read_file[m]^<>chr(form_feed))and(not eof(read_file[m])) do
+ begin read_ln(read_file[m]); read(read_file[m],aux_buf:temp_ptr);
+ end; {skip the directory}
+ buffer[start]:=form_feed; last:=start+1;
+ end;
+ read_open[m]:=normal;
+ end
+@z
+
+@x Still more page number maintenance: (493)
+where skipping began, for use in error messages.
+
+@<Glob...@>=
+@!skip_line:integer; {skipping began here}
+@y
+where skipping began, for use in error messages. Also the page number.
+
+@<Glob...@>=
+@!skip_line,@!skip_page:integer; {skipping began here}
+@z
+@x
+skip_line:=line;
+@y
+skip_line:=line; skip_page:=page;
+@z
+
+@x Parsing file names: (513)
+@ The file names we shall deal with for illustrative purposes have the
+following structure: If the name contains `\.>' or `\.:', the file area
+consists of all characters up to and including the final such character;
+otherwise the file area is null. If the remaining file name contains
+`\..', the file extension consists of all such characters from the first
+remaining `\..' to the end, otherwise the file extension is null.
+@^system dependencies@>
+
+We can scan such file names easily by using two global variables that keep track
+of the occurrences of area and extension delimiters:
+
+@<Glob...@>=
+@!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any}
+@!ext_delimiter:pool_pointer; {the relevant `\..', if any}
+@y
+@ The file names we shall deal with have the following structure:
+If the name contains `\.[', the file area consists of all characters
+from this character to the end; otherwise the file area is null.
+If the remaining file name contains `\..', the file extension consists of all
+such characters from this character to the end, otherwise the file extension
+is null. We can assume that there is at most one `\.[' and at most one `\..'.
+@^system dependencies@>
+
+We can scan such file names easily by using two global variables that keep track
+of the occurrences of area and extension delimiters:
+
+@<Glob...@>=
+@!area_delimiter:pool_pointer; {the most recent `\.[', if any}
+@!ext_delimiter:pool_pointer; {the relevant `\..', if any}
+@z
+@x
+@d TEX_area=="TeXinputs:"
+@.TeXinputs@>
+@d TEX_font_area=="TeXfonts:"
+@.TeXfonts@>
+@y
+@d TEX_area=="[tex,sys]"
+@d TEX_font_area=="[tfm,sys]"
+@z
+@x
+else begin if (c=">")or(c=":") then
+ begin area_delimiter:=pool_ptr; ext_delimiter:=0;
+ end
+ else if (c=".")and(ext_delimiter=0) then ext_delimiter:=pool_ptr;
+@y
+else begin if c="[" then area_delimiter:=pool_ptr
+ else if c="." then ext_delimiter:=pool_ptr;
+@z
+@x
+if area_delimiter=0 then cur_area:=""
+else begin cur_area:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=area_delimiter+1;
+ end;
+if ext_delimiter=0 then
+ begin cur_ext:=""; cur_name:=make_string;
+ end
+else begin cur_name:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=ext_delimiter; cur_ext:=make_string;
+ end;
+@y
+cur_name:=str_ptr;
+if ext_delimiter=0 then cur_ext:=""
+else begin incr(str_ptr);
+ str_start[str_ptr]:=ext_delimiter; cur_ext:=str_ptr;
+ end;
+if area_delimiter<=str_start[str_ptr] then
+ begin cur_area:=""; incr(str_ptr); str_start[str_ptr]:=pool_ptr;
+ end
+else begin incr(str_ptr);
+ str_start[str_ptr]:=area_delimiter; cur_area:=make_string;
+ end;
+@z
+
+@x Printing file names: (518)
+begin print(a); print(n); print(e);
+@y
+begin print(n); print(e); print(a);
+@z
+
+@x Converting file names to Pascal strings: (519)
+allows both lowercase and uppercase letters in the file name.
+@^system dependencies@>
+
+@d append_to_name(#)==begin c:=#; incr(k);
+@y
+converts lowercase letters to uppercase.
+
+A special convention is used here with respect to font metric files: If the
+file name is longer than six characters (e.g., `\.{helvetica}' or
+`\.{oldenglish}'), we abbreviate it by retaining the first three and
+last three characters (e.g., `\.{helica}' or `\.{oldish}').
+@^system dependencies@>
+
+@d append_to_name(#)==begin c:=#; incr(k);
+ if (c>="a")and(c<="z") then c:=c-@'40; {convert to uppercase}
+@z
+@x
+for j:=str_start[a] to str_start[a+1]-1 do append_to_name(str_pool[j]);
+for j:=str_start[n] to str_start[n+1]-1 do append_to_name(str_pool[j]);
+for j:=str_start[e] to str_start[e+1]-1 do append_to_name(str_pool[j]);
+@y
+if (e=".tfm")and(length(n)>6) then
+ begin for j:=str_start[n] to str_start[n]+2 do
+ append_to_name(str_pool[j]);
+ for j:=str_start[n+1]-3 to str_start[n+1]-1 do
+ append_to_name(str_pool[j]);
+ end
+else for j:=str_start[n] to str_start[n+1]-1 do append_to_name(str_pool[j]);
+for j:=str_start[e] to str_start[e+1]-1 do append_to_name(str_pool[j]);
+for j:=str_start[a] to str_start[a+1]-1 do append_to_name(str_pool[j]);
+@z
+
+@x Parsing file names in the buffer: (520)
+@d format_default_length=20 {length of the |TEX_format_default| string}
+@d format_area_length=11 {length of its area part}
+@d format_ext_length=4 {length of its `\.{.fmt}' part}
+@y
+@d format_default_length=18 {length of the |TEX_format_default| string}
+@d format_area_length=9 {length of its area part}
+@d format_ext_length=4 {length of its `\.{.fmt}' part}
+@z
+@x
+TEX_format_default:='TeXformats:plain.fmt';
+@.TeXformats@>
+@y
+TEX_format_default:='plain.fmt[tex,sys]';
+@z
+@x
+|TEX_format_default|.
+@y
+|TEX_format_default|; but it actually switches stuff around to keep the
+file area last.
+@z
+@x
+@!j:integer; {index into |buffer| or |TEX_format_default|}
+@y
+@!j:integer; {index into |buffer| or |TEX_format_default|}
+@!d:integer; {a kludge}
+@z
+@x
+for j:=1 to n do append_to_name(xord[TEX_format_default[j]]);
+for j:=a to b do append_to_name(buffer[j]);
+for j:=format_default_length-format_ext_length+1 to format_default_length do
+ append_to_name(xord[TEX_format_default[j]]);
+@y
+for j:=a to b do append_to_name(buffer[j]);
+if b=0 then
+ begin d:=format_default_length-format_area_length+1;
+ n:=format_default_length;
+ end
+else d:=format_default_length-format_area_length-format_ext_length+1;
+for j:=d to format_default_length-format_area_length do
+ append_to_name(xord[TEX_format_default[j]]);
+for j:=format_default_length-n+1 to format_default_length do
+ append_to_name(xord[TEX_format_default[j]]);
+@z
+
+@x The real file names: (525)
+@ Operating systems often make it possible to determine the exact name (and
+possible version number) of a file that has been opened. The following routine,
+which simply makes a \TeX\ string from the value of |name_of_file|, should
+ideally be changed to deduce the full name of file~|f|, which is the file
+most recently opened, if it is possible to do this in a \PASCAL\ program.
+@^system dependencies@>
+
+This routine might be called after string memory has overflowed, hence
+we dare not use `|str_room|'.
+
+@p function make_name_string:str_number;
+var k:1..file_name_size; {index into |name_of_file|}
+begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings) then
+ make_name_string:="?"
+else begin for k:=1 to name_length do append_char(xord[name_of_file[k]]);
+ make_name_string:=make_string;
+ end;
+end;
+function a_make_name_string(var f:alpha_file):str_number;
+begin a_make_name_string:=make_name_string;
+end;
+function b_make_name_string(var f:byte_file):str_number;
+begin b_make_name_string:=make_name_string;
+end;
+function w_make_name_string(var f:word_file):str_number;
+begin w_make_name_string:=make_name_string;
+end;
+@y
+@ Operating systems often make it possible to determine the exact name (and
+possible version number) of a file that has been opened. The following routine,
+due to David Fuchs, deduces the full name of file~|f| on {\mc WAITS}:
+@^system dependencies@>
+@^Fuchs, David Raymond@>
+
+@p procedure cur_nam(var chan:f@&i@&l@&e;var s:string); extern; @t\2@>@/
+function make_name_string(var f:f@&i@&l@&e):str_number;
+var s:packed array[1..24] of char;
+@!k:1..24; {file names at {\sc SAIL} have at most 23 characters}
+begin if (pool_ptr+24>pool_size)or(str_ptr=max_strings) then
+ make_name_string:="?"
+else begin cur_nam(f,s); k:=1;
+ while ord(s[k])<>0 do
+ begin append_char(xord[s[k]]); incr(k);
+ end;
+ make_name_string:=make_string;
+ end;
+end;
+function a_make_name_string(var f:alpha_file):str_number;
+begin a_make_name_string:=make_name_string(f);
+end;
+function b_make_name_string(var f:byte_file):str_number;
+begin b_make_name_string:=make_name_string(f);
+end;
+function w_make_name_string(var f:word_file):str_number;
+begin w_make_name_string:=make_name_string(f);
+end;
+@z
+
+@x Line editor gets misspelled file name: (530)
+begin if interaction=scroll_mode then wake_up_terminal;
+@y
+@!i:pool_pointer; {index into |str_pool|}
+begin if interaction=scroll_mode then wake_up_terminal;
+@z
+@x
+clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
+@y
+clear_terminal; {now we'll fill the line editor's buffer with the old name}
+for i:=str_start[cur_name] to str_start[cur_name+1]-1 do
+ pto_chr(xchr[str_pool[i]]);
+for i:=str_start[cur_ext] to str_start[cur_ext+1]-1 do
+ pto_chr(xchr[str_pool[i]]);
+for i:=str_start[cur_area] to str_start[cur_area+1]-1 do
+ pto_chr(xchr[str_pool[i]]);
+ptwr1w(0,@'214); {control-formfeed returns cursor to start of line}
+prompt_input(": "); @<Scan file name in the buffer@>;
+@z
+
+@x Reading the first line of a file, again: (538)
+@ Here we have to remember to tell the |input_ln| routine not to
+start with a |get|. If the file is empty, it is considered to
+contain a single blank line.
+@^system dependencies@>
+@^empty line at end of file@>
+
+@<Read the first line...@>=
+begin if not input_ln(cur_file,false) then do_nothing;
+@y
+@ Here we have to remember to tell |input_ln| not to do the first |get|,
+and we also want to skip over a file directory page. An empty file
+is considered to contain a single blank line.
+@^system dependencies@>
+@^empty line at end of file@>
+
+@<Read the first line...@>=
+begin if input_ln(cur_file,false) then
+ begin if(last-start=29)and(buffer[start]="C")and(buffer[start+8]=@'26) then
+ begin while (cur_file^<>chr(form_feed))and(not eof(cur_file)) do
+ begin read_ln(cur_file); read(cur_file,aux_buf:temp_ptr);
+ end; {skip the directory}
+ buffer[start]:=form_feed; last:=start+1;
+ end;
+ end;
+page:=1;
+@z
+
+@x new DVI opcodes [585-586]
+\yskip\noindent Commands 250--255 are undefined at the present time.
+
+@ @d set_char_0=0 {typeset character 0 and move right}
+@y
+\yskip\hang|begin_reflect| 250. Begin a (possibly recursive) reflected segment.
+
+\yskip\hang|end_reflect| 251. End a (possibly recursive) reflected segment.
+
+\yskip\noindent Commands 250--255 are undefined in normal \.{DVI} files,
+but 250 and 251 are permitted in the special `\.{DVI-IVD}' files
+produced by this variant of \TeX.
+
+@ @d begin_reflect=250 {begin a reflected segment (not normally allowed)}
+@d end_reflect=251 {end a reflected segment (not normally allowed)}
+@d set_char_0=0 {typeset character 0 and move right}
+@z
+
+@x The DVI output buffer: (594)
+@!dvi_index=0..dvi_buf_size; {an index into the output buffer}
+@y
+@!dvi_index=0..dvi_buf_size; {an index into the output buffer}
+@!packed_bytes=packed array[dvi_index] of eight_bits;
+ {buffer for \.{DVI} output}
+@z
+@x
+@!dvi_buf:array[dvi_index] of eight_bits; {buffer for \.{DVI} output}
+@y
+@!dvi_buf:packed_bytes; {buffer for \.{DVI} output}
+@z
+@x
+@p procedure write_dvi(@!a,@!b:dvi_index);
+var k:dvi_index;
+begin for k:=a to b do write(dvi_file,dvi_buf[k]);
+end;
+@y
+@p procedure ary_out(var f:file;@!b:packed_bytes; @!o,@!c:integer);
+ extern;@t\2@>@#
+procedure write_dvi(@!a,@!b:dvi_index);
+begin ary_out(dvi_file,dvi_buf,a div 4,(b+1-a)div 4);
+end;
+@z
+
+@x changes to ship_out [638]
+begin if tracing_output>0 then
+@y
+begin LR_ptr:=get_avail; info(LR_ptr):=0; {|begin_L_code| at outer level}
+if tracing_output>0 then
+@z
+@x (module 639)
+flush_node_list(p);
+@y
+flush_node_list(p); @<Flush the LR stack@>;
+@z
+
+@x "r DVIdover": (642)
+ b_close(dvi_file);
+@y
+ b_close(dvi_file);
+ if pseudo_typein=0 then
+ begin k:=selector; selector:=new_string;
+ pool_ptr:=str_start[str_ptr];
+ print("r DVIdover;"); print(output_file_name);
+ selector:=k;
+ if pool_ptr<pool_size then
+ if str_ptr<max_strings then {|overflow| can't occur}
+ pseudo_typein:=make_string;
+ end;
+@z
+
+@x hpack changes [649]
+begin r:=get_node(box_node_size); type(r):=hlist_node;
+@y
+@!LR_ptr,@!LR_tmp:pointer; {for LR stack maintenance}
+@!LR_problems:integer; {counts missing begins and ends}
+begin LR_ptr:=null; LR_problems:=0;
+r:=get_node(box_node_size); type(r):=hlist_node;
+@z
+@x (module 649, continued)
+exit: hpack:=r;
+@y
+exit: @<Check for LR anomalies at the end of |hpack|@>;
+hpack:=r;
+@z
+
+@x Page numbers on over/underfull box messages: (663)
+ print_int(line);
+@y
+ print_int(line);
+ if page>1 then
+ begin print(", p."); print_int(page);
+ end;
+@z
+@x
+ print_int(line);
+@y
+ print_int(line);
+ if page>1 then
+ begin print(", p."); print_int(page);
+ end;
+@z
+
+@x post_line_break stuff [877]
+begin @<Reverse the links of the relevant passive nodes, setting |cur_p| to the
+@y
+@!LR_ptr,@!LR_tmp:pointer; {for LR stack maintenance}
+begin LR_ptr:=null;
+ @<Reverse the links of the relevant passive nodes, setting |cur_p| to the
+@z
+@x (module 877, continued)
+prev_graf:=best_line-1;
+@y
+prev_graf:=best_line-1;
+@<Flush the LR stack@>;
+@z
+@x (module 880)
+@<Modify the end of the line to reflect the nature of the break and to include
+ \.{\\rightskip}; also set the proper value of |disc_break|@>;
+@y
+@<Insert LR nodes at the beginning of the current line@>;
+@<Adjust the LR stack based on LR nodes in this line@>;
+@<Modify the end of the line to reflect the nature of the break and to include
+ \.{\\rightskip}; also set the proper value of |disc_break|@>;
+@<Insert LR nodes at the end of the current line@>;
+@z
+
+@x new horizontal command [1090]
+ vmode+ex_space:@t@>@;@/
+@y
+ vmode+ex_space,vmode+LR:@t@>@;@/
+@z
+
+@x math in text is L-text [module 1196]
+begin tail_append(new_math(math_surround,before));
+@y
+begin tail_append(new_math(math_surround,before));
+@<Append a |begin_L| to the tail of the current list@>;
+@z
+@x (module 1196, continued)
+tail_append(new_math(math_surround,after));
+@y
+@<Append an |end_L| to the tail of the current list@>;
+tail_append(new_math(math_surround,after));
+@z
+
+@x The endgame: (1335)
+@<Last-minute...@>=
+@y
+The new stuff at {\mc SAIL} has to do with preparing for what the user
+presumably wants to do next, by typing it for him/her.
+
+@<Last-minute...@>=
+@z
+@x
+end;
+@y
+if (pseudo_typein<>0)and(interaction>batch_mode) then
+ begin write_ln(term_out);
+ for k:=str_start[pseudo_typein] to str_start[pseudo_typein+1]-1 do
+ pto_chr(xchr[str_pool[k]]);
+ end;
+end;
+@z
+
+@x whatsit processing [1341]
+@d special_node=3 {|subtype| in whatsits that represent \.{\\special} things}
+@y
+@d special_node=3 {|subtype| in whatsits that represent \.{\\special} things}
+@d LR_node=4 {|subtype| in whatsits that represent \.{\\beginL}, etc.}
+@d LR_type(#)==mem[#+1].int {the sub-subtype}
+@z
+@x (module 1344)
+@d immediate_code=4 {command modifier for \.{\\immediate}}
+
+@<Put each...@>=
+@y
+@d immediate_code=4 {command modifier for \.{\\immediate}}
+@d begin_L_code=0 {command modifier for \.{\\beginL}}
+@d begin_R_code=1 {command modifier for \.{\\beginR}}
+@d end_L_code=2 {command modifier for \.{\\endL}}
+@d end_R_code=3 {command modifier for \.{\\endR}}
+@d begin_LR(#)==(LR_type(#)<end_L_code)
+@d begin_LR_type(#)==(LR_type(#)-end_L_code)
+
+@<Put each...@>=
+primitive("beginL",LR,begin_L_code);@/
+@!@:begin_L_}{\.{\\beginL} primitive@>
+primitive("beginR",LR,begin_R_code);@/
+@!@:begin_R_}{\.{\\beginR} primitive@>
+primitive("endL",LR,end_L_code);@/
+@!@:end_L_}{\.{\\endL} primitive@>
+primitive("endR",LR,end_R_code);@/
+@!@:end_R_}{\.{\\endR} primitive@>
+@z
+@x (module 1346)
+@ @<Cases of |print_cmd_chr|...@>=
+@y
+@ @<Cases of |print_cmd_chr|...@>=
+LR: case chr_code of
+begin_L_code: print_esc("beginL");
+begin_R_code: print_esc("beginR");
+end_L_code: print_esc("endL");
+othercases print_esc("endR")
+endcases;
+@z
+@x (module 1356)
+othercases print("whatsit?")
+@y
+LR_node: case LR_type(p) of
+begin_L_code: print_esc("beginL");
+begin_R_code: print_esc("beginR");
+end_L_code: print_esc("endL");
+othercases print_esc("endR")
+endcases;
+othercases print("whatsit?")
+@z
+@x (module 1357)
+close_node: begin r:=get_node(small_node_size); words:=small_node_size;
+@y
+close_node,LR_node: begin r:=get_node(small_node_size); words:=small_node_size;
+@z
+@x (module 1358)
+close_node: free_node(p,small_node_size);
+@y
+close_node,LR_node: free_node(p,small_node_size);
+@z
+@x (module 1360)
+@ @<Incorporate a whatsit node into an hbox@>=do_nothing
+@y
+@ @<Incorporate a whatsit node into an hbox@>=
+if subtype(p)=LR_node then @<Adjust the LR stack for the |hpack| routine@>
+@z
+@x (module 1366)
+@ @<Output the whatsit node |p| in an hlist@>=
+out_what(p)
+@y
+@ @<Output the whatsit node |p| in an hlist@>=
+if subtype(p)<>LR_node then out_what(p)
+else @<Output a reflection instruction if the direction has changed@>
+@z
+
+@x Final system-dependent changes: [1376]
+This section should be replaced, if necessary, by changes to the program
+that are necessary to make \TeX\ work at a particular installation.
+It is usually best to design your change file so that all changes to
+previous sections preserve the section numbering; then everybody's version
+will be consistent with the published program. More extensive changes,
+which introduce new sections, can be inserted here; then only the index
+itself will get a new section number.
+@^system dependencies@>
+@y
+Now we do the main work required for mixed-direction texts.
+
+@<Cases of |main_control| that build...@>=
+hmode+LR: begin new_whatsit(LR_node,small_node_size); LR_type(tail):=cur_chr;
+ end;
+mmode+LR: report_illegal_case;
+
+@ @<Glob...@>=
+@!LR_ptr,@!LR_tmp:pointer; {stack of LR codes and temp for manipulation}
+
+@ @<Declare functions needed for special kinds of nodes@>=
+function new_LR(@!s:small_number): pointer;
+var p: pointer; {the new node}
+begin p:=get_node(small_node_size); type(p):=whatsit_node; subtype(p):=LR_node;
+LR_type(p):=s; new_LR:=p;
+end;
+
+@ @<Declare functions needed for special kinds of nodes@>=
+function safe_info(@!p:pointer): integer;
+begin if p=null then safe_info:=-1@+else safe_info:=info(p);
+end;
+
+@ @<Append a |begin_L| to the tail of the current list@>=
+tail_append(new_LR(begin_L_code))
+
+@ @<Append an |end_L| to the tail of the current list@>=
+tail_append(new_LR(end_L_code))
+
+@ A number of routines are based on a stack of one-word nodes whose |info|
+fields contain either |begin_L_code| or |begin_R_code|. The top of the
+stack is pointed to by |LR_ptr|, and an auxiliary variable |LR_tmp| is
+available for stack manipulation.
+
+@d push_LR(#)==begin LR_tmp:=get_avail; info(LR_tmp):=LR_type(#);
+ link(LR_tmp):=LR_ptr; LR_ptr:=LR_tmp;
+ end
+@d pop_LR==begin LR_tmp:=LR_ptr; LR_ptr:=link(LR_tmp); free_avail(LR_tmp);
+ end
+
+@<Flush the LR stack@>=while LR_ptr<>null do pop_LR
+
+@ @<Insert LR nodes at the beginning of the current line@>=
+while LR_ptr<>null do
+ begin LR_tmp:=new_LR(info(LR_ptr)); link(LR_tmp):=link(temp_head);
+ link(temp_head):=LR_tmp; pop_LR;
+ end
+
+@ @<Adjust the LR stack based on LR nodes in this line@>=
+q:=link(temp_head);
+while q<>cur_break(cur_p) do
+ begin if notis_char_node(q) then if type(q)=whatsit_node then
+ if subtype(q)=LR_node then
+ if begin_LR(q) then push_LR(q)
+ else if LR_ptr<>null then
+ if info(LR_ptr)=begin_LR_type(q) then pop_LR;
+ q:=link(q);
+ end
+
+@ We use the fact that |q| now points to the node with \.{\\rightskip} glue.
+
+@<Insert LR nodes at the end of the current line@>=
+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 LR_tmp:=new_LR(info(r)+end_L_code);
+ link(s):=LR_tmp; s:=LR_tmp; r:=link(r);
+ end;
+ link(s):=q;
+ end
+
+@ @<Adjust the LR stack for the |hpack| routine@>=
+if begin_LR(p) then push_LR(p)
+else if safe_info(LR_ptr)=begin_LR_type(p) then pop_LR
+else begin incr(LR_problems);
+ while link(q)<>p do q:=link(q);
+ link(q):=link(p); free_node(p,small_node_size); p:=q;
+ end
+
+@ @<Check for LR anomalies at the end of |hpack|@>=
+if LR_ptr<>null then
+ begin while link(q)<>null do q:=link(q);
+ repeat link(q):=new_LR(info(LR_ptr)+end_L_code); q:=link(q);
+ LR_problems:=LR_problems+10000; pop_LR;
+ until LR_ptr=null;
+ end;
+if LR_problems>0 then
+ 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; goto common_ending;
+ end
+
+@ @<Output a reflection instruction if the direction has changed@>=
+if begin_LR(p) then
+ begin if safe_info(LR_ptr)<>LR_type(p) then
+ begin synch_h; synch_v; dvi_out(begin_reflect);
+ end;
+ push_LR(p);
+ end
+else if safe_info(LR_ptr)=begin_LR_type(p) then
+ begin pop_LR;
+ if info(LR_ptr)+end_L_code<>LR_type(p) then
+ begin synch_h; synch_v; dvi_out(end_reflect);
+ end;
+ end
+else confusion("LR")
+@:this can't happen LR}{\quad LR@>
+
+
+@ Finally, here are the remaining things needed to make the implementation
+complete at {\mc SAIL}.
+@^system dependencies@>
+
+@ The |pseudo_typein| variable is set nonzero if the |error| routine
+uses the `\.E' option to exit and edit.
+
+@<Glob...@>=
+@!pseudo_typein:str_number;
+
+@ @<Set init...@>=
+pseudo_typein:=0; page:=0;
+
+@ The |mem| array is declared after the other global variables, so
+that our friendly \PASCAL\ will compile things correctly.
+
+@<Glob...@>=
+@!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area}
+@z