diff options
Diffstat (limited to 'language/xettex')
-rw-r--r-- | language/xettex/cxet.ch | 2098 | ||||
-rw-r--r-- | language/xettex/waits-xe.ch | 1979 |
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 |