diff options
author | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
commit | 487ca4806cc046076293cf6cc5fbba0db282bac7 (patch) | |
tree | 847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/web2c/tex.ch | |
parent | a3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff) |
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/tex.ch')
-rw-r--r-- | Build/source/texk/web2c/tex.ch | 5808 |
1 files changed, 5808 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/tex.ch b/Build/source/texk/web2c/tex.ch new file mode 100644 index 00000000000..e0da76b7b89 --- /dev/null +++ b/Build/source/texk/web2c/tex.ch @@ -0,0 +1,5808 @@ +% tex.ch for C compilation with web2c, derived from various other change files. +% By Tim Morgan, UC Irvine ICS Department, and many others. +% +% Be very careful when making changes to this file, as it is used to +% generate TeX, e-TeX, and pdf[ex]TeX, and most changes require similar +% changes to be made to the Omega sources. +% +% (05/28/86) ETM Started with TeX 2.0 +% (06/03/87) ETM Brought up to TeX 2.2 +% (09/26/87) ETM Brought up to TeX 2.3 +% (10/01/87) ETM Brought up to TeX 2.5 +% (12/21/87) ETM Brought up to TeX 2.7 +% (01/14/88) ETM Brought up to TeX 2.9 +% (02/20/88) PAM Revised format and module numbers +% (03/01/88) ETM Eliminated some unused variables and unnecesary tests +% (05/09/88) ETM Added yet another casting bug fix +% (06/21/88) ETM Brought up to TeX version 2.93 +% (12/11/88) ETM Brought up to TeX version 2.94 +% (01/12/89) PAM Brought up to TeX version 2.95 +% (02/14/89) ETM Brought up to TeX version 2.96 +% (03/10/89) ETM Brought up to TeX version 2.98 +% (07/06/89) ETM Brought up to TeX version 2.991 +% (11/30/89) KB To version 2.992 (8-bit). +% (01/10/90) SR To version 2.993. +% (03/27/90) KY To version 3.0. +% (more recent changes in ChangeLog) +% +% The TeX program is copyright (C) 1982 by D. E. Knuth. +% TeX is a trademark of the American Mathematical Society. +% +% Includes MLTEX.CH (Version 2.2) in text format, as of Dec 17, 1995. +% MLTeX is copyright (C) 1990-92 by Michael J. Ferguson; all rights reserved. +% MLTeX Version 2.2 is copyright (C) 1995 by B. Raichle; all rights reserved. +% +% The MLTeX changes are copyrighted so that we have some chance to +% forbid unauthorized copies; we explicitly authorize copying of +% correct MLTeX implementations, and not of incorrect ones! +% +% (This means that you can use the MLTeX changes as free as you can +% use TeX and its algorithm.) +% +% Copying of this file is authorized only if either +% (1) you make absolutely no changes to your copy, including name, or +% (2) if you do make changes, you name it to something other than +% "mltex.ch", "char_sub.ch", or "charsub.ch". +% +% The module numbers in this change file refer to TEX.WEB 3.14159 as +% of March, 1995 (published as Donald E. Knuth, TeX: The Program, +% Volume B of Computers & Typesetting). + +@x [0.0] l.83 - WEAVE: print changes only. + \def\?##1]{\hbox to 1in{\hfil##1.\ }} + } +@y 83 + \def\?##1]{\hbox{Changes to \hbox to 1em{\hfil##1}.\ }} + } +\let\maybe=\iffalse +@z + +@x [1.2] l.185 - MLTeX: add comment about banner line change +November 1984]. +@y +November 1984]. + +ML\TeX{} will add new primitives changing the behaviour of \TeX. The +|banner| string has to be changed. We do not change the |banner| +string, but will output an additional line to make clear that this is +a modified \TeX{} version. + +@z + +@x [1.2] l.188 +@d banner=='This is TeX, Version 3.141592' {printed when \TeX\ starts} +@y +@d TeX_banner_k=='This is TeXk, Version 3.141592' {printed when \TeX\ starts} +@d TeX_banner=='This is TeX, Version 3.141592' {printed when \TeX\ starts} +@# +@d banner==TeX_banner +@d banner_k==TeX_banner_k +@z + +@x [1.4] l.233 - program header +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@> +@y +@z + +@x [1.4] l.243 - labels in outer block not needed +program TEX; {all file names are defined dynamically} +label @<Labels in the outer block@>@/ +@y +program TEX; {all file names are defined dynamically} +@z + +@x [1.6] l.267 - labels in outer block not needed +@ Three labels must be declared in the main program, so we give them +symbolic names. + +@d start_of_TEX=1 {go here when \TeX's variables are initialized} +@d end_of_TEX=9998 {go here to close files and terminate gracefully} +@d final_end=9999 {this label marks the ending of the program} + +@<Labels in the out...@>= +start_of_TEX@t\hskip-2pt@>, end_of_TEX@t\hskip-2pt@>,@,final_end; + {key control points} +@y +@ For Web2c, labels are not declared in the main program, but +we still have to declare the symbolic names. + +@d start_of_TEX=1 {go here when \TeX's variables are initialized} +@d final_end=9999 {this label marks the ending of the program} +@z + +% Here we change these WEB symbols, which are used much as #ifdef's +% are in C, into something which will get translated into actual #ifdef's. +@x [1.7] l.292 - debug..gubed, stat..tats +@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('TEXMF_DEBUG') +@d gubed==endif('TEXMF_DEBUG') +@z +@x [1.7] l.297 - debug..gubed, stat..tats +@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 + +@x [1.8] Somewhat different for `init...tini'.. 310 m.8 +the codewords `$|init|\ldots|tini|$'. + +@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version} +@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version} +@y 314 +the codewords `$|init|\ldots|tini|$' for declarations and by the codewords +`$|Init|\ldots|Tini|$' for executable code. This distinction is helpful for +implementations where a run-time switch differentiates between the two +versions of the program. + +@d init==ifdef('INITEX') +@d tini==endif('INITEX') +@d Init==init if ini_version then begin +@d Tini==end;@+tini +@f Init==begin +@f Tini==end +@z + +@x [1.8] l.319 - init...tini is dynamic +@!init @<Initialize table entries (done by \.{INITEX} only)@>@;@+tini +@y 318 +@!Init @<Initialize table entries (done by \.{INITEX} only)@>@;@+Tini +@z + +@x [1.11] l.375 - Compile-time constants: most removed for dynamic allocation. +@<Constants...@>= +@!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} +@!trie_op_size=500; {space for ``opcodes'' in the hyphenation patterns} +@!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 +@d file_name_size == maxint +@d ssup_error_line = 255 +@d ssup_max_strings == 262143 +{Larger values than 65536 cause the arrays consume much more memory.} +@d ssup_trie_opcode == 65535 +@d ssup_trie_size == @"3FFFFF + +@d ssup_hyph_size == 65535 {Changing this requires changing (un)dumping!} +@d iinf_hyphen_size == 610 {Must be not less than |hyph_prime|!} + +@d max_font_max=2000 {maximum number of internal fonts; this can be + increased, but |hash_size+max_font_max| + should not exceed 29000.} +@d font_base=0 {smallest internal font number; must be + |>= min_quarterword|; do not change this without + modifying the dynamic definition of the font arrays.} + + +@<Constants...@>= +@!hash_offset=514; {smallest index in hash array, i.e., |hash_base| } + {Use |hash_offset=0| for compilers which cannot decrement pointers.} +@!trie_op_size=35111; {space for ``opcodes'' in the hyphenation patterns; + best if relatively prime to 313, 361, and 1009.} +@!neg_trie_op_size=-35111; {for lower |trie_op_hash| array bound; + must be equal to |-trie_op_size|.} +@!min_trie_op=0; {first possible trie op code for any language} +@!max_trie_op=ssup_trie_opcode; {largest possible trie opcode for any language} +@!pool_name=TEXMF_POOL_NAME; {this is configurable, for the sake of ML-\TeX} + {string of length |file_name_size|; tells where the string pool appears} +@!engine_name=TEXMF_ENGINE_NAME; {the name of this engine} +@# +@!inf_mem_bot = 0; +@!sup_mem_bot = 1; + +@!inf_main_memory = 3000; +@!sup_main_memory = 32000000; + +@!inf_trie_size = 8000; +@!sup_trie_size = ssup_trie_size; + +@!inf_max_strings = 3000; +@!sup_max_strings = ssup_max_strings; +@!inf_strings_free = 100; +@!sup_strings_free = sup_max_strings; + +@!inf_buf_size = 500; +@!sup_buf_size = 300000; + +@!inf_nest_size = 40; +@!sup_nest_size = 4000; + +@!inf_max_in_open = 6; +@!sup_max_in_open = 127; + +@!inf_param_size = 60; +@!sup_param_size = 6000; + +@!inf_save_size = 600; +@!sup_save_size = 40000; + +@!inf_stack_size = 200; +@!sup_stack_size = 30000; + +@!inf_dvi_buf_size = 800; +@!sup_dvi_buf_size = 65536; + +@!inf_font_mem_size = 20000; +@!sup_font_mem_size = 2000000; + +@!sup_font_max = max_font_max; +@!inf_font_max = 50; {could be smaller, but why?} + +@!inf_pool_size = 32000; +@!sup_pool_size = 40000000; +@!inf_pool_free = 1000; +@!sup_pool_free = sup_pool_size; +@!inf_string_vacancies = 8000; +@!sup_string_vacancies = sup_pool_size - 23000; + +@!sup_hash_extra = sup_max_strings; +@!inf_hash_extra = 0; + +@!sup_hyph_size = ssup_hyph_size; +@!inf_hyph_size = iinf_hyphen_size; {Must be not less than |hyph_prime|!} +@z + +@x [1.12] l.427 - Constants that are WEB numeric macros. +@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|} +@d hash_prime=1777 {a prime number equal to about 85\pct! of |hash_size|} +@d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions} +@y +@d hash_size=10000 {maximum number of control sequences; it should be at most + about |(mem_max-mem_min)/10|} +@d hash_prime=8501 {a prime number equal to about 85\pct! of |hash_size|} +@d hyph_prime=607 {another prime for hashing \.{\\hyphenation} exceptions; + if you change this, you should also change |iinf_hyphen_size|.} +@z + +@x [1.16] l.498 - Use C macros for `incr' and `decr'. +@d incr(#) == #:=#+1 {increase a variable by unity} +@d decr(#) == #:=#-1 {decrease a variable by unity} +@y +@z + +% The text_char type is used as an array index into xord. The +% default type `char' produces signed integers, which are bad array +% indices in C. +@x [2.19] l.565 - data type text_char is 8-bit ASCII_code +@d text_char == char {the data type of characters in text files} +@y +@d text_char == ASCII_code {the data type of characters in text files} +@z + +@x [2.20] l.579 - encTeX: global declarations +@!xchr: array [ASCII_code] of text_char; + {specifies conversion of output characters} +@y +xchr: array [ASCII_code] of text_char; + { specifies conversion of output characters } +xprn: array [ASCII_code] of ASCII_code; + { non zero iff character is printable } +mubyte_read: array [ASCII_code] of pointer; + { non zero iff character begins the multi byte code } +mubyte_write: array [ASCII_code] of str_number; + { non zero iff character expands to multi bytes in log and write files } +mubyte_cswrite: array [0..127] of pointer; + { non null iff cs mod 128 expands to multi bytes in log and write files } +mubyte_skip: integer; { the number of bytes to skip in |buffer| } +mubyte_keep: integer; { the number of chars we need to keep unchanged } +mubyte_skeep: integer; { saved |mubyte_keep| } +mubyte_prefix: integer; { the type of mubyte prefix } +mubyte_tablein: boolean; { the input side of table will be updated } +mubyte_tableout: boolean; { the output side of table will be updated } +mubyte_relax: boolean; { the relax prefix is used } +mubyte_start: boolean; { we are making the token at the start of the line } +mubyte_sstart: boolean; { saved |mubyte_start| } +mubyte_token: pointer; { the token returned by |read_buffer| } +mubyte_stoken: pointer; { saved first token in mubyte primitive } +mubyte_sout: integer; { saved value of |mubyte_out| } +mubyte_slog: integer; { saved value of |mubyte_log| } +spec_sout: integer; { saved value of |spec_out| } +no_convert: boolean; { conversion supressed by noconvert primitive } +active_noconvert: boolean; { true if noconvert primitive is active } +write_noexpanding: boolean; { true only if we need not write expansion } +cs_converting: boolean; { true only if we need csname converting } +special_printing: boolean; { true only if we need converting in special } +message_printing: boolean; { true if message or errmessage prints to string } +@z + +@x [2.23] l.723 - Translate characters if desired, otherwise allow them all. +for i:=0 to @'37 do xchr[i]:=' '; +for i:=@'177 to @'377 do xchr[i]:=' '; +@y +{Initialize |xchr| to the identity mapping.} +for i:=0 to @'37 do xchr[i]:=i; +for i:=@'177 to @'377 do xchr[i]:=i; +{Initialize enc\TeX\ data.} +for i:=0 to 255 do mubyte_read[i]:=null; +for i:=0 to 255 do mubyte_write[i]:=0; +for i:=0 to 128 do mubyte_cswrite[i]:=null; +mubyte_keep := 0; mubyte_start := false; +write_noexpanding := false; cs_converting := false; +special_printing := false; message_printing := false; +no_convert := false; active_noconvert := false; +@z + +@x [2.24] l.733 - Don't reinitialize xord. +for i:=0 to @'176 do xord[xchr[i]]:=i; +@y +for i:=0 to @'176 do xord[xchr[i]]:=i; +{Set |xprn| for printable ASCII, unless |eight_bit_p| is set.} +for i:=0 to 255 do xprn[i]:=(eight_bit_p or ((i>=" ")and(i<="~"))); + +{The idea for this dynamic translation comes from the patch by + Libor Skarvada \.{<libor@@informatics.muni.cz>} + and Petr Sojka \.{<sojka@@informatics.muni.cz>}. I didn't use any of the + actual code, though, preferring a more general approach.} + +{This updates the |xchr|, |xord|, and |xprn| arrays from the provided + |translate_filename|. See the function definition in \.{texmfmp.c} for + more comments.} +if translate_filename then read_tcx_file; +@z + +% [3.26] name_of_file is no longer an array. And change the destination +% type to text_char, which fixes: +% +% Date: 19 Sep 1994 10:38:24 +0200 +% From: thorinn@diku.dk (Lars Mathiesen) +% When echoed to the screen and in the log, character codes +% above '177 in file names are shown wrongly (typically as ^@). +% +@x [3.26] l.789 - name_of_file is no longer an array +@!name_of_file:packed array[1..file_name_size] of char;@;@/ + {on some systems this may be a \&{record} variable} +@y +@!name_of_file:^text_char; +@z + +@x [3.27] l.794 - Do file opening in C. +@ 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 are defined in C. +@z + +@x [3.28] l.850 - Do file closing in C. +@ 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 the file closing routines as well. +@z + +@x [3.30] l.888 - Array size of input buffer is determined at runtime. +@!buffer:array[0..buf_size] of ASCII_code; {lines of characters being read} +@y +@!buffer:^ASCII_code; {lines of characters being read} +@z + +@x [3.31] l.933 - Do `input_ln' in C. +@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 + @<Report overflow of the input buffer, and abort@>; + 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 define |input_ln| in C, for efficiency. Nevertheless we quote the module +`Report overflow of the input buffer, and abort' here in order to make +\.{WEAVE} happy, since part of that module is needed by e-TeX. + +@p @{ @<Report overflow of the input buffer, and abort@> @} +@z + +% [3.32] `term_in' and `term_out' are standard input and output. +% Declare the variables that used to be constants. +@x [3.32] l.961 - `term_in' and `term_out' are standard input and output. +@<Glob...@>= +@!term_in:alpha_file; {the terminal as an input file} +@!term_out:alpha_file; {the terminal as an output file} +@y +@d term_in==stdin {the terminal as an input file} +@d term_out==stdout {the terminal as an output file} + +@<Glob...@>= +@!init +@!ini_version:boolean; {are we \.{INITEX}?} +@!dump_option:boolean; {was the dump name option used?} +@!dump_line:boolean; {was a \.{\%\AM format} line seen?} +tini@/ +@# +@!bound_default:integer; {temporary for setup} +@!bound_name:^char; {temporary for setup} +@# +@!mem_bot:integer;{smallest index in the |mem| array dumped by \.{INITEX}; + must not be less than |mem_min|} +@!main_memory:integer; {total memory words allocated in initex} +@!extra_mem_bot:integer; {|mem_min:=mem_bot-extra_mem_bot| except in \.{INITEX}} +@!mem_min:integer; {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|} +@!mem_top:integer; {largest index in the |mem| array dumped by \.{INITEX}; + must be substantially larger than |mem_bot|, + equal to |mem_max| in \.{INITEX}, else not greater than |mem_max|} +@!extra_mem_top:integer; {|mem_max:=mem_top+extra_mem_top| except in \.{INITEX}} +@!mem_max:integer; {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|} +@!error_line:integer; {width of context lines on terminal error messages} +@!half_error_line:integer; {width of first lines of contexts in terminal + error messages; should be between 30 and |error_line-15|} +@!max_print_line:integer; + {width of longest text lines output; should be at least 60} +@!max_strings:integer; {maximum number of strings; must not exceed |max_halfword|} +@!strings_free:integer; {strings available after format loaded} +@!string_vacancies:integer; {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:integer; {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} +@!pool_free:integer;{pool space free after format loaded} +@!font_mem_size:integer; {number of words of |font_info| for all fonts} +@!font_max:integer; {maximum internal font number; ok to exceed |max_quarterword| + and must be at most |font_base|+|max_font_max|} +@!font_k:integer; {loop variable for initialization} +@!hyph_size:integer; {maximun number of hyphen exceptions} +@!trie_size:integer; {space for hyphenation patterns; should be larger for + \.{INITEX} than it is in production versions of \TeX. 50000 is + needed for English, German, and Portuguese.} +@!buf_size:integer; {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|} +@!stack_size:integer; {maximum number of simultaneous input sources} +@!max_in_open:integer; {maximum number of input files and error insertions that + can be going on simultaneously} +@!param_size:integer; {maximum number of simultaneous macro parameters} +@!nest_size:integer; {maximum number of semantic levels simultaneously active} +@!save_size:integer; {space for saving values outside of current group; must be + at most |max_halfword|} +@!dvi_buf_size:integer; {size of the output buffer; must be a multiple of 8} +@!parse_first_line_p:c_int_type; {parse the first line for options} +@!file_line_error_style_p:c_int_type; {format messages as file:line:error} +@!eight_bit_p:c_int_type; {make all characters printable by default} +@!halt_on_error_p:c_int_type; {stop at first error} +@!quoted_filename:boolean; {current filename is quoted} +{Variables for source specials} +@!src_specials_p : boolean;{Whether |src_specials| are enabled at all} +@!insert_src_special_auto : boolean; +@!insert_src_special_every_par : boolean; +@!insert_src_special_every_parend : boolean; +@!insert_src_special_every_cr : boolean; +@!insert_src_special_every_math : boolean; +@!insert_src_special_every_hbox : boolean; +@!insert_src_special_every_vbox : boolean; +@!insert_src_special_every_display : boolean; +@z + +@x [3.33] l.964 - We don't need to open terminal files. +@ 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 defined in C. + +@d t_open_out == {output already open for text output} +@z + +@x [3.34] l.982 - Flushing output to terminal files. +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} +@y +these operations can be specified with {\mc UNIX}. |update_terminal| +does an |fflush|. |clear_terminal| is redefined +to do nothing, since the user should control the terminal. +@^system dependencies@> + +@d update_terminal == fflush (term_out) +@d clear_terminal == do_nothing +@z + +@x [3.35] l.1017 - needed for e-TeX, but differently +@<Report overflow of the input buffer, and abort@>= +if format_ident=0 then + begin write_ln(term_out,'Buffer size exceeded!'); goto final_end; +@.Buffer size exceeded@> + end +else begin cur_input.loc_field:=first; cur_input.limit_field:=last-1; +@y +Routine is implemented in C; part of module is, however, needed for e-TeX. + +@<Report overflow of the input buffer, and abort@>= + begin cur_input.loc_field:=first; cur_input.limit_field:=last-1; +@z + +@x [3.37] l.1055 - |init_terminal|, reading the command line. +@ 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; +@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; +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; +@z + +@x [3.37] l.1068 - |init_terminal|, output missing newline. + write(term_out,'! End of file on the terminal... why?'); +@y + write_ln(term_out,'! End of file on the terminal... why?'); +@z + +@x [4.38] l.1126 - Array size for string pool is determined at runtime. +@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|} +@!str_number = 0..max_strings; {for variables that point into |str_start|} +@y +@!pool_pointer = integer; {for variables that point into |str_pool|} +@!str_number = 0..ssup_max_strings; {for variables that point into |str_start|} +@z + +@x [4.39] l.1131 - Dynamically size pool arrays. +@!str_pool:packed array[pool_pointer] of packed_ASCII_code; {the characters} +@!str_start : array[str_number] of pool_pointer; {the starting pointers} +@y +@!str_pool: ^packed_ASCII_code; {the characters} +@!str_start : ^pool_pointer; {the starting pointers} +@z + +@x [4.47] l.1237 - string recycling +@p @!init function get_strings_started:boolean; {initializes the string pool, +@y +@p @t\4@>@<Declare additional routines for string recycling@>@/ + +@!init function get_strings_started:boolean; {initializes the string pool, +@z + +@x [4.49] l.1272 -- Change documentation (probably needed in more places) +would like string @'32 to be the single character @'32 instead of the +@y +would like string @'32 to be printed as the single character @'32 +instead of the +@z + +% [4.51] Open the pool file using a path, and can't do string +% assignments directly. (`strcpy' and `strlen' work here because +% `pool_name' is a constant string, and thus ends in a null and doesn't +% start with a space.) +@x [4.51] l.1314 - Open the pool file. +name_of_file:=pool_name; {we needn't set |name_length|} +if a_open_in(pool_file) then +@y +name_length := strlen (pool_name); +name_of_file := xmalloc_array (ASCII_code, name_length + 1); +strcpy (stringcast(name_of_file+1), pool_name); {copy the string} +if a_open_in (pool_file, kpse_texpool_format) then +@z + +@x [4.51] l.1322 - Make `TEX.POOL' lowercase, and change how it's read. +else bad_pool('! I can''t read TEX.POOL.') +@y +else bad_pool('! I can''t read ', pool_name, '; bad path?') +@z +@x [4.52] l.1326 - Make `TEX.POOL' lowercase, and change how it's read. +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('! ', pool_name, ' 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 [4.52] l.1332 - Make `TEX.POOL' lowercase, and change how it's read. + bad_pool('! TEX.POOL line doesn''t begin with two digits.'); +@y + bad_pool('! ', pool_name, ' line doesn''t begin with two digits.'); +@z +@x [4.53] l.1354 - Make `TEX.POOL' lowercase, and change how it's read. + bad_pool('! TEX.POOL check sum doesn''t have nine digits.'); +@y + bad_pool('! ', pool_name, ' check sum doesn''t have nine digits.'); +@z +@x [4.53] l.1360 - Make `TEX.POOL' lowercase, and change how it's read. +done: if a<>@$ then bad_pool('! TEX.POOL doesn''t match; TANGLE me again.'); +@y +done: if a<>@$ then + bad_pool('! ', pool_name, ' doesn''t match; tangle me again (or fix the path).'); +@z + +@x [5.54] l.1422 - error_line +@!trick_buf:array[0..error_line] of ASCII_code; {circular buffer for +@y +@!trick_buf:array[0..ssup_error_line] of ASCII_code; {circular buffer for +@z + +@x [5.59] l.1508FIXME -- enc\TeX\ modifications of |print|. + else begin if selector>pseudo then + begin print_char(s); return; {internal strings are not expanded} + end; + if (@<Character |s| is the current new-line character@>) then + if selector<pseudo then + begin print_ln; return; + end; +@y + else begin if (selector>pseudo) and (not special_printing) + and (not message_printing) then + begin print_char(s); return; {internal strings are not expanded} + end; + if (@<Character |s| is the current new-line character@>) then + if selector<pseudo then + begin print_ln; no_convert := false; return; + end + else if message_printing then + begin print_char(s); no_convert := false; return; + end; + if (mubyte_log>0) and (not no_convert) and (mubyte_write[s]>0) then + s := mubyte_write[s] + else if xprn[s] or special_printing then + begin print_char(s); no_convert := false; return; end; + no_convert := false; +@z + +@x l.1536 -- If the ``src-specials'' feature is active, change the banner. +wterm(banner); +@y +if src_specials_p or file_line_error_style_p or parse_first_line_p then + wterm(banner_k) +else + wterm(banner); +@z + +@x [5.61] l.1556 - Print rest of banner, eliminate misleading `(no format preloaded)'. +if format_ident=0 then wterm_ln(' (no format preloaded)') +else begin slow_print(format_ident); print_ln; + end; +@y +wterm(version_string); +if format_ident>0 then slow_print(format_ident); +print_ln; +if shell_enabled_p then begin + wterm_ln(' \write18 enabled.') +end; +if src_specials_p then begin + wterm_ln(' Source specials enabled.') +end; +if file_line_error_style_p then begin + wterm_ln(' file:line:error style messages enabled.') +end; +if parse_first_line_p then begin + wterm_ln(' %&-line parsing enabled.') +end; +if translate_filename then begin + wterm(' ('); + fputs(translate_filename, stdout); + wterm_ln(')'); +end; +@z + +@x [5.71] encTeX - native buffer printing +if last<>first then for k:=first to last-1 do print(buffer[k]); +@y +k:=first; while k < last do begin print_buffer(k) end; +@z + +@x [6.73] l.1732 - Add unspecified_mode. +@d error_stop_mode=3 {stops at every opportunity to interact} +@y +@d error_stop_mode=3 {stops at every opportunity to interact} +@d unspecified_mode=4 {extra value for command-line switch} +@z + +@x [6.73] l.1734 - file:line:error style error messages. + print_nl("! "); print(#); +@y + if file_line_error_style_p then print_file_line + else print_nl("! "); + print(#); +@z + + +@x [6.73] l.1738 - Add interaction_option. +@!interaction:batch_mode..error_stop_mode; {current level of interaction} +@y +@!interaction:batch_mode..error_stop_mode; {current level of interaction} +@!interaction_option:batch_mode..unspecified_mode; {set from command line} +@z + +@x [6.74] l.1740 - Allow override by command line switch. +@ @<Set init...@>=interaction:=error_stop_mode; +@y +@ @<Set init...@>=if interaction_option=unspecified_mode then + interaction:=error_stop_mode +else + interaction:=interaction_option; +@z + +% [6.81] Eliminate nonlocal goto, since C doesn't have them. +% 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 [6.81] l.1852 - Eliminate nonlocal goto, since C doesn't have them. +@<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 + +@x [6.82] l.1866 - halt on error? +print_char("."); show_context; +@y +print_char("."); show_context; +if (halt_on_error_p) then begin + history:=fatal_error_stop; jump_out; +end; +@z + +@x [6.84] l.1888 - Implement the switch-to-editor option. +line ready to be edited. But such an extension requires some system +wizardry, so the present implementation simply types out the name of the +file that should be +edited and the relevant line number. +@^system dependencies@> + +There is a secret `\.D' option available when the debugging routines haven't +been commented~out. +@^debugging@> +@y +line ready to be edited. +We do this by calling the external procedure |call_edit| 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 haven't +been commented~out. +@^debugging@> +@d edit_file==input_stack[base_ptr] +@z + +@x [6.84] l.1903 - Implement the switch-to-editor option. +"E": if base_ptr>0 then + begin print_nl("You want to edit file "); +@.You want to edit file x@> + slow_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.104] `remainder' is a library routine on some systems, so change +% its name to avoid conflicts. +@x [7.104] l.2227 - avoid name conflicts with lib routine remainder() +|remainder|, holds the remainder after a division. + +@<Glob...@>= +@y +|remainder|, holds the remainder after a division. + +@d remainder==tex_remainder + +@<Glob...@>= +@z + +@x [7.109] l.2352 - Define glue_ratio in C. +@!glue_ratio=real; {one-word representation of a glue expansion factor} +@y +@z + +% [8.110] Make it easy to change constants. Do not increase +% max_quarterword without changing the memoryword structure in `texmfmem.h'. +% If you set min_quarterword or min_halfword to a non-zero value, you have +% to remove the definitions of qi/qo, hi/ho in this change file! +@x [8.110] l.2405 - increase |max_halfword| +@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 2407 +@d min_quarterword=0 {smallest allowable value in a |quarterword|} +@d max_quarterword=255 {largest allowable value in a |quarterword|} +@d min_halfword==-@"FFFFFFF {smallest allowable value in a |halfword|} +@d max_halfword==@"FFFFFFF {largest allowable value in a |halfword|} +@z + +@x [8.111] l.2422 - max_font_max +if (font_base<min_quarterword)or(font_max>max_quarterword) then bad:=15; +if font_max>font_base+256 then bad:=16; +@y +if (max_font_max<min_halfword)or(max_font_max>max_halfword) then bad:=15; +if font_max>font_base+max_font_max then bad:=16; +@z + +@x [8.112] l.2435 - Efficiency. +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 +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] We've put the memory structure into the include file +% `texmf.h', since it's too hard to translate automatically. +@x [8.113] l.2453 - data structures for main memory +@!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; +@y +@!quarterword = min_quarterword..max_quarterword; +@!halfword = min_halfword..max_halfword; +@!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 "texmfmem.h";@> +@z + +% [9.116] Change `mem' to `zmem', so we can define mem to be a register +% pointer to the memory array for speed. +@x [9.116] l.2545 - definition of main memory array +@!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area} +@y +@!yzmem : ^memory_word; {the big dynamic storage area} +@!zmem : ^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 [9.127] l.2739 - Fix casting problem in C. +if r>p+1 then @<Allocate from the top of node |p| and |goto found|@>; +@y 2738 +if r>intcast(p+1) then @<Allocate from the top of node |p| and |goto found|@>; +@z + +@x [10.144] l.3006 - font numbers can be >255 now. +@p function new_ligature(@!f,@!c:quarterword; @!q:pointer):pointer; +@y +@p function new_ligature(@!f:internal_font_number; @!c:quarterword; + @!q:pointer):pointer; +@z + +% [11.165] Fix the word `free' so that it doesn't conflict with the +% standard C library routine of the same name. +@x [11.165] l.3364 - avoid conflict with lib function free() +are debugging.) +@y +are debugging.) + +@d free==free_arr +@z + +@x [11.165] l.3367 - dummy |free| and |was_free| arrays +@!debug @!free: packed array [mem_min..mem_max] of boolean; {free cells} +@t\hskip10pt@>@!was_free: packed array [mem_min..mem_max] of boolean; +@y + {The debug memory arrays have not been mallocated yet.} +@!debug @!free: packed array [0..9] of boolean; {free cells} +@t\hskip10pt@>@!was_free: packed array [0..9] of boolean; +@z + +@x [12.174] l.3526 - Eliminate unsigned comparisons to zero. + begin if (font(p)<font_base)or(font(p)>font_max) then +@y + begin if (font(p)>font_max) then +@z + +@x [12.176] l.3563 - Eliminate unsigned comparisons to zero. +@p procedure print_font_and_char(@!p:integer); {prints |char_node| data} +begin if p>mem_end then print_esc("CLOBBERED.") +else begin if (font(p)<font_base)or(font(p)>font_max) then print_char("*") +@y +@p procedure print_font_and_char(@!p:integer); {prints |char_node| data} +begin if p>mem_end then print_esc("CLOBBERED.") +else begin if (font(p)>font_max) then print_char("*") +@z + +@x [12.186] l.3747 - Don't worry about strange floating point values. + if abs(mem[p+glue_offset].int)<@'4000000 then print("?.?") + else if abs(g)>float_constant(20000) then +@y 3747 + { 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 +@z + + +@x [15.209] l.4165 - MLTeX: \charsubdef primitive +@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} +@y +@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} + {or \.{\\charsubdef}} +@z + +% i18n fix: messages printed by print_mode in [16.211] and [46.1049] +% can not be translated. For example, messages printed by |print_mode| +% from [16.211] use different word order and [46.1049] use different +% word order and words are declined. +@x [16.211] l.4256 +begin if m>0 then + case m div (max_command+1) of + 0:print("vertical"); + 1:print("horizontal"); + 2:print("display math"); + end +else if m=0 then print("no") +else case (-m) div (max_command+1) of + 0:print("internal vertical"); + 1:print("restricted horizontal"); + 2:print("math"); + end; +print(" mode"); +end; +@y +begin if m>0 then + case m div (max_command+1) of + 0:print("vertical mode"); + 1:print("horizontal mode"); + 2:print("display math mode"); + end +else if m=0 then print("no mode") +else case (-m) div (max_command+1) of + 0:print("internal vertical mode"); + 1:print("restricted horizontal mode"); + 2:print("math mode"); + end; +end; + +procedure print_in_mode(@!m:integer); {prints the mode represented by |m|} +begin if m>0 then + case m div (max_command+1) of + 0:print("' in vertical mode"); + 1:print("' in horizontal mode"); + 2:print("' in display math mode"); + end +else if m=0 then print("' in no mode") +else case (-m) div (max_command+1) of + 0:print("' in internal vertical mode"); + 1:print("' in restricted horizontal mode"); + 2:print("' in math mode"); + end; +end; +@z + +@x [16.213] l.4321 - texarray +@!nest:array[0..nest_size] of list_state_record; +@y +@!nest:^list_state_record; +@z + +@x [16.215] l.4344 - remove mem[] reference from initialize. +prev_graf:=0; shown_mode:=0; +@<Start a new current page@>; +@y +prev_graf:=0; shown_mode:=0; +@/{The following piece of code is a copy of module 991:} +page_contents:=empty; page_tail:=page_head; {|link(page_head):=null;|}@/ +last_glue:=max_halfword; last_penalty:=0; last_kern:=0; +page_depth:=0; page_max_depth:=0; +@z + +@x [16.219] l.4409 - i18n fix + print_int(nest[p].pg_field); print(" line"); + if nest[p].pg_field<>1 then print_char("s"); +@y + print_int(nest[p].pg_field); + if nest[p].pg_field<>1 then print(" lines") + else print(" line"); +@z + +@x [17.220] l.4448 - MLTeX: char_sub_code_base +paragraph shape. +@y +paragraph shape. +Additionally region~4 contains the table with ML\TeX's character +substitution definitions. +@z + +@x [17.222] l.4523 - frozen_special, for source specials. +@d frozen_null_font=frozen_control_sequence+10 + {permanent `\.{\\nullfont}'} +@y +@d frozen_special=frozen_control_sequence+10 + {permanent `\.{\\special}'} +@d frozen_null_font=frozen_control_sequence+11 + {permanent `\.{\\nullfont}'} +@z + +@x [17.222] l.4526 - max_font_max +@d undefined_control_sequence=frozen_null_font+257 {dummy location} +@y +@d undefined_control_sequence=frozen_null_font+max_font_max+1 {dummy location} +@z + +@x [17.222] l.4533 - hash_extra +for k:=active_base to undefined_control_sequence-1 do + eqtb[k]:=eqtb[undefined_control_sequence]; +@y +for k:=active_base to eqtb_top do + eqtb[k]:=eqtb[undefined_control_sequence]; +@z + +@x [17.230] l.4725 - encTeX: xord_code_base, xchr_code_base, prn_code_base, +@d math_font_base=cur_font_loc+1 {table of 48 math font numbers} +@y +@d xord_code_base=cur_font_loc+1 +@d xchr_code_base=xord_code_base+1 +@d xprn_code_base=xchr_code_base+1 +@d math_font_base=xprn_code_base+1 +@z + +@x [17.230] l.4731 - MLTeX: char_sub_code_base +@d int_base=math_code_base+256 {beginning of region 5} +@y +@d char_sub_code_base=math_code_base+256 {table of character substitutions} +@d int_base=char_sub_code_base+256 {beginning of region 5} +@z + +@x [17.230] l.4752 - MLTeX: char_sub_code_base + {Note: |math_code(c)| is the true math code plus |min_halfword|} +@y + {Note: |math_code(c)| is the true math code plus |min_halfword|} +@d char_sub_code(#)==equiv(char_sub_code_base+#) + {Note: |char_sub_code(c)| is the true substitution info plus |min_halfword|} +@z + +% MLTeX: \charsubdefmax and \tracingcharsubdef +% encTeX: \mubytein \mubyteout \mubytelog and \specialout +@x [17.236] l.4954 +@d int_pars=55 {total number of integer parameters} +@y +@d tex_int_pars=55 {total number of \TeX's integer parameters} +@# +@d web2c_int_base=tex_int_pars {base for web2c's integer parameters} +@d char_sub_def_min_code=web2c_int_base {smallest value in the charsubdef list} +@d char_sub_def_max_code=web2c_int_base+1 {largest value in the charsubdef list} +@d tracing_char_sub_def_code=web2c_int_base+2 {traces changes to a charsubdef def} +@d mubyte_in_code=web2c_int_base+3 {if positive then reading mubytes is active} +@d mubyte_out_code=web2c_int_base+4 {if positive then printing mubytes is active} +@d mubyte_log_code=web2c_int_base+5 {if positive then print mubytes to log and terminal} +@d spec_out_code=web2c_int_base+6 {if positive then print specials by mubytes} +@d web2c_int_pars=web2c_int_base+7 {total number of web2c's integer parameters} +@# +@d int_pars=web2c_int_pars {total number of integer parameters} +@z + +% MLTeX: \charsubdefmax and \tracingcharsubdef +% encTeX: \mubytein \mubyteout \mubytelog and \specialout +@x [17.236] l.5016 +@d error_context_lines==int_par(error_context_lines_code) +@y +@d error_context_lines==int_par(error_context_lines_code) +@# +@d char_sub_def_min==int_par(char_sub_def_min_code) +@d char_sub_def_max==int_par(char_sub_def_max_code) +@d tracing_char_sub_def==int_par(tracing_char_sub_def_code) +@d mubyte_in==int_par(mubyte_in_code) +@d mubyte_out==int_par(mubyte_out_code) +@d mubyte_log==int_par(mubyte_log_code) +@d spec_out==int_par(spec_out_code) +@z + +% MLTeX: \charsubdefmax and \tracingcharsubdef +% encTeX: \mubytein \mubyteout \mubytelog and \specialout +@x [17.237] l.5080 +error_context_lines_code:print_esc("errorcontextlines"); +@y +error_context_lines_code:print_esc("errorcontextlines"); +char_sub_def_min_code:print_esc("charsubdefmin"); +char_sub_def_max_code:print_esc("charsubdefmax"); +tracing_char_sub_def_code:print_esc("tracingcharsubdef"); +mubyte_in_code:print_esc("mubytein"); +mubyte_out_code:print_esc("mubyteout"); +mubyte_log_code:print_esc("mubytelog"); +spec_out_code:print_esc("specialout"); +@z + +% MLTeX: \charsubdefmax and \tracingcharsubdef +% encTeX: \mubytein \mubyteout \mubytelog and \specialout +@x [17.238] l.5200 +@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> +@y +@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> +if mltex_p then + begin mltex_enabled_p:=true; {enable character substitution} + if false then {remove the if-clause to enable \.{\\charsubdefmin}} + primitive("charsubdefmin",assign_int,int_base+char_sub_def_min_code);@/ +@!@:char_sub_def_min_}{\.{\\charsubdefmin} primitive@> + primitive("charsubdefmax",assign_int,int_base+char_sub_def_max_code);@/ +@!@:char_sub_def_max_}{\.{\\charsubdefmax} primitive@> + primitive("tracingcharsubdef",assign_int,int_base+tracing_char_sub_def_code);@/ +@!@:tracing_char_sub_def_}{\.{\\tracingcharsubdef} primitive@> + end; +if enctex_p then + begin enctex_enabled_p:=true; + primitive("mubytein",assign_int,int_base+mubyte_in_code);@/ +@!@:mubyte_in_}{\.{\\mubytein} primitive@> + primitive("mubyteout",assign_int,int_base+mubyte_out_code);@/ +@!@:mubyte_out_}{\.{\\mubyteout} primitive@> + primitive("mubytelog",assign_int,int_base+mubyte_log_code);@/ +@!@:mubyte_log_}{\.{\\mubytelog} primitive@> + primitive("specialout",assign_int,int_base+spec_out_code);@/ +@!@:spec_out_}{\.{\\specialout} primitive@> +end; +@z + +@x [17.240] l.5213 - MLTeX: \charsubdefmax and \tracingcharsubdef +for k:=int_base to del_code_base-1 do eqtb[k].int:=0; +@y +for k:=int_base to del_code_base-1 do eqtb[k].int:=0; +char_sub_def_min:=256; char_sub_def_max:=-1; +{allow \.{\\charsubdef} for char 0}@/ +{|tracing_char_sub_def:=0| is already done}@/ +@z + +@x [17.241] l.5219 - Do `fix_date_and_time' in C. +@ 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| +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 + +@x [17.252] l.5420 - hash_extra +else if n<glue_base then @<Show equivalent |n|, in region 1 or 2@> +@y +else if (n<glue_base) or ((n>eqtb_size)and(n<=eqtb_top)) then + @<Show equivalent |n|, in region 1 or 2@> +@z + +@x [17.253] l.5435 - Change eqtb to zeqtb. +@!eqtb:array[active_base..eqtb_size] of memory_word; +@y +@!zeqtb:^memory_word; +@z + +@x [18.256] l.5483 - hash_extra +@!hash: array[hash_base..undefined_control_sequence-1] of two_halves; + {the hash table} +@!hash_used:pointer; {allocation pointer for |hash|} +@y +@!hash: ^two_halves; {the hash table} +@!yhash: ^two_halves; {auxiliary pointer for freeing hash} +@!hash_used:pointer; {allocation pointer for |hash|} +@!hash_extra:pointer; {|hash_extra=hash| above |eqtb_size|} +@!hash_top:pointer; {maximum of the hash array} +@!eqtb_top:pointer; {maximum of the |eqtb|} +@!hash_high:pointer; {pointer to next high hash location} +@z + +@x [18.257] l.5491 - hash_extra +next(hash_base):=0; text(hash_base):=0; +for k:=hash_base+1 to undefined_control_sequence-1 do hash[k]:=hash[hash_base]; +@y +@z + +@x [18.258] l.5495 - hash_extra +hash_used:=frozen_control_sequence; {nothing is used} +@y +hash_used:=frozen_control_sequence; {nothing is used} +hash_high:=0; +@z + +@x [18.260] l.5531 - hash_extra +@ @<Insert a new control...@>= +begin if text(p)>0 then + begin repeat if hash_is_full then overflow("hash size",hash_size); +@:TeX capacity exceeded hash size}{\quad hash size@> + decr(hash_used); + until text(hash_used)=0; {search for an empty location in |hash|} + next(p):=hash_used; p:=hash_used; + end; +@y +@ @<Insert a new control...@>= +begin if text(p)>0 then + begin if hash_high<hash_extra then + begin incr(hash_high); + next(p):=hash_high+eqtb_size; p:=hash_high+eqtb_size; + end + else begin + repeat if hash_is_full then overflow("hash size",hash_size+hash_extra); +@:TeX capacity exceeded hash size}{\quad hash size@> + decr(hash_used); + until text(hash_used)=0; {search for an empty location in |hash|} + next(p):=hash_used; p:=hash_used; + end; + end; +@z + +@x [18.262] - encTeX: control sequence to byte sequence +@<Basic printing...@>= +procedure print_cs(@!p:integer); {prints a purported control sequence} +begin if p<hash_base then {single character} +@y +The conversion from control sequence to byte sequence for enc\TeX is +implemented here. Of course, the simplest way is to implement an array +of string pointers with |hash_size| length, but we assume that only a +few control sequences will need to be converted. So |mubyte_cswrite|, +an array with only 128 items, is used. The items point to the token +lists. First token includes a csname number and the second points the +string to be output. The third token includes the number of another +csname and fourth token its pointer to the string etc. We need to do +the sequential searching in one of the 128 token lists. + +@<Basic printing...@>= +procedure print_cs(@!p:integer); {prints a purported control sequence} +var q: pointer; + s: str_number; +begin + if active_noconvert and (not no_convert) and + (eq_type(p) = let) and (equiv(p) = normal+11) then { noconvert } + begin + no_convert := true; + return; + end; + s := 0; + if cs_converting and (not no_convert) then + begin + q := mubyte_cswrite [p mod 128] ; + while q <> null do + if info (q) = p then + begin + s := info (link(q)); q := null; + end else q := link (link (q)); + end; + no_convert := false; + if s > 0 then print (s) + else if p<hash_base then {single character} +@z + +@x [18.262] l.5583 - hash_extra +else if p>=undefined_control_sequence then print_esc("IMPOSSIBLE.") +@y +else if ((p>=undefined_control_sequence)and(p<=eqtb_size))or(p>eqtb_top) then + print_esc("IMPOSSIBLE.") +@z + +@x [18.262] l.5584 - Remove more unsigned comparisons to zero. +else if (text(p)<0)or(text(p)>=str_ptr) then print_esc("NONEXISTENT.") +@y +else if (text(p)>=str_ptr) then print_esc("NONEXISTENT.") +@z + +@x [18.262] - encTeX: exit label for print_cs + print_char(" "); + end; +end; +@y + print_char(" "); + end; +exit: end; +@z + +@x [18.265] - encTeX: \endmubyte primitive +primitive("endcsname",end_cs_name,0);@/ +@!@:end_cs_name_}{\.{\\endcsname} primitive@> +@y +primitive("endcsname",end_cs_name,0);@/ +@!@:end_cs_name_}{\.{\\endcsname} primitive@> +if enctex_p then +begin + primitive("endmubyte",end_cs_name,10);@/ +@!@:end_mubyte_}{\.{\\endmubyte} primitive@> +end; +@z + +@x [18.266] - encTeX: \endmubyte primitive +end_cs_name: print_esc("endcsname"); +@y +end_cs_name: if chr_code = 10 then print_esc("endmubyte") + else print_esc("endcsname"); +@z + +@x [19.271] l.5872 - texarray +@!save_stack : array[0..save_size] of memory_word; +@y +@!save_stack : ^memory_word; +@z + +@x [19.283] l.6050 - hash_extra +if p<int_base then +@y +if (p<int_base)or(p>eqtb_size) then +@z + +@x [20.290] l.6158 - hash_extra +if cs_token_flag+undefined_control_sequence>max_halfword then bad:=21; +@y +if cs_token_flag+eqtb_size+hash_extra>max_halfword then bad:=21; +if (hash_offset<0)or(hash_offset>hash_base) then bad:=42; +@z + +@x [22.301] l.6432 - texarray +@!input_stack : array[0..stack_size] of in_state_record; +@y +@!input_stack : ^in_state_record; +@z + +@x [22.304] l.6536 - texarray; additions for file:line:error style. +@!input_file : array[1..max_in_open] of alpha_file; +@!line : integer; {current line number in the current source file} +@!line_stack : array[1..max_in_open] of integer; +@y +@!input_file : ^alpha_file; +@!line : integer; {current line number in the current source file} +@!line_stack : ^integer; +@!source_filename_stack : ^str_number; +@!full_source_filename_stack : ^str_number; +@z + +@x [22.306] l.6855 - i18n fix + begin print_nl("Runaway "); +@.Runaway...@> + case scanner_status of + defining: begin print("definition"); p:=def_ref; + end; + matching: begin print("argument"); p:=temp_head; + end; + aligning: begin print("preamble"); p:=hold_head; + end; + absorbing: begin print("text"); p:=def_ref; + end; + end; {there are no other cases} +@y + begin +@.Runaway...@> + case scanner_status of + defining: begin print_nl("Runaway definition"); p:=def_ref; + end; + matching: begin print_nl("Runaway argument"); p:=temp_head; + end; + aligning: begin print_nl("Runaway preamble"); p:=hold_head; + end; + absorbing: begin print_nl("Runaway text"); p:=def_ref; + end; + end; {there are no other cases} +@z + +@x [22.308] l.6701 - texarray +@!param_stack:array [0..param_size] of pointer; + {token list pointers for parameters} +@y +@!param_stack: ^pointer; + {token list pointers for parameters} +@z + +@x [22.318] encTeX - native buffer printing +if j>0 then for i:=start to j-1 do + begin if i=loc then set_trick_count; + print(buffer[i]); + end +@y +i := start; mubyte_skeep := mubyte_keep; +mubyte_sstart := mubyte_start; mubyte_start := false; +if j>0 then while i < j do +begin + if i=loc then set_trick_count; + print_buffer(i); +end; +mubyte_keep := mubyte_skeep; mubyte_start := mubyte_sstart +@z + +@x [23.328] l.7043 - keep top of source_filename_stack initialized +incr(in_open); push_input; index:=in_open; +@y +incr(in_open); push_input; index:=in_open; +source_filename_stack[index]:=0;full_source_filename_stack[index]:=0; +@z + +@x [23.331] l.7071 - init source file name stacks +begin input_ptr:=0; max_in_stack:=0; +@y +begin input_ptr:=0; max_in_stack:=0; +source_filename_stack[0]:=0;full_source_filename_stack[0]:=0; +@z + +@x [24.332] encTeX: insert the added functions +appear on that line. (There might not be any tokens at all, if the +|end_line_char| has |ignore| as its catcode.) +@y +appear on that line. (There might not be any tokens at all, if the +|end_line_char| has |ignore| as its catcode.) + +Some additional routines used by the enc\TeX extension have to be +declared at this point. + +@p @t\4@>@<Declare additional routines for enc\TeX@>@/ +@z + +@x [24.338] l.7164 - i18n fix +print(" while scanning "); +@y +@z + +@x [24.339] l.7185 - i18n fix +defining:begin print("definition"); info(p):=right_brace_token+"}"; + end; +matching:begin print("use"); info(p):=par_token; long_state:=outer_call; + end; +aligning:begin print("preamble"); info(p):=right_brace_token+"}"; q:=p; + p:=get_avail; link(p):=q; info(p):=cs_token_flag+frozen_cr; + align_state:=-1000000; + end; +absorbing:begin print("text"); info(p):=right_brace_token+"}"; +@y +defining:begin print(" while scanning definition"); info(p):=right_brace_token+"}"; + end; +matching:begin print(" while scanning use"); info(p):=par_token; long_state:=outer_call; + end; +aligning:begin print(" while scanning preamble"); info(p):=right_brace_token+"}"; q:=p; + p:=get_avail; link(p):=q; info(p):=cs_token_flag+frozen_cr; + align_state:=-1000000; + end; +absorbing:begin print(" while scanning text"); info(p):=right_brace_token+"}"; +@z + +@x [24.341] - encTeX: more declarations in expand processor +var k:0..buf_size; {an index into |buffer|} +@!t:halfword; {a token} +@y +var k:0..buf_size; {an index into |buffer|} +@!t:halfword; {a token} +@!i,@!j: 0..buf_size; {more indexes for encTeX} +@!mubyte_incs: boolean; {control sequence is converted by mubyte} +@!p:pointer; {for encTeX test if noexpanding} +@z + +@x [24.343] - encTeX: access the buffer via read_buffer + begin cur_chr:=buffer[loc]; incr(loc); +@y + begin + { Use |k| instead of |loc| for type correctness. } + k := loc; + cur_chr := read_buffer (k); + loc := k; incr (loc); + if (mubyte_token > 0) then + begin + state := mid_line; + cur_cs := mubyte_token - cs_token_flag; + goto found; + end; +@z + +@x [24.354] - encTeX: access the buffer via read_buffer +else begin start_cs: k:=loc; cur_chr:=buffer[k]; cat:=cat_code(cur_chr); + incr(k); +@y +else begin start_cs: + mubyte_incs := false; k := loc; mubyte_skeep := mubyte_keep; + cur_chr := read_buffer (k); cat := cat_code (cur_chr); + if (mubyte_in>0) and (not mubyte_incs) and + ((mubyte_skip>0) or (cur_chr<>buffer[k])) then mubyte_incs := true; + incr (k); + if mubyte_token > 0 then + begin + state := mid_line; + cur_cs := mubyte_token - cs_token_flag; + goto found; + end; +@z + +@x [24.354] - encTeX: noexpanding the marked control sequence + cur_cs:=single_base+buffer[loc]; incr(loc); + end; +found: cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs); +if cur_cmd>=outer_call then check_outer_validity; +@y + mubyte_keep := mubyte_skeep; + cur_cs:=single_base + read_buffer(loc); incr(loc); + end; +found: cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs); +if cur_cmd>=outer_call then check_outer_validity; +if write_noexpanding then +begin + p := mubyte_cswrite [cur_cs mod 128]; + while p <> null do + if info (p) = cur_cs then + begin + cur_cmd := relax; cur_chr := 256; p := null; + end else p := link (link (p)); +end; +@z + +@x [24.356] - encTeX: access the buffer via read_buffer +begin repeat cur_chr:=buffer[k]; cat:=cat_code(cur_chr); incr(k); +until (cat<>letter)or(k>limit); +@<If an expanded...@>; +if cat<>letter then decr(k); + {now |k| points to first nonletter} +if k>loc+1 then {multiletter control sequence has been scanned} + begin cur_cs:=id_lookup(loc,k-loc); loc:=k; goto found; + end; +end +@y +begin + repeat cur_chr := read_buffer (k); cat := cat_code (cur_chr); + if mubyte_token>0 then cat := escape; + if (mubyte_in>0) and (not mubyte_incs) and (cat=letter) and + ((mubyte_skip>0) or (cur_chr<>buffer[k])) then mubyte_incs := true; + incr (k); + until (cat <> letter) or (k > limit); + @<If an expanded...@>; + if cat <> letter then + begin + decr (k); k := k - mubyte_skip; + end; + if k > loc + 1 then { multiletter control sequence has been scanned } + begin + if mubyte_incs then { multibyte in csname occurrs } + begin + i := loc; j := first; mubyte_keep := mubyte_skeep; + if j - loc + k > max_buf_stack then + begin + max_buf_stack := j - loc + k; + if max_buf_stack >= buf_size then + begin + max_buf_stack := buf_size; + overflow ("buffer size", buf_size); + end; + end; + while i < k do + begin + buffer [j] := read_buffer (i); + incr (i); incr (j); + end; + if j = first+1 then + cur_cs := single_base + buffer [first] + else + cur_cs := id_lookup (first, j-first); + end else cur_cs := id_lookup (loc, k-loc) ; + loc := k; + goto found; + end; +end +@z + +@x [24.357] - encTeX: noexpanding the marked control sequence + else check_outer_validity; +@y + else check_outer_validity; + if write_noexpanding then + begin + p := mubyte_cswrite [cur_cs mod 128]; + while p <> null do + if info (p) = cur_cs then + begin + cur_cmd := relax; cur_chr := 256; p := null; + end else p := link (link (p)); + end; +@z + +@x [24.363] encTeX - native buffer printing + if start<limit then for k:=start to limit-1 do print(buffer[k]); +@y + k := start; + while k < limit do begin print_buffer(k) end; +@z + +@x [25.372] - encTeX: we need to distinguish \endcsname and \endmubyte +if cur_cmd<>end_cs_name then @<Complain about missing \.{\\endcsname}@>; +@y +if (cur_cmd<>end_cs_name) or (cur_chr<>0) then @<Complain about missing \.{\\endcsname}@>; +@z + +@x [26.414] l.8358 - encTeX: accessing xord/xchr/xprn +if m=math_code_base then scanned_result(ho(math_code(cur_val)))(int_val) +@y +if m=xord_code_base then scanned_result(xord[cur_val])(int_val) +else if m=xchr_code_base then scanned_result(xchr[cur_val])(int_val) +else if m=xprn_code_base then scanned_result(xprn[cur_val])(int_val) +else if m=math_code_base then scanned_result(ho(math_code(cur_val)))(int_val) +@z + +@x [28.501] l.9747 - \eof18 +if_eof_code: begin scan_four_bit_int; b:=(read_open[cur_val]=closed); + end; +@y +if_eof_code: begin scan_four_bit_int_or_18; + if cur_val=18 then b:=not shell_enabled_p + else b:=(read_open[cur_val]=closed); + end; +@z + +@x [29.513] l.9951 - Area and extension rules for filenames. +@ 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. +@y +@ The file names we shall deal with have the +following structure: If the name contains `\./' or `\.:' +(for Amiga only), 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 last +`\..' to the end, otherwise the file extension is null. +@z + +@x [29.513] l.9963 - Area and extension rules for filenames. +@!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any} +@!ext_delimiter:pool_pointer; {the relevant `\..', if any} +@y +@!area_delimiter:pool_pointer; {the most recent `\./', if any} +@!ext_delimiter:pool_pointer; {the most recent `\..', if any} +@z + +@x [29.514] l.9973 - TeX area directories. +@d TEX_area=="TeXinputs:" +@.TeXinputs@> +@d TEX_font_area=="TeXfonts:" +@.TeXfonts@> +@y +In C, the default paths are specified separately. +@z + +@x [29.515] l.9995 - filenames: quoted +begin area_delimiter:=0; ext_delimiter:=0; +@y +begin area_delimiter:=0; ext_delimiter:=0; quoted_filename:=false; +@z + +@x [29.516] l.9992 - filenames: more_name +begin if c=" " then more_name:=false +@y +begin if (c=" ") and stop_at_space and (not quoted_filename) then + more_name:=false +else if c="""" then begin + quoted_filename:=not quoted_filename; + more_name:=true; + end +@z + +@x [29.516] l.9994 - filenames: more_name + if (c=">")or(c=":") then +@y + if IS_DIR_SEP(c) then +@z + +@x [29.516] l.9997 - filenames: more_name + else if (c=".")and(ext_delimiter=0) then ext_delimiter:=cur_length; +@y + else if c="." then ext_delimiter:=cur_length; +@z + +@x [29.517] l.10002 - end_name: string recycling +@ The third. +@^system dependencies@> + +@p procedure end_name; +@y +@ The third. +@^system dependencies@> +If a string is already in the string pool, the function +|slow_make_string| does not create a new string but returns this string +number, thus saving string space. Because of this new property of the +returned string number it is not possible to apply |flush_string| to +these strings. + +@p procedure end_name; +var temp_str: str_number; {result of file name cache lookups} +@!j,@!s,@!t: pool_pointer; {running indices} +@!must_quote:boolean; {whether we need to quote a string} +@z + +@x [29.517] l.10022 - end_name: spaces in filenames +@:TeX capacity exceeded number of strings}{\quad number of strings@> +@y +@:TeX capacity exceeded number of strings}{\quad number of strings@> +str_room(6); {Room for quotes, if needed.} +{add quotes if needed} +if area_delimiter<>0 then begin + {maybe quote |cur_area|} + must_quote:=false; + s:=str_start[str_ptr]; + t:=str_start[str_ptr]+area_delimiter; + j:=s; + while (not must_quote) and (j<>t) do begin + must_quote:=str_pool[j]=" "; incr(j); + end; + if must_quote then begin + for j:=pool_ptr-1 downto t do str_pool[j+2]:=str_pool[j]; + str_pool[t+1]:=""""; + for j:=t-1 downto s do str_pool[j+1]:=str_pool[j]; + str_pool[s]:=""""; + if ext_delimiter<>0 then ext_delimiter:=ext_delimiter+2; + area_delimiter:=area_delimiter+2; + pool_ptr:=pool_ptr+2; + end; + end; +{maybe quote |cur_name|} +s:=str_start[str_ptr]+area_delimiter; +if ext_delimiter=0 then t:=pool_ptr else t:=str_start[str_ptr]+ext_delimiter-1; +must_quote:=false; +j:=s; +while (not must_quote) and (j<>t) do begin + must_quote:=str_pool[j]=" "; incr(j); + end; +if must_quote then begin + for j:=pool_ptr-1 downto t do str_pool[j+2]:=str_pool[j]; + str_pool[t+1]:=""""; + for j:=t-1 downto s do str_pool[j+1]:=str_pool[j]; + str_pool[s]:=""""; + if ext_delimiter<>0 then ext_delimiter:=ext_delimiter+2; + pool_ptr:=pool_ptr+2; + end; +if ext_delimiter<>0 then begin + {maybe quote |cur_ext|} + s:=str_start[str_ptr]+ext_delimiter-1; + t:=pool_ptr; + must_quote:=false; + j:=s; + while (not must_quote) and (j<>t) do begin + must_quote:=str_pool[j]=" "; incr(j); + end; + if must_quote then begin + str_pool[t+1]:=""""; + for j:=t-1 downto s do str_pool[j+1]:=str_pool[j]; + str_pool[s]:=""""; + pool_ptr:=pool_ptr+2; + end; + end; +@z + +@x [29.517] l.10011 - end_name: string recycling + str_start[str_ptr+1]:=str_start[str_ptr]+area_delimiter; incr(str_ptr); + end; +if ext_delimiter=0 then + begin cur_ext:=""; cur_name:=make_string; +@y + str_start[str_ptr+1]:=str_start[str_ptr]+area_delimiter; incr(str_ptr); + temp_str:=search_string(cur_area); + if temp_str>0 then + begin cur_area:=temp_str; + decr(str_ptr); {no |flush_string|, |pool_ptr| will be wrong!} + for j:=str_start[str_ptr+1] to pool_ptr-1 do + begin str_pool[j-area_delimiter]:=str_pool[j]; + end; + pool_ptr:=pool_ptr-area_delimiter; {update |pool_ptr|} + end; + end; +if ext_delimiter=0 then + begin cur_ext:=""; cur_name:=slow_make_string; +@z + +@x [29.517] l.10016 - end_name: string recycling +else begin cur_name:=str_ptr; + str_start[str_ptr+1]:=str_start[str_ptr]+ext_delimiter-area_delimiter-1; + incr(str_ptr); cur_ext:=make_string; +@y +else begin cur_name:=str_ptr; + str_start[str_ptr+1]:=str_start[str_ptr]+ext_delimiter-area_delimiter-1; + incr(str_ptr); cur_ext:=make_string; + decr(str_ptr); {undo extension string to look at name part} + temp_str:=search_string(cur_name); + if temp_str>0 then + begin cur_name:=temp_str; + decr(str_ptr); {no |flush_string|, |pool_ptr| will be wrong!} + for j:=str_start[str_ptr+1] to pool_ptr-1 do + begin str_pool[j-ext_delimiter+area_delimiter+1]:=str_pool[j]; + end; + pool_ptr:=pool_ptr-ext_delimiter+area_delimiter+1; {update |pool_ptr|} + end; + cur_ext:=slow_make_string; {remake extension string} +@z + +@x [29.518] l.10042 - print_file_name: quote if spaces in names. +begin slow_print(a); slow_print(n); slow_print(e); +@y +var must_quote: boolean; {whether to quote the filename} +@!j:pool_pointer; {index into |str_pool|} +begin +must_quote:=false; +if a<>0 then begin + j:=str_start[a]; + while (not must_quote) and (j<>str_start[a+1]) do begin + must_quote:=str_pool[j]=" "; incr(j); + end; +end; +if n<>0 then begin + j:=str_start[n]; + while (not must_quote) and (j<>str_start[n+1]) do begin + must_quote:=str_pool[j]=" "; incr(j); + end; +end; +if e<>0 then begin + j:=str_start[e]; + while (not must_quote) and (j<>str_start[e+1]) do begin + must_quote:=str_pool[j]=" "; incr(j); + end; +end; +{FIXME: Alternative is to assume that any filename that has to be quoted has + at least one quoted component...if we pick this, a number of insertions + of |print_file_name| should go away. +|must_quote|:=((|a|<>0)and(|str_pool|[|str_start|[|a|]]=""""))or + ((|n|<>0)and(|str_pool|[|str_start|[|n|]]=""""))or + ((|e|<>0)and(|str_pool|[|str_start|[|e|]]=""""));} +if must_quote then print_char(""""); +if a<>0 then + for j:=str_start[a] to str_start[a+1]-1 do + if so(str_pool[j])<>"""" then + print(so(str_pool[j])); +if n<>0 then + for j:=str_start[n] to str_start[n+1]-1 do + if so(str_pool[j])<>"""" then + print(so(str_pool[j])); +if e<>0 then + for j:=str_start[e] to str_start[e+1]-1 do + if so(str_pool[j])<>"""" then + print(so(str_pool[j])); +if must_quote then print_char(""""); +@z + +@x [29.519] l.10051 - have append_to_name skip quotes. +@d append_to_name(#)==begin c:=#; incr(k); + if k<=file_name_size then name_of_file[k]:=xchr[c]; + end +@y +@d append_to_name(#)==begin c:=#; if not (c="""") then begin incr(k); + if k<=file_name_size then name_of_file[k]:=xchr[c]; + end end +@z + +% [29.519] In pack_file_name, leave room for the extra null we append at +% the end of a filename. +@x [29.519] l.10047 - pack_file_name, leave room for the extra null +for j:=str_start[a] to str_start[a+1]-1 do append_to_name(so(str_pool[j])); +@y +if name_of_file then libc_free (name_of_file); +name_of_file:= xmalloc_array (ASCII_code, length(a)+length(n)+length(e)+1); +for j:=str_start[a] to str_start[a+1]-1 do append_to_name(so(str_pool[j])); +@z + +@x [29.519] l.10051 - pack_file_name, append the extra null +for k:=name_length+1 to file_name_size do name_of_file[k]:=' '; +@y +name_of_file[name_length+1]:=0; +@z + +@x [29.520] l.10060 - filenames: default format. +@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 {\mc UNIX} we don't give the area part, instead depending +on the path searching that will happen during file opening. Also, the +length will be set in the main program. + +@d format_area_length=0 {length of its area part} +@d format_ext_length=4 {length of its `\.{.fmt}' part} +@z + +@x [29.521] l.10066 - filenames: default format, where `plain.fmt' is. +@!TEX_format_default:packed array[1..format_default_length] of char; + +@ @<Set init...@>= +TEX_format_default:='TeXformats:plain.fmt'; +@y +@!format_default_length: integer; +@!TEX_format_default: ^char; + +@ We set the name of the default format file and the length of that name +in C, instead of Pascal, since we want them to depend on the name of the +program. +@z + +@x [29.523] l.10095 - Change to pack_buffered_name as with pack_file_name. +for j:=1 to n do append_to_name(xord[TEX_format_default[j]]); +@y +if name_of_file then libc_free (name_of_file); +name_of_file := xmalloc_array (ASCII_code, n+(b-a+1)+format_ext_length+1); +for j:=1 to n do append_to_name(xord[TEX_format_default[j]]); +@z + +% @x [29.523] l.10097 - Set program name to match format. +% for j:=a to b do append_to_name(buffer[j]); +% @y +% for j:=a to b do append_to_name(buffer[j]); +% name_of_file[k+1]:=0; +% kpse_reset_program_name(name_of_file+1); +% @z + +@x [29.523] l.10100 - Change to pack_buffered_name as with pack_file_name. +for k:=name_length+1 to file_name_size do name_of_file[k]:=' '; +@y +name_of_file[name_length+1]:=0; +@z + +@x [29.524] l.10118 - Format file opening: only try once, with path searching. + 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); {Kpathsea does everything} + if w_open_in(fmt_file) then goto found; +@z + +@x [29.524] l.10124 - replace `PLAIN' in error messages with `default'. + wterm_ln('Sorry, I can''t find that format;',' will try PLAIN.'); +@y + wterm ('Sorry, I can''t find the format `'); + fputs (stringcast(name_of_file + 1), stdout); + wterm ('''; will try `'); + fputs (TEX_format_default + 1, stdout); + wterm_ln ('''.'); +@z + +@x [29.524] l.10132 - replace `PLAIN' in error messages with `default'. + wterm_ln('I can''t find the PLAIN format file!'); +@.I can't find PLAIN...@> +@y + wterm ('I can''t find the format file `'); + fputs (TEX_format_default + 1, stdout); + wterm_ln ('''!'); +@.I can't find the format...@> +@z + +@x [29.525] l.10163 - make_name_string + make_name_string:=make_string; + end; +@y + make_name_string:=make_string; + end; + {At this point we also set |cur_name|, |cur_ext|, and |cur_area| to + match the contents of |name_of_file|.} + k:=1; + name_in_progress:=true; + begin_name; + stop_at_space:=false; + while (k<=name_length)and(more_name(name_of_file[k])) do + incr(k); + stop_at_space:=true; + end_name; + name_in_progress:=false; +@z + +@x [29.526] l.10194 - stop scanning file name if we're at end-of-line. + if not more_name(cur_chr) then goto done; +@y + {If |cur_chr| is a space and we're not scanning a token list, check + whether we're at the end of the buffer. Otherwise we end up adding + spurious spaces to file names in some cases.} + if (cur_chr=" ") and (state<>token_list) and (loc>limit) then goto done; + if not more_name(cur_chr) then goto done; +@z + +@x [29.530] l.10245 - prompt_file_name: prevent empty filenames. +var k:0..buf_size; {index into |buffer|} +@y +var k:0..buf_size; {index into |buffer|} +@!saved_cur_name:str_number; {to catch empty terminal input} +@z + +@x [29.530] l.10252 - prompt_file_name: No default extension is TeX input file. +if e=".tex" then show_context; +@y +if (e=".tex") or (e="") then show_context; +@z + +@x [29.530] l.10258 - prompt_file_name: prevent empty filenames. +clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>; +if cur_ext="" then cur_ext:=e; +@y +saved_cur_name:=cur_name; +clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>; +if cur_ext="" then cur_ext:=e; +if length(cur_name)=0 then cur_name:=saved_cur_name; +@z + +@x [29.532] l.10263 - avoid conflict, `logname' in <unistd.h> on some systems. +@d ensure_dvi_open==if output_file_name=0 then +@y +@d log_name == texmf_log_name +@d ensure_dvi_open==if output_file_name=0 then +@z + +@x [29.534] l.10285 - Adjust for C string conventions. +@!months:packed array [1..36] of char; {abbreviations of month names} +@y +@!months:^char; +@z + +@x [29.534] l.10300 - Filename change for the recorder. +if job_name=0 then job_name:="texput"; +@.texput@> +@y +if job_name=0 then job_name:=get_job_name("texput"); +@.texput@> +pack_job_name(".fls"); +recorder_change_filename(stringcast(name_of_file+1)); +@z + +@x [29.534] l.10293 - MLTeX: add MLTeX banner after loading fmt file +@<Print the banner line, including the date and time@>; +@y +@<Print the banner line, including the date and time@>; +if mltex_enabled_p then + begin wlog_cr; wlog('MLTeX v2.2 enabled'); + end; +if enctex_enabled_p then + begin wlog_cr; wlog(encTeX_banner); wlog(', reencoding enabled'); + if translate_filename then + begin wlog_cr; + wlog(' (\xordcode, \xchrcode, \xprncode overridden by TCX)'); + end; + end; +@z + +@x +begin wlog(banner); +@y +begin +if src_specials_p or file_line_error_style_p or parse_first_line_p +then + wlog(banner_k) +else + wlog(banner); +@z + +@x [29.536] l.10324 - Print rest of banner. +slow_print(format_ident); print(" "); +@y +wlog(version_string); +slow_print(format_ident); print(" "); +@z + +@x [29.536] l.10327 - Adjust for C string conventions. +months:='JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'; +@y +months := ' JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'; +@z + +% Print whether we're using src-specials. +% Print TCX name if one's given. +@x [29/536] l.10331 +end +@y +if shell_enabled_p then begin + wlog_cr; + wlog('\write18 enabled.') + end; +if src_specials_p then begin + wlog_cr; + wlog(' Source specials enabled.') + end; +if file_line_error_style_p then begin + wlog_cr; + wlog(' file:line:error style messages enabled.') + end; +if parse_first_line_p then begin + wlog_cr; + wlog(' %&-line parsing enabled.'); + end; +if translate_filename then begin + wlog_cr; + wlog(' ('); + fputs(translate_filename, log_file); + wlog(')'); + end; +end +@z + +% [29.537] Use a path when calling a_open_in to do a \input; also, try +% to open the file with and without the `.tex' extension, regardless of +% whether the file already has an extension. This allows filenames like +% `foo' and `foo.bar.tex', as well as `foo.tex' and `foo.bar'. +@x [29.537] l.10338 - start_input +begin scan_file_name; {set |cur_name| to desired file name} +if cur_ext="" then cur_ext:=".tex"; +pack_cur_name; +loop@+ begin begin_file_reading; {set up |cur_file| and new level of input} + 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 +var temp_str: str_number; k: integer; +begin scan_file_name; {set |cur_name| to desired file name} +pack_cur_name; +loop@+begin + begin_file_reading; {set up |cur_file| and new level of input} + tex_input_type := 1; {Tell |open_input| we are \.{\\input}.} + {Kpathsea tries all the various ways to get the file.} + if open_in_name_ok(stringcast(name_of_file+1)) + and a_open_in(cur_file, kpse_tex_format) then + goto done; +@z + +@x [29.537] l.10348 - start_input: don't force ".tex" extension. + prompt_file_name("input file name",".tex"); +@y + prompt_file_name("input file name",""); +@z + +@x [29.537] l.10350 - start_input: string recycling +done: name:=a_make_name_string(cur_file); +@y +done: name:=a_make_name_string(cur_file); +source_filename_stack[in_open]:=name; +full_source_filename_stack[in_open]:=make_full_name_string; +if name=str_ptr-1 then {we can try to conserve string pool space now} + begin temp_str:=search_string(name); + if temp_str>0 then + begin name:=temp_str; flush_string; + end; + end; +@z + +@x [29.537] l.10352 - start_input: was job_name given on the command line? + begin job_name:=cur_name; open_log_file; +@y + begin job_name:=get_job_name(cur_name); open_log_file; +@z + +@x [29.537] l.10356 - +if term_offset+length(name)>max_print_line-2 then print_ln +else if (term_offset>0)or(file_offset>0) then print_char(" "); +print_char("("); incr(open_parens); slow_print(name); update_terminal; +@y +if term_offset+length(full_source_filename_stack[in_open])>max_print_line-2 +then print_ln +else if (term_offset>0)or(file_offset>0) then print_char(" "); +print_char("("); incr(open_parens); +slow_print(full_source_filename_stack[in_open]); update_terminal; +@z + +@x [29.537] l.10360 - start_input: don't return filename to string pool. +if name=str_ptr-1 then {we can conserve string pool space now} + begin flush_string; name:=cur_name; + end; +@y +@z + +@x [30.548] l.10673 - texarray +@!internal_font_number=font_base..font_max; {|font| in a |char_node|} +@!font_index=0..font_mem_size; {index into |font_info|} +@y +@!internal_font_number=integer; {|font| in a |char_node|} +@!font_index=integer; {index into |font_info|} +@!nine_bits=min_quarterword..non_char; +@z + +@x [30.549] l.10682 - texarray +@!font_info:array[font_index] of memory_word; + {the big collection of font data} +@!fmem_ptr:font_index; {first unused word of |font_info|} +@!font_ptr:internal_font_number; {largest internal font number in use} +@!font_check:array[internal_font_number] of four_quarters; {check sum} +@!font_size:array[internal_font_number] of scaled; {``at'' size} +@!font_dsize:array[internal_font_number] of scaled; {``design'' size} +@!font_params:array[internal_font_number] of font_index; {how many font + parameters are present} +@!font_name:array[internal_font_number] of str_number; {name of the font} +@!font_area:array[internal_font_number] of str_number; {area of the font} +@!font_bc:array[internal_font_number] of eight_bits; + {beginning (smallest) character code} +@!font_ec:array[internal_font_number] of eight_bits; + {ending (largest) character code} +@!font_glue:array[internal_font_number] of pointer; + {glue specification for interword space, |null| if not allocated} +@!font_used:array[internal_font_number] of boolean; + {has a character from this font actually appeared in the output?} +@!hyphen_char:array[internal_font_number] of integer; + {current \.{\\hyphenchar} values} +@!skew_char:array[internal_font_number] of integer; + {current \.{\\skewchar} values} +@!bchar_label:array[internal_font_number] of font_index; + {start of |lig_kern| program for left boundary character, + |non_address| if there is none} +@!font_bchar:array[internal_font_number] of min_quarterword..non_char; + {right boundary character, |non_char| if there is none} +@!font_false_bchar:array[internal_font_number] of min_quarterword..non_char; + {|font_bchar| if it doesn't exist in the font, otherwise |non_char|} +@y +@!font_info: ^fmemory_word; + {the big collection of font data} +@!fmem_ptr:font_index; {first unused word of |font_info|} +@!font_ptr:internal_font_number; {largest internal font number in use} +@!font_check: ^four_quarters; {check sum} +@!font_size: ^scaled; {``at'' size} +@!font_dsize: ^scaled; {``design'' size} +@!font_params: ^font_index; {how many font + parameters are present} +@!font_name: ^str_number; {name of the font} +@!font_area: ^str_number; {area of the font} +@!font_bc: ^eight_bits; + {beginning (smallest) character code} +@!font_ec: ^eight_bits; + {ending (largest) character code} +@!font_glue: ^pointer; + {glue specification for interword space, |null| if not allocated} +@!font_used: ^boolean; + {has a character from this font actually appeared in the output?} +@!hyphen_char: ^integer; + {current \.{\\hyphenchar} values} +@!skew_char: ^integer; + {current \.{\\skewchar} values} +@!bchar_label: ^font_index; + {start of |lig_kern| program for left boundary character, + |non_address| if there is none} +@!font_bchar: ^nine_bits; + {right boundary character, |non_char| if there is none} +@!font_false_bchar: ^nine_bits; + {|font_bchar| if it doesn't exist in the font, otherwise |non_char|} +@z + +@x [30.550] l.10723 - texarray +@!char_base:array[internal_font_number] of integer; + {base addresses for |char_info|} +@!width_base:array[internal_font_number] of integer; + {base addresses for widths} +@!height_base:array[internal_font_number] of integer; + {base addresses for heights} +@!depth_base:array[internal_font_number] of integer; + {base addresses for depths} +@!italic_base:array[internal_font_number] of integer; + {base addresses for italic corrections} +@!lig_kern_base:array[internal_font_number] of integer; + {base addresses for ligature/kerning programs} +@!kern_base:array[internal_font_number] of integer; + {base addresses for kerns} +@!exten_base:array[internal_font_number] of integer; + {base addresses for extensible recipes} +@!param_base:array[internal_font_number] of integer; + {base addresses for font parameters} +@y +@!char_base: ^integer; + {base addresses for |char_info|} +@!width_base: ^integer; + {base addresses for widths} +@!height_base: ^integer; + {base addresses for heights} +@!depth_base: ^integer; + {base addresses for depths} +@!italic_base: ^integer; + {base addresses for italic corrections} +@!lig_kern_base: ^integer; + {base addresses for ligature/kerning programs} +@!kern_base: ^integer; + {base addresses for kerns} +@!exten_base: ^integer; + {base addresses for extensible recipes} +@!param_base: ^integer; + {base addresses for font parameters} +@z + +@x [30.551] l.10743 - texarray +for k:=font_base to font_max do font_used[k]:=false; +@y +@z + +@x [30.552] l.10749 - texarray +font_ptr:=null_font; fmem_ptr:=7; +font_name[null_font]:="nullfont"; font_area[null_font]:=""; +hyphen_char[null_font]:="-"; skew_char[null_font]:=-1; +bchar_label[null_font]:=non_address; +font_bchar[null_font]:=non_char; font_false_bchar[null_font]:=non_char; +font_bc[null_font]:=1; font_ec[null_font]:=0; +font_size[null_font]:=0; font_dsize[null_font]:=0; +char_base[null_font]:=0; width_base[null_font]:=0; +height_base[null_font]:=0; depth_base[null_font]:=0; +italic_base[null_font]:=0; lig_kern_base[null_font]:=0; +kern_base[null_font]:=0; exten_base[null_font]:=0; +font_glue[null_font]:=null; font_params[null_font]:=7; +param_base[null_font]:=-1; +for k:=0 to 6 do font_info[k].sc:=0; +@y +@z + +@x [30.554] l.10795 - MLTeX: |effective_char| in |char_info| +as fast as possible under the circumstances. +@^inner loop@> + +@d char_info_end(#)==#].qqqq +@d char_info(#)==font_info[char_base[#]+char_info_end +@y +as fast as possible under the circumstances. +@^inner loop@> + +ML\TeX{} will assume that a character |c| exists iff either exists in +the current font or a character substitution definition for this +character was defined using \.{\\charsubdef}. To avoid the +distinction between these two cases, ML\TeX{} introduces the notion +``effective character'' of an input character |c|. If |c| exists in +the current font, the effective character of |c| is the character |c| +itself. If it doesn't exist but a character substitution is defined, +the effective character of |c| is the base character defined in the +character substitution. If there is an effective character for a +non-existing character |c|, the ``virtual character'' |c| will get +appended to the horizontal lists. + +The effective character is used within |char_info| to access +appropriate character descriptions in the font. For example, when +calculating the width of a box, ML\TeX{} will use the metrics of the +effective characters. For the case of a substitution, ML\TeX{} uses +the metrics of the base character, ignoring the metrics of the accent +character. + +If character substitutions are changed, it will be possible that a +character |c| neither exists in a font nor there is a valid character +substitution for |c|. To handle these cases |effective_char| should +be called with its first argument set to |true| to ensure that it +will still return an existing character in the font. If neither |c| +nor the substituted base character in the current character +substitution exists, |effective_char| will output a warning and +return the character |font_bc[f]| (which is incorrect, but can not be +changed within the current framework). + +Sometimes character substitutions are unwanted, therefore the +original definition of |char_info| can be used using the macro +|orig_char_info|. Operations in which character substitutions should +be avoided are, for example, loading a new font and checking the font +metric information in this font, and character accesses in math mode. + +@d char_list_exists(#)==(char_sub_code(#)>hi(0)) +@d char_list_accent(#)==(ho(char_sub_code(#)) div 256) +@d char_list_char(#)==(ho(char_sub_code(#)) mod 256) +@# +@d char_info_end(#)== #@=)@>].qqqq +@d char_info(#)== + font_info[char_base[#]+effective_char@=(@>true,#,char_info_end +@# +@d orig_char_info_end(#)==#].qqqq +@d orig_char_info(#)==font_info[char_base[#]+orig_char_info_end +@# +@z + +@x [30] m.560 l.10876 - MLTeX: |effective_char| in |char_info| +@p function read_font_info(@!u:pointer;@!nom,@!aire:str_number; +@y +@p @t\4@>@<Declare additional functions for ML\TeX@>@/ + +function read_font_info(@!u:pointer;@!nom,@!aire:str_number; +@z + +@x [30.563] l.10943 - Don't use TEX_font_area. +if aire="" then pack_file_name(nom,TEX_font_area,".tfm") +else pack_file_name(nom,aire,".tfm"); +@y +{|kpse_find_file| will append the |".tfm"|, and avoid searching the disk + before the font alias files as well.} +pack_file_name(nom,aire,""); +@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 [30.564] l.10956 - reading the tfm file, define fget & fbyte +@d fget==get(tfm_file) +@d fbyte==tfm_file^ +@y +@d fget==tfm_temp:=getc(tfm_file) +@d fbyte==tfm_temp +@z + +@x [30.570] l.11064 - MLTeX: fix for bug while loading font + begin qw:=char_info(f)(d); +@y + begin qw:=orig_char_info(f)(d); +@z + +@x [30.573] l.11116 - MLTeX: fix for bug while loading font + qw:=char_info(f)(#); {N.B.: not |qi(#)|} +@y + qw:=orig_char_info(f)(#); {N.B.: not |qi(#)|} +@z + +% [32.575] We only want `eof' on the TFM file to be true if we +% previously had EOF, not if we're at EOF now. This is like `feof', and +% unlike our implementation of `eof' elsewhere. +@x [32.575] l.11161 - Reading the tfm file, replace eof() by feof(). +if eof(tfm_file) then abort; +@y +if feof(tfm_file) then abort; +@z + +@x [30.576] l.11180 - MLTeX: fix for bug while loading font + begin qw:=char_info(f)(bchar); {N.B.: not |qi(bchar)|} +@y + begin qw:=orig_char_info(f)(bchar); {N.B.: not |qi(bchar)|} +@z + +@x [30.582] l.11276 - MLTeX: call |effective_char| in |new_character| +@p function new_character(@!f:internal_font_number;@!c:eight_bits):pointer; +label exit; +var p:pointer; {newly allocated node} +begin if font_bc[f]<=c then if font_ec[f]>=c then + if char_exists(char_info(f)(qi(c))) then +@y + +This allows a character node to be used if there is an equivalent +in the |char_sub_code| list. + +@p function new_character(@!f:internal_font_number;@!c:eight_bits):pointer; +label exit; +var p:pointer; {newly allocated node} +@!ec:quarterword; {effective character of |c|} +begin ec:=effective_char(false,f,qi(c)); +if font_bc[f]<=qo(ec) then if font_ec[f]>=qo(ec) then + if char_exists(orig_char_info(f)(ec)) then {N.B.: not |char_info|} +@z + +@x [32.592] l.11820 - font numbers can be >255 now. +@!c,@!f:quarterword; {character and font in current |char_node|} +@y + {character and font in current |char_node|} +@!c:quarterword; +@!f:internal_font_number; +@z + +@x [32.595] l.11860 - texarray +@!dvi_buf:array[dvi_index] of eight_bits; {buffer for \.{DVI} output} +@!half_buf:dvi_index; {half of |dvi_buf_size|} +@!dvi_limit:dvi_index; {end of the current half buffer} +@!dvi_ptr:dvi_index; {the next available buffer address} +@y +@!dvi_buf:^eight_bits; {buffer for \.{DVI} output} +@!half_buf:integer; {half of |dvi_buf_size|} +@!dvi_limit:integer; {end of the current half buffer} +@!dvi_ptr:integer; {the next available buffer address} +@z + +@x [32.597] l.11886 - write_dvi done in C. +@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 in one shot. Much better even than writing four +bytes at a time. +@z + +@x [32.602] l.11944 - Allow for outputting more than 256 fonts. +begin dvi_out(fnt_def1); +dvi_out(f-font_base-1);@/ +@y +begin if f<=256+font_base then + begin dvi_out(fnt_def1); + dvi_out(f-font_base-1); + end +else begin dvi_out(fnt_def1+1); + dvi_out((f-font_base-1) div @'400); + dvi_out((f-font_base-1) mod @'400); + end; +@z + +@x [32.617] l.12261 - Use output_comment if the user set it. Assume it's short enough. + old_setting:=selector; selector:=new_string; +@y +if output_comment then + begin l:=strlen(output_comment); dvi_out(l); + for s:=0 to l-1 do dvi_out(output_comment[s]); + end +else begin {the default code is unchanged} + old_setting:=selector; selector:=new_string; +@z + +@x [32.617] l.12268 - Use output_comment if the user set it. + pool_ptr:=str_start[str_ptr]; {flush the current string} +@y + pool_ptr:=str_start[str_ptr]; {flush the current string} +end; +@z + +@x [32.619] l.12294 - MLTeX: substitute character in |hlist_out| +procedure hlist_out; {output an |hlist_node| box} +label reswitch, move_past, fin_rule, next_p; +@y +procedure hlist_out; {output an |hlist_node| box} +label reswitch, move_past, fin_rule, next_p, continue, found; +@z + +@x [32.620] l.12326 - MLTeX: replace virtual character in |hlist_out| +reaching a non-|char_node|. The program uses the fact that |set_char_0=0|. +@^inner loop@> +@y +reaching a non-|char_node|. The program uses the fact that |set_char_0=0|. + +In ML\TeX{} this part looks for the existence of a substitution +definition for a character |c|, if |c| does not exist in the font, +and create appropriate \.{DVI} commands. Former versions of ML\TeX{} +have spliced appropriate character, kern, and box nodes into the +horizontal list. +% +% 91/05/08 \charsubdefmax bug detected by Bernd Raichle +Because the user can change character substitions or +\.{\\charsubdefmax} on the fly, we have to test a again +for valid substitutions. +% +% 93/10/29 \leaders bug detected by Eberhard Mattes +(Additional it is necessary to be careful---if leaders are used +the current hlist is normally traversed more than once!) +@^inner loop@> +@z + +@x [32.620] l.12334 - MLTeX: substitute character during |shipout| + if c>=qi(128) then dvi_out(set1); + dvi_out(qo(c));@/ + cur_h:=cur_h+char_width(f)(char_info(f)(c)); +@y + if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then + if char_exists(orig_char_info(f)(c)) then {N.B.: not |char_info|} + begin if c>=qi(128) then dvi_out(set1); + dvi_out(qo(c));@/ + cur_h:=cur_h+char_width(f)(orig_char_info(f)(c)); + goto continue; + end; + if mltex_enabled_p then + @<Output a substitution, |goto continue| if not possible@>; +continue: +@z + +@x [32.622] l.12349 - more >256 font output stuff. +else begin dvi_out(fnt1); dvi_out(f-font_base-1); + end; +@y +else if f<=256+font_base then + begin dvi_out(fnt1); dvi_out(f-font_base-1); + end +else begin dvi_out(fnt1+1); + dvi_out((f-font_base-1) div @'400); + dvi_out((f-font_base-1) mod @'400); + end; +@z + +% We output each portion of the page as we get to it, if we are using +% IPC, so that the previewer (TeXView) can display it immediately. [SPM] +@x [32.640] l.12690 - IPC +dvi_out(eop); incr(total_pages); cur_s:=-1; +@y +dvi_out(eop); incr(total_pages); cur_s:=-1; +ifdef ('IPC') +if ipc_on>0 then + begin if dvi_limit=half_buf then + begin write_dvi(half_buf, dvi_buf_size-1); + flush_dvi; + dvi_gone:=dvi_gone+half_buf; + end; + if dvi_ptr>0 then + begin write_dvi(0, dvi_ptr-1); + flush_dvi; + dvi_offset:=dvi_offset+dvi_ptr; dvi_gone:=dvi_gone+dvi_ptr; + end; + dvi_ptr:=0; dvi_limit:=dvi_buf_size; + ipc_page(dvi_gone); + end; +endif ('IPC'); +@z + +@x [32.642] l.12742 - Use dvi_offset instead of dvi_buf_size with IPC stuff. + k:=4+((dvi_buf_size-dvi_ptr) mod 4); {the number of 223's} +@y +ifdef ('IPC') + k:=7-((3+dvi_offset+dvi_ptr) mod 4); {the number of 223's} +endif ('IPC') +ifndef ('IPC') + k:=4+((dvi_buf_size-dvi_ptr) mod 4); {the number of 223's} +endifn ('IPC') +@z + +@x [32.642] l.12773 - use print_file_name + print_nl("Output written on "); slow_print(output_file_name); +@y + print_nl("Output written on "); print_file_name(0, output_file_name, 0); +@z + +@x [32.642] l.12750 - i18n fix + print(" ("); print_int(total_pages); print(" page"); + if total_pages<>1 then print_char("s"); +@y + print(" ("); print_int(total_pages); + if total_pages<>1 then print(" pages") + else print(" page"); +@z + +% The MLTeX changes never dealt with the problems of character +% substitutions in math mode. With the new additions in v2.2, +% non-existing characters between |font_bc[f]| and |font_ec[f]| +% can be substituted => we have to avoid this in math mode +% (for compatibility reasons and to avoid other problems). +% +@x [35.708] l.13903 - MLTeX: avoid substitution in |var_delimiter| +if (qo(y)>=font_bc[g])and(qo(y)<=font_ec[g]) then + begin continue: q:=char_info(g)(y); +@y +if (qo(y)>=font_bc[g])and(qo(y)<=font_ec[g]) then + begin continue: q:=orig_char_info(g)(y); +@z + +@x [36.722] l.14172 - MLTeX: avoid substitution in |fetch| +else begin if (qo(cur_c)>=font_bc[cur_f])and(qo(cur_c)<=font_ec[cur_f]) then + cur_i:=char_info(cur_f)(cur_c) +@y +else begin if (qo(cur_c)>=font_bc[cur_f])and(qo(cur_c)<=font_ec[cur_f]) then + cur_i:=orig_char_info(cur_f)(cur_c) +@z + +@x [36.740] l.14486 - MLTeX: avoid substitution in |make_math_accent| + i:=char_info(f)(y); +@y + i:=orig_char_info(f)(y); +@z + +@x [36.749] l.14638 - MLTeX: avoid substitution in |make_op| + begin c:=rem_byte(cur_i); i:=char_info(cur_f)(c); +@y + begin c:=rem_byte(cur_i); i:=orig_char_info(cur_f)(c); +@z + +% disabled in original tex-src-special.ch + @x [37.774] l.15291 - source specials +if every_cr<>null then begin_token_list(every_cr,every_cr_text); + @y +if (insert_src_special_every_cr and head<>tail) then insert_src_special; +if every_cr<>null then begin_token_list(every_cr,every_cr_text); + @z + +% disabled in original tex-source-special.ch + @x [37.799] l.15682 - source specials +if every_cr<>null then begin_token_list(every_cr,every_cr_text); + @y +if (insert_src_special_every_cr) then insert_src_special; +if every_cr<>null then begin_token_list(every_cr,every_cr_text); + @z + +@x [38.859] l.16855 - Fix a casting/expression evaluation problem. +if abs(fit_class-fitness(r))>1 then d:=d+adj_demerits; +@y +if abs(intcast(fit_class)-intcast(fitness(r)))>1 then d:=d+adj_demerits; +@z + +@x [39.875] l.17170 - Another casting problem. + begin line_diff:=line_number(r)-best_line; +@y + begin line_diff:=intcast(line_number(r))-intcast(best_line); +@z + +@x [42.920] l.18056 - bigtrie: allow larger hyphenation tries. +Comparatively few different number sequences $n_0\ldots n_k$ actually occur, +since most of the |n|'s are generally zero. Therefore the number sequences +are encoded in such a way that |trie_op|$(z_k)$ is only one byte long. +If |trie_op(@t$z_k$@>)<>min_quarterword|, when $p_1\ldots p_k$ has matched +the letters in |hc[(l-k+1)..l@,]| of language |t|, +we perform all of the required operations +for this pattern by carrying out the following little program: Set +|v:=trie_op(@t$z_k$@>)|. Then set |v:=v+op_start[t]|, +|hyf[l-hyf_distance[v]]:=@tmax@>(hyf[l-hyf_distance[v]], hyf_num[v])|, +and |v:=hyf_next[v]|; repeat, if necessary, until |v=min_quarterword|. +@y +The theory that comparatively few different number sequences $n_0\ldots n_k$ +actually occur, since most of the |n|'s are generally zero, seems to fail +at least for the large German hyphenation patterns. +Therefore the number sequences cannot any longer be encoded in such a way +that |trie_op|$(z_k)$ is only one byte long. +We have introduced a new constant |max_trie_op| for the maximum allowable +hyphenation operation code value; |max_trie_op| might be different for +\TeX\ and \.{INITEX} and must not exceed |max_halfword|. +An opcode will occupy a halfword if |max_trie_op| exceeds |max_quarterword| +or a quarterword otherwise. +@^system dependencies@> +If |trie_op(@t$z_k$@>)<>min_trie_op|, when $p_1\ldots p_k$ has matched +the letters in |hc[(l-k+1)..l@,]| of language |t|, +we perform all of the required operations +for this pattern by carrying out the following little program: Set +|v:=trie_op(@t$z_k$@>)|. Then set |v:=v+op_start[t]|, +|hyf[l-hyf_distance[v]]:=@tmax@>(hyf[l-hyf_distance[v]], hyf_num[v])|, +and |v:=hyf_next[v]|; repeat, if necessary, until |v=min_trie_op|. +@z + +@x [42.920] l.18068 - bigtrie: allow larger hyphenation tries. +@!trie_pointer=0..trie_size; {an index into |trie|} +@y +@!trie_pointer=0..ssup_trie_size; {an index into |trie|} +@!trie_opcode=0..ssup_trie_opcode; {a trie opcode} +@z + +@x [42.921] l.18070 - bigtrie: allow larger hyphenation tries. +@ @d trie_link(#)==trie[#].rh {``downward'' link in a trie} +@d trie_char(#)==trie[#].b1 {character matched at this trie location} +@d trie_op(#)==trie[#].b0 {program for hyphenation at this trie location} +@y +@ For more than 255 trie op codes, the three fields |trie_link|, |trie_char|, +and |trie_op| will no longer fit into one memory word; thus using web2c +we define |trie| as three array instead of an array of records. +The variant will be implented by reusing the opcode field later on with +another macro. + +@d trie_link(#)==trie_trl[#] {``downward'' link in a trie} +@d trie_char(#)==trie_trc[#] {character matched at this trie location} +@d trie_op(#)==trie_tro[#] {program for hyphenation at this trie location} +@z + +@x [42.921] l.18075 - bigtrie: allow larger hyphenation tries. +@!trie:array[trie_pointer] of two_halves; {|trie_link|, |trie_char|, |trie_op|} +@y +{We will dynamically allocate these arrays.} +@!trie_trl:^trie_pointer; {|trie_link|} +@!trie_tro:^trie_pointer; {|trie_op|} +@!trie_trc:^quarterword; {|trie_char|} +@z + +@x [42.921] l.18078 - bigtrie: allow larger hyphenation tries. +@!hyf_next:array[1..trie_op_size] of quarterword; {continuation code} +@y +@!hyf_next:array[1..trie_op_size] of trie_opcode; {continuation code} +@z + +@x [42.923] l.18099 - bigtrie: allow larger hyphenation tries. + begin if trie_op(z)<>min_quarterword then +@y + begin if trie_op(z)<>min_trie_op then +@z + +@x [42.924] l.18112 - bigtrie: allow larger hyphenation tries. +until v=min_quarterword; +@y +until v=min_trie_op; +@z + +%%%%%%%% dynamic hyph_size +@x 18126 m.925 +different from $\alpha$, we can conclude that $\alpha$ is not in the table. +@y 18126 +different from $\alpha$, we can conclude that $\alpha$ is not in the table. +This is a clever scheme which saves the need for a hash link array. +However, it is difficult to increase the size of the hyphen exception +arrays. To make this easier, the ordered hash has been replaced by +a simple hash, using an additional array |hyph_link|. The value +|0| in |hyph_link[k]| means that there are no more entries corresponding +to the specific hash chain. When |hyph_link[k]>0|, the next entry in +the hash chain is |hyph_link[k]-1|. This value is used because the +arrays start at |0|. +@z + +%%%%%%%% dynamic hyph_size +@x 18134 m.925 +@!hyph_pointer=0..hyph_size; {an index into the ordered hash table} +@y 18134 +@!hyph_pointer=0..ssup_hyph_size; {index into hyphen exceptions hash table; + enlarging this requires changing (un)dump code} +@z + +%%%%%%%% dynamic hyph_size +@x 18137 m.926 +@!hyph_word:array[hyph_pointer] of str_number; {exception words} +@!hyph_list:array[hyph_pointer] of pointer; {list of hyphen positions} +@!hyph_count:hyph_pointer; {the number of words in the exception dictionary} +@y 18139 +@!hyph_word: ^str_number; {exception words} +@!hyph_list: ^pointer; {list of hyphen positions} +@!hyph_link: ^hyph_pointer; {link array for hyphen exceptions hash table} +@!hyph_count:integer; {the number of words in the exception dictionary} +@!hyph_next:integer; {next free slot in hyphen exceptions hash table} +@z + +%%%%%%%% dynamic hyph_size +@x 18145 m.928 +for z:=0 to hyph_size do + begin hyph_word[z]:=0; hyph_list[z]:=null; + end; +hyph_count:=0; +@y 18148 +for z:=0 to hyph_size do + begin hyph_word[z]:=0; hyph_list[z]:=null; hyph_link[z]:=0; + end; +hyph_count:=0; +hyph_next:=hyph_prime+1; if hyph_next>hyph_size then hyph_next:=hyph_prime; +@z + +%%%%%%%% dynamic hyph_size +@x 18163 m.930 +h:=hc[1]; incr(hn); hc[hn]:=cur_lang; +for j:=2 to hn do h:=(h+h+hc[j]) mod hyph_size; +loop@+ begin @<If the string |hyph_word[h]| is less than \(hc)|hc[1..hn]|, + |goto not_found|; but if the two strings are equal, + set |hyf| to the hyphen positions and |goto found|@>; + if h>0 then decr(h)@+else h:=hyph_size; + end; +not_found: decr(hn) +@y 18170 +h:=hc[1]; incr(hn); hc[hn]:=cur_lang; +for j:=2 to hn do h:=(h+h+hc[j]) mod hyph_prime; +loop@+ begin @<If the string |hyph_word[h]| is less than \(hc)|hc[1..hn]|, + |goto not_found|; but if the two strings are equal, + set |hyf| to the hyphen positions and |goto found|@>; + h:=hyph_link[h]; if h=0 then goto not_found; + decr(h); + end; +not_found: decr(hn) +@z + +%%%%%%%% dynamic hyph_size +@x 18172 m.931 +@ @<If the string |hyph_word[h]| is less than \(hc)...@>= +k:=hyph_word[h]; if k=0 then goto not_found; +if length(k)<hn then goto not_found; +if length(k)=hn then + begin j:=1; u:=str_start[k]; + repeat if so(str_pool[u])<hc[j] then goto not_found; + if so(str_pool[u])>hc[j] then goto done; + incr(j); incr(u); + until j>hn; + @<Insert hyphens as specified in |hyph_list[h]|@>; + decr(hn); goto found; + end; +done: +@y 18184 +@ @<If the string |hyph_word[h]| is less than \(hc)...@>= +{This is now a simple hash list, not an ordered one, so +the module title is no longer descriptive.} +k:=hyph_word[h]; if k=0 then goto not_found; +if length(k)=hn then + begin j:=1; u:=str_start[k]; + repeat + if so(str_pool[u])<>hc[j] then goto done; + incr(j); incr(u); + until j>hn; + @<Insert hyphens as specified in |hyph_list[h]|@>; + decr(hn); goto found; + end; +done: +@z + +%%%%%%%% dynamic hyph_size +@x 18274 m.939 + begin h:=(h+h+hc[j]) mod hyph_size; +@y 18274 + begin h:=(h+h+hc[j]) mod hyph_prime; +@z + +%%%%%%%% dynamic hyph_size +@x 18281 m.940 +@ @<Insert the \(p)pair |(s,p)|...@>= +if hyph_count=hyph_size then overflow("exception dictionary",hyph_size); +@:TeX capacity exceeded exception dictionary}{\quad exception dictionary@> +incr(hyph_count); +while hyph_word[h]<>0 do + begin @<If the string |hyph_word[h]| is less than \(or)or equal to + |s|, interchange |(hyph_word[h],hyph_list[h])| with |(s,p)|@>; + if h>0 then decr(h)@+else h:=hyph_size; + end; +hyph_word[h]:=s; hyph_list[h]:=p +@y 18290 +@ @<Insert the \(p)pair |(s,p)|...@>= + if hyph_next <= hyph_prime then + while (hyph_next>0) and (hyph_word[hyph_next-1]>0) do decr(hyph_next); +if (hyph_count=hyph_size)or(hyph_next=0) then + overflow("exception dictionary",hyph_size); +@:TeX capacity exceeded exception dictionary}{\quad exception dictionary@> +incr(hyph_count); +while hyph_word[h]<>0 do + begin @<If the string |hyph_word[h]| is less than \(or)or equal to + |s|, interchange |(hyph_word[h],hyph_list[h])| with |(s,p)|@>; + if hyph_link[h]=0 then + begin + hyph_link[h]:=hyph_next; + if hyph_next >= hyph_size then hyph_next:=hyph_prime; + if hyph_next > hyph_prime then incr(hyph_next); + end; + h:=hyph_link[h]-1; + end; + +found: hyph_word[h]:=s; hyph_list[h]:=p +@z + +%%%%%%%% dynamic hyph_size +@x 18292 m.941 +@ @<If the string |hyph_word[h]| is less than \(or)...@>= +k:=hyph_word[h]; +if length(k)<length(s) then goto found; +if length(k)>length(s) then goto not_found; +u:=str_start[k]; v:=str_start[s]; +repeat if str_pool[u]<str_pool[v] then goto found; +if str_pool[u]>str_pool[v] then goto not_found; +incr(u); incr(v); +until u=str_start[k+1]; +found:q:=hyph_list[h]; hyph_list[h]:=p; p:=q;@/ +t:=hyph_word[h]; hyph_word[h]:=s; s:=t; +not_found: +@y 18303 +@ @<If the string |hyph_word[h]| is less than \(or)...@>= +{This is now a simple hash list, not an ordered one, so +the module title is no longer descriptive.} +k:=hyph_word[h]; +if length(k)<>length(s) then goto not_found; +u:=str_start[k]; v:=str_start[s]; +repeat if str_pool[u]<>str_pool[v] then goto not_found; +incr(u); incr(v); +until u=str_start[k+1]; +{repeat hyphenation exception; flushing old data} +flush_string; s:=hyph_word[h]; {avoid |slow_make_string|!} +decr(hyph_count); +{ We could also |flush_list(hyph_list[h]);|, but it interferes + with \.{trip.log}. } +goto found; +not_found: +@z + +@x [43.943] l.18332 - bigtrie: Larger tries, also in documentation parts. +|hyf_next[@t$v^\prime$@>]=min_quarterword|. +@y +|hyf_next[@t$v^\prime$@>]=min_trie_op|. +@z + +@x [43.943] l.18336 - bigtrie: Larger tries, also in documentation parts. +$$\hbox{|@t$v^\prime$@>:=new_trie_op(0,1,min_quarterword)|,\qquad +@y +$$\hbox{|@t$v^\prime$@>:=new_trie_op(0,1,min_trie_op)|,\qquad +@z + +@x [43.943] l.18346 - web2c can't parse negative lower bounds in arrays. Sorry. +@!init@! trie_op_hash:array[-trie_op_size..trie_op_size] of 0..trie_op_size; +@y +@!init@! trie_op_hash:array[neg_trie_op_size..trie_op_size] of 0..trie_op_size; +@z + +@x [43.943] l.18348 - bigtrie: Larger hyphenation tries. +@!trie_used:array[ASCII_code] of quarterword; +@y +@!trie_used:array[ASCII_code] of trie_opcode; +@z + +@x [43.943] l.18352 - bigtrie: Larger hyphenation tries. +@!trie_op_val:array[1..trie_op_size] of quarterword; +@y +@!trie_op_val:array[1..trie_op_size] of trie_opcode; +@z + +@x [43.943] l.18355 - Dynamic trie arrays +tini +@y +tini@; +@!max_op_used:trie_opcode; {largest opcode used for any language} +@!small_op:boolean; {flag used while dumping or undumping} +@z + +@x [43.944] l.18358 - bigtrie: Larger tries, also in documentation parts. +|new_trie_op| could return |min_quarterword| (thereby simply ignoring +@y +|new_trie_op| could return |min_trie_op| (thereby simply ignoring +@z + +@x [43.944] l.18365 - bigtrie: Larger hyphenation tries. +function new_trie_op(@!d,@!n:small_number;@!v:quarterword):quarterword; +label exit; +var h:-trie_op_size..trie_op_size; {trial hash location} +@!u:quarterword; {trial op code} +@y +function new_trie_op(@!d,@!n:small_number;@!v:trie_opcode):trie_opcode; +label exit; +var h:neg_trie_op_size..trie_op_size; {trial hash location} +@!u:trie_opcode; {trial op code} +@z + +@x [43.944] l.18370 - Another casting problem, and use |neg_trie_op_size|. +begin h:=abs(n+313*d+361*v+1009*cur_lang) mod (trie_op_size+trie_op_size) + - trie_op_size; +@y +begin h:=abs(intcast(n)+313*intcast(d)+361*intcast(v)+1009*intcast(cur_lang)) + mod (trie_op_size - neg_trie_op_size) + + neg_trie_op_size; +@z + +@x [43.944] l.18377 - bigtrie: And larger tries again. + if u=max_quarterword then + overflow("pattern memory ops per language", + max_quarterword-min_quarterword); + incr(trie_op_ptr); incr(u); trie_used[cur_lang]:=u; +@y + if u=max_trie_op then + overflow("pattern memory ops per language", + max_trie_op-min_trie_op); + incr(trie_op_ptr); incr(u); trie_used[cur_lang]:=u; + if u>max_op_used then max_op_used:=u; +@z + +@x [43.945] l.18399 - bigtrie: And larger tries again. +op_start[0]:=-min_quarterword; +@y +op_start[0]:=-min_trie_op; +@z + +@x [43.946] l.18416 - bigtrie: And larger tries again. +for k:=0 to 255 do trie_used[k]:=min_quarterword; +@y +for k:=0 to 255 do trie_used[k]:=min_trie_op; +@z + +@x [43.946] l.18417 - Dynamic trie arrays. +trie_op_ptr:=0; +@y +max_op_used:=min_trie_op; +trie_op_ptr:=0; +@z + +@x [43.947] l.18438 - Dynamically allocate arrays, and a casting problem. +@!init @!trie_c:packed array[trie_pointer] of packed_ASCII_code; + {characters to match} +@t\hskip10pt@>@!trie_o:packed array[trie_pointer] of quarterword; + {operations to perform} +@t\hskip10pt@>@!trie_l:packed array[trie_pointer] of trie_pointer; + {left subtrie links} +@t\hskip10pt@>@!trie_r:packed array[trie_pointer] of trie_pointer; + {right subtrie links} +@t\hskip10pt@>@!trie_ptr:trie_pointer; {the number of nodes in the trie} +@t\hskip10pt@>@!trie_hash:packed array[trie_pointer] of trie_pointer; + {used to identify equivalent subtries} +tini +@y +@!init @!trie_c:^packed_ASCII_code; + {characters to match} +@t\hskip10pt@>@!trie_o:^trie_opcode; + {operations to perform} +@t\hskip10pt@>@!trie_l:^trie_pointer; + {left subtrie links} +@t\hskip10pt@>@!trie_r:^trie_pointer; + {right subtrie links} +@t\hskip10pt@>@!trie_ptr:trie_pointer; {the number of nodes in the trie} +@t\hskip10pt@>@!trie_hash:^trie_pointer; + {used to identify equivalent subtries} +tini +@z + +@x [43.948] l.18471 - Another casting problem. +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(intcast(trie_c[p])+1009*intcast(trie_o[p])+@| + 2718*intcast(trie_l[p])+3142*intcast(trie_r[p])) mod trie_size; +@z + +@x [43.950] l.18521 - Dynamically allocate & larger tries. +@d trie_back(#)==trie[#].lh {backward links in |trie| holes} +@y +@d trie_back(#)==trie_tro[#] {use the opcode field now for backward links} +@z + +@x [43.590] l.18524 - Dynamically allocate & larger tries. +@!init@!trie_taken:packed array[1..trie_size] of boolean; + {does a family start here?} +@t\hskip10pt@>@!trie_min:array[ASCII_code] of trie_pointer; + {the first possible slot for each character} +@t\hskip10pt@>@!trie_max:trie_pointer; {largest location used in |trie|} +@t\hskip10pt@>@!trie_not_ready:boolean; {is the trie still in linked form?} +tini +@y +@!init@!trie_taken: ^boolean; + {does a family start here?} +@t\hskip10pt@>@!trie_min:array[ASCII_code] of trie_pointer; + {the first possible slot for each character} +@t\hskip10pt@>@!trie_max:trie_pointer; {largest location used in |trie|} +@t\hskip10pt@>@!trie_not_ready:boolean; {is the trie still in linked form?} +tini +@z + +@x [43.951] l.18539 - Dynamically allocate. +trie_not_ready:=true; trie_root:=0; trie_c[0]:=si(0); trie_ptr:=0; +@y +trie_not_ready:=true; +@z + +@x [43.958] l.18634 - bigtrie: Larger tries. +@<Move the data into |trie|@>= +h.rh:=0; h.b0:=min_quarterword; h.b1:=min_quarterword; {|trie_link:=0|, + |trie_op:=min_quarterword|, |trie_char:=qi(0)|} +@y +@d clear_trie == {clear |trie[r]|} + begin trie_link(r):=0; + trie_op(r):=min_trie_op; + trie_char(r):=min_quarterword; {|trie_char:=qi(0)|} + end + +@<Move the data into |trie|@>= +@z + +@x [43.958] l.18638 - bigtrie: Larger tries. + begin for r:=0 to 256 do trie[r]:=h; +@y + begin for r:=0 to 256 do clear_trie; +@z + +@x [43.958] l.18643 - bigtrie: Larger tries. + repeat s:=trie_link(r); trie[r]:=h; r:=s; +@y + repeat s:=trie_link(r); clear_trie; r:=s; +@z + +@x [43.960] l.18677 - bigtrie: Larger tries. +@!v:quarterword; {trie op code} +@y +@!v:trie_opcode; {trie op code} +@z + +@x [43.963] l.18749 - bigtrie: Larger tries. +if trie_o[q]<>min_quarterword then +@y +if trie_o[q]<>min_trie_op then +@z + +@x [43.964] l.18762 - bigtrie: Larger tries. +trie_c[p]:=si(c); trie_o[p]:=min_quarterword; +@y +trie_c[p]:=si(c); trie_o[p]:=min_trie_op; +@z + +@x [43.965] l.18768 - bigtrie: Larger tries. +l:=k; v:=min_quarterword; +@y +l:=k; v:=min_trie_op; +@z + +@x [43.966] l.18786 - bigtrie: Larger tries. +@!h:two_halves; {template used to zero out |trie|'s holes} +@y +@z + +%% +%% We can rewrite the original code after "main_loop_move+2" upto the +%% "tail_append(lig_stack)" in module 1036 as +%% +% +% main_loop_move+2: +% if font_bc[main_f]<=cur_chr then +% if cur_chr<=font_ec[main_f] then +% begin main_i:=char_info(main_f)(cur_l); +% if char_exists(main_i) goto main_loop_move+3; +% end; +% char_warning(main_f,cur_chr); free_avail(lig_stack); goto big_switch; +% main_loop_move+3: +% tail_append(lig_stack) {|main_loop_lookahead| is next} +% +%% +%% We can use the rewritten code above to include additional MLTeX +%% specific parts in the future. Additionally it can be used when +%% optimizing |main_control| to minimize the call of the function +%% |effective_char|. +%% +% +%@x [46.1030] l.19977 - MLTeX: substitution in |main_control| +% main_loop_move,main_loop_move+1,main_loop_move+2,main_loop_move_lig, +%@y +% main_loop_move,main_loop_move+1,main_loop_move+2,main_loop_move+3, +% main_loop_move_lig, +%@z + +@x [46.1034] l.20074 - source specials +@<Append character |cur_chr|...@>= +adjust_space_factor;@/ +@y +@<Append character |cur_chr|...@>= +if ((head=tail) and (mode>0)) then begin + if (insert_src_special_auto) then append_src_special; +end; +adjust_space_factor;@/ +@z + +@x [46.1036] l.20138 - MLTeX: substitution in |main_control| +main_loop_move+2:if(cur_chr<font_bc[main_f])or(cur_chr>font_ec[main_f]) then +@y +main_loop_move+2: +if(qo(effective_char(false,main_f,qi(cur_chr)))>font_ec[main_f])or + (qo(effective_char(false,main_f,qi(cur_chr)))<font_bc[main_f]) then +@z + +@x [46.1036] l.20141 - MLTeX: substitution in |main_control| +main_i:=char_info(main_f)(cur_l); +@y +main_i:=effective_char_info(main_f,cur_l); +@z + +@x [46.1049] l.20407 - i18n fix, see change to [16.211] +print("' in "); print_mode(mode); +@y +print_in_mode(mode); +@z + +% disabled in original tex-src-special.ch + @x [47.1083] l.20966 - source specials + if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text); + @y + if (insert_src_special_every_vbox) then insert_src_special; + if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text); + @z + +% disabled in original tex-src-special.ch + @x [47.1083] l.20969 - source specials + if every_hbox<>null then begin_token_list(every_hbox,every_hbox_text); + @y + if (insert_src_special_every_hbox) then insert_src_special; + if every_hbox<>null then begin_token_list(every_hbox,every_hbox_text); + @z + +@x [47.1091] l.21064 - source specials +if indented then + begin tail:=new_null_box; link(head):=tail; width(tail):=par_indent;@+ + end; +@y +if indented then + begin tail:=new_null_box; link(head):=tail; width(tail):=par_indent; + if (insert_src_special_every_par) then insert_src_special;@+ + end; +@z + +% disabled in original tex-src-special.ch, conflicts with etex. + @x [47.1096] l.21121 - source specials + else line_break(widow_penalty); + @y + else begin + if (insert_src_special_every_parend) then insert_src_special; + line_break(widow_penalty); + end; + @z + +@x +begin print_err("Extra "); print_esc("endcsname"); +@.Extra \\endcsname@> +help1("I'm ignoring this, since I wasn't doing a \csname."); +@y +begin +if cur_chr = 10 then +begin + print_err("Extra "); print_esc("endmubyte"); +@.Extra \\endmubyte@> + help1("I'm ignoring this, since I wasn't doing a \mubyte."); +end else begin + print_err("Extra "); print_esc("endcsname"); +@.Extra \\endcsname@> + help1("I'm ignoring this, since I wasn't doing a \csname."); +end; +@z + +@x [48.1139] l.21650 - source specials +if every_math<>null then begin_token_list(every_math,every_math_text); +@y +if (insert_src_special_every_math) then insert_src_special; +if every_math<>null then begin_token_list(every_math,every_math_text); +@z + +% disabled in original tex-src-special.ch + @x [48.1145] l.21705 - source specials +if every_display<>null then begin_token_list(every_display,every_display_text); + @y +if (insert_src_special_every_display) then append_src_special; +if every_display<>null then begin_token_list(every_display,every_display_text); + @z + +@x [48.1167] l.22042 - source specials + if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text); +@y + if (insert_src_special_every_vbox) then insert_src_special; + if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text); +@z + +@x [49.1211] - encTeX: extra variables for \mubyte primitive +@!p,@!q:pointer; {for temporary short-term use} +@y +@!p,@!q,@!r:pointer; {for temporary short-term use} +@z + +@x [49.1215] l.22719 - hash_extra +if (cur_cs=0)or(cur_cs>frozen_control_sequence) then +@y +if (cur_cs=0)or(cur_cs>eqtb_top)or + ((cur_cs>frozen_control_sequence)and(cur_cs<=eqtb_size)) then +@z + +@x [49.1219] - encTeX: \mubyte and \noconvert primitives +primitive("futurelet",let,normal+1);@/ +@!@:future_let_}{\.{\\futurelet} primitive@> +@y +primitive("futurelet",let,normal+1);@/ +@!@:future_let_}{\.{\\futurelet} primitive@> +if enctex_p then +begin + primitive("mubyte",let,normal+10);@/ +@!@:mubyte_}{\.{\\mubyte} primitive@> + primitive("noconvert",let,normal+11);@/ +@!@:noconvert_}{\.{\\noconvert} primitive@> +end; +@z + +@x [49.1220] - encTeX: \mubyte primitive +let: if chr_code<>normal then print_esc("futurelet")@+else print_esc("let"); +@y +let: if chr_code<>normal then + if chr_code = normal+10 then print_esc("mubyte") + else if chr_code = normal+11 then print_esc("noconvert") + else print_esc("futurelet") + else print_esc("let"); +@z + +@x [49.1221] - encTeX: \mubyte primitive +let: begin n:=cur_chr; +@y +let: if cur_chr = normal+11 then do_nothing { noconvert primitive } + else if cur_chr = normal+10 then { mubyte primitive } + begin + selector:=term_and_log; + get_token; + mubyte_stoken := cur_tok; + if cur_tok <= cs_token_flag then mubyte_stoken := cur_tok mod 256; + mubyte_prefix := 60; mubyte_relax := false; + mubyte_tablein := true; mubyte_tableout := true; + get_x_token; + if cur_cmd = spacer then get_x_token; + if cur_cmd = sub_mark then + begin + mubyte_tableout := false; get_x_token; + if cur_cmd = sub_mark then + begin + mubyte_tableout := true; mubyte_tablein := false; + get_x_token; + end; + end else if (mubyte_stoken > cs_token_flag) and + (cur_cmd = mac_param) then + begin + mubyte_tableout := false; + scan_int; mubyte_prefix := cur_val; get_x_token; + if mubyte_prefix > 50 then mubyte_prefix := 52; + if mubyte_prefix <= 0 then mubyte_prefix := 51; + end + else if (mubyte_stoken > cs_token_flag) and (cur_cmd = relax) then + begin + mubyte_tableout := true; mubyte_tablein := false; + mubyte_relax := true; get_x_token; + end; + r := get_avail; p := r; + while cur_cs = 0 do begin store_new_token (cur_tok); get_x_token; end; + if (cur_cmd <> end_cs_name) or (cur_chr <> 10) then + begin + print_err("Missing "); print_esc("endmubyte"); print(" inserted"); + help2("The control sequence marked <to be read again> should")@/ +("not appear in <byte sequence> between \mubyte and \endmubyte."); + back_error; + end; + p := link(r); + if (p = null) and mubyte_tablein then + begin + print_err("The empty <byte sequence>, "); + print_esc("mubyte"); print(" ignored"); + help2("The <byte sequence> in")@/ +("\mubyte <token> <byte sequence>\endmubyte should not be empty."); + error; + end else begin + while p <> null do + begin + append_char (info(p) mod 256); + p := link (p); + end; + flush_list (r); + if (str_start [str_ptr] + 1 = pool_ptr) and + (str_pool [pool_ptr-1] = mubyte_stoken) then + begin + if mubyte_read [mubyte_stoken] <> null + and mubyte_tablein then { clearing data } + dispose_munode (mubyte_read [mubyte_stoken]); + if mubyte_tablein then mubyte_read [mubyte_stoken] := null; + if mubyte_tableout then mubyte_write [mubyte_stoken] := 0; + pool_ptr := str_start [str_ptr]; + end else begin + if mubyte_tablein then mubyte_update; { updating input side } + if mubyte_tableout then { updating output side } + begin + if mubyte_stoken > cs_token_flag then { control sequence } + begin + dispose_mutableout (mubyte_stoken-cs_token_flag); + if (str_start [str_ptr] < pool_ptr) or mubyte_relax then + begin { store data } + r := mubyte_cswrite[(mubyte_stoken-cs_token_flag) mod 128]; + p := get_avail; + mubyte_cswrite[(mubyte_stoken-cs_token_flag) mod 128] := p; + info (p) := mubyte_stoken-cs_token_flag; + link (p) := get_avail; + p := link (p); + if mubyte_relax then begin + info (p) := 0; pool_ptr := str_start [str_ptr]; + end else info (p) := slow_make_string; + link (p) := r; + end; + end else begin { single character } + if str_start [str_ptr] = pool_ptr then + mubyte_write [mubyte_stoken] := 0 + else + mubyte_write [mubyte_stoken] := slow_make_string; + end; + end else pool_ptr := str_start [str_ptr]; + end; + end; + end else begin { let primitive } + n:=cur_chr; +@z + +@x [49.1222] l.22794 - MLTeX: \charsubdef primitive +@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}} +@y +@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}} +@d char_sub_def_code=7 {|shorthand_def| for \.{\\charsubdef}} +@z + +@x [49.1222] l.22810 - MLTeX: \charsubdef primitive +@!@:toks_def_}{\.{\\toksdef} primitive@> +@y +@!@:toks_def_}{\.{\\toksdef} primitive@> +if mltex_p then + begin + primitive("charsubdef",shorthand_def,char_sub_def_code);@/ +@!@:char_sub_def_}{\.{\\charsubdef} primitive@> + end; +@z + +@x [49.1222] l.22820 - MLTeX: \charsubdef primitive + othercases print_esc("toksdef") +@y + char_sub_def_code: print_esc("charsubdef"); + othercases print_esc("toksdef") +@z + +@x [49.1222] l.22833 - MLTeX: \charsubdef primitive +shorthand_def: begin n:=cur_chr; get_r_token; p:=cur_cs; define(p,relax,256); +@y +shorthand_def: if cur_chr=char_sub_def_code then + begin scan_char_num; p:=char_sub_code_base+cur_val; scan_optional_equals; + scan_char_num; n:=cur_val; {accent character in substitution} + scan_char_num; + if (tracing_char_sub_def>0) then + begin begin_diagnostic; print_nl("New character substitution: "); + print_ASCII(p-char_sub_code_base); print(" = "); + print_ASCII(n); print_char(" "); + print_ASCII(cur_val); end_diagnostic(false); + end; + n:=n*256+cur_val; + define(p,data,hi(n)); + if (p-char_sub_code_base)<char_sub_def_min then + word_define(int_base+char_sub_def_min_code,p-char_sub_code_base); + if (p-char_sub_code_base)>char_sub_def_max then + word_define(int_base+char_sub_def_max_code,p-char_sub_code_base); + end +else begin n:=cur_chr; get_r_token; p:=cur_cs; define(p,relax,256); +@z + +@x [49.1230] l.22936 - encTeX: \xordcode, \xchrcode, \xprncode primitives +primitive("catcode",def_code,cat_code_base); +@!@:cat_code_}{\.{\\catcode} primitive@> +@y +primitive("catcode",def_code,cat_code_base); +@!@:cat_code_}{\.{\\catcode} primitive@> +if enctex_p then +begin + primitive("xordcode",def_code,xord_code_base); +@!@:xord_code_}{\.{\\xordcode} primitive@> + primitive("xchrcode",def_code,xchr_code_base); +@!@:xchr_code_}{\.{\\xchrcode} primitive@> + primitive("xprncode",def_code,xprn_code_base); +@!@:xprn_code_}{\.{\\xprncode} primitive@> +end; +@z + +@x [49.1231] l.22956 - encTeX: \xordcode, \xchrcode, \xprncode primitives +def_code: if chr_code=cat_code_base then print_esc("catcode") +@y +def_code: if chr_code=xord_code_base then print_esc("xordcode") + else if chr_code=xchr_code_base then print_esc("xchrcode") + else if chr_code=xprn_code_base then print_esc("xprncode") + else if chr_code=cat_code_base then print_esc("catcode") +@z + +@x [49.1232] l.22969 - encTeX: setting a new value to xchr/xord/xprn + p:=cur_chr; scan_char_num; p:=p+cur_val; scan_optional_equals; + scan_int; +@y + p:=cur_chr; scan_char_num; + if p=xord_code_base then p:=cur_val + else if p=xchr_code_base then p:=cur_val+256 + else if p=xprn_code_base then p:=cur_val+512 + else p:=p+cur_val; + scan_optional_equals; + scan_int; +@z + +@x [49.1232] l.22980 - encTeX: setting a new value to xchr/xord/xprn + if p<math_code_base then define(p,data,cur_val) +@y + if p<256 then xord[p]:=cur_val + else if p<512 then xchr[p-256]:=cur_val + else if p<768 then xprn[p-512]:=cur_val + else if p<math_code_base then define(p,data,cur_val) +@z + +@x [49.1252] l.23230 - INI = VIR, so have to do runtime test. + begin @!init new_patterns; goto done;@;@+tini@/ +@y 23215 + begin @!Init new_patterns; goto done;@;@+Tini@/ +@z + +% undo Knuth's change because +% a) the string is already replaced in |scan_file_name| and therefore +% b) the wrong string will get flushed!!! +% +@x [49.1260] l.23331 new_font: string recycling -- already done +flushable_string:=str_ptr-1; +@y +@z + +% If you don't want to remove code with the following change, +% please replace the former change by +% +% @x +% flushable_string:=str_ptr-1; +% @y +% if cur_name=str_ptr-1 then +% flushable_string:=str_ptr-1 +% else +% flushable_string:=str_ptr; {number of a non-existing} +% @z +% +% otherwise the wrong string will get removed by |flush_string|!! +% +@x [49.1260] l.23334 new_font: string recycling -- already done + begin if cur_name=flushable_string then + begin flush_string; cur_name:=font_name[f]; + end; + if s>0 then +@y + begin if s>0 then +@z + +@x [49.1265] if batchmode, mktex... scripts should be silent. +interaction:=cur_chr; +@y +interaction:=cur_chr; +if interaction = batch_mode +then kpse_make_tex_discard_errors := 1 +else kpse_make_tex_discard_errors := 0; +@z + +@x [49.1275] l.23434 - Index variable for next fragment of code. +@!n:0..15; {stream number} +@y +@!n:0..15; {stream number} +@!k:integer; +@z + +@x [49.1275] l.23441 - Same stuff as for \input, this time for \openin. + if cur_ext="" then cur_ext:=".tex"; + pack_cur_name; + if a_open_in(read_file[n]) then read_open[n]:=just_open; +@y + pack_cur_name; + tex_input_type:=0; {Tell |open_input| we are \.{\\openin}.} + if open_in_name_ok(stringcast(name_of_file+1)) + and a_open_in(read_file[n], kpse_tex_format) then + read_open[n]:=just_open; +@z + +@x [49.1279] - encTeX: implement \noconvert +old_setting:=selector; selector:=new_string; +token_show(def_ref); selector:=old_setting; +@y +old_setting:=selector; selector:=new_string; +message_printing := true; active_noconvert := true; +token_show(def_ref); +message_printing := false; active_noconvert := false; +selector:=old_setting; +@z + +% encTeX: |slow_print| is too eager to expand printed strings. To +% selectively suppress or enable expansion (needed to \noconvert) +% |print| will look at |message_printing|. So we bypass |slow_print| +% and go directly to |print| instead. +@x [49.1279] - encTeX: to handle \noconvert in messages go directly to |print| +slow_print(s); update_terminal; +@y +print(s); update_terminal; +@z + +@x [49.1279] - encTeX: to handle \noconvert in messages go directly to |print| +begin print_err(""); slow_print(s); +@y +begin print_err(""); print(s); +@z + +@x [50.1301] l.23679 - INI = VIR, so runtime test. +format_ident:=" (INITEX)"; +@y +if ini_version then format_ident:=" (INITEX)"; +@z + +% Eliminate now-unused variable `w' in `store_fmt_file'. +% Add format_engine. +@x [50.1302] l.23690 +@!w: four_quarters; {four ASCII codes} +@y +@!format_engine: ^text_char; +@z + +% MLTeX: dump |mltex_p| to fmt file +% encTeX: dump encTeX-specific data to fmt file. +@x [50.1302] l.23694 +@<Dump constants for consistency check@>; +@y +@<Dump constants for consistency check@>; +@<Dump ML\TeX-specific data@>; +@<Dump enc\TeX-specific data@>; +@z + +% Eliminate now-unused variable `w' in `load_fmt_file'. +% Add dummies for undumping encTeX into the void. +% Add format_engine. +@x [50.1303] l.23722 +@!w: four_quarters; {four ASCII codes} +@y +@!format_engine: ^text_char; +@!dummy_xord: ASCII_code; +@!dummy_xchr: text_char; +@!dummy_xprn: ASCII_code; +@z + +% MLTeX: undump |mltex_enabled_p| from fmt file +% encTeX: undump encTeX-specific data from fmt file. +@x [50.1303] l.23694 +begin @<Undump constants for consistency check@>; +@y +begin @<Undump constants for consistency check@>; +@<Undump ML\TeX-specific data@>; +@<Undump enc\TeX-specific data@>; +@z + +@x [50.1305] l.23751 - Do dumping and undumping of fmt files in C. +@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 +@z +@x [1306] +@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 +@z +@x [still 1306] debug format file +@d undump_size_end_end(#)==too_small(#)@+else undump_end_end +@y +@d format_debug_end(#)== + write_ln (stderr, ' = ', #); + end; +@d format_debug(#)== + if debug_format_file then begin + write (stderr, 'fmtdebug:', #); + format_debug_end +@d undump_size_end_end(#)== + too_small(#)@+else format_debug (#)(x); undump_end_end +@z + +@x [50,1307] l.23779 - texarray +dump_int(@$);@/ +@y +dump_int(@"57325458); {Web2C \TeX's magic constant: "W2TX"} +{Align engine to 4 bytes with one or more trailing NUL} +x:=strlen(engine_name); +format_engine:=xmalloc_array(text_char,x+4); +strcpy(format_engine, engine_name); +for k:=x to x+3 do format_engine[k]:=0; +x:=x+4-(x mod 4); +dump_int(x);dump_things(format_engine[0], x); +libc_free(format_engine);@/ +dump_int(@$);@/ +@<Dump |xord|, |xchr|, and |xprn|@>; +dump_int(max_halfword);@/ +dump_int(hash_high); +@z + +%%%%%%%% dynamic hyph_size +@x 23784 m.1307 +dump_int(hyph_size) +@y 23784 +dump_int(hyph_prime) +@z + +@x [50.1308] l.23793 - texarray +x:=fmt_file^.int; +if x<>@$ then goto bad_fmt; {check that strings are the same} +@y +@+Init +libc_free(font_info); libc_free(str_pool); libc_free(str_start); +libc_free(yhash); libc_free(zeqtb); libc_free(yzmem); +@+Tini +undump_int(x); +format_debug('format magic number')(x); +if x<>@"57325458 then goto bad_fmt; {not a format file} +undump_int(x); +format_debug('engine name size')(x); +if (x<0) or (x>256) then goto bad_fmt; {corrupted format file} +format_engine:=xmalloc_array(text_char, x); +undump_things(format_engine[0], x); +format_engine[x-1]:=0; {force string termination, just in case} +if strcmp(engine_name, format_engine) then + begin wake_up_terminal; + wterm_ln('---! ', stringcast(name_of_file+1), ' was written by ', format_engine); + libc_free(format_engine); + goto bad_fmt; +end; +libc_free(format_engine); +undump_int(x); +format_debug('string pool checksum')(x); +if x<>@$ then begin {check that strings are the same} + wake_up_terminal; + wterm_ln('---! ', stringcast(name_of_file+1), ' doesn''t match ', pool_name); + goto bad_fmt; +end; +@<Undump |xord|, |xchr|, and |xprn|@>; +undump_int(x); +if x<>max_halfword then goto bad_fmt; {check |max_halfword|} +undump_int(hash_high); + if (hash_high<0)or(hash_high>sup_hash_extra) then goto bad_fmt; + if hash_extra<hash_high then hash_extra:=hash_high; + eqtb_top:=eqtb_size+hash_extra; + if hash_extra=0 then hash_top:=undefined_control_sequence else + hash_top:=eqtb_top; + yhash:=xmalloc_array(two_halves,1+hash_top-hash_offset); + hash:=yhash - hash_offset; + next(hash_base):=0; text(hash_base):=0; + for x:=hash_base+1 to hash_top do hash[x]:=hash[hash_base]; + zeqtb:=xmalloc_array (memory_word,eqtb_top+1); + eqtb:=zeqtb; + + eq_type(undefined_control_sequence):=undefined_cs; + equiv(undefined_control_sequence):=null; + eq_level(undefined_control_sequence):=level_zero; + for x:=eqtb_size+1 to eqtb_top do + eqtb[x]:=eqtb[undefined_control_sequence]; +@z + +@x [50.1308] l.23795 - texarray +undump_int(x); +if x<>mem_bot then goto bad_fmt; +undump_int(x); +if x<>mem_top then goto bad_fmt; +@y +undump_int(x); format_debug ('mem_bot')(x); +if x<>mem_bot then goto bad_fmt; +undump_int(mem_top); format_debug ('mem_top')(mem_top); +if mem_bot+1100>mem_top then goto bad_fmt; + + +head:=contrib_head; tail:=contrib_head; + page_tail:=page_head; {page initialization} + +mem_min := mem_bot - extra_mem_bot; +mem_max := mem_top + extra_mem_top; + +yzmem:=xmalloc_array (memory_word, mem_max - mem_min + 1); +zmem := yzmem - mem_min; {this pointer arithmetic fails with some compilers} +mem := zmem; +@z + +%%%%%%%% dynamic hyph_size +@x 23804 m.1308 +if x<>hyph_size then goto bad_fmt +@y 23804 +if x<>hyph_prime then goto bad_fmt +@z + +% [1309] Make dumping/undumping more efficient by doing whole arrays at +% a time, via fread/fwrite in texmfmp.c. +@x [50.1309] l.23814 - Make dumping/undumping more efficient. +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 [50.1310] l.23829 - Make dumping/undumping more efficient. +undump_size(0)(pool_size)('string pool size')(pool_ptr); +undump_size(0)(max_strings)('max strings')(str_ptr); +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_size(0)(sup_pool_size-pool_free)('string pool size')(pool_ptr); +if pool_size<pool_ptr+pool_free then + pool_size:=pool_ptr+pool_free; +undump_size(0)(sup_max_strings-strings_free)('sup strings')(str_ptr);@/ +if max_strings<str_ptr+strings_free then + max_strings:=str_ptr+strings_free; +str_start:=xmalloc_array(pool_pointer, max_strings); +undump_checked_things(0, pool_ptr, str_start[0], str_ptr+1);@/ +str_pool:=xmalloc_array(packed_ASCII_code, pool_size); +undump_things(str_pool[0], pool_ptr); +@z + +@x [50.1311] l.23850 - Make dumping/undumping more efficient. +repeat for k:=p to q+1 do dump_wd(mem[k]); +@y +repeat dump_things(mem[p], q+2-p); +@z + +@x [50.1311] l.23855 - Make dumping/undumping more efficient. +for k:=p to lo_mem_max do dump_wd(mem[k]); +@y +dump_things(mem[p], lo_mem_max+1-p); +@z + +@x [50.1311] l.23858 - Make dumping/undumping more efficient. +for k:=hi_mem_min to mem_end do dump_wd(mem[k]); +@y +dump_things(mem[hi_mem_min], mem_end+1-hi_mem_min); +@z + +@x [50.1312] l.23873 - Make dumping/undumping more efficient. +repeat for k:=p to q+1 do undump_wd(mem[k]); +@y +repeat undump_things(mem[p], q+2-p); +@z + +@x [50.1312] l.23878 - Make dumping/undumping more efficient. +for k:=p to lo_mem_max do undump_wd(mem[k]); +@y +undump_things(mem[p], lo_mem_max+1-p); +@z + +@x [50.1312] l.23888 - Make dumping/undumping more efficient. +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 [50.1314] l.23899 - hash_extra, source specials +undump(hash_base)(frozen_control_sequence)(par_loc); +par_token:=cs_token_flag+par_loc;@/ +undump(hash_base)(frozen_control_sequence)(write_loc);@/ +@y +undump(hash_base)(hash_top)(par_loc); +par_token:=cs_token_flag+par_loc;@/ +undump(hash_base)(hash_top)(write_loc);@/ +@z + +@x [50.1315] l.23925 - Make dumping/undumping more efficient - eqtb +while k<l do + begin dump_wd(eqtb[k]); incr(k); + end; +@y +dump_things(eqtb[k], l-k); +@z + +@x [50.1316] l.23944 - Make dumping/undumping more efficient - eqtb +while k<l do + begin dump_wd(eqtb[k]); incr(k); + end; +@y +dump_things(eqtb[k], l-k); +@z + +@x [50.1316] l.23947 - hash_extra +k:=j+1; dump_int(k-l); +until k>eqtb_size +@y +k:=j+1; dump_int(k-l); +until k>eqtb_size; +if hash_high>0 then dump_things(eqtb[eqtb_size+1],hash_high); + {dump |hash_extra| part} +@z + +@x [50.1317] l.23958 - Make dumping/undumping more efficient - eqtb +for j:=k to k+x-1 do undump_wd(eqtb[j]); +@y +undump_things(eqtb[k], x); +@z + +@x [50.1317] l.23960 - hash_extra +until k>eqtb_size +@y +until k>eqtb_size; +if hash_high>0 then undump_things(eqtb[eqtb_size+1],hash_high); + {undump |hash_extra| part} +@z + +@x [50.1318] l.23968 - hash_extra +dump_int(hash_used); cs_count:=frozen_control_sequence-1-hash_used; +@y 23968 +dump_int(hash_used); cs_count:=frozen_control_sequence-1-hash_used+hash_high; +@z + +@x [50.1318] l.23972 - Make dumping/undumping more efficient, hash_extra +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); +if hash_high>0 then dump_things(hash[eqtb_size+1], hash_high); +@z + +@x [50.1319] l.23980 - Make dumping/undumping more efficient, hash_extra +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); +if debug_format_file then begin + print_csnames (hash_base, undefined_control_sequence - 1); +end; +if hash_high > 0 then begin + undump_things (hash[eqtb_size+1], hash_high); + if debug_format_file then begin + print_csnames (eqtb_size + 1, hash_high - (eqtb_size + 1)); + end; +end; +@z + +@x [50.1320] l.23985 - Make dumping/undumping more efficient - tfm +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_things(font_info[0], fmem_ptr); +dump_int(font_ptr); +@<Dump the array info for internal font number |k|@>; +@z + +@x [50.1320] l.23991 - i18n fix +print_int(font_ptr-font_base); print(" preloaded font"); +if font_ptr<>font_base+1 then print_char("s") +@y +print_int(font_ptr-font_base); +if font_ptr<>font_base+1 then print(" preloaded fonts") +else print(" preloaded font") +@z + +@x [50.1321] l.23994 - texarray +undump_size(7)(font_mem_size)('font mem size')(fmem_ptr); +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_size(7)(sup_font_mem_size)('font mem size')(fmem_ptr); +if fmem_ptr>font_mem_size then font_mem_size:=fmem_ptr; +font_info:=xmalloc_array(fmemory_word, font_mem_size); +undump_things(font_info[0], fmem_ptr);@/ +undump_size(font_base)(font_base+max_font_max)('font max')(font_ptr); +{This undumps all of the font info, despite the name.} +@<Undump the array info for internal font number |k|@>; +@z + +% [50.1322] Dumping font_info. +% Knuth's code writes all the information relevant to a single font +% in the same section of the fmt file. But it's a lot faster to +% write the arrays of information out, one whole array at a time. +% So that's the way we handle dumping and undumping font info. +@x [50.1322] l.24000 - Make dumping/undumping more efficient - tfm +@ @<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]);@/ +dump_int(bchar_label[k]); +dump_int(font_bchar[k]); +dump_int(font_false_bchar[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_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); +dump_things(bchar_label[null_font], font_ptr+1-null_font); +dump_things(font_bchar[null_font], font_ptr+1-null_font); +dump_things(font_false_bchar[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 + +@x [50.1322] l.24031 - Make dumping/undumping more efficient - tfm +@ @<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]);@/ +undump(0)(fmem_ptr-1)(bchar_label[k]); +undump(min_quarterword)(non_char)(font_bchar[k]); +undump(min_quarterword)(non_char)(font_false_bchar[k]); +end +@y +@ This module should now be named `Undump all the font arrays'. + +@<Undump the array info for internal font number |k|@>= +begin {Allocate the font arrays} +font_check:=xmalloc_array(four_quarters, font_max); +font_size:=xmalloc_array(scaled, font_max); +font_dsize:=xmalloc_array(scaled, font_max); +font_params:=xmalloc_array(font_index, font_max); +font_name:=xmalloc_array(str_number, font_max); +font_area:=xmalloc_array(str_number, font_max); +font_bc:=xmalloc_array(eight_bits, font_max); +font_ec:=xmalloc_array(eight_bits, font_max); +font_glue:=xmalloc_array(halfword, font_max); +hyphen_char:=xmalloc_array(integer, font_max); +skew_char:=xmalloc_array(integer, font_max); +bchar_label:=xmalloc_array(font_index, font_max); +font_bchar:=xmalloc_array(nine_bits, font_max); +font_false_bchar:=xmalloc_array(nine_bits, font_max); +char_base:=xmalloc_array(integer, font_max); +width_base:=xmalloc_array(integer, font_max); +height_base:=xmalloc_array(integer, font_max); +depth_base:=xmalloc_array(integer, font_max); +italic_base:=xmalloc_array(integer, font_max); +lig_kern_base:=xmalloc_array(integer, font_max); +kern_base:=xmalloc_array(integer, font_max); +exten_base:=xmalloc_array(integer, font_max); +param_base:=xmalloc_array(integer, font_max); + +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_checked_things(min_halfword, max_halfword, + 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_upper_check_things(str_ptr, font_name[null_font], font_ptr+1-null_font); +undump_upper_check_things(str_ptr, font_area[null_font], font_ptr+1-null_font); +{There's no point in checking these values against the range $[0,255]$, + since the data type is |unsigned char|, and all values of that type are + in that range by definition.} +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_checked_things(min_halfword, lo_mem_max, + font_glue[null_font], font_ptr+1-null_font); +undump_checked_things(0, fmem_ptr-1, + bchar_label[null_font], font_ptr+1-null_font); +undump_checked_things(min_quarterword, non_char, + font_bchar[null_font], font_ptr+1-null_font); +undump_checked_things(min_quarterword, non_char, + font_false_bchar[null_font], font_ptr+1-null_font); +end +@z + +%%%%%%%% dynamic hyph_size +@x 24058 m.1324 +dump_int(hyph_count); +for k:=0 to hyph_size do if hyph_word[k]<>0 then + begin dump_int(k); dump_int(hyph_word[k]); dump_int(hyph_list[k]); + end; +@y 24061 +dump_int(hyph_count); +if hyph_next <= hyph_prime then hyph_next:=hyph_size; +dump_int(hyph_next);{minumum value of |hyphen_size| needed} +for k:=0 to hyph_size do if hyph_word[k]<>0 then + begin dump_int(k+65536*hyph_link[k]); + {assumes number of hyphen exceptions does not exceed 65535} + dump_int(hyph_word[k]); dump_int(hyph_list[k]); + end; +@z + +@x [50.1324] l.24063 - i18n fix +print_ln; print_int(hyph_count); print(" hyphenation exception"); +if hyph_count<>1 then print_char("s"); +@y +print_ln; print_int(hyph_count); +if hyph_count<>1 then print(" hyphenation exceptions") +else print(" hyphenation exception"); +@z + +@x [50.1324] l.24066 - Make dumping/undumping more efficient - trie +for k:=0 to trie_max do dump_hh(trie[k]); +dump_int(trie_op_ptr); +for k:=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_trl[0], trie_max+1); +dump_things(trie_tro[0], trie_max+1); +dump_things(trie_trc[0], trie_max+1); +dump_int(trie_op_ptr); +dump_things(hyf_distance[1], trie_op_ptr); +dump_things(hyf_num[1], trie_op_ptr); +dump_things(hyf_next[1], trie_op_ptr); +@z + +@x [50.1324] l.24076 - i18n fix +print(" has "); print_int(trie_op_ptr); print(" op"); +if trie_op_ptr<>1 then print_char("s"); +@y +print(" has "); print_int(trie_op_ptr); +if trie_op_ptr<>1 then print(" ops") +else print(" op"); +@z + +%%%%%%%% dynamic hyph_size +@x 24087 m.1325 +undump(0)(hyph_size)(hyph_count); +for k:=1 to hyph_count do + begin undump(0)(hyph_size)(j); + undump(0)(str_ptr)(hyph_word[j]); + undump(min_halfword)(max_halfword)(hyph_list[j]); + end; +@y 24092 +undump_size(0)(hyph_size)('hyph_size')(hyph_count); +undump_size(hyph_prime)(hyph_size)('hyph_size')(hyph_next); +j:=0; +for k:=1 to hyph_count do + begin undump_int(j); if j<0 then goto bad_fmt; + if j>65535 then + begin hyph_next:= j div 65536; j:=j - hyph_next * 65536; end + else hyph_next:=0; + if (j>=hyph_size)or(hyph_next>hyph_size) then goto bad_fmt; + hyph_link[j]:=hyph_next; + undump(0)(str_ptr)(hyph_word[j]); + undump(min_halfword)(max_halfword)(hyph_list[j]); + end; + {|j| is now the largest occupied location in |hyph_word|} + incr(j); + if j<hyph_prime then j:=hyph_prime; + hyph_next:=j; + if hyph_next >= hyph_size then hyph_next:=hyph_prime else + if hyph_next >= hyph_prime then incr(hyph_next); +@z + + +@x [50.1325] l.24094 - Make dumping/undumping more efficient - trie +for k:=0 to j do undump_hh(trie[k]); +undump_size(0)(trie_op_size)('trie op size')(j); @+init trie_op_ptr:=j;@+tini +for k:=1 to j 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 +{These first three haven't been allocated yet unless we're \.{INITEX}; + we do that precisely so we don't allocate more space than necessary.} +if not trie_trl then trie_trl:=xmalloc_array(trie_pointer,j+1); +undump_things(trie_trl[0], j+1); +if not trie_tro then trie_tro:=xmalloc_array(trie_pointer,j+1); +undump_things(trie_tro[0], j+1); +if not trie_trc then trie_trc:=xmalloc_array(quarterword, j+1); +undump_things(trie_trc[0], j+1); +undump_size(0)(trie_op_size)('trie op size')(j); @+init trie_op_ptr:=j;@+tini +{I'm not sure we have such a strict limitation (64) on these values, so + let's leave them unchecked.} +undump_things(hyf_distance[1], j); +undump_things(hyf_num[1], j); +undump_upper_check_things(max_trie_op, hyf_next[1], j); +@z + +@x [50.1327] l.24117 - Allow command line to override dumped value. +undump(batch_mode)(error_stop_mode)(interaction); +@y +undump(batch_mode)(error_stop_mode)(interaction); +if interaction_option<>unspecified_mode then interaction:=interaction_option; +@z + +% [50.1327] As with TFM files, `eof' here means `have we previously +% encountered the end-of-file', not `are we at the end of the file'. +@x [50.1327] l.24120 - dumping/undumping, replace eof() by feof() +if (x<>69069)or eof(fmt_file) then goto bad_fmt +@y +if (x<>69069)or feof(fmt_file) then goto bad_fmt +@z + +% Eliminate probably wrong word `preloaded' from format_idents. +@x [50.1328] l.24124 +print(" (preloaded format="); print(job_name); print_char(" "); +@y +print(" (format="); print(job_name); print_char(" "); +@z + +@x [51.1332] l.24203 - make the main program a procedure, for eqtb hack. +@p begin @!{|start_here|} +@y +@d const_chk(#)==begin if # < inf@&# then # := inf@&# else + if # > sup@&# then # := sup@&# end + +{|setup_bound_var| stuff duplicated in \.{mf.ch}.} +@d setup_bound_var(#)==bound_default:=#; setup_bound_var_end +@d setup_bound_var_end(#)==bound_name:=#; setup_bound_var_end_end +@d setup_bound_var_end_end(#)== + setup_bound_variable(address_of(#), bound_name, bound_default); + +@p procedure main_body; +begin @!{|start_here|} + +{Bounds that may be set from the configuration file. We want the user to + be able to specify the names with underscores, but \.{TANGLE} removes + underscores, so we're stuck giving the names twice, once as a string, + once as the identifier. How ugly.} + setup_bound_var (0)('mem_bot')(mem_bot); + setup_bound_var (250000)('main_memory')(main_memory); + {|memory_word|s for |mem| in \.{INITEX}} + setup_bound_var (0)('extra_mem_top')(extra_mem_top); + {increase high mem in \.{VIRTEX}} + setup_bound_var (0)('extra_mem_bot')(extra_mem_bot); + {increase low mem in \.{VIRTEX}} + setup_bound_var (100000)('pool_size')(pool_size); + setup_bound_var (75000)('string_vacancies')(string_vacancies); + setup_bound_var (5000)('pool_free')(pool_free); {min pool avail after fmt} + setup_bound_var (15000)('max_strings')(max_strings); + setup_bound_var (100)('strings_free')(strings_free); + setup_bound_var (100000)('font_mem_size')(font_mem_size); + setup_bound_var (500)('font_max')(font_max); + setup_bound_var (20000)('trie_size')(trie_size); + {if |ssup_trie_size| increases, recompile} + setup_bound_var (659)('hyph_size')(hyph_size); + setup_bound_var (3000)('buf_size')(buf_size); + setup_bound_var (50)('nest_size')(nest_size); + setup_bound_var (15)('max_in_open')(max_in_open); + setup_bound_var (60)('param_size')(param_size); + setup_bound_var (4000)('save_size')(save_size); + setup_bound_var (300)('stack_size')(stack_size); + setup_bound_var (16384)('dvi_buf_size')(dvi_buf_size); + setup_bound_var (79)('error_line')(error_line); + setup_bound_var (50)('half_error_line')(half_error_line); + setup_bound_var (79)('max_print_line')(max_print_line); + setup_bound_var (0)('hash_extra')(hash_extra); + + const_chk (mem_bot); + const_chk (main_memory); +@+Init + extra_mem_top := 0; + extra_mem_bot := 0; +@+Tini + if extra_mem_bot>sup_main_memory then extra_mem_bot:=sup_main_memory; + if extra_mem_top>sup_main_memory then extra_mem_top:=sup_main_memory; + {|mem_top| is an index, |main_memory| a size} + mem_top := mem_bot + main_memory -1; + mem_min := mem_bot; + mem_max := mem_top; + + {Check other constants against their sup and inf.} + const_chk (trie_size); + const_chk (hyph_size); + const_chk (buf_size); + const_chk (nest_size); + const_chk (max_in_open); + const_chk (param_size); + const_chk (save_size); + const_chk (stack_size); + const_chk (dvi_buf_size); + const_chk (pool_size); + const_chk (string_vacancies); + const_chk (pool_free); + const_chk (max_strings); + const_chk (strings_free); + const_chk (font_mem_size); + const_chk (font_max); + const_chk (hash_extra); + if error_line > ssup_error_line then error_line := ssup_error_line; + + {array memory allocation} + buffer:=xmalloc_array (ASCII_code, buf_size); + nest:=xmalloc_array (list_state_record, nest_size); + save_stack:=xmalloc_array (memory_word, save_size); + input_stack:=xmalloc_array (in_state_record, stack_size); + input_file:=xmalloc_array (alpha_file, max_in_open); + line_stack:=xmalloc_array (integer, max_in_open); + source_filename_stack:=xmalloc_array (str_number, max_in_open); + full_source_filename_stack:=xmalloc_array (str_number, max_in_open); + param_stack:=xmalloc_array (halfword, param_size); + dvi_buf:=xmalloc_array (eight_bits, dvi_buf_size); + hyph_word :=xmalloc_array (str_number, hyph_size); + hyph_list :=xmalloc_array (halfword, hyph_size); + hyph_link :=xmalloc_array (hyph_pointer, hyph_size); +@+Init + yzmem:=xmalloc_array (memory_word, mem_top - mem_bot + 1); + zmem := yzmem - mem_bot; {Some compilers require |mem_bot=0|} + eqtb_top := eqtb_size+hash_extra; + if hash_extra=0 then hash_top:=undefined_control_sequence else + hash_top:=eqtb_top; + yhash:=xmalloc_array (two_halves,1+hash_top-hash_offset); + hash:=yhash - hash_offset; {Some compilers require |hash_offset=0|} + next(hash_base):=0; text(hash_base):=0; + for hash_used:=hash_base+1 to hash_top do hash[hash_used]:=hash[hash_base]; + zeqtb:=xmalloc_array (memory_word, eqtb_top); + eqtb:=zeqtb; + + str_start:=xmalloc_array (pool_pointer, max_strings); + str_pool:=xmalloc_array (packed_ASCII_code, pool_size); + font_info:=xmalloc_array (fmemory_word, font_mem_size); +@+Tini +@z + +@x [51.1332] l.24215 - INI = VIR, so pool init needs runtime test +@!init if not get_strings_started then goto final_end; +init_prim; {call |primitive| for each primitive} +init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr; fix_date_and_time; +tini@/ +@y +@!Init if not get_strings_started then goto final_end; +init_prim; {call |primitive| for each primitive} +init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr; fix_date_and_time; +Tini@/ +@z + +@x [51.1332] l.24225 - main +end_of_TEX: close_files_and_terminate; +final_end: ready_already:=0; +end. +@y +close_files_and_terminate; +final_end: do_final_end; +end {|main_body|}; +@z + +@x [51.1333] l.24254 - Print new line before termination; switch to editor if necessary. + slow_print(log_name); print_char("."); + end; + end; +@y + print_file_name(0, log_name, 0); print_char("."); + end; + end; +print_ln; +if (edit_name_start<>0) and (interaction>batch_mode) then + call_edit(str_pool,edit_name_start,edit_name_length,edit_line); +@z + +@x [51.1334] l.24275 - hash_extra + wlog_ln(' ',cs_count:1,' multiletter control sequences out of ', + hash_size:1);@/ +@y 24276 + wlog_ln(' ',cs_count:1,' multiletter control sequences out of ', + hash_size:1, '+', hash_extra:1);@/ +@z + +@x [51.1335] l.24335 - Only do dump if ini. + begin @!init for c:=top_mark_code to split_bot_mark_code do +@y + begin @!Init for c:=top_mark_code to split_bot_mark_code do +@z + +@x [51.1335] l.24337 - Only do dump if ini. + store_fmt_file; return;@+tini@/ +@y + store_fmt_file; return;@+Tini@/ +@z + +@x [51.1337] l.24361 - Handle %&format in all cases. +if (format_ident=0)or(buffer[loc]="&") then +@y +if (format_ident=0)or(buffer[loc]="&")or dump_line then +@z + +@x [51.1337] l.24366 - Dynamic arrays size. + w_close(fmt_file); +@y + w_close(fmt_file); + eqtb:=zeqtb; +@z + +%% [51] m.1337 l.24371 - MLTeX: add. MLTeX banner after loading fmt file +%% (MLTeX change: only "if mltex_enabled_p then ....;") +@x [51.1337] l.24371 - Allocate hyphenation tries, do char translation, MLTeX +fix_date_and_time;@/ +@y +if mltex_enabled_p then + begin wterm_ln('MLTeX v2.2 enabled'); + end; +if enctex_enabled_p then + begin wterm(encTeX_banner); wterm_ln(', reencoding enabled.'); + if translate_filename then begin + wterm_ln(' (\xordcode, \xchrcode, \xprncode overridden by TCX)'); + end; + end; +fix_date_and_time;@/ + +@!init +if trie_not_ready then begin {initex without format loaded} + trie_trl:=xmalloc_array (trie_pointer, trie_size); + trie_tro:=xmalloc_array (trie_pointer, trie_size); + trie_trc:=xmalloc_array (quarterword, trie_size); + + trie_c:=xmalloc_array (packed_ASCII_code, trie_size); + trie_o:=xmalloc_array (trie_opcode, trie_size); + trie_l:=xmalloc_array (trie_pointer, trie_size); + trie_r:=xmalloc_array (trie_pointer, trie_size); + trie_hash:=xmalloc_array (trie_pointer, trie_size); + trie_taken:=xmalloc_array (boolean, trie_size); + + trie_root:=0; trie_c[0]:=si(0); trie_ptr:=0; + + {Allocate and initialize font arrays} + font_check:=xmalloc_array(four_quarters, font_max); + font_size:=xmalloc_array(scaled, font_max); + font_dsize:=xmalloc_array(scaled, font_max); + font_params:=xmalloc_array(font_index, font_max); + font_name:=xmalloc_array(str_number, font_max); + font_area:=xmalloc_array(str_number, font_max); + font_bc:=xmalloc_array(eight_bits, font_max); + font_ec:=xmalloc_array(eight_bits, font_max); + font_glue:=xmalloc_array(halfword, font_max); + hyphen_char:=xmalloc_array(integer, font_max); + skew_char:=xmalloc_array(integer, font_max); + bchar_label:=xmalloc_array(font_index, font_max); + font_bchar:=xmalloc_array(nine_bits, font_max); + font_false_bchar:=xmalloc_array(nine_bits, font_max); + char_base:=xmalloc_array(integer, font_max); + width_base:=xmalloc_array(integer, font_max); + height_base:=xmalloc_array(integer, font_max); + depth_base:=xmalloc_array(integer, font_max); + italic_base:=xmalloc_array(integer, font_max); + lig_kern_base:=xmalloc_array(integer, font_max); + kern_base:=xmalloc_array(integer, font_max); + exten_base:=xmalloc_array(integer, font_max); + param_base:=xmalloc_array(integer, font_max); + + font_ptr:=null_font; fmem_ptr:=7; + font_name[null_font]:="nullfont"; font_area[null_font]:=""; + hyphen_char[null_font]:="-"; skew_char[null_font]:=-1; + bchar_label[null_font]:=non_address; + font_bchar[null_font]:=non_char; font_false_bchar[null_font]:=non_char; + font_bc[null_font]:=1; font_ec[null_font]:=0; + font_size[null_font]:=0; font_dsize[null_font]:=0; + char_base[null_font]:=0; width_base[null_font]:=0; + height_base[null_font]:=0; depth_base[null_font]:=0; + italic_base[null_font]:=0; lig_kern_base[null_font]:=0; + kern_base[null_font]:=0; exten_base[null_font]:=0; + font_glue[null_font]:=null; font_params[null_font]:=7; + param_base[null_font]:=-1; + for font_k:=0 to 6 do font_info[font_k].sc:=0; + end; + tini@/ + + font_used:=xmalloc_array (boolean, font_max); + for font_k:=font_base to font_max do font_used[font_k]:=false; +@z + +% [52.1338] Core-dump in debugging mode on 0 input. Under Unix, it's +% not possible to portably 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 [52.1338] l.24411 - Core-dump in debugging mode on 0 input. + 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 + +@x [52.1339] l.24429 - debug - print tfm info +5: print_word(font_info[n]); +@y 24397 +5: begin print_scaled(font_info[n].sc); print_char(" ");@/ + print_int(font_info[n].qqqq.b0); print_char(":");@/ + print_int(font_info[n].qqqq.b1); print_char(":");@/ + print_int(font_info[n].qqqq.b2); print_char(":");@/ + print_int(font_info[n].qqqq.b3); + end; +@z + +@x [53.1341] - encTeX: keep track of mubyte value for \write +@d write_stream(#) == info(#+1) {stream number (0 to 17)} +@y +@d write_stream(#) == type(#+1) {stream number (0 to 17)} +@d mubyte_zero == 64 +@d write_mubyte(#) == subtype(#+1) {mubyte value + |mubyte_zero|} +@z + +@x [53.1344] l.24544 - source specials +primitive("special",extension,special_node);@/ +@y +primitive("special",extension,special_node);@/ +text(frozen_special):="special"; eqtb[frozen_special]:=eqtb[cur_val];@/ +@z + +% [53.1350] (new_write_whatsit) Allow 18 as a \write stream. We never +% refer to an actual file, though, so we don't need to change the +% write_file or write_open arrays. We provide for disabling this at +% runtime, for paranoids. +@x [53.1350] l.24609 - system: Allow 18 as a \write stream. + else if cur_val>15 then cur_val:=16; +@y + else if (cur_val>15) and (cur_val <> 18) then cur_val:=16; +@z + +@x [53.1350] - encTeX: \write stores mubyte_out value +write_stream(tail):=cur_val; +@y +write_stream(tail):=cur_val; +if mubyte_out + mubyte_zero < 0 then write_mubyte(tail) := 0 +else if mubyte_out + mubyte_zero >= 2*mubyte_zero then + write_mubyte(tail) := 2*mubyte_zero - 1 + else write_mubyte(tail) := mubyte_out + mubyte_zero; +@z + +@x [53.1353] - encTeX: \special stores specialout and mubyteout values +begin new_whatsit(special_node,write_node_size); write_stream(tail):=null; +p:=scan_toks(false,true); write_tokens(tail):=def_ref; +@y +begin new_whatsit(special_node,write_node_size); +if spec_out + mubyte_zero < 0 then write_stream(tail) := 0 +else if spec_out + mubyte_zero >= 2*mubyte_zero then + write_stream(tail) := 2*mubyte_zero - 1 + else write_stream(tail) := spec_out + mubyte_zero; +if mubyte_out + mubyte_zero < 0 then write_mubyte(tail) := 0 +else if mubyte_out + mubyte_zero >= 2*mubyte_zero then + write_mubyte(tail) := 2*mubyte_zero - 1 + else write_mubyte(tail) := mubyte_out + mubyte_zero; +if (spec_out = 2) or (spec_out = 3) then + if (mubyte_out > 2) or (mubyte_out = -1) or (mubyte_out = -2) then + write_noexpanding := true; +p:=scan_toks(false,true); write_tokens(tail):=def_ref; +write_noexpanding := false; +@z + +@x [53.1355] - encTeX: \write prints \mubyteout value +else print_char("-"); +@y +else print_char("-"); +if (s = "write") and (write_mubyte (p) <> mubyte_zero) then +begin + print_char ("<"); print_int (write_mubyte(p)-mubyte_zero); print_char (">"); +end; +@z + +@x [53.1356] - encTeX: \special prints \specialout and \mubyteout values +special_node:begin print_esc("special"); +@y +special_node:begin print_esc("special"); +if write_stream(p) <> mubyte_zero then +begin + print_char ("<"); print_int (write_stream(p)-mubyte_zero); + if (write_stream(p)-mubyte_zero = 2) or + (write_stream(p)-mubyte_zero = 3) then + begin + print_char (":"); print_int (write_mubyte(p)-mubyte_zero); + end; + print_char (">"); +end; +@z + +@x [53.1368] - encTeX: conversions in \special +old_setting:=selector; selector:=new_string; +@y +old_setting:=selector; selector:=new_string; +spec_sout := spec_out; spec_out := write_stream(p) - mubyte_zero; +mubyte_sout := mubyte_out; mubyte_out := write_mubyte(p) - mubyte_zero; +active_noconvert := true; +mubyte_slog := mubyte_log; +mubyte_log := 0; +if (mubyte_out > 0) or (mubyte_out = -1) then mubyte_log := 1; +if (spec_out = 2) or (spec_out = 3) then +begin + if (mubyte_out > 0) or (mubyte_out = -1) then + begin + special_printing := true; mubyte_log := 1; + end; + if mubyte_out > 1 then cs_converting := true; +end; +@z + +@x [53.1368] - encTeX: conversions in \special +for k:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[k])); +@y +if (spec_out = 1) or (spec_out = 3) then + for k:=str_start[str_ptr] to pool_ptr-1 do + str_pool[k] := si(xchr[so(str_pool[k])]); +for k:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[k])); +spec_out := spec_sout; mubyte_out := mubyte_sout; mubyte_log := mubyte_slog; +special_printing := false; cs_converting := false; +active_noconvert := false; +@z + +@x [53.1370] l.24770 - \write18{foo} / encTeX +begin @<Expand macros in the token list +@y +@!d:integer; {number of characters in incomplete current string} +@!clobbered:boolean; {system string is ok?} +begin +mubyte_sout := mubyte_out; mubyte_out := write_mubyte(p) - mubyte_zero; +if (mubyte_out > 2) or (mubyte_out = -1) or (mubyte_out = -2) then + write_noexpanding := true; +@<Expand macros in the token list +@z + +@x [53.1370] l.24773 - system: (write_out) \write18{foo} => system(foo). +if write_open[j] then selector:=j +@y +if j=18 then selector := new_string +else if write_open[j] then selector:=j +@z + +@x [53.1370] - encTeX: conversion in parameter of \write +token_show(def_ref); print_ln; +@y +active_noconvert := true; +if mubyte_out > 1 then cs_converting := true; +mubyte_slog := mubyte_log; +if (mubyte_out > 0) or (mubyte_out = -1) then mubyte_log := 1 +else mubyte_log := 0; +token_show(def_ref); print_ln; +cs_converting := false; write_noexpanding := false; +active_noconvert := false; +mubyte_out := mubyte_sout; mubyte_log := mubyte_slog; +@z + +% Then call system(3) on that string. +@x [53.1370] l.24779 - system: (write_out) \write18{foo} => system(foo). +flush_list(def_ref); selector:=old_setting; +@y +flush_list(def_ref); +if j=18 then + begin if (tracing_online<=0) then + selector:=log_only {Show what we're doing in the log file.} + else selector:=term_and_log; {Show what we're doing.} + {If the log file isn't open yet, we can only send output to the terminal. + Calling |open_log_file| from here seems to result in bad data in the log.} + if not log_opened then selector:=term_only; + print_nl("system("); + for d:=0 to cur_length-1 do + begin {|print| gives up if passed |str_ptr|, so do it by hand.} + print(so(str_pool[str_start[str_ptr]+d])); {N.B.: not |print_char|} + end; + print(")..."); + if shell_enabled_p then + begin str_room(1); append_char(0); {Append a null byte to the expansion.} + clobbered:=false; + for d:=0 to cur_length-1 do {Convert to external character set.} + begin str_pool[str_start[str_ptr]+d]:=xchr[str_pool[str_start[str_ptr]+d]]; + if (str_pool[str_start[str_ptr]+d]=null_code) + and (d<cur_length-1) then clobbered:=true; + {minimal checking: NUL not allowed in argument string of |system|()} + end; + if clobbered then print("clobbered") + else begin {We have the string; run system(3). We don't have anything + reasonable to do with the return status, unfortunately discard it.} + system(stringcast(address_of(str_pool[str_start[str_ptr]]))); + print("executed"); + end; + end + else begin print("disabled"); + end; + print_char("."); print_nl(""); print_ln; + pool_ptr:=str_start[str_ptr]; {erase the string} +end; +selector:=old_setting; +@z + +@x [53.1373] Need new local. +procedure out_what(@!p:pointer); +var j:small_number; {write stream number} +@y +procedure out_what(@!p:pointer); +var j:small_number; {write stream number} + @!old_setting:0..max_selector; +@z + +@x [53.1374] Disallow certain \openout filenames, and log results. + while not a_open_out(write_file[j]) do + prompt_file_name("output file name",".tex"); + write_open[j]:=true; +@y + while not open_out_name_ok(stringcast(name_of_file+1)) + or not a_open_out(write_file[j]) do + prompt_file_name("output file name",".tex"); + write_open[j]:=true; + {If on first line of input, log file is not ready yet, so don't log.} + if log_opened then begin + old_setting:=selector; + if (tracing_online<=0) then + selector:=log_only {Show what we're doing in the log file.} + else selector:=term_and_log; {Show what we're doing.} + print_nl("\openout"); + print_int(j); + print(" = `"); + print_file_name(cur_name,cur_area,cur_ext); + print("'."); print_nl(""); print_ln; + selector:=old_setting; + end; +@z + +@x [54.1376] l.24903 - Add editor-switch variables to globals. +@* \[54] System-dependent changes. +@y +@* \[54/web2c] System-dependent changes for Web2c. +Here are extra variables for Web2c. (This numbering of the +system-dependent section allows easy integration of Web2c and e-\TeX, etc.) +@^<system dependencies@> + +@<Glob...@>= +@!edit_name_start: pool_pointer; {where the filename to switch to starts} +@!edit_name_length,@!edit_line: integer; {what line to start editing at} +@!ipc_on: c_int_type; {level of IPC action, 0 for none [default]} +@!stop_at_space: boolean; {whether |more_name| returns false for space} + +@ 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; +stop_at_space:=true; + +@ These are used when we regenerate the representation of the first 256 +strings. + +@<Global...@> = +@!save_str_ptr: str_number; +@!save_pool_ptr: pool_pointer; +@!shell_enabled_p: c_int_type; +@!output_comment: ^char; +@!k,l: 0..255; {used by `Make the first 256 strings', etc.} + +@ When debugging a macro package, it can be useful to see the exact +control sequence names in the format file. For example, if ten new +csnames appear, it's nice to know what they are, to help pinpoint where +they came from. (This isn't a truly ``basic'' printing procedure, but +that's a convenient module in which to put it.) + +@<Basic printing procedures@> = +procedure print_csnames (hstart:integer; hfinish:integer); +var c,h,where:integer; +begin + write_ln(stderr, 'fmtdebug:csnames from ', hstart, ' to ', hfinish, ':'); + for h := hstart to hfinish do begin + if text(h) > 0 then begin {if have anything at this position} + for c := str_start[text(h)] to str_start[text(h) + 1] - 1 + do begin + put_byte(str_pool[c], stderr); {print the characters} + end; + write_ln(stderr, '|'); + end; + end; +end; + +@ Are we printing extra info as we read the format file? + +@<Glob...@> = +@!debug_format_file: boolean; + + +@ A helper for printing file:line:error style messages. Look for a +filename in |full_source_filename_stack|, and if we fail to find +one fall back on the non-file:line:error style. + +@<Basic print...@>= +procedure print_file_line; +var level: 0..max_in_open; +begin + level:=in_open; + while (level>0) and (full_source_filename_stack[level]=0) do + decr(level); + if level=0 then + print_nl("! ") + else begin + print_nl (""); print (full_source_filename_stack[level]); print (":"); + if level=in_open then print_int (line) + else print_int (line_stack[index+1-(in_open-level)]); + print (": "); + end; +end; + +@ To be able to determine whether \.{\\write18} is enabled from within +\TeX\ we also implement \.{\\eof18}. We sort of cheat by having an +additional route |scan_four_bit_int_or_18| which is the same as +|scan_four_bit_int| except it also accepts the value 18. + +@<Declare procedures that scan restricted classes of integers@>= +procedure scan_four_bit_int_or_18; +begin scan_int; +if (cur_val<0)or((cur_val>15)and(cur_val<>18)) then + begin print_err("Bad number"); +@.Bad number@> + help2("Since I expected to read a number between 0 and 15,")@/ + ("I changed this one to zero."); int_error(cur_val); cur_val:=0; + end; +end; + +@ Dumping the |xord|, |xchr|, and |xprn| arrays. We dump these always +in the format, so a TCX file loaded during format creation can set a +default for users of the format. + +@<Dump |xord|, |xchr|, and |xprn|@>= +dump_things(xord[0], 256); +dump_things(xchr[0], 256); +dump_things(xprn[0], 256); + +@ Undumping the |xord|, |xchr|, and |xprn| arrays. This code is more +complicated, because we want to ensure that a TCX file specified on +the command line will override whatever is in the format. Since the +tcx file has already been loaded, that implies throwing away the data +in the format. Also, if no |translate_filename| is given, but +|eight_bit_p| is set we have to make all characters printable. + +@<Undump |xord|, |xchr|, and |xprn|@>= +if translate_filename then begin + for k:=0 to 255 do undump_things(dummy_xord, 1); + for k:=0 to 255 do undump_things(dummy_xchr, 1); + for k:=0 to 255 do undump_things(dummy_xprn, 1); + end +else begin + undump_things(xord[0], 256); + undump_things(xchr[0], 256); + undump_things(xprn[0], 256); + if eight_bit_p then + for k:=0 to 255 do + xprn[k]:=1; +end; + + +@* \[54/web2c-string] The string recycling routines. \TeX{} uses 2 +upto 4 {\it new\/} strings when scanning a filename in an \.{\\input}, +\.{\\openin}, or \.{\\openout} operation. These strings are normally +lost because the reference to them are not saved after finishing the +operation. |search_string| searches through the string pool for the +given string and returns either 0 or the found string number. + +@<Declare additional routines for string recycling@>= +function search_string(@!search:str_number):str_number; +label found; +var result: str_number; +@!s: str_number; {running index} +@!len: integer; {length of searched string} +begin result:=0; len:=length(search); +if len=0 then {trivial case} + begin result:=""; goto found; + end +else begin s:=search-1; {start search with newest string below |s|; |search>1|!} + while s>255 do {first 256 strings depend on implementation!!} + begin if length(s)=len then + if str_eq_str(s,search) then + begin result:=s; goto found; + end; + decr(s); + end; + end; +found:search_string:=result; +end; + +@ The following routine is a variant of |make_string|. It searches +the whole string pool for a string equal to the string currently built +and returns a found string. Otherwise a new string is created and +returned. Be cautious, you can not apply |flush_string| to a replaced +string! + +@<Declare additional routines for string recycling@>= +function slow_make_string : str_number; +label exit; +var s: str_number; {result of |search_string|} +@!t: str_number; {new string} +begin t:=make_string; s:=search_string(t); +if s>0 then + begin flush_string; slow_make_string:=s; return; + end; +slow_make_string:=t; +exit:end; + + +@* \[54/ML\TeX] System-dependent changes for ML\TeX. + +The boolean variable |mltex_p| is set by web2c according to the given +command line option (or an entry in the configuration file) before any +\TeX{} function is called. + +@<Global...@> = +@!mltex_p: boolean; + +@ The boolean variable |mltex_enabled_p| is used to enable ML\TeX's +character substitution. It is initialised to |false|. When loading +a \.{FMT} it is set to the value of the boolean |mltex_p| saved in +the \.{FMT} file. Additionally it is set to the value of |mltex_p| +in Ini\TeX. + +@<Glob...@>= +@!mltex_enabled_p:boolean; {enable character substitution} + + +@ @<Set init...@>= +mltex_enabled_p:=false; + + +@ The function |effective_char| computes the effective character with +respect to font information. The effective character is either the +base character part of a character substitution definition, if the +character does not exist in the font or the character itself. + +Inside |effective_char| we can not use |char_info| because the macro +|char_info| uses |effective_char| calling this function a second time +with the same arguments. + +If neither the character |c| exists in font |f| nor a character +substitution for |c| was defined, you can not use the function value +as a character offset in |char_info| because it will access an +undefined or invalid |font_info| entry! Therefore inside |char_info| +and in other places, |effective_char|'s boolean parameter |err_p| is +set to |true| to issue a warning and return the incorrect +replacement, but always existing character |font_bc[f]|. +@^inner loop@> + +@<Declare additional functions for ML\TeX@>= +function effective_char(@!err_p:boolean; + @!f:internal_font_number;@!c:quarterword):integer; +label found; +var base_c: integer; {or |eightbits|: replacement base character} +@!result: integer; {or |quarterword|} +begin result:=c; {return |c| unless it does not exist in the font} +if not mltex_enabled_p then goto found; +if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then + if char_exists(orig_char_info(f)(c)) then {N.B.: not |char_info|(f)(c)} + goto found; +if qo(c)>=char_sub_def_min then if qo(c)<=char_sub_def_max then + if char_list_exists(qo(c)) then + begin base_c:=char_list_char(qo(c)); + result:=qi(base_c); {return |base_c|} + if not err_p then goto found; + if font_ec[f]>=base_c then if font_bc[f]<=base_c then + if char_exists(orig_char_info(f)(qi(base_c))) then goto found; + end; +if err_p then {print error and return existing character?} + begin begin_diagnostic; + print_nl("Missing character: There is no "); print("substitution for "); +@.Missing character@> + print_ASCII(qo(c)); print(" in font "); + slow_print(font_name[f]); print_char("!"); end_diagnostic(false); + result:=qi(font_bc[f]); {N.B.: not non-existing character |c|!} + end; +found: effective_char:=result; +end; + + +@ The function |effective_char_info| is equivalent to |char_info|, +except it will return |null_character| if neither the character |c| +exists in font |f| nor is there a substitution definition for |c|. +(For these cases |char_info| using |effective_char| will access an +undefined or invalid |font_info| entry. See the documentation of +|effective_char| for more information.) +@^inner loop@> + +@<Declare additional functions for ML\TeX@>= +function effective_char_info(@!f:internal_font_number; + @!c:quarterword):four_quarters; +label exit; +var ci:four_quarters; {character information bytes for |c|} +@!base_c:integer; {or |eightbits|: replacement base character} +begin if not mltex_enabled_p then + begin effective_char_info:=orig_char_info(f)(c); return; + end; +if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then + begin ci:=orig_char_info(f)(c); {N.B.: not |char_info|(f)(c)} + if char_exists(ci) then + begin effective_char_info:=ci; return; + end; + end; +if qo(c)>=char_sub_def_min then if qo(c)<=char_sub_def_max then + if char_list_exists(qo(c)) then + begin {|effective_char_info:=char_info(f)(qi(char_list_char(qo(c))));|} + base_c:=char_list_char(qo(c)); + if font_ec[f]>=base_c then if font_bc[f]<=base_c then + begin ci:=orig_char_info(f)(qi(base_c)); {N.B.: not |char_info|(f)(c)} + if char_exists(ci) then + begin effective_char_info:=ci; return; + end; + end; + end; +effective_char_info:=null_character; +exit:end; + + +@ This code is called for a virtual character |c| in |hlist_out| +during |ship_out|. It tries to built a character substitution +construct for |c| generating appropriate \.{DVI} code using the +character substitution definition for this character. If a valid +character substitution exists \.{DVI} code is created as if +|make_accent| was used. In all other cases the status of the +substituion for this character has been changed between the creation +of the character node in the hlist and the output of the page---the +created \.{DVI} code will be correct but the visual result will be +undefined. + +Former ML\TeX\ versions have replaced the character node by a +sequence of character, box, and accent kern nodes splicing them into +the original horizontal list. This version does not do this to avoid +a)~a memory overflow at this processing stage, b)~additional code to +add a pointer to the previous node needed for the replacement, and +c)~to avoid wrong code resulting in anomalies because of the use +within a \.{\\leaders} box. + +@<Output a substitution, |goto continue| if not possible@>= + begin + @<Get substitution information, check it, goto |found| + if all is ok, otherwise goto |continue|@>; +found: @<Print character substition tracing log@>; + @<Rebuild character using substitution information@>; + end + + +@ The global variables for the code to substitute a virtual character +can be declared as local. Nonetheless we declare them as global to +avoid stack overflows because |hlist_out| can be called recursivly. + +@<Glob...@>= +@!accent_c,@!base_c,@!replace_c:integer; +@!ia_c,@!ib_c:four_quarters; {accent and base character information} +@!base_slant,@!accent_slant:real; {amount of slant} +@!base_x_height:scaled; {accent is designed for characters of this height} +@!base_width,@!base_height:scaled; {height and width for base character} +@!accent_width,@!accent_height:scaled; {height and width for accent} +@!delta:scaled; {amount of right shift} + + +@ Get the character substitution information in |char_sub_code| for +the character |c|. The current code checks that the substition +exists and is valid and all substitution characters exist in the +font, so we can {\it not\/} substitute a character used in a +substitution. This simplifies the code because we have not to check +for cycles in all character substitution definitions. + +@<Get substitution information, check it...@>= + if qo(c)>=char_sub_def_min then if qo(c)<=char_sub_def_max then + if char_list_exists(qo(c)) then + begin base_c:=char_list_char(qo(c)); + accent_c:=char_list_accent(qo(c)); + if (font_ec[f]>=base_c) then if (font_bc[f]<=base_c) then + if (font_ec[f]>=accent_c) then if (font_bc[f]<=accent_c) then + begin ia_c:=char_info(f)(qi(accent_c)); + ib_c:=char_info(f)(qi(base_c)); + if char_exists(ib_c) then + if char_exists(ia_c) then goto found; + end; + begin_diagnostic; + print_nl("Missing character: Incomplete substitution "); +@.Missing character@> + print_ASCII(qo(c)); print(" = "); print_ASCII(accent_c); + print(" "); print_ASCII(base_c); print(" in font "); + slow_print(font_name[f]); print_char("!"); end_diagnostic(false); + goto continue; + end; + begin_diagnostic; + print_nl("Missing character: There is no "); print("substitution for "); +@.Missing character@> + print_ASCII(qo(c)); print(" in font "); + slow_print(font_name[f]); print_char("!"); end_diagnostic(false); + goto continue + + +@ For |tracinglostchars>99| the substitution is shown in the log file. + +@<Print character substition tracing log@>= + if tracing_lost_chars>99 then + begin begin_diagnostic; + print_nl("Using character substitution: "); + print_ASCII(qo(c)); print(" = "); + print_ASCII(accent_c); print(" "); print_ASCII(base_c); + print(" in font "); slow_print(font_name[f]); print_char("."); + end_diagnostic(false); + end + + +@ This outputs the accent and the base character given in the +substitution. It uses code virtually identical to the |make_accent| +procedure, but without the node creation steps. + +Additionally if the accent character has to be shifted vertically it +does {\it not\/} create the same code. The original routine in +|make_accent| and former versions of ML\TeX{} creates a box node +resulting in |push| and |pop| operations, whereas this code simply +produces vertical positioning operations. This can influence the +pixel rounding algorithm in some \.{DVI} drivers---and therefore will +probably be changed in one of the next ML\TeX{} versions. + +@<Rebuild character using substitution information@>= + base_x_height:=x_height(f); + base_slant:=slant(f)/float_constant(65536); +@^real division@> + accent_slant:=base_slant; {slant of accent character font} + base_width:=char_width(f)(ib_c); + base_height:=char_height(f)(height_depth(ib_c)); + accent_width:=char_width(f)(ia_c); + accent_height:=char_height(f)(height_depth(ia_c)); + @/{compute necessary horizontal shift (don't forget slant)}@/ + delta:=round((base_width-accent_width)/float_constant(2)+ + base_height*base_slant-base_x_height*accent_slant); +@^real multiplication@> +@^real addition@> + dvi_h:=cur_h; {update |dvi_h|, similar to the last statement in module 620} + @/{1. For centering/horizontal shifting insert a kern node.}@/ + cur_h:=cur_h+delta; synch_h; + @/{2. Then insert the accent character possibly shifted up or down.}@/ + if ((base_height<>base_x_height) and (accent_height>0)) then + begin {the accent must be shifted up or down} + cur_v:=base_line+(base_x_height-base_height); synch_v; + if accent_c>=128 then dvi_out(set1); + dvi_out(accent_c);@/ + cur_v:=base_line; + end + else begin synch_v; + if accent_c>=128 then dvi_out(set1); + dvi_out(accent_c);@/ + end; + cur_h:=cur_h+accent_width; dvi_h:=cur_h; + @/{3. For centering/horizontal shifting insert another kern node.}@/ + cur_h:=cur_h+(-accent_width-delta); + @/{4. Output the base character.}@/ + synch_h; synch_v; + if base_c>=128 then dvi_out(set1); + dvi_out(base_c);@/ + cur_h:=cur_h+base_width; + dvi_h:=cur_h {update of |dvi_h| is unnecessary, will be set in module 620} + +@ Dumping ML\TeX-related material. This is just the flag in the +format that tells us whether ML\TeX{} is enabled. + +@<Dump ML\TeX-specific data@>= +dump_int(@"4D4C5458); {ML\TeX's magic constant: "MLTX"} +if mltex_p then dump_int(1) +else dump_int(0); + +@ Undump ML\TeX-related material, which is just a flag in the format +that tells us whether ML\TeX{} is enabled. + +@<Undump ML\TeX-specific data@>= +undump_int(x); {check magic constant of ML\TeX} +if x<>@"4D4C5458 then goto bad_fmt; +undump_int(x); {undump |mltex_p| flag into |mltex_enabled_p|} +if x=1 then mltex_enabled_p:=true +else if x<>0 then goto bad_fmt; + + +@* \[54/enc\TeX] System-dependent changes for enc\TeX. + +@d encTeX_banner == ' encTeX v. Jun. 2004' + +@ The boolean variable |enctex_p| is set by web2c according to the given +command line option (or an entry in the configuration file) before any +\TeX{} function is called. + +@<Global...@> = +@!enctex_p: boolean; + + +@ The boolean variable |enctex_enabled_p| is used to enable enc\TeX's +primitives. It is initialised to |false|. When loading a \.{FMT} it +is set to the value of the boolean |enctex_p| saved in the \.{FMT} file. +Additionally it is set to the value of |enctex_p| in Ini\TeX. + +@<Glob...@>= +@!enctex_enabled_p:boolean; {enable encTeX} + + +@ @<Set init...@>= +enctex_enabled_p:=false; + + +@ Auxiliary functions/procedures for enc\TeX{} (by Petr Olsak) follow. +These functions implement the \.{\\mubyte} code to convert +the multibytes in |buffer| to one byte or to one control +sequence. These functions manipulate a mubyte tree: each node of +this tree is token list with n+1 tokens (first token consist the byte +from the byte sequence itself and the other tokens point to the +branches). If you travel from root of the tree to a leaf then you +find exactly one byte sequence which we have to convert to one byte or +control sequence. There are two variants of the leaf: the ``definitive +end'' or the ``middle leaf'' if a longer byte sequence exists and the mubyte +tree continues under this leaf. First variant is implemented as one +memory word where the link part includes the token to +which we have to convert and type part includes the number 60 (normal +conversion) or 1..52 (insert the control sequence). +The second variant of ``middle leaf'' is implemented as two memory words: +first one has a type advanced by 64 and link points to the second +word where info part includes the token to which we have to convert +and link points to the next token list with the branches of +the subtree. + +The inverse: one byte to multi byte (for log printing and \.{\\write} +printing) is implemented via a pool. Each multibyte sequence is stored +in a pool as a string and |mubyte_write|[{\it printed char\/}] points +to this string. + +@d new_mubyte_node == + link (p) := get_avail; p := link (p); info (p) := get_avail; p := info (p) +@d subinfo (#) == subtype (#) + +@<Basic printing...@>= +{ read |buffer|[|i|] and convert multibyte. |i| should have been + of type 0..|buf_size|, but web2c doesn't like that construct in + argument lists. } +function read_buffer(var i:integer):ASCII_code; +var p: pointer; + last_found: integer; + last_type: integer; +begin + mubyte_skip := 0; mubyte_token := 0; + read_buffer := buffer[i]; + if mubyte_in = 0 then + begin + if mubyte_keep > 0 then mubyte_keep := 0; + return ; + end; + last_found := -2; + if (i = start) and (not mubyte_start) then + begin + mubyte_keep := 0; + if (end_line_char >= 0) and (end_line_char < 256) then + if mubyte_read [end_line_char] <> null then + begin + mubyte_start := true; mubyte_skip := -1; + p := mubyte_read [end_line_char]; + goto continue; + end; + end; +restart: + mubyte_start := false; + if (mubyte_read [buffer[i]] = null) or (mubyte_keep > 0) then + begin + if mubyte_keep > 0 then decr (mubyte_keep); + return ; + end; + p := mubyte_read [buffer[i]]; +continue: + if type (p) >= 64 then + begin + last_type := type (p) - 64; + p := link (p); + mubyte_token := info (p); last_found := mubyte_skip; + end else if type (p) > 0 then + begin + last_type := type (p); + mubyte_token := link (p); + goto found; + end; + incr (mubyte_skip); + if i + mubyte_skip > limit then + begin + mubyte_skip := 0; + if mubyte_start then goto restart; + return; + end; + repeat + p := link (p); + if subinfo (info(p)) = buffer [i+mubyte_skip] then + begin + p := info (p); goto continue; + end; + until link (p) = null; + mubyte_skip := 0; + if mubyte_start then goto restart; + if last_found = -2 then return; { no found } + mubyte_skip := last_found; +found: + if mubyte_token < 256 then { multibyte to one byte } + begin + read_buffer := mubyte_token; mubyte_token := 0; + i := i + mubyte_skip; + if mubyte_start and (i >= start) then mubyte_start := false; + return; + end else begin { multibyte to control sequence } + read_buffer := 0; + if last_type = 60 then { normal conversion } + i := i + mubyte_skip + else begin { insert control sequence } + decr (i); mubyte_keep := last_type; + if i < start then mubyte_start := true; + if last_type = 52 then mubyte_keep := 10000; + if last_type = 51 then mubyte_keep := mubyte_skip + 1; + mubyte_skip := -1; + end; + if mubyte_start and (i >= start) then mubyte_start := false; + return; + end; +exit: end; + +@ @<Declare additional routines for enc\TeX@>= +procedure mubyte_update; { saves new string to mubyte tree } +var j: pool_pointer; + p: pointer; + q: pointer; + in_mutree: integer; +begin + j := str_start [str_ptr]; + if mubyte_read [so(str_pool[j])] = null then + begin + in_mutree := 0; + p := get_avail; + mubyte_read [so(str_pool[j])] := p; + subinfo (p) := so(str_pool[j]); type (p) := 0; + end else begin + in_mutree := 1; + p := mubyte_read [so(str_pool[j])]; + end; + incr (j); + while j < pool_ptr do + begin + if in_mutree = 0 then + begin + new_mubyte_node; subinfo (p) := so(str_pool[j]); type (p) := 0; + end else { |in_mutree| = 1 } + if (type (p) > 0) and (type (p) < 64) then + begin + type (p) := type (p) + 64; + q := link (p); link (p) := get_avail; p := link (p); + info (p) := q; + new_mubyte_node; subinfo (p) := so(str_pool[j]); type (p) := 0; + in_mutree := 0; + end else begin + if type (p) >= 64 then p := link (p); + repeat + p := link (p); + if subinfo (info(p)) = so(str_pool[j]) then + begin + p := info (p); + goto continue; + end; + until link (p) = null; + new_mubyte_node; subinfo (p) := so(str_pool[j]); type (p) := 0; + in_mutree := 0; + end; +continue: + incr (j); + end; + if in_mutree = 1 then + begin + if type (p) = 0 then + begin + type (p) := mubyte_prefix + 64; + q := link (p); link (p) := get_avail; p := link (p); + link (p) := q; info (p) := mubyte_stoken; + return; + end; + if type (p) >= 64 then + begin + type (p) := mubyte_prefix + 64; + p := link (p); info (p) := mubyte_stoken; + return; + end; + end; + type (p) := mubyte_prefix; + link (p) := mubyte_stoken; +exit: end; +@# +procedure dispose_munode (p: pointer); { frees a mu subtree recursivelly } +var q: pointer; +begin + if (type (p) > 0) and (type (p) < 64) then free_avail (p) + else begin + if type (p) >= 64 then + begin + q := link (p); free_avail (p); p := q; + end; + q := link (p); free_avail (p); p := q; + while p <> null do + begin + dispose_munode (info (p)); + q := link (p); + free_avail (p); + p := q; + end; + end; +end; +@# +procedure dispose_mutableout (cs: pointer); { frees record from out table } +var p, q, r: pointer; +begin + p := mubyte_cswrite [cs mod 128]; + r := null; + while p <> null do + if info (p) = cs then + begin + if r <> null then link (r) := link (link (p)) + else mubyte_cswrite[cs mod 128] := link (link (p)); + q := link (link(p)); + free_avail (link(p)); free_avail (p); + p := q; + end else begin + r := link (p); p := link (r); + end; +end; + +@ The |print_buffer| procedure prints one character from |buffer|[|i|]. +It also increases |i| to the next character in the buffer. + +@<Basic printing...@>= +{ print one char from |buffer|[|i|]. |i| should have been of type + 0..|buf_size|, but web2c doesn't like that construct in argument lists. } +procedure print_buffer(var i:integer); +var c: ASCII_code; +begin + if mubyte_in = 0 then print (buffer[i]) { normal TeX } + else if mubyte_log > 0 then print_char (buffer[i]) + else begin + c := read_buffer (i); + if mubyte_token > 0 then print_cs (mubyte_token-cs_token_flag) + else print (c); + end; + incr (i); +end; + +@ Additional material to dump for enc\TeX. This includes whether +enc\TeX is enabled, and if it is we also have to dump the \.{\\mubyte} +arrays. + +@<Dump enc\TeX-specific data@>= +dump_int(@"45435458); {enc\TeX's magic constant: "ECTX"} +if not enctex_p then dump_int(0) +else begin + dump_int(1); + dump_things(mubyte_read[0], 256); + dump_things(mubyte_write[0], 256); + dump_things(mubyte_cswrite[0], 128); +end; + +@ Undumping the additional material we dumped for enc\TeX. This includes +conditionally undumping the \.{\\mubyte} arrays. + +@<Undump enc\TeX-specific data@>= +undump_int(x); {check magic constant of enc\TeX} +if x<>@"45435458 then goto bad_fmt; +undump_int(x); {undump |enctex_p| flag into |enctex_enabled_p|} +if x=0 then enctex_enabled_p:=false +else if x<>1 then goto bad_fmt +else begin + enctex_enabled_p:=true; + undump_things(mubyte_read[0], 256); + undump_things(mubyte_write[0], 256); + undump_things(mubyte_cswrite[0], 128); +end; + + +@* \[54] System-dependent changes. +@z + +@x [54.1379] l.24916 - extra routines +@* \[55] Index. +@y + +@ @<Declare action procedures for use by |main_control|@>= + +procedure insert_src_special; +var toklist, p, q : pointer; +begin + if (source_filename_stack[in_open] > 0 and is_new_source (source_filename_stack[in_open] +, line)) then begin + toklist := get_avail; + p := toklist; + info(p) := cs_token_flag+frozen_special; + link(p) := get_avail; p := link(p); + info(p) := left_brace_token+"{"; + q := str_toks (make_src_special (source_filename_stack[in_open], line)); + link(p) := link(temp_head); + p := q; + link(p) := get_avail; p := link(p); + info(p) := right_brace_token+"}"; + ins_list (toklist); + remember_source_info (source_filename_stack[in_open], line); + end; +end; + +procedure append_src_special; +var p, q : pointer; +begin + if (source_filename_stack[in_open] > 0 and is_new_source (source_filename_stack[in_open] +, line)) then begin + new_whatsit (special_node, write_node_size); + write_stream(tail) := 0; + def_ref := get_avail; + token_ref_count(def_ref) := null; + q := str_toks (make_src_special (source_filename_stack[in_open], line)); + link(def_ref) := link(temp_head); + write_tokens(tail) := def_ref; + remember_source_info (source_filename_stack[in_open], line); + end; +end; + +@ This function used to be in pdftex, but is useful in tex too. + +@p function get_nullstr: str_number; +begin + get_nullstr := ""; +end; + +@* \[55] Index. +@z |