1% tex.ch for C compilation with web2c, derived from various other change files.
2% By Tim Morgan, UC Irvine ICS Department, and many others.
3%
4% Be very careful when making changes to this file, as it is used to
5% generate TeX, e-TeX, and pdfTeX, and most changes require similar
6% changes to be made to the Aleph sources.
7%
8% (05/28/86) ETM Started with TeX 2.0
9% (06/03/87) ETM Brought up to TeX 2.2
10% (09/26/87) ETM Brought up to TeX 2.3
11% (10/01/87) ETM Brought up to TeX 2.5
12% (12/21/87) ETM Brought up to TeX 2.7
13% (01/14/88) ETM Brought up to TeX 2.9
14% (02/20/88) PAM Revised format and module numbers
15% (03/01/88) ETM Eliminated some unused variables and unnecesary tests
16% (05/09/88) ETM Added yet another casting bug fix
17% (06/21/88) ETM Brought up to TeX version 2.93
18% (12/11/88) ETM Brought up to TeX version 2.94
19% (01/12/89) PAM Brought up to TeX version 2.95
20% (02/14/89) ETM Brought up to TeX version 2.96
21% (03/10/89) ETM Brought up to TeX version 2.98
22% (07/06/89) ETM Brought up to TeX version 2.991
23% (11/30/89) KB  To version 2.992 (8-bit).
24% (01/10/90) SR  To version 2.993.
25% (03/27/90) KY  To version 3.0.
26% (more recent changes in ChangeLog)
27%
28% The TeX program is copyright (C) 1982 by D. E. Knuth.
29% TeX is a trademark of the American Mathematical Society.
30%
31% Includes MLTEX.CH (Version 2.2) in text format, as of Dec 17, 1995.
32% MLTeX is copyright (C) 1990-92 by Michael J. Ferguson; all rights reserved.
33% MLTeX Version 2.2 is copyright (C) 1995 by B. Raichle; all rights reserved.
34%
35% The MLTeX changes are copyrighted so that we have some chance to
36% forbid unauthorized copies; we explicitly authorize copying of
37% correct MLTeX implementations, and not of incorrect ones!
38%
39% (This means that you can use the MLTeX changes as free as you can
40% use TeX and its algorithm.)
41%
42% Copying of this file is authorized only if either
43% (1) you make absolutely no changes to your copy, including name, or
44% (2) if you do make changes, you name it to something other than
45%     "mltex.ch", "char_sub.ch", or "charsub.ch".
46%
47% Except for MLTeX, the new code in this file is in the public domain.
48%
49% The module numbers in this change file refer to TEX.WEB 3.14159 as
50% of March, 1995 (published as Donald E. Knuth, TeX: The Program,
51% Volume B of Computers & Typesetting).
52
53@x [0.0] l.83 - WEAVE: print changes only.
54  \def\?##1]{\hbox to 1in{\hfil##1.\ }}
55  }
56@y 83
57  \def\?##1]{\hbox{Changes to \hbox to 1em{\hfil##1}.\ }}
58  }
59\let\maybe=\iffalse
60@z
61
62@x [1.2] l.185 - MLTeX: add comment about banner line change
63November 1984].
64@y
65November 1984].
66
67ML\TeX{} will add new primitives changing the behaviour of \TeX.  The
68|banner| string has to be changed.  We do not change the |banner|
69string, but will output an additional line to make clear that this is
70a modified \TeX{} version.
71
72@z
73
74@x [1.2] l.188
75@d banner=='This is TeX, Version 3.14159265' {printed when \TeX\ starts}
76@y
77@d TeX_banner_k=='This is TeXk, Version 3.14159265' {printed when \TeX\ starts}
78@d TeX_banner=='This is TeX, Version 3.14159265' {printed when \TeX\ starts}
79@#
80@d banner==TeX_banner
81@d banner_k==TeX_banner_k
82@z
83
84@x [1.4] l.233 - program header
85Actually the heading shown here is not quite normal: The |program| line
86does not mention any |output| file, because \ph\ would ask the \TeX\ user
87to specify a file name if |output| were specified here.
88@:PASCAL H}{\ph@>
89@^system dependencies@>
90@y
91@z
92
93@x [1.4] l.243 - labels in outer block not needed
94program TEX; {all file names are defined dynamically}
95label @<Labels in the outer block@>@/
96@y
97program TEX; {all file names are defined dynamically}
98@z
99
100@x [1.6] l.267 - labels in outer block not needed
101@ Three labels must be declared in the main program, so we give them
102symbolic names.
103
104@d start_of_TEX=1 {go here when \TeX's variables are initialized}
105@d end_of_TEX=9998 {go here to close files and terminate gracefully}
106@d final_end=9999 {this label marks the ending of the program}
107
108@<Labels in the out...@>=
109start_of_TEX@t\hskip-2pt@>, end_of_TEX@t\hskip-2pt@>,@,final_end;
110  {key control points}
111@y
112@ For Web2c, labels are not declared in the main program, but
113we still have to declare the symbolic names.
114
115@d start_of_TEX=1 {go here when \TeX's variables are initialized}
116@d final_end=9999 {this label marks the ending of the program}
117@z
118
119% Here we change these WEB symbols, which are used much as #ifdef's
120% are in C, into something which will get translated into actual #ifdef's.
121@x [1.7] l.292 - debug..gubed, stat..tats
122@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
123@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
124@y
125@d debug==ifdef('TEXMF_DEBUG')
126@d gubed==endif('TEXMF_DEBUG')
127@z
128@x [1.7] l.297 - debug..gubed, stat..tats
129@d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering
130  usage statistics}
131@d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering
132  usage statistics}
133@y
134@d stat==ifdef('STAT')
135@d tats==endif('STAT')
136@z
137
138@x [1.8] Somewhat different for `init...tini'..  310 m.8
139the codewords `$|init|\ldots|tini|$'.
140
141@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
142@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
143@y 314
144the codewords `$|init|\ldots|tini|$' for declarations and by the codewords
145`$|Init|\ldots|Tini|$' for executable code.  This distinction is helpful for
146implementations where a run-time switch differentiates between the two
147versions of the program.
148
149@d init==ifdef('INITEX')
150@d tini==endif('INITEX')
151@d Init==init if ini_version then begin
152@d Tini==end;@+tini
153@f Init==begin
154@f Tini==end
155@z
156
157@x [1.8] l.319 - init...tini is dynamic
158@!init @<Initialize table entries (done by \.{INITEX} only)@>@;@+tini
159@y  318
160@!Init @<Initialize table entries (done by \.{INITEX} only)@>@;@+Tini
161@z
162
163@x [1.11] l.375 - Compile-time constants: most removed for dynamic allocation.
164@<Constants...@>=
165@!mem_max=30000; {greatest index in \TeX's internal |mem| array;
166  must be strictly less than |max_halfword|;
167  must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
168@!mem_min=0; {smallest index in \TeX's internal |mem| array;
169  must be |min_halfword| or more;
170  must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
171@!buf_size=500; {maximum number of characters simultaneously present in
172  current lines of open files and in control sequences between
173  \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
174@!error_line=72; {width of context lines on terminal error messages}
175@!half_error_line=42; {width of first lines of contexts in terminal
176  error messages; should be between 30 and |error_line-15|}
177@!max_print_line=79; {width of longest text lines output; should be at least 60}
178@!stack_size=200; {maximum number of simultaneous input sources}
179@!max_in_open=6; {maximum number of input files and error insertions that
180  can be going on simultaneously}
181@!font_max=75; {maximum internal font number; must not exceed |max_quarterword|
182  and must be at most |font_base+256|}
183@!font_mem_size=20000; {number of words of |font_info| for all fonts}
184@!param_size=60; {maximum number of simultaneous macro parameters}
185@!nest_size=40; {maximum number of semantic levels simultaneously active}
186@!max_strings=3000; {maximum number of strings; must not exceed |max_halfword|}
187@!string_vacancies=8000; {the minimum number of characters that should be
188  available for the user's control sequences and font names,
189  after \TeX's own error messages are stored}
190@!pool_size=32000; {maximum number of characters in strings, including all
191  error messages and help texts, and the names of all fonts and
192  control sequences; must exceed |string_vacancies| by the total
193  length of \TeX's own strings, which is currently about 23000}
194@!save_size=600; {space for saving values outside of current group; must be
195  at most |max_halfword|}
196@!trie_size=8000; {space for hyphenation patterns; should be larger for
197  \.{INITEX} than it is in production versions of \TeX}
198@!trie_op_size=500; {space for ``opcodes'' in the hyphenation patterns}
199@!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8}
200@!file_name_size=40; {file names shouldn't be longer than this}
201@!pool_name='TeXformats:TEX.POOL                     ';
202  {string of length |file_name_size|; tells where the string pool appears}
203@y
204@d file_name_size == maxint
205@d ssup_error_line = 255
206@d ssup_max_strings == 2097151
207{Larger values than 65536 cause the arrays to consume much more memory.}
208@d ssup_trie_opcode == 65535
209@d ssup_trie_size == @"3FFFFF
210
211@d ssup_hyph_size == 65535 {Changing this requires changing (un)dumping!}
212@d iinf_hyphen_size == 610 {Must be not less than |hyph_prime|!}
213
214@d max_font_max=9000 {maximum number of internal fonts; this can be
215                      increased, but |hash_size+max_font_max|
216                      should not exceed 29000.}
217@d font_base=0 {smallest internal font number; must be
218                |>= min_quarterword|; do not change this without
219                modifying the dynamic definition of the font arrays.}
220
221
222@<Constants...@>=
223@!hash_offset=514; {smallest index in hash array, i.e., |hash_base| }
224  {Use |hash_offset=0| for compilers which cannot decrement pointers.}
225@!trie_op_size=35111; {space for ``opcodes'' in the hyphenation patterns;
226  best if relatively prime to 313, 361, and 1009.}
227@!neg_trie_op_size=-35111; {for lower |trie_op_hash| array bound;
228  must be equal to |-trie_op_size|.}
229@!min_trie_op=0; {first possible trie op code for any language}
230@!max_trie_op=ssup_trie_opcode; {largest possible trie opcode for any language}
231@!pool_name=TEXMF_POOL_NAME; {this is configurable, for the sake of ML-\TeX}
232  {string of length |file_name_size|; tells where the string pool appears}
233@!engine_name=TEXMF_ENGINE_NAME; {the name of this engine}
234@#
235@!inf_mem_bot = 0;
236@!sup_mem_bot = 1;
237
238@!inf_main_memory = 3000;
239@!sup_main_memory = 256000000;
240
241@!inf_trie_size = 8000;
242@!sup_trie_size = ssup_trie_size;
243
244@!inf_max_strings = 3000;
245@!sup_max_strings = ssup_max_strings;
246@!inf_strings_free = 100;
247@!sup_strings_free = sup_max_strings;
248
249@!inf_buf_size = 500;
250@!sup_buf_size = 30000000;
251
252@!inf_nest_size = 40;
253@!sup_nest_size = 4000;
254
255@!inf_max_in_open = 6;
256@!sup_max_in_open = 127;
257
258@!inf_param_size = 60;
259@!sup_param_size = 32767;
260
261@!inf_save_size = 600;
262@!sup_save_size = 80000;
263
264@!inf_stack_size = 200;
265@!sup_stack_size = 30000;
266
267@!inf_dvi_buf_size = 800;
268@!sup_dvi_buf_size = 65536;
269
270@!inf_font_mem_size = 20000;
271@!sup_font_mem_size = 147483647; {|integer|-limited, so 2 could be prepended?}
272
273@!sup_font_max = max_font_max;
274@!inf_font_max = 50; {could be smaller, but why?}
275
276@!inf_pool_size = 32000;
277@!sup_pool_size = 40000000;
278@!inf_pool_free = 1000;
279@!sup_pool_free = sup_pool_size;
280@!inf_string_vacancies = 8000;
281@!sup_string_vacancies = sup_pool_size - 23000;
282
283@!sup_hash_extra = sup_max_strings;
284@!inf_hash_extra = 0;
285
286@!sup_hyph_size = ssup_hyph_size;
287@!inf_hyph_size = iinf_hyphen_size; {Must be not less than |hyph_prime|!}
288
289@!inf_expand_depth = 10;
290@!sup_expand_depth = 10000000;
291@z
292
293@x [1.12] l.427 - Constants that are WEB numeric macros.
294@d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX};
295  must not be less than |mem_min|}
296@d mem_top==30000 {largest index in the |mem| array dumped by \.{INITEX};
297  must be substantially larger than |mem_bot|
298  and not greater than |mem_max|}
299@d font_base=0 {smallest internal font number; must not be less
300  than |min_quarterword|}
301@d hash_size=2100 {maximum number of control sequences; it should be at most
302  about |(mem_max-mem_min)/10|}
303@d hash_prime=1777 {a prime number equal to about 85\pct! of |hash_size|}
304@d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions}
305@y
306@d hash_size=15000 {maximum number of control sequences; it should be at most
307  about |(mem_max-mem_min)/10|; see also |font_max|}
308@d hash_prime=8501 {a prime number equal to about 85\pct! of |hash_size|}
309@d hyph_prime=607 {another prime for hashing \.{\\hyphenation} exceptions;
310                if you change this, you should also change |iinf_hyphen_size|.}
311@z
312
313@x [1.16] l.498 - Use C macros for `incr' and `decr'.
314@d incr(#) == #:=#+1 {increase a variable by unity}
315@d decr(#) == #:=#-1 {decrease a variable by unity}
316@y
317@z
318
319% The text_char type is used as an array index into xord.  The
320% default type `char' produces signed integers, which are bad array
321% indices in C.
322@x [2.19] l.565 - data type text_char is 8-bit ASCII_code
323@d text_char == char {the data type of characters in text files}
324@y
325@d text_char == ASCII_code {the data type of characters in text files}
326@z
327
328@x [2.20] l.579 - printable characters
329@!xchr: array [ASCII_code] of text_char;
330  {specifies conversion of output characters}
331@y
332xchr: array [ASCII_code] of text_char;
333   { specifies conversion of output characters }
334xprn: array [ASCII_code] of ASCII_code;
335   { non zero iff character is printable }
336@z
337
338@x [2.23] l.723 - Translate characters if desired, otherwise allow them all.
339for i:=0 to @'37 do xchr[i]:=' ';
340for i:=@'177 to @'377 do xchr[i]:=' ';
341@y
342{Initialize |xchr| to the identity mapping.}
343for i:=0 to @'37 do xchr[i]:=i;
344for i:=@'177 to @'377 do xchr[i]:=i;
345@z
346
347@x [2.24] l.733 - Don't reinitialize xord.
348for i:=0 to @'176 do xord[xchr[i]]:=i;
349@y
350for i:=0 to @'176 do xord[xchr[i]]:=i;
351{Set |xprn| for printable ASCII, unless |eight_bit_p| is set.}
352for i:=0 to 255 do xprn[i]:=(eight_bit_p or ((i>=" ")and(i<="~")));
353
354{The idea for this dynamic translation comes from the patch by
355 Libor Skarvada \.{<libor@@informatics.muni.cz>}
356 and Petr Sojka \.{<sojka@@informatics.muni.cz>}. I didn't use any of the
357 actual code, though, preferring a more general approach.}
358
359{This updates the |xchr|, |xord|, and |xprn| arrays from the provided
360 |translate_filename|.  See the function definition in \.{texmfmp.c} for
361 more comments.}
362if translate_filename then read_tcx_file;
363@z
364
365% [3.26] name_of_file is no longer an array.  And change the destination
366% type to text_char, which fixes:
367%
368% Date: 19 Sep 1994 10:38:24 +0200
369% From: thorinn@diku.dk (Lars Mathiesen)
370%       When echoed to the screen and in the log, character codes
371%       above '177 in file names are shown wrongly (typically as ^@).
372%
373@x [3.26] l.789 - name_of_file is no longer an array
374@!name_of_file:packed array[1..file_name_size] of char;@;@/
375  {on some systems this may be a \&{record} variable}
376@y
377@!name_of_file:^text_char;
378@z
379
380@x [3.27] l.794 - Do file opening in C.
381@ The \ph\ compiler with which the present version of \TeX\ was prepared has
382extended the rules of \PASCAL\ in a very convenient way. To open file~|f|,
383we can write
384$$\vbox{\halign{#\hfil\qquad&#\hfil\cr
385|reset(f,@t\\{name}@>,'/O')|&for input;\cr
386|rewrite(f,@t\\{name}@>,'/O')|&for output.\cr}}$$
387The `\\{name}' parameter, which is of type `{\bf packed array
388$[\langle\\{any}\rangle]$ of \\{char}}', stands for the name of
389the external file that is being opened for input or output.
390Blank spaces that might appear in \\{name} are ignored.
391
392The `\.{/O}' parameter tells the operating system not to issue its own
393error messages if something goes wrong. If a file of the specified name
394cannot be found, or if such a file cannot be opened for some other reason
395(e.g., someone may already be trying to write the same file), we will have
396|@!erstat(f)<>0| after an unsuccessful |reset| or |rewrite|.  This allows
397\TeX\ to undertake appropriate corrective action.
398@:PASCAL H}{\ph@>
399@^system dependencies@>
400
401\TeX's file-opening procedures return |false| if no file identified by
402|name_of_file| could be opened.
403
404@d reset_OK(#)==erstat(#)=0
405@d rewrite_OK(#)==erstat(#)=0
406
407@p function a_open_in(var f:alpha_file):boolean;
408  {open a text file for input}
409begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f);
410end;
411@#
412function a_open_out(var f:alpha_file):boolean;
413  {open a text file for output}
414begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f);
415end;
416@#
417function b_open_in(var f:byte_file):boolean;
418  {open a binary file for input}
419begin reset(f,name_of_file,'/O'); b_open_in:=reset_OK(f);
420end;
421@#
422function b_open_out(var f:byte_file):boolean;
423  {open a binary file for output}
424begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f);
425end;
426@#
427function w_open_in(var f:word_file):boolean;
428  {open a word file for input}
429begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f);
430end;
431@#
432function w_open_out(var f:word_file):boolean;
433  {open a word file for output}
434begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f);
435end;
436@y
437@ All of the file opening functions are defined in C.
438@z
439
440@x [3.28] l.850 - Do file closing in C.
441@ Files can be closed with the \ph\ routine `|close(f)|', which
442@:PASCAL H}{\ph@>
443@^system dependencies@>
444should be used when all input or output with respect to |f| has been completed.
445This makes |f| available to be opened again, if desired; and if |f| was used for
446output, the |close| operation makes the corresponding external file appear
447on the user's area, ready to be read.
448
449These procedures should not generate error messages if a file is
450being closed before it has been successfully opened.
451
452@p procedure a_close(var f:alpha_file); {close a text file}
453begin close(f);
454end;
455@#
456procedure b_close(var f:byte_file); {close a binary file}
457begin close(f);
458end;
459@#
460procedure w_close(var f:word_file); {close a word file}
461begin close(f);
462end;
463@y
464@ And all the file closing routines as well.
465@z
466
467@x [3.30] l.888 - Array size of input buffer is determined at runtime.
468@!buffer:array[0..buf_size] of ASCII_code; {lines of characters being read}
469@y
470@!buffer:^ASCII_code; {lines of characters being read}
471@z
472
473@x [3.31] l.933 - Do `input_ln' in C.
474@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
475  {inputs the next line or returns |false|}
476var last_nonblank:0..buf_size; {|last| with trailing blanks removed}
477begin if bypass_eoln then if not eof(f) then get(f);
478  {input the first character of the line into |f^|}
479last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
480if eof(f) then input_ln:=false
481else  begin last_nonblank:=first;
482  while not eoln(f) do
483    begin if last>=max_buf_stack then
484      begin max_buf_stack:=last+1;
485      if max_buf_stack=buf_size then
486        @<Report overflow of the input buffer, and abort@>;
487      end;
488    buffer[last]:=xord[f^]; get(f); incr(last);
489    if buffer[last-1]<>" " then last_nonblank:=last;
490    end;
491  last:=last_nonblank; input_ln:=true;
492  end;
493end;
494@y
495We define |input_ln| in C, for efficiency. Nevertheless we quote the module
496`Report overflow of the input buffer, and abort' here in order to make
497\.{WEAVE} happy, since part of that module is needed by e-TeX.
498
499@p @{ @<Report overflow of the input buffer, and abort@> @}
500@z
501
502% [3.32] `term_in' and `term_out' are standard input and output.
503% Declare the variables that used to be constants.
504@x [3.32] l.961 - `term_in' and `term_out' are standard input and output.
505@<Glob...@>=
506@!term_in:alpha_file; {the terminal as an input file}
507@!term_out:alpha_file; {the terminal as an output file}
508@y
509@d term_in==stdin {the terminal as an input file}
510@d term_out==stdout {the terminal as an output file}
511
512@<Glob...@>=
513@!init
514@!ini_version:boolean; {are we \.{INITEX}?}
515@!dump_option:boolean; {was the dump name option used?}
516@!dump_line:boolean; {was a \.{\%\AM format} line seen?}
517tini@/
518@#
519@!dump_name:const_cstring; {format name for terminal display}
520@#
521@!bound_default:integer; {temporary for setup}
522@!bound_name:const_cstring; {temporary for setup}
523@#
524@!mem_bot:integer;{smallest index in the |mem| array dumped by \.{INITEX};
525  must not be less than |mem_min|}
526@!main_memory:integer; {total memory words allocated in initex}
527@!extra_mem_bot:integer; {|mem_min:=mem_bot-extra_mem_bot| except in \.{INITEX}}
528@!mem_min:integer; {smallest index in \TeX's internal |mem| array;
529  must be |min_halfword| or more;
530  must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
531@!mem_top:integer; {largest index in the |mem| array dumped by \.{INITEX};
532  must be substantially larger than |mem_bot|,
533  equal to |mem_max| in \.{INITEX}, else not greater than |mem_max|}
534@!extra_mem_top:integer; {|mem_max:=mem_top+extra_mem_top| except in \.{INITEX}}
535@!mem_max:integer; {greatest index in \TeX's internal |mem| array;
536  must be strictly less than |max_halfword|;
537  must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
538@!error_line:integer; {width of context lines on terminal error messages}
539@!half_error_line:integer; {width of first lines of contexts in terminal
540  error messages; should be between 30 and |error_line-15|}
541@!max_print_line:integer;
542  {width of longest text lines output; should be at least 60}
543@!max_strings:integer; {maximum number of strings; must not exceed |max_halfword|}
544@!strings_free:integer; {strings available after format loaded}
545@!string_vacancies:integer; {the minimum number of characters that should be
546  available for the user's control sequences and font names,
547  after \TeX's own error messages are stored}
548@!pool_size:integer; {maximum number of characters in strings, including all
549  error messages and help texts, and the names of all fonts and
550  control sequences; must exceed |string_vacancies| by the total
551  length of \TeX's own strings, which is currently about 23000}
552@!pool_free:integer;{pool space free after format loaded}
553@!font_mem_size:integer; {number of words of |font_info| for all fonts}
554@!font_max:integer; {maximum internal font number; ok to exceed |max_quarterword|
555  and must be at most |font_base|+|max_font_max|}
556@!font_k:integer; {loop variable for initialization}
557@!hyph_size:integer; {maximun number of hyphen exceptions}
558@!trie_size:integer; {space for hyphenation patterns; should be larger for
559  \.{INITEX} than it is in production versions of \TeX.  50000 is
560  needed for English, German, and Portuguese.}
561@!buf_size:integer; {maximum number of characters simultaneously present in
562  current lines of open files and in control sequences between
563  \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
564@!stack_size:integer; {maximum number of simultaneous input sources}
565@!max_in_open:integer; {maximum number of input files and error insertions that
566  can be going on simultaneously}
567@!param_size:integer; {maximum number of simultaneous macro parameters}
568@!nest_size:integer; {maximum number of semantic levels simultaneously active}
569@!save_size:integer; {space for saving values outside of current group; must be
570  at most |max_halfword|}
571@!dvi_buf_size:integer; {size of the output buffer; must be a multiple of 8}
572@!expand_depth:integer; {limits recursive calls to the |expand| procedure}
573@!parse_first_line_p:cinttype; {parse the first line for options}
574@!file_line_error_style_p:cinttype; {format messages as file:line:error}
575@!eight_bit_p:cinttype; {make all characters printable by default}
576@!halt_on_error_p:cinttype; {stop at first error}
577@!quoted_filename:boolean; {current filename is quoted}
578{Variables for source specials}
579@!src_specials_p : boolean;{Whether |src_specials| are enabled at all}
580@!insert_src_special_auto : boolean;
581@!insert_src_special_every_par : boolean;
582@!insert_src_special_every_parend : boolean;
583@!insert_src_special_every_cr : boolean;
584@!insert_src_special_every_math : boolean;
585@!insert_src_special_every_hbox : boolean;
586@!insert_src_special_every_vbox : boolean;
587@!insert_src_special_every_display : boolean;
588@z
589
590@x [3.33] l.964 - We don't need to open terminal files.
591@ Here is how to open the terminal files
592in \ph. The `\.{/I}' switch suppresses the first |get|.
593@:PASCAL H}{\ph@>
594@^system dependencies@>
595
596@d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input}
597@d t_open_out==rewrite(term_out,'TTY:','/O') {open the terminal for text output}
598@y
599@ Here is how to open the terminal files.  |t_open_out| does nothing.
600|t_open_in|, on the other hand, does the work of ``rescanning,'' or getting
601any command line arguments the user has provided.  It's defined in C.
602
603@d t_open_out == {output already open for text output}
604@z
605
606@x [3.34] l.982 - Flushing output to terminal files.
607these operations can be specified in \ph:
608@:PASCAL H}{\ph@>
609@^system dependencies@>
610
611@d update_terminal == break(term_out) {empty the terminal output buffer}
612@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer}
613@y
614these operations can be specified with {\mc UNIX}.  |update_terminal|
615does an |fflush|. |clear_terminal| is redefined
616to do nothing, since the user should control the terminal.
617@^system dependencies@>
618
619@d update_terminal == fflush (term_out)
620@d clear_terminal == do_nothing
621@z
622
623@x [3.35] l.1017 - needed for e-TeX, but differently
624@<Report overflow of the input buffer, and abort@>=
625if format_ident=0 then
626  begin write_ln(term_out,'Buffer size exceeded!'); goto final_end;
627@.Buffer size exceeded@>
628  end
629else begin cur_input.loc_field:=first; cur_input.limit_field:=last-1;
630@y
631Routine is implemented in C; part of module is, however, needed for e-TeX.
632
633@<Report overflow of the input buffer, and abort@>=
634  begin cur_input.loc_field:=first; cur_input.limit_field:=last-1;
635@z
636
637@x [3.37] l.1055 - |init_terminal|, reading the command line.
638@ The following program does the required initialization
639without retrieving a possible command line.
640It should be clear how to modify this routine to deal with command lines,
641if the system permits them.
642@^system dependencies@>
643
644@p function init_terminal:boolean; {gets the terminal input started}
645label exit;
646begin t_open_in;
647@y
648@ The following program does the required initialization.
649Iff anything has been specified on the command line, then |t_open_in|
650will return with |last > first|.
651@^system dependencies@>
652
653@p function init_terminal:boolean; {gets the terminal input started}
654label exit;
655begin t_open_in;
656if last > first then
657  begin loc := first;
658  while (loc < last) and (buffer[loc]=' ') do incr(loc);
659  if loc < last then
660    begin init_terminal := true; goto exit;
661    end;
662  end;
663@z
664
665@x [3.37] l.1068 - |init_terminal|, output missing newline.
666    write(term_out,'! End of file on the terminal... why?');
667@y
668    write_ln(term_out,'! End of file on the terminal... why?');
669@z
670
671@x [4.38] l.1126 - Array size for string pool is determined at runtime.
672@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|}
673@!str_number = 0..max_strings; {for variables that point into |str_start|}
674@y
675@!pool_pointer = integer; {for variables that point into |str_pool|}
676@!str_number = 0..ssup_max_strings; {for variables that point into |str_start|}
677@z
678
679@x [4.39] l.1131 - Dynamically size pool arrays.
680@!str_pool:packed array[pool_pointer] of packed_ASCII_code; {the characters}
681@!str_start : array[str_number] of pool_pointer; {the starting pointers}
682@y
683@!str_pool: ^packed_ASCII_code; {the characters}
684@!str_start : ^pool_pointer; {the starting pointers}
685@z
686
687@x [4.47] l.1237 - string recycling
688@p @!init function get_strings_started:boolean; {initializes the string pool,
689@y
690@p @t\4@>@<Declare additional routines for string recycling@>@/
691
692@!init function get_strings_started:boolean; {initializes the string pool,
693@z
694
695@x [4.49] l.1272 -- Change documentation (probably needed in more places)
696would like string @'32 to be the single character @'32 instead of the
697@y
698would like string @'32 to be printed as the single character @'32
699instead of the
700@z
701
702% [4.51] Open the pool file using a path, and can't do string
703% assignments directly.  (`strcpy' and `strlen' work here because
704% `pool_name' is a constant string, and thus ends in a null and doesn't
705% start with a space.)
706@x [4.51] l.1314 - Open the pool file.
707name_of_file:=pool_name; {we needn't set |name_length|}
708if a_open_in(pool_file) then
709@y
710name_length := strlen (pool_name);
711name_of_file := xmalloc_array (ASCII_code, name_length + 1);
712strcpy (stringcast(name_of_file+1), pool_name); {copy the string}
713if a_open_in (pool_file, kpse_texpool_format) then
714@z
715
716@x [4.51] l.1322 - Make `TEX.POOL' lowercase, and change how it's read.
717else  bad_pool('! I can''t read TEX.POOL.')
718@y
719else  bad_pool('! I can''t read ', pool_name, '; bad path?')
720@z
721@x [4.52] l.1326 - Make `TEX.POOL' lowercase, and change how it's read.
722begin if eof(pool_file) then bad_pool('! TEX.POOL has no check sum.');
723@.TEX.POOL has no check sum@>
724read(pool_file,m,n); {read two digits of string length}
725@y
726begin if eof(pool_file) then bad_pool('! ', pool_name, ' has no check sum.');
727@.TEX.POOL has no check sum@>
728read(pool_file,m); read(pool_file,n); {read two digits of string length}
729@z
730@x [4.52] l.1332 - Make `TEX.POOL' lowercase, and change how it's read.
731    bad_pool('! TEX.POOL line doesn''t begin with two digits.');
732@y
733    bad_pool('! ', pool_name, ' line doesn''t begin with two digits.');
734@z
735@x [4.53] l.1354 - Make `TEX.POOL' lowercase, and change how it's read.
736  bad_pool('! TEX.POOL check sum doesn''t have nine digits.');
737@y
738  bad_pool('! ', pool_name, ' check sum doesn''t have nine digits.');
739@z
740@x [4.53] l.1360 - Make `TEX.POOL' lowercase, and change how it's read.
741done: if a<>@$ then bad_pool('! TEX.POOL doesn''t match; TANGLE me again.');
742@y
743done: if a<>@$ then
744  bad_pool('! ', pool_name, ' doesn''t match; tangle me again (or fix the path).');
745@z
746
747@x [5.54] l.1422 - error_line
748@!trick_buf:array[0..error_line] of ASCII_code; {circular buffer for
749@y
750@!trick_buf:array[0..ssup_error_line] of ASCII_code; {circular buffer for
751@z
752
753@x l.1536 --  If the ``src-specials'' feature is active, change the banner.
754wterm(banner);
755@y
756if src_specials_p or file_line_error_style_p or parse_first_line_p then
757  wterm(banner_k)
758else
759  wterm(banner);
760@z
761
762@x [5.61] l.1556 - Print rest of banner.
763if format_ident=0 then wterm_ln(' (no format preloaded)')
764else  begin slow_print(format_ident); print_ln;
765  end;
766@y
767wterm(version_string);
768if format_ident=0 then wterm_ln(' (preloaded format=',dump_name,')')
769else  begin slow_print(format_ident); print_ln;
770  end;
771if shellenabledp then begin
772  wterm(' ');
773  if restrictedshell then begin
774    wterm('restricted ');
775  end;
776  wterm_ln('\write18 enabled.');
777end;
778if src_specials_p then begin
779  wterm_ln(' Source specials enabled.')
780end;
781if translate_filename then begin
782  wterm(' (');
783  fputs(translate_filename, stdout);
784  wterm_ln(')');
785end;
786@z
787
788@x [6.73] l.1732 - Add unspecified_mode.
789@d error_stop_mode=3 {stops at every opportunity to interact}
790@y
791@d error_stop_mode=3 {stops at every opportunity to interact}
792@d unspecified_mode=4 {extra value for command-line switch}
793@z
794
795@x [6.73] l.1734 - file:line:error style error messages.
796  print_nl("! "); print(#);
797@y
798  if file_line_error_style_p then print_file_line
799  else print_nl("! ");
800  print(#);
801@z
802
803
804@x [6.73] l.1738 - Add interaction_option.
805@!interaction:batch_mode..error_stop_mode; {current level of interaction}
806@y
807@!interaction:batch_mode..error_stop_mode; {current level of interaction}
808@!interaction_option:batch_mode..unspecified_mode; {set from command line}
809@z
810
811@x [6.74] l.1740 - Allow override by command line switch.
812@ @<Set init...@>=interaction:=error_stop_mode;
813@y
814@ @<Set init...@>=if interaction_option=unspecified_mode then
815  interaction:=error_stop_mode
816else
817  interaction:=interaction_option;
818@z
819
820% [6.81] Eliminate nonlocal goto, since C doesn't have them.
821% Plus, it's nicer just to do an exit with the appropriate status code
822% under Unix.  We call it `uexit' because there's a WEB symbol called
823% `exit' already.  We use a C macro to change `uexit' back to `exit'.
824@x [6.81] l.1852 - Eliminate nonlocal goto, since C doesn't have them.
825@<Error hand...@>=
826procedure jump_out;
827begin goto end_of_TEX;
828end;
829@y
830@d do_final_end==begin
831   update_terminal;
832   ready_already:=0;
833   if (history <> spotless) and (history <> warning_issued) then
834       uexit(1)
835   else
836       uexit(0);
837   end
838
839@<Error hand...@>=
840noreturn procedure jump_out;
841begin
842close_files_and_terminate;
843do_final_end;
844end;
845@z
846
847@x [6.82] l.1866 - halt on error?
848print_char("."); show_context;
849@y
850print_char("."); show_context;
851if (halt_on_error_p) then begin
852  history:=fatal_error_stop; jump_out;
853end;
854@z
855
856@x [6.84] l.1888 - Implement the switch-to-editor option.
857line ready to be edited. But such an extension requires some system
858wizardry, so the present implementation simply types out the name of the
859file that should be
860edited and the relevant line number.
861@^system dependencies@>
862
863There is a secret `\.D' option available when the debugging routines haven't
864been commented~out.
865@^debugging@>
866@y
867line ready to be edited.
868We do this by calling the external procedure |call_edit| with a pointer to
869the filename, its length, and the line number.
870However, here we just set up the variables that will be used as arguments,
871since we don't want to do the switch-to-editor until after TeX has closed
872its files.
873@^system dependencies@>
874
875There is a secret `\.D' option available when the debugging routines haven't
876been commented~out.
877@^debugging@>
878@d edit_file==input_stack[base_ptr]
879@z
880
881@x [6.84] l.1903 - Implement the switch-to-editor option.
882"E": if base_ptr>0 then
883  begin print_nl("You want to edit file ");
884@.You want to edit file x@>
885  slow_print(input_stack[base_ptr].name_field);
886  print(" at line "); print_int(line);
887  interaction:=scroll_mode; jump_out;
888@y
889"E": if base_ptr>0 then
890    begin edit_name_start:=str_start[edit_file.name_field];
891    edit_name_length:=str_start[edit_file.name_field+1] -
892                      str_start[edit_file.name_field];
893    edit_line:=line;
894    jump_out;
895@z
896
897@x [6.93] l.2056 - Declare fatal_error as noreturn.
898procedure fatal_error(@!s:str_number); {prints |s|, and that's it}
899@y
900noreturn procedure fatal_error(@!s:str_number); {prints |s|, and that's it}
901@z
902
903@x [6.94] l.2065 - Declare overflow as noreturn.
904procedure overflow(@!s:str_number;@!n:integer); {stop due to finiteness}
905@y
906noreturn procedure overflow(@!s:str_number;@!n:integer); {stop due to finiteness}
907@z
908
909@x [6.95] l.2084 - Declare confusion as noreturn.
910procedure confusion(@!s:str_number);
911@y
912noreturn procedure confusion(@!s:str_number);
913@z
914
915% [7.104] `remainder' is a library routine on some systems, so change
916% its name to avoid conflicts.
917@x [7.104] l.2227 - avoid name conflicts with lib routine remainder()
918|remainder|, holds the remainder after a division.
919
920@<Glob...@>=
921@y
922|remainder|, holds the remainder after a division.
923
924@d remainder==tex_remainder
925
926@<Glob...@>=
927@z
928
929@x [7.109] l.2352 - Define glue_ratio in C.
930@!glue_ratio=real; {one-word representation of a glue expansion factor}
931@y
932@z
933
934% [8.110] Make it easy to change constants.  Do not increase
935% max_quarterword without changing the memoryword structure in `texmfmem.h'.
936@x [8.110] l.2422 - increase |max_halfword|
937@d min_halfword==0 {smallest allowable value in a |halfword|}
938@d max_halfword==65535 {largest allowable value in a |halfword|}
939@y 2424
940@d min_halfword==-@"FFFFFFF {smallest allowable value in a |halfword|}
941@d max_halfword==@"FFFFFFF {largest allowable value in a |halfword|}
942@z
943
944@x [8.111] l.2435 - min_halfword and max_halfword
945if (mem_min<min_halfword)or(mem_max>=max_halfword)or@|
946  (mem_bot-mem_min>max_halfword+1) then bad:=14;
947@y
948if (mem_bot-sup_main_memory<min_halfword)or@|
949  (mem_top+sup_main_memory>=max_halfword) then bad:=14;
950@z
951
952@x [8.111] l.2437 - max_font_max
953if (font_base<min_quarterword)or(font_max>max_quarterword) then bad:=15;
954if font_max>font_base+256 then bad:=16;
955@y
956if (max_font_max<min_halfword)or(max_font_max>max_halfword) then bad:=15;
957if font_max>font_base+max_font_max then bad:=16;
958@z
959
960@x [8.112] l.2450 - Efficiency.
961macros are simplified in the obvious way when |min_quarterword=0|.
962@^inner loop@>@^system dependencies@>
963
964@d qi(#)==#+min_quarterword
965  {to put an |eight_bits| item into a quarterword}
966@d qo(#)==#-min_quarterword
967  {to take an |eight_bits| item out of a quarterword}
968@d hi(#)==#+min_halfword
969  {to put a sixteen-bit item into a halfword}
970@d ho(#)==#-min_halfword
971  {to take a sixteen-bit item from a halfword}
972@y
973macros are simplified in the obvious way when |min_quarterword=0|.
974So they have been simplified here in the obvious way.
975@^inner loop@>@^system dependencies@>
976
977The \.{WEB} source for \TeX\ defines |hi(#)==#+min_halfword| which can be
978simplified when |min_halfword=0|.  The Web2C implemetation of \TeX\ can use
979|hi(#)==#| together with |min_halfword<0| as long as |max_halfword| is
980sufficiently large.
981
982@d qi(#)==# {to put an |eight_bits| item into a quarterword}
983@d qo(#)==# {to take an |eight_bits| item from a quarterword}
984@d hi(#)==# {to put a sixteen-bit item into a halfword}
985@d ho(#)==# {to take a sixteen-bit item from a halfword}
986@z
987
988% [8.113] We've put the memory structure into the include file
989% `texmf.h', since it's too hard to translate automatically.
990@x [8.113] l.2453 - data structures for main memory
991@!quarterword = min_quarterword..max_quarterword; {1/4 of a word}
992@!halfword=min_halfword..max_halfword; {1/2 of a word}
993@!two_choices = 1..2; {used when there are two variants in a record}
994@!four_choices = 1..4; {used when there are four variants in a record}
995@!two_halves = packed record@;@/
996  @!rh:halfword;
997  case two_choices of
998  1: (@!lh:halfword);
999  2: (@!b0:quarterword; @!b1:quarterword);
1000  end;
1001@!four_quarters = packed record@;@/
1002  @!b0:quarterword;
1003  @!b1:quarterword;
1004  @!b2:quarterword;
1005  @!b3:quarterword;
1006  end;
1007@!memory_word = record@;@/
1008  case four_choices of
1009  1: (@!int:integer);
1010  2: (@!gr:glue_ratio);
1011  3: (@!hh:two_halves);
1012  4: (@!qqqq:four_quarters);
1013  end;
1014@y
1015@!quarterword = min_quarterword..max_quarterword;
1016@!halfword = min_halfword..max_halfword;
1017@!two_choices = 1..2; {used when there are two variants in a record}
1018@!four_choices = 1..4; {used when there are four variants in a record}
1019@=#include "texmfmem.h";@>
1020@z
1021
1022% [9.116] Change `mem' to `zmem', so we can define mem to be a register
1023% pointer to the memory array for speed.
1024@x [9.116] l.2545 - definition of main memory array
1025@!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area}
1026@y
1027@!yzmem : ^memory_word; {the big dynamic storage area}
1028@!zmem : ^memory_word; {the big dynamic storage area}
1029@z
1030
1031@x [10.144] l.3006 - font numbers can be >255 now.
1032@p function new_ligature(@!f,@!c:quarterword; @!q:pointer):pointer;
1033@y
1034@p function new_ligature(@!f:internal_font_number; @!c:quarterword;
1035                         @!q:pointer):pointer;
1036@z
1037
1038% [11.165] Fix the word `free' so that it doesn't conflict with the
1039% standard C library routine of the same name.
1040@x [11.165] l.3364 - avoid conflict with lib function free()
1041are debugging.)
1042@y
1043are debugging.)
1044
1045@d free==free_arr
1046@z
1047
1048@x [11.165] l.3367 - dummy |free| and |was_free| arrays
1049@!debug @!free: packed array [mem_min..mem_max] of boolean; {free cells}
1050@t\hskip10pt@>@!was_free: packed array [mem_min..mem_max] of boolean;
1051@y
1052 {The debug memory arrays have not been mallocated yet.}
1053@!debug @!free: packed array [0..9] of boolean; {free cells}
1054@t\hskip10pt@>@!was_free: packed array [0..9] of boolean;
1055@z
1056
1057@x [12.174] l.3526 - Eliminate unsigned comparisons to zero.
1058        begin if (font(p)<font_base)or(font(p)>font_max) then
1059@y
1060        begin if (font(p)>font_max) then
1061@z
1062
1063@x [12.176] l.3563 - Eliminate unsigned comparisons to zero.
1064@p procedure print_font_and_char(@!p:integer); {prints |char_node| data}
1065begin if p>mem_end then print_esc("CLOBBERED.")
1066else  begin if (font(p)<font_base)or(font(p)>font_max) then print_char("*")
1067@y
1068@p procedure print_font_and_char(@!p:integer); {prints |char_node| data}
1069begin if p>mem_end then print_esc("CLOBBERED.")
1070else  begin if (font(p)>font_max) then print_char("*")
1071@z
1072
1073@x [12.186] l.3747 - Don't worry about strange floating point values.
1074  if abs(mem[p+glue_offset].int)<@'4000000 then print("?.?")
1075  else if abs(g)>float_constant(20000) then
1076@y 3747
1077  { The Unix |pc| folks removed this restriction with a remark that
1078    invalid bit patterns were vanishingly improbable, so we follow
1079    their example without really understanding it.
1080  |if abs(mem[p+glue_offset].int)<@'4000000 then print('?.?')|
1081  |else| }
1082  if fabs(g)>float_constant(20000) then
1083@z
1084
1085
1086@x [15.209] l.4165 - MLTeX: \charsubdef primitive
1087@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
1088@y
1089@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
1090  {or \.{\\charsubdef}}
1091@z
1092
1093% i18n fix: messages printed by print_mode in [16.211] and [46.1049]
1094% can not be translated. For example, messages printed by |print_mode|
1095% from [16.211] use different word order and [46.1049] use different
1096% word order and words are declined.
1097@x [16.211] l.4256
1098begin if m>0 then
1099  case m div (max_command+1) of
1100  0:print("vertical");
1101  1:print("horizontal");
1102  2:print("display math");
1103  end
1104else if m=0 then print("no")
1105else  case (-m) div (max_command+1) of
1106  0:print("internal vertical");
1107  1:print("restricted horizontal");
1108  2:print("math");
1109  end;
1110print(" mode");
1111end;
1112@y
1113begin if m>0 then
1114  case m div (max_command+1) of
1115  0:print("vertical mode");
1116  1:print("horizontal mode");
1117  2:print("display math mode");
1118  end
1119else if m=0 then print("no mode")
1120else  case (-m) div (max_command+1) of
1121  0:print("internal vertical mode");
1122  1:print("restricted horizontal mode");
1123  2:print("math mode");
1124  end;
1125end;
1126
1127procedure print_in_mode(@!m:integer); {prints the mode represented by |m|}
1128begin if m>0 then
1129  case m div (max_command+1) of
1130  0:print("' in vertical mode");
1131  1:print("' in horizontal mode");
1132  2:print("' in display math mode");
1133  end
1134else if m=0 then print("' in no mode")
1135else  case (-m) div (max_command+1) of
1136  0:print("' in internal vertical mode");
1137  1:print("' in restricted horizontal mode");
1138  2:print("' in math mode");
1139  end;
1140end;
1141@z
1142
1143@x [16.213] l.4321 - texarray
1144@!nest:array[0..nest_size] of list_state_record;
1145@y
1146@!nest:^list_state_record;
1147@z
1148
1149@x [16.215] l.4344 - remove mem[] reference from initialize.
1150prev_graf:=0; shown_mode:=0;
1151@<Start a new current page@>;
1152@y
1153prev_graf:=0; shown_mode:=0;
1154@/{The following piece of code is a copy of module 991:}
1155page_contents:=empty; page_tail:=page_head; {|link(page_head):=null;|}@/
1156last_glue:=max_halfword; last_penalty:=0; last_kern:=0;
1157page_depth:=0; page_max_depth:=0;
1158@z
1159
1160@x [16.219] l.4409 - i18n fix
1161    print_int(nest[p].pg_field); print(" line");
1162    if nest[p].pg_field<>1 then print_char("s");
1163@y
1164    print_int(nest[p].pg_field);
1165    if nest[p].pg_field<>1 then print(" lines")
1166    else print(" line");
1167@z
1168
1169@x [17.220] l.4448 - MLTeX: char_sub_code_base
1170paragraph shape.
1171@y
1172paragraph shape.
1173Additionally region~4 contains the table with ML\TeX's character
1174substitution definitions.
1175@z
1176
1177@x [17.222] l.4523 - frozen_special, for source specials.
1178@d frozen_null_font=frozen_control_sequence+10
1179@y
1180@d frozen_special=frozen_control_sequence+10
1181  {permanent `\.{\\special}'}
1182@d frozen_null_font=frozen_control_sequence+11
1183@z
1184
1185@x [17.222] l.4526 - max_font_max
1186@d undefined_control_sequence=frozen_null_font+257 {dummy location}
1187@y
1188@d undefined_control_sequence=frozen_null_font+max_font_max+1 {dummy location}
1189@z
1190
1191@x [17.222] l.4533 - hash_extra
1192for k:=active_base to undefined_control_sequence-1 do
1193  eqtb[k]:=eqtb[undefined_control_sequence];
1194@y
1195for k:=active_base to eqtb_top do
1196  eqtb[k]:=eqtb[undefined_control_sequence];
1197@z
1198
1199@x [17.230] l.4731 - MLTeX: char_sub_code_base
1200@d int_base=math_code_base+256 {beginning of region 5}
1201@y
1202@d char_sub_code_base=math_code_base+256 {table of character substitutions}
1203@d int_base=char_sub_code_base+256 {beginning of region 5}
1204@z
1205
1206@x [17.230] l.4752 - MLTeX: char_sub_code_base
1207  {Note: |math_code(c)| is the true math code plus |min_halfword|}
1208@y
1209  {Note: |math_code(c)| is the true math code plus |min_halfword|}
1210@d char_sub_code(#)==equiv(char_sub_code_base+#)
1211  {Note: |char_sub_code(c)| is the true substitution info plus |min_halfword|}
1212@z
1213
1214% MLTeX: \charsubdefmax and \tracingcharsubdef
1215@x [17.236] l.4954
1216@d int_pars=55 {total number of integer parameters}
1217@y
1218@d tex_int_pars=55 {total number of \TeX's integer parameters}
1219@#
1220@d web2c_int_base=tex_int_pars {base for web2c's integer parameters}
1221@d char_sub_def_min_code=web2c_int_base {smallest value in the charsubdef list}
1222@d char_sub_def_max_code=web2c_int_base+1 {largest value in the charsubdef list}
1223@d tracing_char_sub_def_code=web2c_int_base+2 {traces changes to a charsubdef def}
1224@d web2c_int_pars=web2c_int_base+3 {total number of web2c's integer parameters}
1225@#
1226@d int_pars=web2c_int_pars {total number of integer parameters}
1227@z
1228
1229% MLTeX: \charsubdefmax and \tracingcharsubdef
1230@x [17.236] l.5016
1231@d error_context_lines==int_par(error_context_lines_code)
1232@y
1233@d error_context_lines==int_par(error_context_lines_code)
1234@#
1235@d char_sub_def_min==int_par(char_sub_def_min_code)
1236@d char_sub_def_max==int_par(char_sub_def_max_code)
1237@d tracing_char_sub_def==int_par(tracing_char_sub_def_code)
1238@z
1239
1240% MLTeX: \charsubdefmax and \tracingcharsubdef
1241@x [17.237] l.5080
1242error_context_lines_code:print_esc("errorcontextlines");
1243@y
1244error_context_lines_code:print_esc("errorcontextlines");
1245char_sub_def_min_code:print_esc("charsubdefmin");
1246char_sub_def_max_code:print_esc("charsubdefmax");
1247tracing_char_sub_def_code:print_esc("tracingcharsubdef");
1248@z
1249
1250% MLTeX: \charsubdefmax and \tracingcharsubdef
1251@x [17.238] l.5200
1252@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@>
1253@y
1254@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@>
1255if mltex_p then
1256  begin mltex_enabled_p:=true;  {enable character substitution}
1257  if false then {remove the if-clause to enable \.{\\charsubdefmin}}
1258  primitive("charsubdefmin",assign_int,int_base+char_sub_def_min_code);@/
1259@!@:char_sub_def_min_}{\.{\\charsubdefmin} primitive@>
1260  primitive("charsubdefmax",assign_int,int_base+char_sub_def_max_code);@/
1261@!@:char_sub_def_max_}{\.{\\charsubdefmax} primitive@>
1262  primitive("tracingcharsubdef",assign_int,int_base+tracing_char_sub_def_code);@/
1263@!@:tracing_char_sub_def_}{\.{\\tracingcharsubdef} primitive@>
1264  end;
1265@z
1266
1267@x [17.240] l.5213 - MLTeX: \charsubdefmax and \tracingcharsubdef
1268for k:=int_base to del_code_base-1 do eqtb[k].int:=0;
1269@y
1270for k:=int_base to del_code_base-1 do eqtb[k].int:=0;
1271char_sub_def_min:=256; char_sub_def_max:=-1;
1272{allow \.{\\charsubdef} for char 0}@/
1273{|tracing_char_sub_def:=0| is already done}@/
1274@z
1275
1276@x [17.241] l.5219 - Do `fix_date_and_time' in C.
1277@ The following procedure, which is called just before \TeX\ initializes its
1278input and output, establishes the initial values of the date and time.
1279@^system dependencies@>
1280Since standard \PASCAL\ cannot provide such information, something special
1281is needed. The program here simply specifies July 4, 1776, at noon; but
1282users probably want a better approximation to the truth.
1283
1284@p procedure fix_date_and_time;
1285begin time:=12*60; {minutes since midnight}
1286day:=4; {fourth day of the month}
1287month:=7; {seventh month of the year}
1288year:=1776; {Anno Domini}
1289end;
1290@y
1291@ The following procedure, which is called just before \TeX\ initializes its
1292input and output, establishes the initial values of the date and time.
1293It calls a macro-defined |date_and_time| routine.  |date_and_time|
1294in turn is a C macro, which calls |get_date_and_time|, passing
1295it the addresses of the day, month, etc., so they can be set by the
1296routine.  |get_date_and_time| also sets up interrupt catching if that
1297is conditionally compiled in the C code.
1298@^system dependencies@>
1299
1300@d fix_date_and_time==date_and_time(time,day,month,year)
1301@z
1302
1303@x [17.252] l.5420 - hash_extra
1304else if n<glue_base then @<Show equivalent |n|, in region 1 or 2@>
1305@y
1306else if (n<glue_base) or ((n>eqtb_size)and(n<=eqtb_top)) then
1307  @<Show equivalent |n|, in region 1 or 2@>
1308@z
1309
1310@x [17.253] l.5435 - Change eqtb to zeqtb.
1311@!eqtb:array[active_base..eqtb_size] of memory_word;
1312@y
1313@!zeqtb:^memory_word;
1314@z
1315
1316@x [18.256] l.5483 - hash_extra
1317@!hash: array[hash_base..undefined_control_sequence-1] of two_halves;
1318  {the hash table}
1319@!hash_used:pointer; {allocation pointer for |hash|}
1320@y
1321@!hash: ^two_halves; {the hash table}
1322@!yhash: ^two_halves; {auxiliary pointer for freeing hash}
1323@!hash_used:pointer; {allocation pointer for |hash|}
1324@!hash_extra:pointer; {|hash_extra=hash| above |eqtb_size|}
1325@!hash_top:pointer; {maximum of the hash array}
1326@!eqtb_top:pointer; {maximum of the |eqtb|}
1327@!hash_high:pointer; {pointer to next high hash location}
1328@z
1329
1330@x [18.257] l.5491 - hash_extra
1331next(hash_base):=0; text(hash_base):=0;
1332for k:=hash_base+1 to undefined_control_sequence-1 do hash[k]:=hash[hash_base];
1333@y
1334@z
1335
1336@x [18.258] l.5495 - hash_extra
1337hash_used:=frozen_control_sequence; {nothing is used}
1338@y
1339hash_used:=frozen_control_sequence; {nothing is used}
1340hash_high:=0;
1341@z
1342
1343@x [18.260] l.5531 - hash_extra
1344@ @<Insert a new control...@>=
1345begin if text(p)>0 then
1346  begin repeat if hash_is_full then overflow("hash size",hash_size);
1347@:TeX capacity exceeded hash size}{\quad hash size@>
1348  decr(hash_used);
1349  until text(hash_used)=0; {search for an empty location in |hash|}
1350  next(p):=hash_used; p:=hash_used;
1351  end;
1352@y
1353@ @<Insert a new control...@>=
1354begin if text(p)>0 then
1355  begin if hash_high<hash_extra then
1356      begin incr(hash_high);
1357      next(p):=hash_high+eqtb_size; p:=hash_high+eqtb_size;
1358      end
1359    else begin
1360      repeat if hash_is_full then overflow("hash size",hash_size+hash_extra);
1361@:TeX capacity exceeded hash size}{\quad hash size@>
1362      decr(hash_used);
1363      until text(hash_used)=0; {search for an empty location in |hash|}
1364    next(p):=hash_used; p:=hash_used;
1365    end;
1366  end;
1367@z
1368
1369@x [18.262] l.5583 - hash_extra
1370else if p>=undefined_control_sequence then print_esc("IMPOSSIBLE.")
1371@y
1372else if ((p>=undefined_control_sequence)and(p<=eqtb_size))or(p>eqtb_top) then
1373  print_esc("IMPOSSIBLE.")
1374@z
1375
1376@x [18.262] l.5584 - Remove more unsigned comparisons to zero.
1377else if (text(p)<0)or(text(p)>=str_ptr) then print_esc("NONEXISTENT.")
1378@y
1379else if (text(p)>=str_ptr) then print_esc("NONEXISTENT.")
1380@z
1381
1382@x [19.271] l.5872 - texarray
1383@!save_stack : array[0..save_size] of memory_word;
1384@y
1385@!save_stack : ^memory_word;
1386@z
1387
1388@x [19.283] l.6050 - hash_extra
1389if p<int_base then
1390@y
1391if (p<int_base)or(p>eqtb_size) then
1392@z
1393
1394@x [20.290] l.6158 - hash_extra
1395if cs_token_flag+undefined_control_sequence>max_halfword then bad:=21;
1396@y
1397if cs_token_flag+eqtb_size+hash_extra>max_halfword then bad:=21;
1398if (hash_offset<0)or(hash_offset>hash_base) then bad:=42;
1399@z
1400
1401@x [22.301] l.6432 - texarray
1402@!input_stack : array[0..stack_size] of in_state_record;
1403@y
1404@!input_stack : ^in_state_record;
1405@z
1406
1407@x [22.304] l.6536 - texarray; additions for file:line:error style.
1408@!input_file : array[1..max_in_open] of alpha_file;
1409@!line : integer; {current line number in the current source file}
1410@!line_stack : array[1..max_in_open] of integer;
1411@y
1412@!input_file : ^alpha_file;
1413@!line : integer; {current line number in the current source file}
1414@!line_stack : ^integer;
1415@!source_filename_stack : ^str_number;
1416@!full_source_filename_stack : ^str_number;
1417@z
1418
1419@x [22.306] l.6855 - i18n fix
1420  begin print_nl("Runaway ");
1421@.Runaway...@>
1422  case scanner_status of
1423  defining: begin print("definition"); p:=def_ref;
1424    end;
1425  matching: begin print("argument"); p:=temp_head;
1426    end;
1427  aligning: begin print("preamble"); p:=hold_head;
1428    end;
1429  absorbing: begin print("text"); p:=def_ref;
1430    end;
1431  end; {there are no other cases}
1432@y
1433  begin
1434@.Runaway...@>
1435  case scanner_status of
1436  defining: begin print_nl("Runaway definition"); p:=def_ref;
1437    end;
1438  matching: begin print_nl("Runaway argument"); p:=temp_head;
1439    end;
1440  aligning: begin print_nl("Runaway preamble"); p:=hold_head;
1441    end;
1442  absorbing: begin print_nl("Runaway text"); p:=def_ref;
1443    end;
1444  end; {there are no other cases}
1445@z
1446
1447@x [22.308] l.6701 - texarray
1448@!param_stack:array [0..param_size] of pointer;
1449  {token list pointers for parameters}
1450@y
1451@!param_stack: ^pointer;
1452  {token list pointers for parameters}
1453@z
1454
1455@x [23.328] l.7043 - keep top of source_filename_stack initialized
1456incr(in_open); push_input; index:=in_open;
1457@y
1458incr(in_open); push_input; index:=in_open;
1459source_filename_stack[index]:=0;full_source_filename_stack[index]:=0;
1460@z
1461
1462@x [23.331] l.7071 - init source file name stacks
1463begin input_ptr:=0; max_in_stack:=0;
1464@y
1465begin input_ptr:=0; max_in_stack:=0;
1466source_filename_stack[0]:=0;full_source_filename_stack[0]:=0;
1467@z
1468
1469@x [24.338] l.7164 - i18n fix
1470print(" while scanning ");
1471@y
1472@z
1473
1474@x [24.339] l.7185 - i18n fix
1475defining:begin print("definition"); info(p):=right_brace_token+"}";
1476  end;
1477matching:begin print("use"); info(p):=par_token; long_state:=outer_call;
1478  end;
1479aligning:begin print("preamble"); info(p):=right_brace_token+"}"; q:=p;
1480  p:=get_avail; link(p):=q; info(p):=cs_token_flag+frozen_cr;
1481  align_state:=-1000000;
1482  end;
1483absorbing:begin print("text"); info(p):=right_brace_token+"}";
1484@y
1485defining:begin print(" while scanning definition"); info(p):=right_brace_token+"}";
1486  end;
1487matching:begin print(" while scanning use"); info(p):=par_token; long_state:=outer_call;
1488  end;
1489aligning:begin print(" while scanning preamble"); info(p):=right_brace_token+"}"; q:=p;
1490  p:=get_avail; link(p):=q; info(p):=cs_token_flag+frozen_cr;
1491  align_state:=-1000000;
1492  end;
1493absorbing:begin print(" while scanning text"); info(p):=right_brace_token+"}";
1494@z
1495
1496@x [25.366] expansion depth check
1497The |expand| subroutine is used when |cur_cmd>max_command|. It removes a
1498@y
1499@ Sometimes, recursive calls to the following |expand| routine may
1500cause exhaustion of the run-time calling stack, resulting in
1501forced execution stops by the operating system. To diminish the chance
1502of this happening, a counter is used to keep track of the recursion
1503depth, in conjunction with a constant called |expand_depth|.
1504
1505This does not catch all possible infinite recursion loops, just the ones
1506that exhaust the application calling stack. The actual maximum value of
1507|expand_depth| is outside of our control, but the initial setting of
1508|10000| should be enough to prevent problems.
1509@^system dependencies@>
1510
1511@<Global...@>=
1512expand_depth_count:integer;
1513
1514@ @<Set init...@>=
1515expand_depth_count:=0;
1516
1517@ The |expand| subroutine is used when |cur_cmd>max_command|. It removes a
1518@z
1519
1520@x [25.366]
1521begin cv_backup:=cur_val; cvl_backup:=cur_val_level; radix_backup:=radix;
1522@y
1523begin
1524incr(expand_depth_count);
1525if expand_depth_count>=expand_depth then overflow("expansion depth",expand_depth);
1526cv_backup:=cur_val; cvl_backup:=cur_val_level; radix_backup:=radix;
1527@z
1528
1529@x [25.366]
1530cur_order:=co_backup; link(backup_head):=backup_backup;
1531@y
1532cur_order:=co_backup; link(backup_head):=backup_backup;
1533decr(expand_depth_count);
1534@z
1535
1536@x [28.501] l.9747 - \eof18
1537if_eof_code: begin scan_four_bit_int; b:=(read_open[cur_val]=closed);
1538  end;
1539@y
1540if_eof_code: begin scan_four_bit_int_or_18;
1541  if cur_val=18 then b:=not shellenabledp
1542  else b:=(read_open[cur_val]=closed);
1543  end;
1544@z
1545
1546@x [29.513] l.9951 - Area and extension rules for filenames.
1547@ The file names we shall deal with for illustrative purposes have the
1548following structure:  If the name contains `\.>' or `\.:', the file area
1549consists of all characters up to and including the final such character;
1550otherwise the file area is null.  If the remaining file name contains
1551`\..', the file extension consists of all such characters from the first
1552remaining `\..' to the end, otherwise the file extension is null.
1553@y
1554@ The file names we shall deal with have the
1555following structure:  If the name contains `\./' or `\.:'
1556(for Amiga only), the file area
1557consists of all characters up to and including the final such character;
1558otherwise the file area is null.  If the remaining file name contains
1559`\..', the file extension consists of all such characters from the last
1560`\..' to the end, otherwise the file extension is null.
1561@z
1562
1563@x [29.513] l.9963 - Area and extension rules for filenames.
1564@!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any}
1565@!ext_delimiter:pool_pointer; {the relevant `\..', if any}
1566@y
1567@!area_delimiter:pool_pointer; {the most recent `\./', if any}
1568@!ext_delimiter:pool_pointer; {the most recent `\..', if any}
1569@z
1570
1571@x [29.514] l.9973 - TeX area directories.
1572@d TEX_area=="TeXinputs:"
1573@.TeXinputs@>
1574@d TEX_font_area=="TeXfonts:"
1575@.TeXfonts@>
1576@y
1577In C, the default paths are specified separately.
1578@z
1579
1580@x [29.515] l.9995 - filenames: quoted
1581begin area_delimiter:=0; ext_delimiter:=0;
1582@y
1583begin area_delimiter:=0; ext_delimiter:=0; quoted_filename:=false;
1584@z
1585
1586@x [29.516] l.9992 - filenames: more_name
1587begin if c=" " then more_name:=false
1588@y
1589begin if (c=" ") and stop_at_space and (not quoted_filename) then
1590  more_name:=false
1591else  if c="""" then begin
1592  quoted_filename:=not quoted_filename;
1593  more_name:=true;
1594  end
1595@z
1596
1597@x [29.516] l.9994 - filenames: more_name
1598  if (c=">")or(c=":") then
1599@y
1600  if IS_DIR_SEP(c) then
1601@z
1602
1603@x [29.516] l.9997 - filenames: more_name
1604  else if (c=".")and(ext_delimiter=0) then ext_delimiter:=cur_length;
1605@y
1606  else if c="." then ext_delimiter:=cur_length;
1607@z
1608
1609@x [29.517] l.10002 - end_name: string recycling
1610@ The third.
1611@^system dependencies@>
1612
1613@p procedure end_name;
1614@y
1615@ The third.
1616@^system dependencies@>
1617If a string is already in the string pool, the function
1618|slow_make_string| does not create a new string but returns this string
1619number, thus saving string space.  Because of this new property of the
1620returned string number it is not possible to apply |flush_string| to
1621these strings.
1622
1623@p procedure end_name;
1624var temp_str: str_number; {result of file name cache lookups}
1625@!j,@!s,@!t: pool_pointer; {running indices}
1626@!must_quote:boolean; {whether we need to quote a string}
1627@z
1628
1629@x [29.517] l.10022 - end_name: spaces in filenames
1630@:TeX capacity exceeded number of strings}{\quad number of strings@>
1631@y
1632@:TeX capacity exceeded number of strings}{\quad number of strings@>
1633str_room(6); {Room for quotes, if needed.}
1634{add quotes if needed}
1635if area_delimiter<>0 then begin
1636  {maybe quote |cur_area|}
1637  must_quote:=false;
1638  s:=str_start[str_ptr];
1639  t:=str_start[str_ptr]+area_delimiter;
1640  j:=s;
1641  while (not must_quote) and (j<t) do begin
1642    must_quote:=str_pool[j]=" "; incr(j);
1643    end;
1644  if must_quote then begin
1645    for j:=pool_ptr-1 downto t do str_pool[j+2]:=str_pool[j];
1646    str_pool[t+1]:="""";
1647    for j:=t-1 downto s do str_pool[j+1]:=str_pool[j];
1648    str_pool[s]:="""";
1649    if ext_delimiter<>0 then ext_delimiter:=ext_delimiter+2;
1650    area_delimiter:=area_delimiter+2;
1651    pool_ptr:=pool_ptr+2;
1652    end;
1653  end;
1654{maybe quote |cur_name|}
1655s:=str_start[str_ptr]+area_delimiter;
1656if ext_delimiter=0 then t:=pool_ptr else t:=str_start[str_ptr]+ext_delimiter-1;
1657must_quote:=false;
1658j:=s;
1659while (not must_quote) and (j<t) do begin
1660  must_quote:=str_pool[j]=" "; incr(j);
1661  end;
1662if must_quote then begin
1663  for j:=pool_ptr-1 downto t do str_pool[j+2]:=str_pool[j];
1664  str_pool[t+1]:="""";
1665  for j:=t-1 downto s do str_pool[j+1]:=str_pool[j];
1666  str_pool[s]:="""";
1667  if ext_delimiter<>0 then ext_delimiter:=ext_delimiter+2;
1668  pool_ptr:=pool_ptr+2;
1669  end;
1670if ext_delimiter<>0 then begin
1671  {maybe quote |cur_ext|}
1672  s:=str_start[str_ptr]+ext_delimiter-1;
1673  t:=pool_ptr;
1674  must_quote:=false;
1675  j:=s;
1676  while (not must_quote) and (j<t) do begin
1677    must_quote:=str_pool[j]=" "; incr(j);
1678    end;
1679  if must_quote then begin
1680    str_pool[t+1]:="""";
1681    for j:=t-1 downto s do str_pool[j+1]:=str_pool[j];
1682    str_pool[s]:="""";
1683    pool_ptr:=pool_ptr+2;
1684    end;
1685  end;
1686@z
1687
1688@x [29.517] l.10011 - end_name: string recycling
1689  end;
1690if ext_delimiter=0 then
1691  begin cur_ext:=""; cur_name:=make_string;
1692@y
1693  temp_str:=search_string(cur_area);
1694  if temp_str>0 then
1695    begin cur_area:=temp_str;
1696    decr(str_ptr);  {no |flush_string|, |pool_ptr| will be wrong!}
1697    for j:=str_start[str_ptr+1] to pool_ptr-1 do
1698      begin str_pool[j-area_delimiter]:=str_pool[j];
1699      end;
1700    pool_ptr:=pool_ptr-area_delimiter; {update |pool_ptr|}
1701    end;
1702  end;
1703if ext_delimiter=0 then
1704  begin cur_ext:=""; cur_name:=slow_make_string;
1705@z
1706
1707@x [29.517] l.10016 - end_name: string recycling
1708  incr(str_ptr); cur_ext:=make_string;
1709@y
1710  incr(str_ptr); cur_ext:=make_string;
1711  decr(str_ptr); {undo extension string to look at name part}
1712  temp_str:=search_string(cur_name);
1713  if temp_str>0 then
1714    begin cur_name:=temp_str;
1715    decr(str_ptr);  {no |flush_string|, |pool_ptr| will be wrong!}
1716    for j:=str_start[str_ptr+1] to pool_ptr-1 do
1717      begin str_pool[j-ext_delimiter+area_delimiter+1]:=str_pool[j];
1718      end;
1719    pool_ptr:=pool_ptr-ext_delimiter+area_delimiter+1;  {update |pool_ptr|}
1720    end;
1721  cur_ext:=slow_make_string;  {remake extension string}
1722@z
1723
1724@x [29.518] l.10042 - print_file_name: quote if spaces in names.
1725some operating systems put the file area last instead of first.)
1726@^system dependencies@>
1727@y
1728some operating systems put the file area last instead of first.)
1729@^system dependencies@>
1730
1731@d check_quoted(#) == {check if string |#| needs quoting}
1732if #<>0 then begin
1733  j:=str_start[#];
1734  while (not must_quote) and (j<str_start[#+1]) do begin
1735    must_quote:=str_pool[j]=" "; incr(j);
1736  end;
1737end
1738@#
1739@d print_quoted(#) == {print string |#|, omitting quotes}
1740if #<>0 then
1741  for j:=str_start[#] to str_start[#+1]-1 do
1742    if so(str_pool[j])<>"""" then
1743      print(so(str_pool[j]))
1744@z
1745
1746@x [29.518] l.10042 - print_file_name: quote if spaces in names.
1747begin slow_print(a); slow_print(n); slow_print(e);
1748@y
1749var must_quote: boolean; {whether to quote the filename}
1750@!j:pool_pointer; {index into |str_pool|}
1751begin
1752must_quote:=false;
1753check_quoted(a); check_quoted(n); check_quoted(e);
1754{FIXME: Alternative is to assume that any filename that has to be quoted has
1755 at least one quoted component...if we pick this, a number of insertions
1756 of |print_file_name| should go away.
1757|must_quote|:=((|a|<>0)and(|str_pool|[|str_start|[|a|]]=""""))or
1758              ((|n|<>0)and(|str_pool|[|str_start|[|n|]]=""""))or
1759              ((|e|<>0)and(|str_pool|[|str_start|[|e|]]=""""));}
1760if must_quote then print_char("""");
1761print_quoted(a); print_quoted(n); print_quoted(e);
1762if must_quote then print_char("""");
1763@z
1764
1765@x [29.519] l.10051 - have append_to_name skip quotes.
1766@d append_to_name(#)==begin c:=#; incr(k);
1767  if k<=file_name_size then name_of_file[k]:=xchr[c];
1768  end
1769@y
1770@d append_to_name(#)==begin c:=#; if not (c="""") then begin incr(k);
1771  if k<=file_name_size then name_of_file[k]:=xchr[c];
1772  end end
1773@z
1774
1775% [29.519] In pack_file_name, leave room for the extra null we append at
1776% the end of a filename.
1777@x [29.519] l.10047 - pack_file_name, leave room for the extra null
1778begin k:=0;
1779@y
1780begin k:=0;
1781if name_of_file then libc_free (name_of_file);
1782name_of_file:= xmalloc_array (ASCII_code, length(a)+length(n)+length(e)+1);
1783@z
1784
1785@x [29.519] l.10051 - pack_file_name, append the extra null
1786for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
1787@y
1788name_of_file[name_length+1]:=0;
1789@z
1790
1791@x [29.520] l.10060 - filenames: default format.
1792@d format_default_length=20 {length of the |TEX_format_default| string}
1793@d format_area_length=11 {length of its area part}
1794@d format_ext_length=4 {length of its `\.{.fmt}' part}
1795@y
1796Under {\mc UNIX} we don't give the area part, instead depending
1797on the path searching that will happen during file opening.  Also, the
1798length will be set in the main program.
1799
1800@d format_area_length=0 {length of its area part}
1801@d format_ext_length=4 {length of its `\.{.fmt}' part}
1802@z
1803
1804@x [29.521] l.10066 - filenames: default format, where `plain.fmt' is.
1805@!TEX_format_default:packed array[1..format_default_length] of char;
1806
1807@ @<Set init...@>=
1808TEX_format_default:='TeXformats:plain.fmt';
1809@y
1810@!format_default_length: integer;
1811@!TEX_format_default: cstring;
1812
1813@ We set the name of the default format file and the length of that name
1814in C, instead of Pascal, since we want them to depend on the name of the
1815program.
1816@z
1817
1818@x [29.523] l.10095 - Change to pack_buffered_name as with pack_file_name.
1819for j:=1 to n do append_to_name(xord[TEX_format_default[j]]);
1820for j:=a to b do append_to_name(buffer[j]);
1821for j:=format_default_length-format_ext_length+1 to format_default_length do
1822  append_to_name(xord[TEX_format_default[j]]);
1823if k<=file_name_size then name_length:=k@+else name_length:=file_name_size;
1824for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
1825@y
1826if name_of_file then libc_free (name_of_file);
1827name_of_file := xmalloc_array (ASCII_code, n+(b-a+1)+format_ext_length+1);
1828for j:=1 to n do append_to_name(xord[ucharcast(TEX_format_default[j])]);
1829for j:=a to b do append_to_name(buffer[j]);
1830for j:=format_default_length-format_ext_length+1 to format_default_length do
1831  append_to_name(xord[ucharcast(TEX_format_default[j])]);
1832if k<=file_name_size then name_length:=k@+else name_length:=file_name_size;
1833name_of_file[name_length+1]:=0;
1834@z
1835
1836@x [29.524] l.10118 - Format file opening: only try once, with path searching.
1837  pack_buffered_name(0,loc,j-1); {try first without the system file area}
1838  if w_open_in(fmt_file) then goto found;
1839  pack_buffered_name(format_area_length,loc,j-1);
1840    {now try the system format file area}
1841  if w_open_in(fmt_file) then goto found;
1842@y
1843  pack_buffered_name(0,loc,j-1); {Kpathsea does everything}
1844  if w_open_in(fmt_file) then goto found;
1845@z
1846
1847@x [29.524] l.10124 - replace `PLAIN' in error messages with `default'.
1848  wterm_ln('Sorry, I can''t find that format;',' will try PLAIN.');
1849@y
1850  wterm ('Sorry, I can''t find the format `');
1851  fputs (stringcast(name_of_file + 1), stdout);
1852  wterm ('''; will try `');
1853  fputs (TEX_format_default + 1, stdout);
1854  wterm_ln ('''.');
1855@z
1856
1857@x [29.524] l.10132 - replace `PLAIN' in error messages with `default'.
1858  wterm_ln('I can''t find the PLAIN format file!');
1859@.I can't find PLAIN...@>
1860@y
1861  wterm ('I can''t find the format file `');
1862  fputs (TEX_format_default + 1, stdout);
1863  wterm_ln ('''!');
1864@.I can't find the format...@>
1865@z
1866
1867@x [29.525] l.10170 - make_name_string
1868begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or
1869@y
1870save_area_delimiter, save_ext_delimiter: pool_pointer;
1871save_name_in_progress, save_stop_at_space: boolean;
1872begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or
1873@z
1874
1875@x [29.525] l.10174 - make_name_string
1876  make_name_string:=make_string;
1877@y
1878  make_name_string:=make_string;
1879  {At this point we also set |cur_name|, |cur_ext|, and |cur_area| to
1880   match the contents of |name_of_file|.}
1881  save_area_delimiter:=area_delimiter; save_ext_delimiter:=ext_delimiter;
1882  save_name_in_progress:=name_in_progress; save_stop_at_space:=stop_at_space;
1883  name_in_progress:=true;
1884  begin_name;
1885  stop_at_space:=false;
1886  k:=1;
1887  while (k<=name_length)and(more_name(name_of_file[k])) do
1888    incr(k);
1889  stop_at_space:=save_stop_at_space;
1890  end_name;
1891  name_in_progress:=save_name_in_progress;
1892  area_delimiter:=save_area_delimiter; ext_delimiter:=save_ext_delimiter;
1893@z
1894
1895@x [29.526] l.10194 - stop scanning file name if we're at end-of-line.
1896  if not more_name(cur_chr) then goto done;
1897@y
1898  {If |cur_chr| is a space and we're not scanning a token list, check
1899   whether we're at the end of the buffer. Otherwise we end up adding
1900   spurious spaces to file names in some cases.}
1901  if (cur_chr=" ") and (state<>token_list) and (loc>limit) then goto done;
1902  if not more_name(cur_chr) then goto done;
1903@z
1904
1905@x [29.530] l.10245 - prompt_file_name: prevent empty filenames.
1906var k:0..buf_size; {index into |buffer|}
1907@y
1908var k:0..buf_size; {index into |buffer|}
1909@!saved_cur_name:str_number; {to catch empty terminal input}
1910@!saved_cur_ext:str_number; {to catch empty terminal input}
1911@!saved_cur_area:str_number; {to catch empty terminal input}
1912@z
1913
1914@x [29.530] l.10252 - prompt_file_name: No default extension is TeX input file.
1915if e=".tex" then show_context;
1916@y
1917if (e=".tex") or (e="") then show_context;
1918print_ln; print_c_string(prompt_file_name_help_msg);
1919if (e<>"") then
1920  begin
1921    print("; default file extension is `"); print(e); print("'");
1922  end;
1923print(")"); print_ln;
1924@z
1925
1926@x [29.530] l.10258 - prompt_file_name: prevent empty filenames.
1927clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
1928if cur_ext="" then cur_ext:=e;
1929@y
1930saved_cur_name:=cur_name;
1931saved_cur_ext:=cur_ext;
1932saved_cur_area:=cur_area;
1933clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
1934if (length(cur_name)=0) and (cur_ext="") and (cur_area="") then
1935  begin
1936    cur_name:=saved_cur_name;
1937    cur_ext:=saved_cur_ext;
1938    cur_area:=saved_cur_area;
1939  end
1940else
1941  if cur_ext="" then cur_ext:=e;
1942@z
1943
1944@x [29.532] l.10263 - avoid conflict, `logname' in <unistd.h> on some systems.
1945@d ensure_dvi_open==if output_file_name=0 then
1946@y
1947@d log_name == texmf_log_name
1948@d ensure_dvi_open==if output_file_name=0 then
1949@z
1950
1951@x [29.534] l.10285 - Adjust for C string conventions.
1952@!months:packed array [1..36] of char; {abbreviations of month names}
1953@y
1954@!months:const_cstring;
1955@z
1956
1957@x [29.534] l.10300 - Filename change for the recorder.
1958if job_name=0 then job_name:="texput";
1959@.texput@>
1960@y
1961if job_name=0 then job_name:=get_job_name("texput");
1962@.texput@>
1963pack_job_name(".fls");
1964recorder_change_filename(stringcast(name_of_file+1));
1965@z
1966
1967@x [29.534] l.10293 - MLTeX: add MLTeX banner after loading fmt file
1968@<Print the banner line, including the date and time@>;
1969@y
1970@<Print the banner line, including the date and time@>;
1971if mltex_enabled_p then
1972  begin wlog_cr; wlog('MLTeX v2.2 enabled');
1973  end;
1974@z
1975
1976@x
1977begin wlog(banner);
1978@y
1979begin
1980if src_specials_p or file_line_error_style_p or parse_first_line_p
1981then
1982  wlog(banner_k)
1983else
1984  wlog(banner);
1985@z
1986
1987@x [29.536] l.10324 - Print rest of banner.
1988slow_print(format_ident); print("  ");
1989@y
1990wlog(version_string);
1991slow_print(format_ident); print("  ");
1992@z
1993
1994@x [29.536] l.10327 - Adjust for C string conventions.
1995months:='JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC';
1996@y
1997months := ' JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC';
1998@z
1999
2000% Print whether we're using src-specials and other such features.
2001% Print TCX name if one's given.
2002@x [29.536] l.10331
2003end
2004@y
2005if shellenabledp then begin
2006  wlog_cr;
2007  wlog(' ');
2008  if restrictedshell then begin
2009    wlog('restricted ');
2010  end;
2011  wlog('\write18 enabled.')
2012  end;
2013if src_specials_p then begin
2014  wlog_cr;
2015  wlog(' Source specials enabled.')
2016  end;
2017if file_line_error_style_p then begin
2018  wlog_cr;
2019  wlog(' file:line:error style messages enabled.')
2020  end;
2021if parse_first_line_p then begin
2022  wlog_cr;
2023  wlog(' %&-line parsing enabled.');
2024  end;
2025if translate_filename then begin
2026  wlog_cr;
2027  wlog(' (');
2028  fputs(translate_filename, log_file);
2029  wlog(')');
2030  end;
2031end
2032@z
2033
2034% [29.537] Use a path when calling a_open_in to do a \input; also, try
2035% to open the file with and without the `.tex' extension, regardless of
2036% whether the file already has an extension.  This allows filenames like
2037% `foo' and `foo.bar.tex', as well as `foo.tex' and `foo.bar'.
2038@x [29.537] l.10338 - start_input
2039begin scan_file_name; {set |cur_name| to desired file name}
2040if cur_ext="" then cur_ext:=".tex";
2041pack_cur_name;
2042loop@+  begin begin_file_reading; {set up |cur_file| and new level of input}
2043  if a_open_in(cur_file) then goto done;
2044  if cur_area="" then
2045    begin pack_file_name(cur_name,TEX_area,cur_ext);
2046    if a_open_in(cur_file) then goto done;
2047    end;
2048@y
2049var temp_str: str_number;
2050begin scan_file_name; {set |cur_name| to desired file name}
2051pack_cur_name;
2052loop@+begin
2053  begin_file_reading; {set up |cur_file| and new level of input}
2054  tex_input_type := 1; {Tell |open_input| we are \.{\\input}.}
2055  {Kpathsea tries all the various ways to get the file.}
2056  if kpse_in_name_ok(stringcast(name_of_file+1))
2057     and a_open_in(cur_file, kpse_tex_format) then
2058    goto done;
2059@z
2060
2061@x [29.537] l.10348 - start_input: don't force ".tex" extension.
2062  prompt_file_name("input file name",".tex");
2063@y
2064  prompt_file_name("input file name","");
2065@z
2066
2067@x [29.537] l.10350 - start_input: string recycling
2068done: name:=a_make_name_string(cur_file);
2069@y
2070done: name:=a_make_name_string(cur_file);
2071source_filename_stack[in_open]:=name;
2072full_source_filename_stack[in_open]:=make_full_name_string;
2073if name=str_ptr-1 then {we can try to conserve string pool space now}
2074  begin temp_str:=search_string(name);
2075  if temp_str>0 then
2076    begin name:=temp_str; flush_string;
2077    end;
2078  end;
2079@z
2080
2081@x [29.537] l.10352 - start_input: was job_name given on the command line?
2082  begin job_name:=cur_name; open_log_file;
2083@y
2084  begin job_name:=get_job_name(cur_name); open_log_file;
2085@z
2086
2087@x [29.537] l.10356 -
2088if term_offset+length(name)>max_print_line-2 then print_ln
2089else if (term_offset>0)or(file_offset>0) then print_char(" ");
2090print_char("("); incr(open_parens); slow_print(name); update_terminal;
2091@y
2092if term_offset+length(full_source_filename_stack[in_open])>max_print_line-2
2093then print_ln
2094else if (term_offset>0)or(file_offset>0) then print_char(" ");
2095print_char("("); incr(open_parens);
2096slow_print(full_source_filename_stack[in_open]); update_terminal;
2097@z
2098
2099@x [29.537] l.10360 - start_input: don't return filename to string pool.
2100if name=str_ptr-1 then {we can conserve string pool space now}
2101  begin flush_string; name:=cur_name;
2102  end;
2103@y
2104@z
2105
2106@x [30.548] l.10673 - texarray
2107@!internal_font_number=font_base..font_max; {|font| in a |char_node|}
2108@!font_index=0..font_mem_size; {index into |font_info|}
2109@y
2110@!internal_font_number=integer; {|font| in a |char_node|}
2111@!font_index=integer; {index into |font_info|}
2112@!nine_bits=min_quarterword..non_char;
2113@z
2114
2115@x [30.549] l.10682 - texarray
2116@!font_info:array[font_index] of memory_word;
2117  {the big collection of font data}
2118@!fmem_ptr:font_index; {first unused word of |font_info|}
2119@!font_ptr:internal_font_number; {largest internal font number in use}
2120@!font_check:array[internal_font_number] of four_quarters; {check sum}
2121@!font_size:array[internal_font_number] of scaled; {``at'' size}
2122@!font_dsize:array[internal_font_number] of scaled; {``design'' size}
2123@!font_params:array[internal_font_number] of font_index; {how many font
2124  parameters are present}
2125@!font_name:array[internal_font_number] of str_number; {name of the font}
2126@!font_area:array[internal_font_number] of str_number; {area of the font}
2127@!font_bc:array[internal_font_number] of eight_bits;
2128  {beginning (smallest) character code}
2129@!font_ec:array[internal_font_number] of eight_bits;
2130  {ending (largest) character code}
2131@!font_glue:array[internal_font_number] of pointer;
2132  {glue specification for interword space, |null| if not allocated}
2133@!font_used:array[internal_font_number] of boolean;
2134  {has a character from this font actually appeared in the output?}
2135@!hyphen_char:array[internal_font_number] of integer;
2136  {current \.{\\hyphenchar} values}
2137@!skew_char:array[internal_font_number] of integer;
2138  {current \.{\\skewchar} values}
2139@!bchar_label:array[internal_font_number] of font_index;
2140  {start of |lig_kern| program for left boundary character,
2141  |non_address| if there is none}
2142@!font_bchar:array[internal_font_number] of min_quarterword..non_char;
2143  {right boundary character, |non_char| if there is none}
2144@!font_false_bchar:array[internal_font_number] of min_quarterword..non_char;
2145  {|font_bchar| if it doesn't exist in the font, otherwise |non_char|}
2146@y
2147@!font_info: ^fmemory_word;
2148  {the big collection of font data}
2149@!fmem_ptr:font_index; {first unused word of |font_info|}
2150@!font_ptr:internal_font_number; {largest internal font number in use}
2151@!font_check: ^four_quarters; {check sum}
2152@!font_size: ^scaled; {``at'' size}
2153@!font_dsize: ^scaled; {``design'' size}
2154@!font_params: ^font_index; {how many font
2155  parameters are present}
2156@!font_name: ^str_number; {name of the font}
2157@!font_area: ^str_number; {area of the font}
2158@!font_bc: ^eight_bits;
2159  {beginning (smallest) character code}
2160@!font_ec: ^eight_bits;
2161  {ending (largest) character code}
2162@!font_glue: ^pointer;
2163  {glue specification for interword space, |null| if not allocated}
2164@!font_used: ^boolean;
2165  {has a character from this font actually appeared in the output?}
2166@!hyphen_char: ^integer;
2167  {current \.{\\hyphenchar} values}
2168@!skew_char: ^integer;
2169  {current \.{\\skewchar} values}
2170@!bchar_label: ^font_index;
2171  {start of |lig_kern| program for left boundary character,
2172  |non_address| if there is none}
2173@!font_bchar: ^nine_bits;
2174  {right boundary character, |non_char| if there is none}
2175@!font_false_bchar: ^nine_bits;
2176  {|font_bchar| if it doesn't exist in the font, otherwise |non_char|}
2177@z
2178
2179@x [30.550] l.10723 - texarray
2180@!char_base:array[internal_font_number] of integer;
2181  {base addresses for |char_info|}
2182@!width_base:array[internal_font_number] of integer;
2183  {base addresses for widths}
2184@!height_base:array[internal_font_number] of integer;
2185  {base addresses for heights}
2186@!depth_base:array[internal_font_number] of integer;
2187  {base addresses for depths}
2188@!italic_base:array[internal_font_number] of integer;
2189  {base addresses for italic corrections}
2190@!lig_kern_base:array[internal_font_number] of integer;
2191  {base addresses for ligature/kerning programs}
2192@!kern_base:array[internal_font_number] of integer;
2193  {base addresses for kerns}
2194@!exten_base:array[internal_font_number] of integer;
2195  {base addresses for extensible recipes}
2196@!param_base:array[internal_font_number] of integer;
2197  {base addresses for font parameters}
2198@y
2199@!char_base: ^integer;
2200  {base addresses for |char_info|}
2201@!width_base: ^integer;
2202  {base addresses for widths}
2203@!height_base: ^integer;
2204  {base addresses for heights}
2205@!depth_base: ^integer;
2206  {base addresses for depths}
2207@!italic_base: ^integer;
2208  {base addresses for italic corrections}
2209@!lig_kern_base: ^integer;
2210  {base addresses for ligature/kerning programs}
2211@!kern_base: ^integer;
2212  {base addresses for kerns}
2213@!exten_base: ^integer;
2214  {base addresses for extensible recipes}
2215@!param_base: ^integer;
2216  {base addresses for font parameters}
2217@z
2218
2219@x [30.551] l.10743 - texarray
2220for k:=font_base to font_max do font_used[k]:=false;
2221@y
2222@z
2223
2224@x [30.552] l.10749 - texarray
2225font_ptr:=null_font; fmem_ptr:=7;
2226font_name[null_font]:="nullfont"; font_area[null_font]:="";
2227hyphen_char[null_font]:="-"; skew_char[null_font]:=-1;
2228bchar_label[null_font]:=non_address;
2229font_bchar[null_font]:=non_char; font_false_bchar[null_font]:=non_char;
2230font_bc[null_font]:=1; font_ec[null_font]:=0;
2231font_size[null_font]:=0; font_dsize[null_font]:=0;
2232char_base[null_font]:=0; width_base[null_font]:=0;
2233height_base[null_font]:=0; depth_base[null_font]:=0;
2234italic_base[null_font]:=0; lig_kern_base[null_font]:=0;
2235kern_base[null_font]:=0; exten_base[null_font]:=0;
2236font_glue[null_font]:=null; font_params[null_font]:=7;
2237param_base[null_font]:=-1;
2238for k:=0 to 6 do font_info[k].sc:=0;
2239@y
2240@z
2241
2242@x [30.554] l.10795 - MLTeX: |effective_char| in |char_info|
2243as fast as possible under the circumstances.
2244@^inner loop@>
2245
2246@d char_info_end(#)==#].qqqq
2247@d char_info(#)==font_info[char_base[#]+char_info_end
2248@y
2249as fast as possible under the circumstances.
2250@^inner loop@>
2251
2252ML\TeX{} will assume that a character |c| exists iff either exists in
2253the current font or a character substitution definition for this
2254character was defined using \.{\\charsubdef}.  To avoid the
2255distinction between these two cases, ML\TeX{} introduces the notion
2256``effective character'' of an input character |c|.  If |c| exists in
2257the current font, the effective character of |c| is the character |c|
2258itself.  If it doesn't exist but a character substitution is defined,
2259the effective character of |c| is the base character defined in the
2260character substitution.  If there is an effective character for a
2261non-existing character |c|, the ``virtual character'' |c| will get
2262appended to the horizontal lists.
2263
2264The effective character is used within |char_info| to access
2265appropriate character descriptions in the font.  For example, when
2266calculating the width of a box, ML\TeX{} will use the metrics of the
2267effective characters.  For the case of a substitution, ML\TeX{} uses
2268the metrics of the base character, ignoring the metrics of the accent
2269character.
2270
2271If character substitutions are changed, it will be possible that a
2272character |c| neither exists in a font nor there is a valid character
2273substitution for |c|.  To handle these cases |effective_char| should
2274be called with its first argument set to |true| to ensure that it
2275will still return an existing character in the font.  If neither |c|
2276nor the substituted base character in the current character
2277substitution exists, |effective_char| will output a warning and
2278return the character |font_bc[f]| (which is incorrect, but can not be
2279changed within the current framework).
2280
2281Sometimes character substitutions are unwanted, therefore the
2282original definition of |char_info| can be used using the macro
2283|orig_char_info|.  Operations in which character substitutions should
2284be avoided are, for example, loading a new font and checking the font
2285metric information in this font, and character accesses in math mode.
2286
2287@d char_list_exists(#)==(char_sub_code(#)>hi(0))
2288@d char_list_accent(#)==(ho(char_sub_code(#)) div 256)
2289@d char_list_char(#)==(ho(char_sub_code(#)) mod 256)
2290@#
2291@d char_info_end(#)== #@=)@>].qqqq
2292@d char_info(#)==
2293  font_info[char_base[#]+effective_char@=(@>true,#,char_info_end
2294@#
2295@d orig_char_info_end(#)==#].qqqq
2296@d orig_char_info(#)==font_info[char_base[#]+orig_char_info_end
2297@#
2298@z
2299
2300@x [30] m.560 l.10876 - MLTeX: |effective_char| in |char_info|
2301@p function read_font_info(@!u:pointer;@!nom,@!aire:str_number;
2302@y
2303@p @t\4@>@<Declare additional functions for ML\TeX@>@/
2304
2305function read_font_info(@!u:pointer;@!nom,@!aire:str_number;
2306@z
2307
2308@x [30.560] l.10898 - Check lengths
2309@!file_opened:boolean; {was |tfm_file| successfully opened?}
2310@y
2311@!name_too_long:boolean; {|nom| or |aire| exceeds 255 bytes?}
2312@!file_opened:boolean; {was |tfm_file| successfully opened?}
2313@z
2314
2315@x [30.561] l.10939 - Check lengths
2316else print(" not loadable: Metric (TFM) file not found");
2317@y
2318else if name_too_long then print(" not loadable: Metric (TFM) file name too long")
2319else print(" not loadable: Metric (TFM) file not found");
2320@z
2321
2322@x [30.563] l.10961 - Check lengths, don't use TEX_font_area.
2323if aire="" then pack_file_name(nom,TEX_font_area,".tfm")
2324else pack_file_name(nom,aire,".tfm");
2325@y
2326name_too_long:=(length(nom)>255)or(length(aire)>255);
2327if name_too_long then abort;
2328{|kpse_find_file| will append the |".tfm"|, and avoid searching the disk
2329 before the font alias files as well.}
2330pack_file_name(nom,aire,"");
2331@z
2332
2333% [30.564] Reading the tfm file.  As a special case, whenever we open a
2334% tfm file, we read its first byte into `tfm_temp' right away.  TeX
2335% looks at `fbyte' before calling `fget', so it ends up seeing every
2336% byte.  This is Pascal-like I/O.
2337@x [30.564] l.10956 - reading the tfm file, define fget & fbyte
2338@d fget==get(tfm_file)
2339@d fbyte==tfm_file^
2340@y
2341@d fget==tfm_temp:=getc(tfm_file)
2342@d fbyte==tfm_temp
2343@z
2344
2345@x [30.570] l.11064 - MLTeX: fix for bug while loading font
2346  begin qw:=char_info(f)(d);
2347@y
2348  begin qw:=orig_char_info(f)(d);
2349@z
2350
2351@x [30.573] l.11116 - MLTeX: fix for bug while loading font
2352  qw:=char_info(f)(#); {N.B.: not |qi(#)|}
2353@y
2354  qw:=orig_char_info(f)(#); {N.B.: not |qi(#)|}
2355@z
2356
2357% [30.575] We only want `eof' on the TFM file to be true if we
2358% previously had EOF, not if we're at EOF now.  This is like `feof', and
2359% unlike our implementation of `eof' elsewhere.
2360@x [30.575] l.11180 - Reading the tfm file, replace eof() by feof().
2361if eof(tfm_file) then abort;
2362@y
2363if feof(tfm_file) then abort;
2364@z
2365
2366@x [30.576] l.11180 - MLTeX: fix for bug while loading font
2367  begin qw:=char_info(f)(bchar); {N.B.: not |qi(bchar)|}
2368@y
2369  begin qw:=orig_char_info(f)(bchar); {N.B.: not |qi(bchar)|}
2370@z
2371
2372@x [30.582] l.11276 - MLTeX: call |effective_char| in |new_character|
2373@p function new_character(@!f:internal_font_number;@!c:eight_bits):pointer;
2374label exit;
2375var p:pointer; {newly allocated node}
2376begin if font_bc[f]<=c then if font_ec[f]>=c then
2377  if char_exists(char_info(f)(qi(c))) then
2378@y
2379
2380This allows a character node to be used if there is an equivalent
2381in the |char_sub_code| list.
2382
2383@p function new_character(@!f:internal_font_number;@!c:eight_bits):pointer;
2384label exit;
2385var p:pointer; {newly allocated node}
2386@!ec:quarterword;  {effective character of |c|}
2387begin ec:=effective_char(false,f,qi(c));
2388if font_bc[f]<=qo(ec) then if font_ec[f]>=qo(ec) then
2389  if char_exists(orig_char_info(f)(ec)) then  {N.B.: not |char_info|}
2390@z
2391
2392@x [32.592] l.11820 - font numbers can be >255 now.
2393@!c,@!f:quarterword; {character and font in current |char_node|}
2394@y
2395 {character and font in current |char_node|}
2396@!c:quarterword;
2397@!f:internal_font_number;
2398@z
2399
2400@x [32.595] l.11860 - texarray
2401@!dvi_buf:array[dvi_index] of eight_bits; {buffer for \.{DVI} output}
2402@!half_buf:dvi_index; {half of |dvi_buf_size|}
2403@!dvi_limit:dvi_index; {end of the current half buffer}
2404@!dvi_ptr:dvi_index; {the next available buffer address}
2405@y
2406@!dvi_buf:^eight_bits; {buffer for \.{DVI} output}
2407@!half_buf:integer; {half of |dvi_buf_size|}
2408@!dvi_limit:integer; {end of the current half buffer}
2409@!dvi_ptr:integer; {the next available buffer address}
2410@z
2411
2412@x [32.597] l.11886 - write_dvi done in C.
2413@p procedure write_dvi(@!a,@!b:dvi_index);
2414var k:dvi_index;
2415begin for k:=a to b do write(dvi_file,dvi_buf[k]);
2416end;
2417@y
2418In C, we use a macro to call |fwrite| or |write| directly, writing all
2419the bytes in one shot.  Much better even than writing four
2420bytes at a time.
2421@z
2422
2423@x [32.601] l.11911 - check dvi file size
2424each time, we use the macro |dvi_out|.
2425@y
2426each time, we use the macro |dvi_out|.
2427
2428The length of |dvi_file| should not exceed |@"7FFFFFFF|; we set |cur_s:=-2|
2429to prevent further \.{DVI} output causing infinite recursion.
2430@z
2431
2432@x [32.601] l.11918 - dvi_swap: check dvi file size
2433begin if dvi_limit=dvi_buf_size then
2434@y
2435begin if dvi_ptr>(@"7FFFFFFF-dvi_offset) then
2436  begin cur_s:=-2;
2437  fatal_error("dvi length exceeds ""7FFFFFFF");
2438@.dvi length exceeds...@>
2439  end;
2440if dvi_limit=dvi_buf_size then
2441@z
2442
2443@x [32.602] l.11932 -  empty the last bytes: check dvi file size
2444if dvi_ptr>0 then write_dvi(0,dvi_ptr-1)
2445@y
2446if dvi_ptr>(@"7FFFFFFF-dvi_offset) then
2447  begin cur_s:=-2;
2448  fatal_error("dvi length exceeds ""7FFFFFFF");
2449@.dvi length exceeds...@>
2450  end;
2451if dvi_ptr>0 then write_dvi(0,dvi_ptr-1)
2452@z
2453
2454@x [32.602] l.11944 - Allow for outputting more than 256 fonts.
2455begin dvi_out(fnt_def1);
2456dvi_out(f-font_base-1);@/
2457@y
2458begin if f<=256+font_base then
2459  begin dvi_out(fnt_def1);
2460  dvi_out(f-font_base-1);
2461  end
2462else begin dvi_out(fnt_def1+1);
2463  dvi_out((f-font_base-1) div @'400);
2464  dvi_out((f-font_base-1) mod @'400);
2465  end;
2466@z
2467
2468@x [32.617] l.12280 - Use output_comment if the user set it. Assume it's short enough.
2469  old_setting:=selector; selector:=new_string;
2470@y
2471if output_comment then
2472  begin l:=strlen(output_comment); dvi_out(l);
2473  for s:=0 to l-1 do dvi_out(output_comment[s]);
2474  end
2475else begin {the default code is unchanged}
2476  old_setting:=selector; selector:=new_string;
2477@z
2478
2479@x [32.617] l.12288 - Use output_comment if the user set it.
2480  end
2481@y
2482end;
2483  end
2484@z
2485
2486@x [32.619] l.12294 - MLTeX: substitute character in |hlist_out|
2487procedure hlist_out; {output an |hlist_node| box}
2488label reswitch, move_past, fin_rule, next_p;
2489@y
2490procedure hlist_out; {output an |hlist_node| box}
2491label reswitch, move_past, fin_rule, next_p, continue, found;
2492@z
2493
2494@x [32.620] l.12326 - MLTeX: replace virtual character in |hlist_out|
2495reaching a non-|char_node|. The program uses the fact that |set_char_0=0|.
2496@^inner loop@>
2497@y
2498reaching a non-|char_node|. The program uses the fact that |set_char_0=0|.
2499
2500In ML\TeX{} this part looks for the existence of a substitution
2501definition for a character |c|, if |c| does not exist in the font,
2502and create appropriate \.{DVI} commands.  Former versions of ML\TeX{}
2503have spliced appropriate character, kern, and box nodes into the
2504horizontal list.
2505%
2506% 91/05/08 \charsubdefmax bug detected by Bernd Raichle
2507Because the user can change character substitions or
2508\.{\\charsubdefmax} on the fly, we have to test a again
2509for valid substitutions.
2510%
2511% 93/10/29 \leaders bug detected by Eberhard Mattes
2512(Additional it is necessary to be careful---if leaders are used
2513the current hlist is normally traversed more than once!)
2514@^inner loop@>
2515@z
2516
2517@x [32.620] l.12334 - MLTeX: substitute character during |shipout|
2518  if c>=qi(128) then dvi_out(set1);
2519  dvi_out(qo(c));@/
2520  cur_h:=cur_h+char_width(f)(char_info(f)(c));
2521@y
2522  if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
2523    if char_exists(orig_char_info(f)(c)) then  {N.B.: not |char_info|}
2524      begin if c>=qi(128) then dvi_out(set1);
2525      dvi_out(qo(c));@/
2526      cur_h:=cur_h+char_width(f)(orig_char_info(f)(c));
2527      goto continue;
2528      end;
2529  if mltex_enabled_p then
2530    @<Output a substitution, |goto continue| if not possible@>;
2531continue:
2532@z
2533
2534@x [32.622] l.12349 - more >256 font output stuff.
2535else  begin dvi_out(fnt1); dvi_out(f-font_base-1);
2536  end;
2537@y
2538else if f<=256+font_base then
2539  begin dvi_out(fnt1); dvi_out(f-font_base-1);
2540  end
2541else begin dvi_out(fnt1+1);
2542  dvi_out((f-font_base-1) div @'400);
2543  dvi_out((f-font_base-1) mod @'400);
2544  end;
2545@z
2546
2547% We output each portion of the page as we get to it, if we are using
2548% IPC, so that the previewer (TeXView) can display it immediately. [SPM]
2549@x [32.640] l.12723 - IPC
2550done:
2551@y
2552ifdef ('IPC')
2553if ipc_on>0 then
2554  begin if dvi_limit=half_buf then
2555    begin write_dvi(half_buf, dvi_buf_size-1);
2556    flush_dvi;
2557    dvi_gone:=dvi_gone+half_buf;
2558    end;
2559  if dvi_ptr>(@"7FFFFFFF-dvi_offset) then
2560    begin cur_s:=-2;
2561    fatal_error("dvi length exceeds ""7FFFFFFF");
2562@.dvi length exceeds...@>
2563    end;
2564  if dvi_ptr>0 then
2565    begin write_dvi(0, dvi_ptr-1);
2566    flush_dvi;
2567    dvi_offset:=dvi_offset+dvi_ptr; dvi_gone:=dvi_gone+dvi_ptr;
2568    end;
2569  dvi_ptr:=0; dvi_limit:=dvi_buf_size;
2570  ipc_page(dvi_gone);
2571  end;
2572endif ('IPC');
2573done:
2574@z
2575
2576@x [32.645] l.12766 - check dvi file size
2577else  begin dvi_out(post); {beginning of the postamble}
2578@y
2579else if cur_s<>-2 then
2580  begin dvi_out(post); {beginning of the postamble}
2581@z
2582
2583@x [32.645] l.12775 - Use dvi_offset instead of dvi_buf_size with IPC stuff.
2584  k:=4+((dvi_buf_size-dvi_ptr) mod 4); {the number of 223's}
2585@y
2586ifdef ('IPC')
2587  k:=7-((3+dvi_offset+dvi_ptr) mod 4); {the number of 223's}
2588endif ('IPC')
2589ifndef ('IPC')
2590  k:=4+((dvi_buf_size-dvi_ptr) mod 4); {the number of 223's}
2591endifn ('IPC')
2592@z
2593
2594@x [32.645] l.12780 - use print_file_name
2595  print_nl("Output written on "); slow_print(output_file_name);
2596@y
2597  print_nl("Output written on "); print_file_name(0, output_file_name, 0);
2598@z
2599
2600@x [32.645] l.12782 - i18n fix
2601  print(" ("); print_int(total_pages); print(" page");
2602  if total_pages<>1 then print_char("s");
2603@y
2604  print(" ("); print_int(total_pages);
2605  if total_pages<>1 then print(" pages")
2606  else print(" page");
2607@z
2608
2609% The MLTeX changes never dealt with the problems of character
2610% substitutions in math mode.  With the new additions in v2.2,
2611% non-existing characters between |font_bc[f]| and |font_ec[f]|
2612% can be substituted => we have to avoid this in math mode
2613% (for compatibility reasons and to avoid other problems).
2614%
2615@x [35.708] l.13903 - MLTeX: avoid substitution in |var_delimiter|
2616if (qo(y)>=font_bc[g])and(qo(y)<=font_ec[g]) then
2617  begin continue: q:=char_info(g)(y);
2618@y
2619if (qo(y)>=font_bc[g])and(qo(y)<=font_ec[g]) then
2620  begin continue: q:=orig_char_info(g)(y);
2621@z
2622
2623@x [36.722] l.14207 - MLTeX: avoid substitution in |fetch|
2624    cur_i:=char_info(cur_f)(cur_c)
2625@y
2626    cur_i:=orig_char_info(cur_f)(cur_c)
2627@z
2628
2629@x [36.740] l.14486 - MLTeX: avoid substitution in |make_math_accent|
2630  i:=char_info(f)(y);
2631@y
2632  i:=orig_char_info(f)(y);
2633@z
2634
2635@x [36.749] l.14638 - MLTeX: avoid substitution in |make_op|
2636    begin c:=rem_byte(cur_i); i:=char_info(cur_f)(c);
2637@y
2638    begin c:=rem_byte(cur_i); i:=orig_char_info(cur_f)(c);
2639@z
2640
2641% disabled in original tex-src-special.ch
2642 @x [37.774] l.15291 - source specials
2643if every_cr<>null then begin_token_list(every_cr,every_cr_text);
2644 @y
2645if (insert_src_special_every_cr and head<>tail) then insert_src_special;
2646if every_cr<>null then begin_token_list(every_cr,every_cr_text);
2647 @z
2648
2649% disabled in original tex-source-special.ch
2650 @x [37.799] l.15682 - source specials
2651if every_cr<>null then begin_token_list(every_cr,every_cr_text);
2652 @y
2653if (insert_src_special_every_cr) then insert_src_special;
2654if every_cr<>null then begin_token_list(every_cr,every_cr_text);
2655 @z
2656
2657@x [42.920] l.18056 - bigtrie: allow larger hyphenation tries.
2658Comparatively few different number sequences $n_0\ldots n_k$ actually occur,
2659since most of the |n|'s are generally zero. Therefore the number sequences
2660are encoded in such a way that |trie_op|$(z_k)$ is only one byte long.
2661If |trie_op(@t$z_k$@>)<>min_quarterword|, when $p_1\ldots p_k$ has matched
2662the letters in |hc[(l-k+1)..l@,]| of language |t|,
2663we perform all of the required operations
2664for this pattern by carrying out the following little program: Set
2665|v:=trie_op(@t$z_k$@>)|. Then set |v:=v+op_start[t]|,
2666|hyf[l-hyf_distance[v]]:=@tmax@>(hyf[l-hyf_distance[v]], hyf_num[v])|,
2667and |v:=hyf_next[v]|; repeat, if necessary, until |v=min_quarterword|.
2668@y
2669The theory that comparatively few different number sequences $n_0\ldots n_k$
2670actually occur, since most of the |n|'s are generally zero, seems to fail
2671at least for the large German hyphenation patterns.
2672Therefore the number sequences cannot any longer be encoded in such a way
2673that |trie_op|$(z_k)$ is only one byte long.
2674We have introduced a new constant |max_trie_op| for the maximum allowable
2675hyphenation operation code value; |max_trie_op| might be different for
2676\TeX\ and \.{INITEX} and must not exceed |max_halfword|.
2677An opcode will occupy a halfword if |max_trie_op| exceeds |max_quarterword|
2678or a quarterword otherwise.
2679@^system dependencies@>
2680If |trie_op(@t$z_k$@>)<>min_trie_op|, when $p_1\ldots p_k$ has matched
2681the letters in |hc[(l-k+1)..l@,]| of language |t|,
2682we perform all of the required operations
2683for this pattern by carrying out the following little program: Set
2684|v:=trie_op(@t$z_k$@>)|. Then set |v:=v+op_start[t]|,
2685|hyf[l-hyf_distance[v]]:=@tmax@>(hyf[l-hyf_distance[v]], hyf_num[v])|,
2686and |v:=hyf_next[v]|; repeat, if necessary, until |v=min_trie_op|.
2687@z
2688
2689@x [42.920] l.18068 - bigtrie: allow larger hyphenation tries.
2690@!trie_pointer=0..trie_size; {an index into |trie|}
2691@y
2692@!trie_pointer=0..ssup_trie_size; {an index into |trie|}
2693@!trie_opcode=0..ssup_trie_opcode;  {a trie opcode}
2694@z
2695
2696@x [42.921] l.18070 - bigtrie: allow larger hyphenation tries.
2697@ @d trie_link(#)==trie[#].rh {``downward'' link in a trie}
2698@d trie_char(#)==trie[#].b1 {character matched at this trie location}
2699@d trie_op(#)==trie[#].b0 {program for hyphenation at this trie location}
2700@y
2701@ For more than 255 trie op codes, the three fields |trie_link|, |trie_char|,
2702and |trie_op| will no longer fit into one memory word; thus using web2c
2703we define |trie| as three array instead of an array of records.
2704The variant will be implented by reusing the opcode field later on with
2705another macro.
2706
2707@d trie_link(#)==trie_trl[#] {``downward'' link in a trie}
2708@d trie_char(#)==trie_trc[#] {character matched at this trie location}
2709@d trie_op(#)==trie_tro[#] {program for hyphenation at this trie location}
2710@z
2711
2712@x [42.921] l.18075 - bigtrie: allow larger hyphenation tries.
2713@!trie:array[trie_pointer] of two_halves; {|trie_link|, |trie_char|, |trie_op|}
2714@y
2715{We will dynamically allocate these arrays.}
2716@!trie_trl:^trie_pointer; {|trie_link|}
2717@!trie_tro:^trie_pointer; {|trie_op|}
2718@!trie_trc:^quarterword; {|trie_char|}
2719@z
2720
2721@x [42.921] l.18078 - bigtrie: allow larger hyphenation tries.
2722@!hyf_next:array[1..trie_op_size] of quarterword; {continuation code}
2723@y
2724@!hyf_next:array[1..trie_op_size] of trie_opcode; {continuation code}
2725@z
2726
2727@x [42.923] l.18099 - bigtrie: allow larger hyphenation tries.
2728    begin if trie_op(z)<>min_quarterword then
2729@y
2730    begin if trie_op(z)<>min_trie_op then
2731@z
2732
2733@x [42.924] l.18112 - bigtrie: allow larger hyphenation tries.
2734until v=min_quarterword;
2735@y
2736until v=min_trie_op;
2737@z
2738
2739%%%%%%%% dynamic hyph_size
2740@x 18126 m.925
2741different from $\alpha$, we can conclude that $\alpha$ is not in the table.
2742@y  18126
2743different from $\alpha$, we can conclude that $\alpha$ is not in the table.
2744This is a clever scheme which saves the need for a hash link array.
2745However, it is difficult to increase the size of the hyphen exception
2746arrays. To make this easier, the ordered hash has been replaced by
2747a simple hash, using an additional array |hyph_link|. The value
2748|0| in |hyph_link[k]| means that there are no more entries corresponding
2749to the specific hash chain. When |hyph_link[k]>0|, the next entry in
2750the hash chain is |hyph_link[k]-1|. This value is used because the
2751arrays start at |0|.
2752@z
2753
2754%%%%%%%% dynamic hyph_size
2755@x 18134 m.925
2756@!hyph_pointer=0..hyph_size; {an index into the ordered hash table}
2757@y  18134
2758@!hyph_pointer=0..ssup_hyph_size; {index into hyphen exceptions hash table;
2759                     enlarging this requires changing (un)dump code}
2760@z
2761
2762%%%%%%%% dynamic hyph_size
2763@x 18137 m.926
2764@!hyph_word:array[hyph_pointer] of str_number; {exception words}
2765@!hyph_list:array[hyph_pointer] of pointer; {lists of hyphen positions}
2766@!hyph_count:hyph_pointer; {the number of words in the exception dictionary}
2767@y  18139
2768@!hyph_word: ^str_number; {exception words}
2769@!hyph_list: ^pointer; {lists of hyphen positions}
2770@!hyph_link: ^hyph_pointer; {link array for hyphen exceptions hash table}
2771@!hyph_count:integer; {the number of words in the exception dictionary}
2772@!hyph_next:integer; {next free slot in hyphen exceptions hash table}
2773@z
2774
2775%%%%%%%% dynamic hyph_size
2776@x 18145 m.928
2777for z:=0 to hyph_size do
2778  begin hyph_word[z]:=0; hyph_list[z]:=null;
2779  end;
2780hyph_count:=0;
2781@y  18148
2782for z:=0 to hyph_size do
2783  begin hyph_word[z]:=0; hyph_list[z]:=null; hyph_link[z]:=0;
2784  end;
2785hyph_count:=0;
2786hyph_next:=hyph_prime+1; if hyph_next>hyph_size then hyph_next:=hyph_prime;
2787@z
2788
2789%%%%%%%% dynamic hyph_size
2790@x 18163 m.930
2791h:=hc[1]; incr(hn); hc[hn]:=cur_lang;
2792for j:=2 to hn do h:=(h+h+hc[j]) mod hyph_size;
2793loop@+  begin @<If the string |hyph_word[h]| is less than \(hc)|hc[1..hn]|,
2794    |goto not_found|; but if the two strings are equal,
2795    set |hyf| to the hyphen positions and |goto found|@>;
2796  if h>0 then decr(h)@+else h:=hyph_size;
2797  end;
2798not_found: decr(hn)
2799@y  18170
2800h:=hc[1]; incr(hn); hc[hn]:=cur_lang;
2801for j:=2 to hn do h:=(h+h+hc[j]) mod hyph_prime;
2802loop@+  begin @<If the string |hyph_word[h]| is less than \(hc)|hc[1..hn]|,
2803    |goto not_found|; but if the two strings are equal,
2804    set |hyf| to the hyphen positions and |goto found|@>;
2805  h:=hyph_link[h]; if h=0 then goto not_found;
2806  decr(h);
2807  end;
2808not_found: decr(hn)
2809@z
2810
2811@x [42.931] l.18206 - dynamic hyph_size
2812@ @<If the string |hyph_word[h]| is less than \(hc)...@>=
2813k:=hyph_word[h]; if k=0 then goto not_found;
2814if length(k)<hn then goto not_found;
2815@y
2816@ @<If the string |hyph_word[h]| is less than \(hc)...@>=
2817{This is now a simple hash list, not an ordered one, so
2818the module title is no longer descriptive.}
2819k:=hyph_word[h]; if k=0 then goto not_found;
2820@z
2821
2822@x [42.931] l.18211 - dynamic hyph_size
2823  repeat if so(str_pool[u])<hc[j] then goto not_found;
2824  if so(str_pool[u])>hc[j] then goto done;
2825@y
2826  repeat
2827  if so(str_pool[u])<>hc[j] then goto done;
2828@z
2829
2830%%%%%%%% dynamic hyph_size
2831@x 18245 m.934
2832@!s,@!t:str_number; {strings being compared or stored}
2833@y
2834@!s:str_number; {strings being compared or stored}
2835@z
2836
2837%%%%%%%% dynamic hyph_size
2838@x 18274 m.939
2839  begin h:=(h+h+hc[j]) mod hyph_size;
2840@y  18274
2841  begin h:=(h+h+hc[j]) mod hyph_prime;
2842@z
2843
2844%%%%%%%% dynamic hyph_size
2845@x 18281 m.940
2846@ @<Insert the \(p)pair |(s,p)|...@>=
2847if hyph_count=hyph_size then overflow("exception dictionary",hyph_size);
2848@:TeX capacity exceeded exception dictionary}{\quad exception dictionary@>
2849incr(hyph_count);
2850while hyph_word[h]<>0 do
2851  begin @<If the string |hyph_word[h]| is less than \(or)or equal to
2852  |s|, interchange |(hyph_word[h],hyph_list[h])| with |(s,p)|@>;
2853  if h>0 then decr(h)@+else h:=hyph_size;
2854  end;
2855hyph_word[h]:=s; hyph_list[h]:=p
2856@y  18290
2857@ @<Insert the \(p)pair |(s,p)|...@>=
2858  if hyph_next <= hyph_prime then
2859     while (hyph_next>0) and (hyph_word[hyph_next-1]>0) do decr(hyph_next);
2860if (hyph_count=hyph_size)or(hyph_next=0) then
2861   overflow("exception dictionary",hyph_size);
2862@:TeX capacity exceeded exception dictionary}{\quad exception dictionary@>
2863incr(hyph_count);
2864while hyph_word[h]<>0 do
2865  begin @<If the string |hyph_word[h]| is less than \(or)or equal to
2866  |s|, interchange |(hyph_word[h],hyph_list[h])| with |(s,p)|@>;
2867  if hyph_link[h]=0 then
2868  begin
2869    hyph_link[h]:=hyph_next;
2870    if hyph_next >= hyph_size then hyph_next:=hyph_prime;
2871    if hyph_next > hyph_prime then incr(hyph_next);
2872  end;
2873  h:=hyph_link[h]-1;
2874  end;
2875
2876found: hyph_word[h]:=s; hyph_list[h]:=p
2877@z
2878
2879@x [42.941] l.18326 - dynamic hyph_size
2880@ @<If the string |hyph_word[h]| is less than \(or)...@>=
2881k:=hyph_word[h];
2882if length(k)<length(s) then goto found;
2883if length(k)>length(s) then goto not_found;
2884@y
2885@ @<If the string |hyph_word[h]| is less than \(or)...@>=
2886{This is now a simple hash list, not an ordered one, so
2887the module title is no longer descriptive.}
2888k:=hyph_word[h];
2889if length(k)<>length(s) then goto not_found;
2890@z
2891
2892@x [42.941] l.18331 - dynamic hyph_size
2893repeat if str_pool[u]<str_pool[v] then goto found;
2894if str_pool[u]>str_pool[v] then goto not_found;
2895@y
2896repeat if str_pool[u]<>str_pool[v] then goto not_found;
2897@z
2898
2899@x [42.941] l.18335 - dynamic hyph_size
2900found:q:=hyph_list[h]; hyph_list[h]:=p; p:=q;@/
2901t:=hyph_word[h]; hyph_word[h]:=s; s:=t;
2902not_found:
2903@y
2904{repeat hyphenation exception; flushing old data}
2905flush_string; s:=hyph_word[h]; {avoid |slow_make_string|!}
2906decr(hyph_count);
2907{ We could also |flush_list(hyph_list[h]);|, but it interferes
2908  with \.{trip.log}. }
2909goto found;
2910not_found:
2911@z
2912
2913@x [43.943] l.18332 - bigtrie: Larger tries, also in documentation parts.
2914|hyf_next[@t$v^\prime$@>]=min_quarterword|.
2915@y
2916|hyf_next[@t$v^\prime$@>]=min_trie_op|.
2917@z
2918
2919@x [43.943] l.18336 - bigtrie: Larger tries, also in documentation parts.
2920$$\hbox{|@t$v^\prime$@>:=new_trie_op(0,1,min_quarterword)|,\qquad
2921@y
2922$$\hbox{|@t$v^\prime$@>:=new_trie_op(0,1,min_trie_op)|,\qquad
2923@z
2924
2925@x [43.943] l.18346 - web2c can't parse negative lower bounds in arrays.  Sorry.
2926@!init@! trie_op_hash:array[-trie_op_size..trie_op_size] of 0..trie_op_size;
2927@y
2928@!init@! trie_op_hash:array[neg_trie_op_size..trie_op_size] of 0..trie_op_size;
2929@z
2930
2931@x [43.943] l.18348 - bigtrie: Larger hyphenation tries.
2932@!trie_used:array[ASCII_code] of quarterword;
2933@y
2934@!trie_used:array[ASCII_code] of trie_opcode;
2935@z
2936
2937@x [43.943] l.18352 - bigtrie: Larger hyphenation tries.
2938@!trie_op_val:array[1..trie_op_size] of quarterword;
2939@y
2940@!trie_op_val:array[1..trie_op_size] of trie_opcode;
2941@z
2942
2943@x [43.943] l.18355 - Dynamic trie arrays
2944tini
2945@y
2946tini@;
2947@!max_op_used:trie_opcode; {largest opcode used for any language}
2948@!small_op:boolean; {flag used while dumping or undumping}
2949@z
2950
2951@x [43.944] l.18358 - bigtrie: Larger tries, also in documentation parts.
2952|new_trie_op| could return |min_quarterword| (thereby simply ignoring
2953@y
2954|new_trie_op| could return |min_trie_op| (thereby simply ignoring
2955@z
2956
2957@x [43.944] l.18365 - bigtrie: Larger hyphenation tries.
2958function new_trie_op(@!d,@!n:small_number;@!v:quarterword):quarterword;
2959label exit;
2960var h:-trie_op_size..trie_op_size; {trial hash location}
2961@!u:quarterword; {trial op code}
2962@y
2963function new_trie_op(@!d,@!n:small_number;@!v:trie_opcode):trie_opcode;
2964label exit;
2965var h:neg_trie_op_size..trie_op_size; {trial hash location}
2966@!u:trie_opcode; {trial op code}
2967@z
2968
2969@x [43.944] l.18370 - Another casting problem, and use |neg_trie_op_size|.
2970begin h:=abs(n+313*d+361*v+1009*cur_lang) mod (trie_op_size+trie_op_size)
2971  - trie_op_size;
2972@y
2973begin h:=abs(n+313*d+361*v+1009*cur_lang) mod (trie_op_size-neg_trie_op_size)
2974  + neg_trie_op_size;
2975@z
2976
2977@x [43.944] l.18377 - bigtrie: And larger tries again.
2978    if u=max_quarterword then
2979      overflow("pattern memory ops per language",
2980        max_quarterword-min_quarterword);
2981    incr(trie_op_ptr); incr(u); trie_used[cur_lang]:=u;
2982@y
2983    if u=max_trie_op then
2984      overflow("pattern memory ops per language",
2985      max_trie_op-min_trie_op);
2986    incr(trie_op_ptr); incr(u); trie_used[cur_lang]:=u;
2987    if u>max_op_used then max_op_used:=u;
2988@z
2989
2990@x [43.945] l.18399 - bigtrie: And larger tries again.
2991op_start[0]:=-min_quarterword;
2992@y
2993op_start[0]:=-min_trie_op;
2994@z
2995
2996@x [43.946] l.18416 - bigtrie: And larger tries again.
2997for k:=0 to 255 do trie_used[k]:=min_quarterword;
2998@y
2999for k:=0 to 255 do trie_used[k]:=min_trie_op;
3000@z
3001
3002@x [43.946] l.18417 - Dynamic trie arrays.
3003trie_op_ptr:=0;
3004@y
3005max_op_used:=min_trie_op;
3006trie_op_ptr:=0;
3007@z
3008
3009@x [43.947] l.18438 - Dynamically allocate arrays, and a casting problem.
3010@!init @!trie_c:packed array[trie_pointer] of packed_ASCII_code;
3011  {characters to match}
3012@t\hskip10pt@>@!trie_o:packed array[trie_pointer] of quarterword;
3013  {operations to perform}
3014@t\hskip10pt@>@!trie_l:packed array[trie_pointer] of trie_pointer;
3015  {left subtrie links}
3016@t\hskip10pt@>@!trie_r:packed array[trie_pointer] of trie_pointer;
3017  {right subtrie links}
3018@t\hskip10pt@>@!trie_ptr:trie_pointer; {the number of nodes in the trie}
3019@t\hskip10pt@>@!trie_hash:packed array[trie_pointer] of trie_pointer;
3020  {used to identify equivalent subtries}
3021tini
3022@y
3023@!init @!trie_c:^packed_ASCII_code;
3024  {characters to match}
3025@t\hskip10pt@>@!trie_o:^trie_opcode;
3026  {operations to perform}
3027@t\hskip10pt@>@!trie_l:^trie_pointer;
3028  {left subtrie links}
3029@t\hskip10pt@>@!trie_r:^trie_pointer;
3030  {right subtrie links}
3031@t\hskip10pt@>@!trie_ptr:trie_pointer; {the number of nodes in the trie}
3032@t\hskip10pt@>@!trie_hash:^trie_pointer;
3033  {used to identify equivalent subtries}
3034tini
3035@z
3036
3037@x [43.950] l.18521 - Dynamically allocate & larger tries.
3038@d trie_back(#)==trie[#].lh {backward links in |trie| holes}
3039@y
3040@d trie_back(#)==trie_tro[#] {use the opcode field now for backward links}
3041@z
3042
3043@x [43.590] l.18524 - Dynamically allocate & larger tries.
3044@!init@!trie_taken:packed array[1..trie_size] of boolean;
3045  {does a family start here?}
3046@t\hskip10pt@>@!trie_min:array[ASCII_code] of trie_pointer;
3047  {the first possible slot for each character}
3048@t\hskip10pt@>@!trie_max:trie_pointer; {largest location used in |trie|}
3049@t\hskip10pt@>@!trie_not_ready:boolean; {is the trie still in linked form?}
3050tini
3051@y
3052@!init@!trie_taken: ^boolean;
3053  {does a family start here?}
3054@t\hskip10pt@>@!trie_min:array[ASCII_code] of trie_pointer;
3055  {the first possible slot for each character}
3056@t\hskip10pt@>@!trie_max:trie_pointer; {largest location used in |trie|}
3057@t\hskip10pt@>@!trie_not_ready:boolean; {is the trie still in linked form?}
3058tini
3059@z
3060
3061@x [43.951] l.18539 - Dynamically allocate.
3062trie_not_ready:=true; trie_root:=0; trie_c[0]:=si(0); trie_ptr:=0;
3063@y
3064trie_not_ready:=true;
3065@z
3066
3067@x [43.958] l.18634 - bigtrie: Larger tries.
3068@<Move the data into |trie|@>=
3069h.rh:=0; h.b0:=min_quarterword; h.b1:=min_quarterword; {|trie_link:=0|,
3070  |trie_op:=min_quarterword|, |trie_char:=qi(0)|}
3071@y
3072@d clear_trie == {clear |trie[r]|}
3073  begin trie_link(r):=0;
3074  trie_op(r):=min_trie_op;
3075  trie_char(r):=min_quarterword; {|trie_char:=qi(0)|}
3076  end
3077
3078@<Move the data into |trie|@>=
3079@z
3080
3081@x [43.958] l.18638 - bigtrie: Larger tries.
3082  begin for r:=0 to 256 do trie[r]:=h;
3083@y
3084  begin for r:=0 to 256 do clear_trie;
3085@z
3086
3087@x [43.958] l.18643 - bigtrie: Larger tries.
3088  repeat s:=trie_link(r); trie[r]:=h; r:=s;
3089@y
3090  repeat s:=trie_link(r); clear_trie; r:=s;
3091@z
3092
3093@x [43.960] l.18677 - bigtrie: Larger tries.
3094@!v:quarterword; {trie op code}
3095@y
3096@!v:trie_opcode; {trie op code}
3097@z
3098
3099@x [43.963] l.18749 - bigtrie: Larger tries.
3100if trie_o[q]<>min_quarterword then
3101@y
3102if trie_o[q]<>min_trie_op then
3103@z
3104
3105@x [43.964] l.18762 - bigtrie: Larger tries.
3106trie_c[p]:=si(c); trie_o[p]:=min_quarterword;
3107@y
3108trie_c[p]:=si(c); trie_o[p]:=min_trie_op;
3109@z
3110
3111@x [43.965] l.18768 - bigtrie: Larger tries.
3112l:=k; v:=min_quarterword;
3113@y
3114l:=k; v:=min_trie_op;
3115@z
3116
3117@x [43.966] l.18786 - bigtrie: Larger tries.
3118@!h:two_halves; {template used to zero out |trie|'s holes}
3119@y
3120@z
3121
3122%%
3123%% We can rewrite the original code after "main_loop_move+2" upto the
3124%% "tail_append(lig_stack)" in module 1036 as
3125%%
3126%
3127% main_loop_move+2:
3128% if font_bc[main_f]<=cur_chr then
3129%  if cur_chr<=font_ec[main_f] then
3130%    begin  main_i:=char_info(main_f)(cur_l);
3131%    if char_exists(main_i) goto main_loop_move+3;
3132%    end;
3133% char_warning(main_f,cur_chr); free_avail(lig_stack); goto big_switch;
3134% main_loop_move+3:
3135% tail_append(lig_stack) {|main_loop_lookahead| is next}
3136%
3137%%
3138%% We can use the rewritten code above to include additional MLTeX
3139%% specific parts in the future.  Additionally it can be used when
3140%% optimizing |main_control| to minimize the call of the function
3141%% |effective_char|.
3142%%
3143%
3144%@x [46.1030] l.19977 - MLTeX: substitution in |main_control|
3145%  main_loop_move,main_loop_move+1,main_loop_move+2,main_loop_move_lig,
3146%@y
3147%  main_loop_move,main_loop_move+1,main_loop_move+2,main_loop_move+3,
3148%  main_loop_move_lig,
3149%@z
3150
3151@x [46.1034] l.20074 - source specials
3152@<Append character |cur_chr|...@>=
3153@y
3154@<Append character |cur_chr|...@>=
3155if ((head=tail) and (mode>0)) then begin
3156  if (insert_src_special_auto) then append_src_special;
3157end;
3158@z
3159
3160@x [46.1036] l.20138 - MLTeX: substitution in |main_control|
3161main_loop_move+2:if(cur_chr<font_bc[main_f])or(cur_chr>font_ec[main_f]) then
3162@y
3163main_loop_move+2:
3164if(qo(effective_char(false,main_f,qi(cur_chr)))>font_ec[main_f])or
3165  (qo(effective_char(false,main_f,qi(cur_chr)))<font_bc[main_f]) then
3166@z
3167
3168@x [46.1036] l.20141 - MLTeX: substitution in |main_control|
3169main_i:=char_info(main_f)(cur_l);
3170@y
3171main_i:=effective_char_info(main_f,cur_l);
3172@z
3173
3174@x [46.1049] l.20407 - i18n fix, see change to [16.211]
3175print("' in "); print_mode(mode);
3176@y
3177print_in_mode(mode);
3178@z
3179
3180% disabled in original tex-src-special.ch
3181 @x [47.1083] l.20966 - source specials
3182  if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text);
3183 @y
3184  if (insert_src_special_every_vbox) then insert_src_special;
3185  if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text);
3186 @z
3187
3188% disabled in original tex-src-special.ch
3189 @x [47.1083] l.20969 - source specials
3190  if every_hbox<>null then begin_token_list(every_hbox,every_hbox_text);
3191 @y
3192  if (insert_src_special_every_hbox) then insert_src_special;
3193  if every_hbox<>null then begin_token_list(every_hbox,every_hbox_text);
3194 @z
3195
3196@x [47.1091] l.21064 - source specials
3197if indented then
3198  begin tail:=new_null_box; link(head):=tail; width(tail):=par_indent;@+
3199  end;
3200@y
3201if indented then
3202  begin tail:=new_null_box; link(head):=tail; width(tail):=par_indent;
3203  if (insert_src_special_every_par) then insert_src_special;@+
3204  end;
3205@z
3206
3207% disabled in original tex-src-special.ch, conflicts with etex.
3208 @x [47.1096] l.21121 - source specials
3209  else line_break(widow_penalty);
3210 @y
3211  else begin
3212    if (insert_src_special_every_parend) then insert_src_special;
3213    line_break(widow_penalty);
3214  end;
3215 @z
3216
3217@x [48.1142] l.21697 - source specials
3218if every_math<>null then begin_token_list(every_math,every_math_text);
3219@y
3220if (insert_src_special_every_math) then insert_src_special;
3221if every_math<>null then begin_token_list(every_math,every_math_text);
3222@z
3223
3224% disabled in original tex-src-special.ch
3225 @x [48.1145] l.21705 - source specials
3226if every_display<>null then begin_token_list(every_display,every_display_text);
3227 @y
3228if (insert_src_special_every_display) then append_src_special;
3229if every_display<>null then begin_token_list(every_display,every_display_text);
3230 @z
3231
3232@x [48.1167] l.22042 - source specials
3233  if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text);
3234@y
3235  if (insert_src_special_every_vbox) then insert_src_special;
3236  if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text);
3237@z
3238
3239@x [49.1215] l.22719 - hash_extra
3240if (cur_cs=0)or(cur_cs>frozen_control_sequence) then
3241@y
3242if (cur_cs=0)or(cur_cs>eqtb_top)or
3243  ((cur_cs>frozen_control_sequence)and(cur_cs<=eqtb_size)) then
3244@z
3245
3246@x [49.1222] l.22794 - MLTeX: \charsubdef primitive
3247@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}}
3248@y
3249@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}}
3250@d char_sub_def_code=7 {|shorthand_def| for \.{\\charsubdef}}
3251@z
3252
3253@x [49.1222] l.22810 - MLTeX: \charsubdef primitive
3254@!@:toks_def_}{\.{\\toksdef} primitive@>
3255@y
3256@!@:toks_def_}{\.{\\toksdef} primitive@>
3257if mltex_p then
3258  begin
3259  primitive("charsubdef",shorthand_def,char_sub_def_code);@/
3260@!@:char_sub_def_}{\.{\\charsubdef} primitive@>
3261  end;
3262@z
3263
3264@x [49.1222] l.22820 - MLTeX: \charsubdef primitive
3265  othercases print_esc("toksdef")
3266@y
3267  char_sub_def_code: print_esc("charsubdef");
3268  othercases print_esc("toksdef")
3269@z
3270
3271@x [49.1222] l.22833 - MLTeX: \charsubdef primitive
3272shorthand_def: begin n:=cur_chr; get_r_token; p:=cur_cs; define(p,relax,256);
3273@y
3274shorthand_def: if cur_chr=char_sub_def_code then
3275 begin scan_char_num; p:=char_sub_code_base+cur_val; scan_optional_equals;
3276  scan_char_num; n:=cur_val; {accent character in substitution}
3277  scan_char_num;
3278  if (tracing_char_sub_def>0) then
3279    begin begin_diagnostic; print_nl("New character substitution: ");
3280    print_ASCII(p-char_sub_code_base); print(" = ");
3281    print_ASCII(n); print_char(" ");
3282    print_ASCII(cur_val); end_diagnostic(false);
3283    end;
3284  n:=n*256+cur_val;
3285  define(p,data,hi(n));
3286  if (p-char_sub_code_base)<char_sub_def_min then
3287    word_define(int_base+char_sub_def_min_code,p-char_sub_code_base);
3288  if (p-char_sub_code_base)>char_sub_def_max then
3289    word_define(int_base+char_sub_def_max_code,p-char_sub_code_base);
3290 end
3291else begin n:=cur_chr; get_r_token; p:=cur_cs; define(p,relax,256);
3292@z
3293
3294@x [49.1252] l.23230 - INI = VIR, so have to do runtime test.
3295    begin @!init new_patterns; goto done;@;@+tini@/
3296@y  23215
3297    begin @!Init new_patterns; goto done;@;@+Tini@/
3298@z
3299
3300% undo Knuth's change because
3301%   a) the string is already replaced in |scan_file_name| and therefore
3302%   b) the wrong string will get flushed!!!
3303%
3304@x [49.1257] l.23328 unused variable
3305@!flushable_string:str_number; {string not yet referenced}
3306@y
3307@z
3308@x [49.1260] l.23383 new_font: string recycling -- already done
3309flushable_string:=str_ptr-1;
3310@y
3311@z
3312
3313% If you don't want to remove code with the following two changes,
3314% please replace the former change by
3315%
3316% @x
3317% flushable_string:=str_ptr-1;
3318% @y
3319% if cur_name=str_ptr-1 then
3320%   flushable_string:=str_ptr-1
3321% else
3322%   flushable_string:=str_ptr;  {number of a non-existing}
3323% @z
3324%
3325% otherwise the wrong string will get removed by |flush_string|!!
3326%
3327@x [49.1260] l.23386 new_font: string recycling -- already done
3328    begin if cur_name=flushable_string then
3329      begin flush_string; cur_name:=font_name[f];
3330      end;
3331    if s>0 then
3332@y
3333    begin if s>0 then
3334@z
3335
3336@x [49.1265] if batchmode, mktex... scripts should be silent.
3337interaction:=cur_chr;
3338@y
3339interaction:=cur_chr;
3340if interaction = batch_mode
3341then kpse_make_tex_discard_errors := 1
3342else kpse_make_tex_discard_errors := 0;
3343@z
3344
3345@x [49.1275] l.23441 - Same stuff as for \input, this time for \openin.
3346  if cur_ext="" then cur_ext:=".tex";
3347  pack_cur_name;
3348  if a_open_in(read_file[n]) then read_open[n]:=just_open;
3349@y
3350  pack_cur_name;
3351  tex_input_type:=0; {Tell |open_input| we are \.{\\openin}.}
3352  if kpse_in_name_ok(stringcast(name_of_file+1))
3353     and a_open_in(read_file[n], kpse_tex_format) then
3354    read_open[n]:=just_open;
3355@z
3356
3357@x [50.1301] l.23679 - INI = VIR, so runtime test.
3358format_ident:=" (INITEX)";
3359@y
3360if ini_version then format_ident:=" (INITEX)";
3361@z
3362
3363% Eliminate now-unused variable `w' in `store_fmt_file'.
3364% Add format_engine.
3365@x [50.1302] l.23690 - store_fmt_file
3366@!w: four_quarters; {four ASCII codes}
3367@y
3368@!format_engine: ^text_char;
3369@z
3370
3371% MLTeX: dump |mltex_p| to fmt file
3372@x [50.1302] l.23694
3373@<Dump constants for consistency check@>;
3374@y
3375@<Dump constants for consistency check@>;
3376@<Dump ML\TeX-specific data@>;
3377@z
3378
3379% Eliminate now-unused variable `w' in `load_fmt_file'.
3380% Add format_engine.
3381% Add dummies for undumping |xord|, |xchr|, and |xprn| into the void.
3382@x [50.1303] l.23722 - load_fmt_file
3383@!w: four_quarters; {four ASCII codes}
3384@y
3385@!format_engine: ^text_char;
3386@!dummy_xord: ASCII_code;
3387@!dummy_xchr: text_char;
3388@!dummy_xprn: ASCII_code;
3389@z
3390
3391% MLTeX: undump |mltex_enabled_p| from fmt file
3392@x [50.1303] l.23694
3393begin @<Undump constants for consistency check@>;
3394@y
3395begin @<Undump constants for consistency check@>;
3396@<Undump ML\TeX-specific data@>;
3397@z
3398
3399@x [50.1305] l.23751 - Do dumping and undumping of fmt files in C.
3400@d dump_wd(#)==begin fmt_file^:=#; put(fmt_file);@+end
3401@d dump_int(#)==begin fmt_file^.int:=#; put(fmt_file);@+end
3402@d dump_hh(#)==begin fmt_file^.hh:=#; put(fmt_file);@+end
3403@d dump_qqqq(#)==begin fmt_file^.qqqq:=#; put(fmt_file);@+end
3404@y
3405@z
3406@x [1306]
3407@d undump_wd(#)==begin get(fmt_file); #:=fmt_file^;@+end
3408@d undump_int(#)==begin get(fmt_file); #:=fmt_file^.int;@+end
3409@d undump_hh(#)==begin get(fmt_file); #:=fmt_file^.hh;@+end
3410@d undump_qqqq(#)==begin get(fmt_file); #:=fmt_file^.qqqq;@+end
3411@y
3412@z
3413@x [still 1306] debug format file
3414@d undump_size_end_end(#)==too_small(#)@+else undump_end_end
3415@y
3416@d format_debug_end(#)==
3417    write_ln (stderr, ' = ', #);
3418  end;
3419@d format_debug(#)==
3420  if debug_format_file then begin
3421    write (stderr, 'fmtdebug:', #);
3422    format_debug_end
3423@d undump_size_end_end(#)==
3424  too_small(#)@+else format_debug (#)(x); undump_end_end
3425@z
3426
3427@x [50,1307] l.23779 - texarray
3428dump_int(@$);@/
3429@y
3430dump_int(@"57325458);  {Web2C \TeX's magic constant: "W2TX"}
3431{Align engine to 4 bytes with one or more trailing NUL}
3432x:=strlen(engine_name);
3433format_engine:=xmalloc_array(text_char,x+4);
3434strcpy(stringcast(format_engine), engine_name);
3435for k:=x to x+3 do format_engine[k]:=0;
3436x:=x+4-(x mod 4);
3437dump_int(x);dump_things(format_engine[0], x);
3438libc_free(format_engine);@/
3439dump_int(@$);@/
3440@<Dump |xord|, |xchr|, and |xprn|@>;
3441dump_int(max_halfword);@/
3442dump_int(hash_high);
3443@z
3444
3445%%%%%%%% dynamic hyph_size
3446@x 23784 m.1307
3447dump_int(hyph_size)
3448@y  23784
3449dump_int(hyph_prime)
3450@z
3451
3452@x [50.1308] l.23793 - texarray
3453x:=fmt_file^.int;
3454if x<>@$ then goto bad_fmt; {check that strings are the same}
3455@y
3456@+Init
3457libc_free(font_info); libc_free(str_pool); libc_free(str_start);
3458libc_free(yhash); libc_free(zeqtb); libc_free(yzmem);
3459@+Tini
3460undump_int(x);
3461format_debug('format magic number')(x);
3462if x<>@"57325458 then goto bad_fmt; {not a format file}
3463undump_int(x);
3464format_debug('engine name size')(x);
3465if (x<0) or (x>256) then goto bad_fmt; {corrupted format file}
3466format_engine:=xmalloc_array(text_char, x);
3467undump_things(format_engine[0], x);
3468format_engine[x-1]:=0; {force string termination, just in case}
3469if strcmp(engine_name, stringcast(format_engine)) then
3470  begin wake_up_terminal;
3471  wterm_ln('---! ', stringcast(name_of_file+1), ' was written by ', format_engine);
3472  libc_free(format_engine);
3473  goto bad_fmt;
3474end;
3475libc_free(format_engine);
3476undump_int(x);
3477format_debug('string pool checksum')(x);
3478if x<>@$ then begin {check that strings are the same}
3479  wake_up_terminal;
3480  wterm_ln('---! ', stringcast(name_of_file+1), ' doesn''t match ', pool_name);
3481  goto bad_fmt;
3482end;
3483@<Undump |xord|, |xchr|, and |xprn|@>;
3484undump_int(x);
3485if x<>max_halfword then goto bad_fmt; {check |max_halfword|}
3486undump_int(hash_high);
3487  if (hash_high<0)or(hash_high>sup_hash_extra) then goto bad_fmt;
3488  if hash_extra<hash_high then hash_extra:=hash_high;
3489  eqtb_top:=eqtb_size+hash_extra;
3490  if hash_extra=0 then hash_top:=undefined_control_sequence else
3491        hash_top:=eqtb_top;
3492  yhash:=xmalloc_array(two_halves,1+hash_top-hash_offset);
3493  hash:=yhash - hash_offset;
3494  next(hash_base):=0; text(hash_base):=0;
3495  for x:=hash_base+1 to hash_top do hash[x]:=hash[hash_base];
3496  zeqtb:=xmalloc_array (memory_word,eqtb_top+1);
3497  eqtb:=zeqtb;
3498
3499  eq_type(undefined_control_sequence):=undefined_cs;
3500  equiv(undefined_control_sequence):=null;
3501  eq_level(undefined_control_sequence):=level_zero;
3502  for x:=eqtb_size+1 to eqtb_top do
3503    eqtb[x]:=eqtb[undefined_control_sequence];
3504@z
3505
3506@x [50.1308] l.23795 - texarray
3507undump_int(x);
3508if x<>mem_bot then goto bad_fmt;
3509undump_int(x);
3510if x<>mem_top then goto bad_fmt;
3511@y
3512undump_int(x); format_debug ('mem_bot')(x);
3513if x<>mem_bot then goto bad_fmt;
3514undump_int(mem_top); format_debug ('mem_top')(mem_top);
3515if mem_bot+1100>mem_top then goto bad_fmt;
3516
3517
3518head:=contrib_head; tail:=contrib_head;
3519     page_tail:=page_head;  {page initialization}
3520
3521mem_min := mem_bot - extra_mem_bot;
3522mem_max := mem_top + extra_mem_top;
3523
3524yzmem:=xmalloc_array (memory_word, mem_max - mem_min + 1);
3525zmem := yzmem - mem_min;   {this pointer arithmetic fails with some compilers}
3526mem := zmem;
3527@z
3528
3529%%%%%%%% dynamic hyph_size
3530@x 23804 m.1308
3531if x<>hyph_size then goto bad_fmt
3532@y  23804
3533if x<>hyph_prime then goto bad_fmt
3534@z
3535
3536% [1309] Make dumping/undumping more efficient by doing whole arrays at
3537% a time, via fread/fwrite in texmfmp.c.
3538@x [50.1309] l.23814 - Make dumping/undumping more efficient.
3539for k:=0 to str_ptr do dump_int(str_start[k]);
3540k:=0;
3541while k+4<pool_ptr do
3542  begin dump_four_ASCII; k:=k+4;
3543  end;
3544k:=pool_ptr-4; dump_four_ASCII;
3545@y
3546dump_things(str_start[0], str_ptr+1);
3547dump_things(str_pool[0], pool_ptr);
3548@z
3549
3550@x [50.1310] l.23829 - Make dumping/undumping more efficient.
3551undump_size(0)(pool_size)('string pool size')(pool_ptr);
3552undump_size(0)(max_strings)('max strings')(str_ptr);
3553for k:=0 to str_ptr do undump(0)(pool_ptr)(str_start[k]);
3554k:=0;
3555while k+4<pool_ptr do
3556  begin undump_four_ASCII; k:=k+4;
3557  end;
3558k:=pool_ptr-4; undump_four_ASCII;
3559@y
3560undump_size(0)(sup_pool_size-pool_free)('string pool size')(pool_ptr);
3561if pool_size<pool_ptr+pool_free then
3562  pool_size:=pool_ptr+pool_free;
3563undump_size(0)(sup_max_strings-strings_free)('sup strings')(str_ptr);@/
3564if max_strings<str_ptr+strings_free then
3565  max_strings:=str_ptr+strings_free;
3566str_start:=xmalloc_array(pool_pointer, max_strings);
3567undump_checked_things(0, pool_ptr, str_start[0], str_ptr+1);@/
3568str_pool:=xmalloc_array(packed_ASCII_code, pool_size);
3569undump_things(str_pool[0], pool_ptr);
3570@z
3571
3572@x [50.1311] l.23850 - Make dumping/undumping more efficient.
3573repeat for k:=p to q+1 do dump_wd(mem[k]);
3574@y
3575repeat dump_things(mem[p], q+2-p);
3576@z
3577
3578@x [50.1311] l.23855 - Make dumping/undumping more efficient.
3579for k:=p to lo_mem_max do dump_wd(mem[k]);
3580@y
3581dump_things(mem[p], lo_mem_max+1-p);
3582@z
3583
3584@x [50.1311] l.23858 - Make dumping/undumping more efficient.
3585for k:=hi_mem_min to mem_end do dump_wd(mem[k]);
3586@y
3587dump_things(mem[hi_mem_min], mem_end+1-hi_mem_min);
3588@z
3589
3590@x [50.1312] l.23873 - Make dumping/undumping more efficient.
3591repeat for k:=p to q+1 do undump_wd(mem[k]);
3592@y
3593repeat undump_things(mem[p], q+2-p);
3594@z
3595
3596@x [50.1312] l.23878 - Make dumping/undumping more efficient.
3597for k:=p to lo_mem_max do undump_wd(mem[k]);
3598@y
3599undump_things(mem[p], lo_mem_max+1-p);
3600@z
3601
3602@x [50.1312] l.23888 - Make dumping/undumping more efficient.
3603for k:=hi_mem_min to mem_end do undump_wd(mem[k]);
3604@y
3605undump_things (mem[hi_mem_min], mem_end+1-hi_mem_min);
3606@z
3607
3608@x [50.1314] l.23899 - hash_extra, source specials
3609undump(hash_base)(frozen_control_sequence)(par_loc);
3610par_token:=cs_token_flag+par_loc;@/
3611undump(hash_base)(frozen_control_sequence)(write_loc);@/
3612@y
3613undump(hash_base)(hash_top)(par_loc);
3614par_token:=cs_token_flag+par_loc;@/
3615undump(hash_base)(hash_top)(write_loc);@/
3616@z
3617
3618@x [50.1315] l.23925 - Make dumping/undumping more efficient - eqtb
3619while k<l do
3620  begin dump_wd(eqtb[k]); incr(k);
3621  end;
3622@y
3623dump_things(eqtb[k], l-k);
3624@z
3625
3626@x [50.1316] l.23944 - Make dumping/undumping more efficient - eqtb
3627while k<l do
3628  begin dump_wd(eqtb[k]); incr(k);
3629  end;
3630@y
3631dump_things(eqtb[k], l-k);
3632@z
3633
3634@x [50.1316] l.23947 - hash_extra
3635k:=j+1; dump_int(k-l);
3636until k>eqtb_size
3637@y
3638k:=j+1; dump_int(k-l);
3639until k>eqtb_size;
3640if hash_high>0 then dump_things(eqtb[eqtb_size+1],hash_high);
3641  {dump |hash_extra| part}
3642@z
3643
3644@x [50.1317] l.23958 - Make dumping/undumping more efficient - eqtb
3645for j:=k to k+x-1 do undump_wd(eqtb[j]);
3646@y
3647undump_things(eqtb[k], x);
3648@z
3649
3650@x [50.1317] l.23960 - hash_extra
3651until k>eqtb_size
3652@y
3653until k>eqtb_size;
3654if hash_high>0 then undump_things(eqtb[eqtb_size+1],hash_high);
3655  {undump |hash_extra| part}
3656@z
3657
3658@x [50.1318] l.23968 - hash_extra
3659dump_int(hash_used); cs_count:=frozen_control_sequence-1-hash_used;
3660@y  23968
3661dump_int(hash_used); cs_count:=frozen_control_sequence-1-hash_used+hash_high;
3662@z
3663
3664@x [50.1318] l.23972 - Make dumping/undumping more efficient, hash_extra
3665for p:=hash_used+1 to undefined_control_sequence-1 do dump_hh(hash[p]);
3666@y
3667dump_things(hash[hash_used+1], undefined_control_sequence-1-hash_used);
3668if hash_high>0 then dump_things(hash[eqtb_size+1], hash_high);
3669@z
3670
3671@x [50.1319] l.23980 - Make dumping/undumping more efficient, hash_extra
3672for p:=hash_used+1 to undefined_control_sequence-1 do undump_hh(hash[p]);
3673@y
3674undump_things (hash[hash_used+1], undefined_control_sequence-1-hash_used);
3675if debug_format_file then begin
3676  print_csnames (hash_base, undefined_control_sequence - 1);
3677end;
3678if hash_high > 0 then begin
3679  undump_things (hash[eqtb_size+1], hash_high);
3680  if debug_format_file then begin
3681    print_csnames (eqtb_size + 1, hash_high - (eqtb_size + 1));
3682  end;
3683end;
3684@z
3685
3686@x [50.1320] l.23985 - Make dumping/undumping more efficient - tfm
3687for k:=0 to fmem_ptr-1 do dump_wd(font_info[k]);
3688dump_int(font_ptr);
3689for k:=null_font to font_ptr do
3690  @<Dump the array info for internal font number |k|@>;
3691@y
3692dump_things(font_info[0], fmem_ptr);
3693dump_int(font_ptr);
3694@<Dump the array info for internal font number |k|@>;
3695@z
3696
3697@x [50.1320] l.23991 - i18n fix
3698print_int(font_ptr-font_base); print(" preloaded font");
3699if font_ptr<>font_base+1 then print_char("s")
3700@y
3701print_int(font_ptr-font_base);
3702if font_ptr<>font_base+1 then print(" preloaded fonts")
3703else print(" preloaded font")
3704@z
3705
3706@x [50.1321] l.23994 - texarray
3707undump_size(7)(font_mem_size)('font mem size')(fmem_ptr);
3708for k:=0 to fmem_ptr-1 do undump_wd(font_info[k]);
3709undump_size(font_base)(font_max)('font max')(font_ptr);
3710for k:=null_font to font_ptr do
3711  @<Undump the array info for internal font number |k|@>
3712@y
3713undump_size(7)(sup_font_mem_size)('font mem size')(fmem_ptr);
3714if fmem_ptr>font_mem_size then font_mem_size:=fmem_ptr;
3715font_info:=xmalloc_array(fmemory_word, font_mem_size);
3716undump_things(font_info[0], fmem_ptr);@/
3717undump_size(font_base)(font_base+max_font_max)('font max')(font_ptr);
3718{This undumps all of the font info, despite the name.}
3719@<Undump the array info for internal font number |k|@>;
3720@z
3721
3722% [50.1322] Dumping font_info.
3723% Knuth's code writes all the information relevant to a single font
3724% in the same section of the fmt file.  But it's a lot faster to
3725% write the arrays of information out, one whole array at a time.
3726% So that's the way we handle dumping and undumping font info.
3727@x [50.1322] l.24000 - Make dumping/undumping more efficient - tfm
3728@ @<Dump the array info for internal font number |k|@>=
3729begin dump_qqqq(font_check[k]);
3730dump_int(font_size[k]);
3731dump_int(font_dsize[k]);
3732dump_int(font_params[k]);@/
3733dump_int(hyphen_char[k]);
3734dump_int(skew_char[k]);@/
3735dump_int(font_name[k]);
3736dump_int(font_area[k]);@/
3737dump_int(font_bc[k]);
3738dump_int(font_ec[k]);@/
3739dump_int(char_base[k]);
3740dump_int(width_base[k]);
3741dump_int(height_base[k]);@/
3742dump_int(depth_base[k]);
3743dump_int(italic_base[k]);
3744dump_int(lig_kern_base[k]);@/
3745dump_int(kern_base[k]);
3746dump_int(exten_base[k]);
3747dump_int(param_base[k]);@/
3748dump_int(font_glue[k]);@/
3749dump_int(bchar_label[k]);
3750dump_int(font_bchar[k]);
3751dump_int(font_false_bchar[k]);@/
3752print_nl("\font"); print_esc(font_id_text(k)); print_char("=");
3753print_file_name(font_name[k],font_area[k],"");
3754if font_size[k]<>font_dsize[k] then
3755  begin print(" at "); print_scaled(font_size[k]); print("pt");
3756  end;
3757end
3758@y
3759@ @<Dump the array info for internal font number |k|@>=
3760begin
3761dump_things(font_check[null_font], font_ptr+1-null_font);
3762dump_things(font_size[null_font], font_ptr+1-null_font);
3763dump_things(font_dsize[null_font], font_ptr+1-null_font);
3764dump_things(font_params[null_font], font_ptr+1-null_font);
3765dump_things(hyphen_char[null_font], font_ptr+1-null_font);
3766dump_things(skew_char[null_font], font_ptr+1-null_font);
3767dump_things(font_name[null_font], font_ptr+1-null_font);
3768dump_things(font_area[null_font], font_ptr+1-null_font);
3769dump_things(font_bc[null_font], font_ptr+1-null_font);
3770dump_things(font_ec[null_font], font_ptr+1-null_font);
3771dump_things(char_base[null_font], font_ptr+1-null_font);
3772dump_things(width_base[null_font], font_ptr+1-null_font);
3773dump_things(height_base[null_font], font_ptr+1-null_font);
3774dump_things(depth_base[null_font], font_ptr+1-null_font);
3775dump_things(italic_base[null_font], font_ptr+1-null_font);
3776dump_things(lig_kern_base[null_font], font_ptr+1-null_font);
3777dump_things(kern_base[null_font], font_ptr+1-null_font);
3778dump_things(exten_base[null_font], font_ptr+1-null_font);
3779dump_things(param_base[null_font], font_ptr+1-null_font);
3780dump_things(font_glue[null_font], font_ptr+1-null_font);
3781dump_things(bchar_label[null_font], font_ptr+1-null_font);
3782dump_things(font_bchar[null_font], font_ptr+1-null_font);
3783dump_things(font_false_bchar[null_font], font_ptr+1-null_font);
3784for k:=null_font to font_ptr do
3785  begin print_nl("\font"); print_esc(font_id_text(k)); print_char("=");
3786  print_file_name(font_name[k],font_area[k],"");
3787  if font_size[k]<>font_dsize[k] then
3788    begin print(" at "); print_scaled(font_size[k]); print("pt");
3789    end;
3790  end;
3791end
3792@z
3793
3794@x [50.1322] l.24031 - Make dumping/undumping more efficient - tfm
3795@ @<Undump the array info for internal font number |k|@>=
3796begin undump_qqqq(font_check[k]);@/
3797undump_int(font_size[k]);
3798undump_int(font_dsize[k]);
3799undump(min_halfword)(max_halfword)(font_params[k]);@/
3800undump_int(hyphen_char[k]);
3801undump_int(skew_char[k]);@/
3802undump(0)(str_ptr)(font_name[k]);
3803undump(0)(str_ptr)(font_area[k]);@/
3804undump(0)(255)(font_bc[k]);
3805undump(0)(255)(font_ec[k]);@/
3806undump_int(char_base[k]);
3807undump_int(width_base[k]);
3808undump_int(height_base[k]);@/
3809undump_int(depth_base[k]);
3810undump_int(italic_base[k]);
3811undump_int(lig_kern_base[k]);@/
3812undump_int(kern_base[k]);
3813undump_int(exten_base[k]);
3814undump_int(param_base[k]);@/
3815undump(min_halfword)(lo_mem_max)(font_glue[k]);@/
3816undump(0)(fmem_ptr-1)(bchar_label[k]);
3817undump(min_quarterword)(non_char)(font_bchar[k]);
3818undump(min_quarterword)(non_char)(font_false_bchar[k]);
3819end
3820@y
3821@ This module should now be named `Undump all the font arrays'.
3822
3823@<Undump the array info for internal font number |k|@>=
3824begin {Allocate the font arrays}
3825font_check:=xmalloc_array(four_quarters, font_max);
3826font_size:=xmalloc_array(scaled, font_max);
3827font_dsize:=xmalloc_array(scaled, font_max);
3828font_params:=xmalloc_array(font_index, font_max);
3829font_name:=xmalloc_array(str_number, font_max);
3830font_area:=xmalloc_array(str_number, font_max);
3831font_bc:=xmalloc_array(eight_bits, font_max);
3832font_ec:=xmalloc_array(eight_bits, font_max);
3833font_glue:=xmalloc_array(halfword, font_max);
3834hyphen_char:=xmalloc_array(integer, font_max);
3835skew_char:=xmalloc_array(integer, font_max);
3836bchar_label:=xmalloc_array(font_index, font_max);
3837font_bchar:=xmalloc_array(nine_bits, font_max);
3838font_false_bchar:=xmalloc_array(nine_bits, font_max);
3839char_base:=xmalloc_array(integer, font_max);
3840width_base:=xmalloc_array(integer, font_max);
3841height_base:=xmalloc_array(integer, font_max);
3842depth_base:=xmalloc_array(integer, font_max);
3843italic_base:=xmalloc_array(integer, font_max);
3844lig_kern_base:=xmalloc_array(integer, font_max);
3845kern_base:=xmalloc_array(integer, font_max);
3846exten_base:=xmalloc_array(integer, font_max);
3847param_base:=xmalloc_array(integer, font_max);
3848
3849undump_things(font_check[null_font], font_ptr+1-null_font);
3850undump_things(font_size[null_font], font_ptr+1-null_font);
3851undump_things(font_dsize[null_font], font_ptr+1-null_font);
3852undump_checked_things(min_halfword, max_halfword,
3853                      font_params[null_font], font_ptr+1-null_font);
3854undump_things(hyphen_char[null_font], font_ptr+1-null_font);
3855undump_things(skew_char[null_font], font_ptr+1-null_font);
3856undump_upper_check_things(str_ptr, font_name[null_font], font_ptr+1-null_font);
3857undump_upper_check_things(str_ptr, font_area[null_font], font_ptr+1-null_font);
3858{There's no point in checking these values against the range $[0,255]$,
3859 since the data type is |unsigned char|, and all values of that type are
3860 in that range by definition.}
3861undump_things(font_bc[null_font], font_ptr+1-null_font);
3862undump_things(font_ec[null_font], font_ptr+1-null_font);
3863undump_things(char_base[null_font], font_ptr+1-null_font);
3864undump_things(width_base[null_font], font_ptr+1-null_font);
3865undump_things(height_base[null_font], font_ptr+1-null_font);
3866undump_things(depth_base[null_font], font_ptr+1-null_font);
3867undump_things(italic_base[null_font], font_ptr+1-null_font);
3868undump_things(lig_kern_base[null_font], font_ptr+1-null_font);
3869undump_things(kern_base[null_font], font_ptr+1-null_font);
3870undump_things(exten_base[null_font], font_ptr+1-null_font);
3871undump_things(param_base[null_font], font_ptr+1-null_font);
3872undump_checked_things(min_halfword, lo_mem_max,
3873                     font_glue[null_font], font_ptr+1-null_font);
3874undump_checked_things(0, fmem_ptr-1,
3875                     bchar_label[null_font], font_ptr+1-null_font);
3876undump_checked_things(min_quarterword, non_char,
3877                     font_bchar[null_font], font_ptr+1-null_font);
3878undump_checked_things(min_quarterword, non_char,
3879                     font_false_bchar[null_font], font_ptr+1-null_font);
3880end
3881@z
3882
3883%%%%%%%% dynamic hyph_size
3884@x 24058 m.1324
3885dump_int(hyph_count);
3886for k:=0 to hyph_size do if hyph_word[k]<>0 then
3887  begin dump_int(k); dump_int(hyph_word[k]); dump_int(hyph_list[k]);
3888  end;
3889@y  24061
3890dump_int(hyph_count);
3891if hyph_next <= hyph_prime then hyph_next:=hyph_size;
3892dump_int(hyph_next);{minumum value of |hyphen_size| needed}
3893for k:=0 to hyph_size do if hyph_word[k]<>0 then
3894  begin dump_int(k+65536*hyph_link[k]);
3895        {assumes number of hyphen exceptions does not exceed 65535}
3896   dump_int(hyph_word[k]); dump_int(hyph_list[k]);
3897  end;
3898@z
3899
3900@x [50.1324] l.24063 - i18n fix
3901print_ln; print_int(hyph_count); print(" hyphenation exception");
3902if hyph_count<>1 then print_char("s");
3903@y
3904print_ln; print_int(hyph_count);
3905if hyph_count<>1 then print(" hyphenation exceptions")
3906else print(" hyphenation exception");
3907@z
3908
3909@x [50.1324] l.24066 - Make dumping/undumping more efficient - trie
3910for k:=0 to trie_max do dump_hh(trie[k]);
3911@y
3912dump_things(trie_trl[0], trie_max+1);
3913dump_things(trie_tro[0], trie_max+1);
3914dump_things(trie_trc[0], trie_max+1);
3915@z
3916
3917@x [50.1324] l.24068 - Make dumping/undumping more efficient - trie
3918for k:=1 to trie_op_ptr do
3919  begin dump_int(hyf_distance[k]);
3920  dump_int(hyf_num[k]);
3921  dump_int(hyf_next[k]);
3922  end;
3923@y
3924dump_things(hyf_distance[1], trie_op_ptr);
3925dump_things(hyf_num[1], trie_op_ptr);
3926dump_things(hyf_next[1], trie_op_ptr);
3927@z
3928
3929@x [50.1324] l.24076 - i18n fix
3930print(" has "); print_int(trie_op_ptr); print(" op");
3931if trie_op_ptr<>1 then print_char("s");
3932@y
3933print(" has "); print_int(trie_op_ptr);
3934if trie_op_ptr<>1 then print(" ops")
3935else print(" op");
3936@z
3937
3938%%%%%%%% dynamic hyph_size
3939@x 24087 m.1325
3940undump(0)(hyph_size)(hyph_count);
3941for k:=1 to hyph_count do
3942  begin undump(0)(hyph_size)(j);
3943  undump(0)(str_ptr)(hyph_word[j]);
3944  undump(min_halfword)(max_halfword)(hyph_list[j]);
3945  end;
3946@y  24092
3947undump_size(0)(hyph_size)('hyph_size')(hyph_count);
3948undump_size(hyph_prime)(hyph_size)('hyph_size')(hyph_next);
3949j:=0;
3950for k:=1 to hyph_count do
3951  begin undump_int(j); if j<0 then goto bad_fmt;
3952   if j>65535 then
3953   begin hyph_next:= j div 65536; j:=j - hyph_next * 65536; end
3954       else hyph_next:=0;
3955   if (j>=hyph_size)or(hyph_next>hyph_size) then goto bad_fmt;
3956   hyph_link[j]:=hyph_next;
3957  undump(0)(str_ptr)(hyph_word[j]);
3958  undump(min_halfword)(max_halfword)(hyph_list[j]);
3959  end;
3960  {|j| is now the largest occupied location in |hyph_word|}
3961  incr(j);
3962  if j<hyph_prime then j:=hyph_prime;
3963  hyph_next:=j;
3964  if hyph_next >= hyph_size then hyph_next:=hyph_prime else
3965  if hyph_next >= hyph_prime then incr(hyph_next);
3966@z
3967
3968@x [50.1325] l.24094 - Make dumping/undumping more efficient - trie
3969for k:=0 to j do undump_hh(trie[k]);
3970@y
3971{These first three haven't been allocated yet unless we're \.{INITEX};
3972 we do that precisely so we don't allocate more space than necessary.}
3973if not trie_trl then trie_trl:=xmalloc_array(trie_pointer,j+1);
3974undump_things(trie_trl[0], j+1);
3975if not trie_tro then trie_tro:=xmalloc_array(trie_pointer,j+1);
3976undump_things(trie_tro[0], j+1);
3977if not trie_trc then trie_trc:=xmalloc_array(quarterword, j+1);
3978undump_things(trie_trc[0], j+1);
3979@z
3980
3981@x [50.1325] l.24096 - Make dumping/undumping more efficient - trie
3982for k:=1 to j do
3983  begin undump(0)(63)(hyf_distance[k]); {a |small_number|}
3984  undump(0)(63)(hyf_num[k]);
3985  undump(min_quarterword)(max_quarterword)(hyf_next[k]);
3986  end;
3987@y
3988{I'm not sure we have such a strict limitation (64) on these values, so
3989 let's leave them unchecked.}
3990undump_things(hyf_distance[1], j);
3991undump_things(hyf_num[1], j);
3992undump_upper_check_things(max_trie_op, hyf_next[1], j);
3993@z
3994
3995@x [50.1327] l.24117 - Allow command line to override dumped value.
3996undump(batch_mode)(error_stop_mode)(interaction);
3997@y
3998undump(batch_mode)(error_stop_mode)(interaction);
3999if interaction_option<>unspecified_mode then interaction:=interaction_option;
4000@z
4001
4002@x [50.1327] l.24172 - Test for end-of-file already done by undump.
4003if (x<>69069)or eof(fmt_file) then goto bad_fmt
4004@y
4005if x<>69069 then goto bad_fmt
4006@z
4007
4008@x [51.1332] l.24203 - make the main program a procedure, for eqtb hack.
4009@p begin @!{|start_here|}
4010@y
4011@d const_chk(#)==begin if # < inf@&# then # := inf@&# else
4012                         if # > sup@&# then # := sup@&# end
4013
4014{|setup_bound_var| stuff duplicated in \.{mf.ch}.}
4015@d setup_bound_var(#)==bound_default:=#; setup_bound_var_end
4016@d setup_bound_var_end(#)==bound_name:=#; setup_bound_var_end_end
4017@d setup_bound_var_end_end(#)==
4018  setup_bound_variable(addressof(#), bound_name, bound_default)
4019
4020@p procedure main_body;
4021begin @!{|start_here|}
4022
4023{Bounds that may be set from the configuration file. We want the user to
4024 be able to specify the names with underscores, but \.{TANGLE} removes
4025 underscores, so we're stuck giving the names twice, once as a string,
4026 once as the identifier. How ugly.}
4027  setup_bound_var (0)('mem_bot')(mem_bot);
4028  setup_bound_var (250000)('main_memory')(main_memory);
4029    {|memory_word|s for |mem| in \.{INITEX}}
4030  setup_bound_var (0)('extra_mem_top')(extra_mem_top);
4031    {increase high mem in \.{VIRTEX}}
4032  setup_bound_var (0)('extra_mem_bot')(extra_mem_bot);
4033    {increase low mem in \.{VIRTEX}}
4034  setup_bound_var (200000)('pool_size')(pool_size);
4035  setup_bound_var (75000)('string_vacancies')(string_vacancies);
4036  setup_bound_var (5000)('pool_free')(pool_free); {min pool avail after fmt}
4037  setup_bound_var (15000)('max_strings')(max_strings);
4038  setup_bound_var (100)('strings_free')(strings_free);
4039  setup_bound_var (100000)('font_mem_size')(font_mem_size);
4040  setup_bound_var (500)('font_max')(font_max);
4041  setup_bound_var (20000)('trie_size')(trie_size);
4042    {if |ssup_trie_size| increases, recompile}
4043  setup_bound_var (659)('hyph_size')(hyph_size);
4044  setup_bound_var (3000)('buf_size')(buf_size);
4045  setup_bound_var (50)('nest_size')(nest_size);
4046  setup_bound_var (15)('max_in_open')(max_in_open);
4047  setup_bound_var (60)('param_size')(param_size);
4048  setup_bound_var (4000)('save_size')(save_size);
4049  setup_bound_var (300)('stack_size')(stack_size);
4050  setup_bound_var (16384)('dvi_buf_size')(dvi_buf_size);
4051  setup_bound_var (79)('error_line')(error_line);
4052  setup_bound_var (50)('half_error_line')(half_error_line);
4053  setup_bound_var (79)('max_print_line')(max_print_line);
4054  setup_bound_var (0)('hash_extra')(hash_extra);
4055  setup_bound_var (10000)('expand_depth')(expand_depth);
4056
4057  const_chk (mem_bot);
4058  const_chk (main_memory);
4059@+Init
4060  extra_mem_top := 0;
4061  extra_mem_bot := 0;
4062@+Tini
4063  if extra_mem_bot>sup_main_memory then extra_mem_bot:=sup_main_memory;
4064  if extra_mem_top>sup_main_memory then extra_mem_top:=sup_main_memory;
4065  {|mem_top| is an index, |main_memory| a size}
4066  mem_top := mem_bot + main_memory -1;
4067  mem_min := mem_bot;
4068  mem_max := mem_top;
4069
4070  {Check other constants against their sup and inf.}
4071  const_chk (trie_size);
4072  const_chk (hyph_size);
4073  const_chk (buf_size);
4074  const_chk (nest_size);
4075  const_chk (max_in_open);
4076  const_chk (param_size);
4077  const_chk (save_size);
4078  const_chk (stack_size);
4079  const_chk (dvi_buf_size);
4080  const_chk (pool_size);
4081  const_chk (string_vacancies);
4082  const_chk (pool_free);
4083  const_chk (max_strings);
4084  const_chk (strings_free);
4085  const_chk (font_mem_size);
4086  const_chk (font_max);
4087  const_chk (hash_extra);
4088  if error_line > ssup_error_line then error_line := ssup_error_line;
4089
4090  {array memory allocation}
4091  buffer:=xmalloc_array (ASCII_code, buf_size);
4092  nest:=xmalloc_array (list_state_record, nest_size);
4093  save_stack:=xmalloc_array (memory_word, save_size);
4094  input_stack:=xmalloc_array (in_state_record, stack_size);
4095  input_file:=xmalloc_array (alpha_file, max_in_open);
4096  line_stack:=xmalloc_array (integer, max_in_open);
4097  source_filename_stack:=xmalloc_array (str_number, max_in_open);
4098  full_source_filename_stack:=xmalloc_array (str_number, max_in_open);
4099  param_stack:=xmalloc_array (halfword, param_size);
4100  dvi_buf:=xmalloc_array (eight_bits, dvi_buf_size);
4101  hyph_word :=xmalloc_array (str_number, hyph_size);
4102  hyph_list :=xmalloc_array (halfword, hyph_size);
4103  hyph_link :=xmalloc_array (hyph_pointer, hyph_size);
4104@+Init
4105  yzmem:=xmalloc_array (memory_word, mem_top - mem_bot + 1);
4106  zmem := yzmem - mem_bot;   {Some compilers require |mem_bot=0|}
4107  eqtb_top := eqtb_size+hash_extra;
4108  if hash_extra=0 then hash_top:=undefined_control_sequence else
4109        hash_top:=eqtb_top;
4110  yhash:=xmalloc_array (two_halves,1+hash_top-hash_offset);
4111  hash:=yhash - hash_offset;   {Some compilers require |hash_offset=0|}
4112  next(hash_base):=0; text(hash_base):=0;
4113  for hash_used:=hash_base+1 to hash_top do hash[hash_used]:=hash[hash_base];
4114  zeqtb:=xmalloc_array (memory_word, eqtb_top);
4115  eqtb:=zeqtb;
4116
4117  str_start:=xmalloc_array (pool_pointer, max_strings);
4118  str_pool:=xmalloc_array (packed_ASCII_code, pool_size);
4119  font_info:=xmalloc_array (fmemory_word, font_mem_size);
4120@+Tini
4121@z
4122
4123@x [51.1332] l.24215 - INI = VIR, so pool init needs runtime test
4124@!init if not get_strings_started then goto final_end;
4125init_prim; {call |primitive| for each primitive}
4126init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr; fix_date_and_time;
4127tini@/
4128@y
4129@!Init if not get_strings_started then goto final_end;
4130init_prim; {call |primitive| for each primitive}
4131init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr; fix_date_and_time;
4132Tini@/
4133@z
4134
4135@x [51.1332] l.24225 - main
4136end_of_TEX: close_files_and_terminate;
4137final_end: ready_already:=0;
4138end.
4139@y
4140close_files_and_terminate;
4141final_end: do_final_end;
4142end {|main_body|};
4143@z
4144
4145@x [51.1333] l.24254 - Print new line before termination; switch to editor if necessary.
4146    slow_print(log_name); print_char(".");
4147    end;
4148  end;
4149@y
4150    print_file_name(0, log_name, 0); print_char(".");
4151    end;
4152  end;
4153print_ln;
4154if (edit_name_start<>0) and (interaction>batch_mode) then
4155  call_edit(str_pool,edit_name_start,edit_name_length,edit_line);
4156@z
4157
4158@x [51.1334] l.24275 - hash_extra
4159  wlog_ln(' ',cs_count:1,' multiletter control sequences out of ',
4160    hash_size:1);@/
4161@y  24276
4162  wlog_ln(' ',cs_count:1,' multiletter control sequences out of ',
4163    hash_size:1, '+', hash_extra:1);@/
4164@z
4165
4166@x [51.1335] l.24335 - Only do dump if ini.
4167  begin @!init for c:=top_mark_code to split_bot_mark_code do
4168@y
4169  begin @!Init for c:=top_mark_code to split_bot_mark_code do
4170@z
4171
4172@x [51.1335] l.24337 - Only do dump if ini.
4173  store_fmt_file; return;@+tini@/
4174@y
4175  store_fmt_file; return;@+Tini@/
4176@z
4177
4178@x [51.1337] l.24361 - Handle %&format in all cases.
4179if (format_ident=0)or(buffer[loc]="&") then
4180@y
4181if (format_ident=0)or(buffer[loc]="&")or dump_line then
4182@z
4183
4184@x [51.1337] l.24366 - Dynamic arrays size.
4185  w_close(fmt_file);
4186@y
4187  w_close(fmt_file);
4188  eqtb:=zeqtb;
4189@z
4190
4191%% [51] m.1337 l.24371 - MLTeX: add. MLTeX banner after loading fmt file
4192%%                     (MLTeX change: only "if mltex_enabled_p then ....;")
4193@x [51.1337] l.24371 - Allocate hyphenation tries, do char translation, MLTeX
4194fix_date_and_time;@/
4195@y
4196if mltex_enabled_p then
4197  begin wterm_ln('MLTeX v2.2 enabled');
4198  end;
4199fix_date_and_time;@/
4200
4201@!init
4202if trie_not_ready then begin {initex without format loaded}
4203  trie_trl:=xmalloc_array (trie_pointer, trie_size);
4204  trie_tro:=xmalloc_array (trie_pointer, trie_size);
4205  trie_trc:=xmalloc_array (quarterword, trie_size);
4206
4207  trie_c:=xmalloc_array (packed_ASCII_code, trie_size);
4208  trie_o:=xmalloc_array (trie_opcode, trie_size);
4209  trie_l:=xmalloc_array (trie_pointer, trie_size);
4210  trie_r:=xmalloc_array (trie_pointer, trie_size);
4211  trie_hash:=xmalloc_array (trie_pointer, trie_size);
4212  trie_taken:=xmalloc_array (boolean, trie_size);
4213
4214  trie_root:=0; trie_c[0]:=si(0); trie_ptr:=0;
4215
4216  {Allocate and initialize font arrays}
4217  font_check:=xmalloc_array(four_quarters, font_max);
4218  font_size:=xmalloc_array(scaled, font_max);
4219  font_dsize:=xmalloc_array(scaled, font_max);
4220  font_params:=xmalloc_array(font_index, font_max);
4221  font_name:=xmalloc_array(str_number, font_max);
4222  font_area:=xmalloc_array(str_number, font_max);
4223  font_bc:=xmalloc_array(eight_bits, font_max);
4224  font_ec:=xmalloc_array(eight_bits, font_max);
4225  font_glue:=xmalloc_array(halfword, font_max);
4226  hyphen_char:=xmalloc_array(integer, font_max);
4227  skew_char:=xmalloc_array(integer, font_max);
4228  bchar_label:=xmalloc_array(font_index, font_max);
4229  font_bchar:=xmalloc_array(nine_bits, font_max);
4230  font_false_bchar:=xmalloc_array(nine_bits, font_max);
4231  char_base:=xmalloc_array(integer, font_max);
4232  width_base:=xmalloc_array(integer, font_max);
4233  height_base:=xmalloc_array(integer, font_max);
4234  depth_base:=xmalloc_array(integer, font_max);
4235  italic_base:=xmalloc_array(integer, font_max);
4236  lig_kern_base:=xmalloc_array(integer, font_max);
4237  kern_base:=xmalloc_array(integer, font_max);
4238  exten_base:=xmalloc_array(integer, font_max);
4239  param_base:=xmalloc_array(integer, font_max);
4240
4241  font_ptr:=null_font; fmem_ptr:=7;
4242  font_name[null_font]:="nullfont"; font_area[null_font]:="";
4243  hyphen_char[null_font]:="-"; skew_char[null_font]:=-1;
4244  bchar_label[null_font]:=non_address;
4245  font_bchar[null_font]:=non_char; font_false_bchar[null_font]:=non_char;
4246  font_bc[null_font]:=1; font_ec[null_font]:=0;
4247  font_size[null_font]:=0; font_dsize[null_font]:=0;
4248  char_base[null_font]:=0; width_base[null_font]:=0;
4249  height_base[null_font]:=0; depth_base[null_font]:=0;
4250  italic_base[null_font]:=0; lig_kern_base[null_font]:=0;
4251  kern_base[null_font]:=0; exten_base[null_font]:=0;
4252  font_glue[null_font]:=null; font_params[null_font]:=7;
4253  param_base[null_font]:=-1;
4254  for font_k:=0 to 6 do font_info[font_k].sc:=0;
4255  end;
4256  tini@/
4257
4258  font_used:=xmalloc_array (boolean, font_max);
4259  for font_k:=font_base to font_max do font_used[font_k]:=false;
4260@z
4261
4262% [52.1338] Core-dump in debugging mode on 0 input.  Under Unix, it's
4263% not possible to portably switch into the debugger while a program is
4264% running.  The best approximation is to do a core dump, then run the
4265% debugger on it later.
4266@x [52.1338] l.24411 - Core-dump in debugging mode on 0 input.
4267    begin goto breakpoint;@\ {go to every label at least once}
4268    breakpoint: m:=0; @{'BREAKPOINT'@}@\
4269    end
4270@y
4271    dump_core {do something to cause a core dump}
4272@z
4273
4274@x [52.1339] l.24429 - debug - print tfm info
42755: print_word(font_info[n]);
4276@y 24397
42775: begin print_scaled(font_info[n].sc); print_char(" ");@/
4278  print_int(font_info[n].qqqq.b0); print_char(":");@/
4279  print_int(font_info[n].qqqq.b1); print_char(":");@/
4280  print_int(font_info[n].qqqq.b2); print_char(":");@/
4281  print_int(font_info[n].qqqq.b3);
4282  end;
4283@z
4284
4285@x [53.1344] l.24544 - source specials
4286primitive("special",extension,special_node);@/
4287@y
4288primitive("special",extension,special_node);@/
4289text(frozen_special):="special"; eqtb[frozen_special]:=eqtb[cur_val];@/
4290@z
4291
4292@x [53.1348] (do_extension) Remove unused variables
4293var i,@!j,@!k:integer; {all-purpose integers}
4294@!p,@!q,@!r:pointer; {all-purpose pointers}
4295@y
4296var k:integer; {all-purpose integers}
4297@!p:pointer; {all-purpose pointers}
4298@z
4299
4300% [53.1350] (new_write_whatsit) Allow 18 as a \write stream. We never
4301% refer to an actual file, though, so we don't need to change the
4302% write_file or write_open arrays. We provide for disabling this at
4303% runtime, for paranoids.
4304@x [53.1350] l.24609 - system: Allow 18 as a \write stream.
4305  else if cur_val>15 then cur_val:=16;
4306@y
4307  else if (cur_val>15) and (cur_val <> 18) then cur_val:=16;
4308@z
4309
4310@x [53.1370] l.24770 - \write18{foo}
4311begin @<Expand macros in the token list
4312@y
4313@!d:integer; {number of characters in incomplete current string}
4314@!clobbered:boolean; {system string is ok?}
4315@!runsystem_ret:integer; {return value from |runsystem|}
4316begin @<Expand macros in the token list
4317@z
4318
4319@x [53.1370] l.24773 - system: (write_out) \write18{foo} => system(foo).
4320if write_open[j] then selector:=j
4321@y
4322if j=18 then selector := new_string
4323else if write_open[j] then selector:=j
4324@z
4325
4326% Then call system(3) on that string.
4327@x [53.1370] l.24779 - system: (write_out) \write18{foo} => system(foo).
4328flush_list(def_ref); selector:=old_setting;
4329@y
4330flush_list(def_ref);
4331if j=18 then
4332  begin if (tracing_online<=0) then
4333    selector:=log_only  {Show what we're doing in the log file.}
4334  else selector:=term_and_log;  {Show what we're doing.}
4335  {If the log file isn't open yet, we can only send output to the terminal.
4336   Calling |open_log_file| from here seems to result in bad data in the log.}
4337  if not log_opened then selector:=term_only;
4338  print_nl("runsystem(");
4339  for d:=0 to cur_length-1 do
4340    begin {|print| gives up if passed |str_ptr|, so do it by hand.}
4341    print(so(str_pool[str_start[str_ptr]+d])); {N.B.: not |print_char|}
4342    end;
4343  print(")...");
4344  if shellenabledp then begin
4345    str_room(1); append_char(0); {Append a null byte to the expansion.}
4346    clobbered:=false;
4347    for d:=0 to cur_length-1 do {Convert to external character set.}
4348      begin
4349        str_pool[str_start[str_ptr]+d]:=xchr[str_pool[str_start[str_ptr]+d]];
4350        if (str_pool[str_start[str_ptr]+d]=null_code)
4351           and (d<cur_length-1) then clobbered:=true;
4352        {minimal checking: NUL not allowed in argument string of |system|()}
4353      end;
4354    if clobbered then print("clobbered")
4355    else begin {We have the command.  See if we're allowed to execute it,
4356         and report in the log.  We don't check the actual exit status of
4357         the command, or do anything with the output.}
4358      runsystem_ret := runsystem(conststringcast(addressof(
4359                                              str_pool[str_start[str_ptr]])));
4360      if runsystem_ret = -1 then print("quotation error in system command")
4361      else if runsystem_ret = 0 then print("disabled (restricted)")
4362      else if runsystem_ret = 1 then print("executed")
4363      else if runsystem_ret = 2 then print("executed safely (allowed)")
4364    end;
4365  end else begin
4366    print("disabled"); {|shellenabledp| false}
4367  end;
4368  print_char("."); print_nl(""); print_ln;
4369  pool_ptr:=str_start[str_ptr];  {erase the string}
4370end;
4371selector:=old_setting;
4372@z
4373
4374@x [53.1373] Need new local.
4375procedure out_what(@!p:pointer);
4376var j:small_number; {write stream number}
4377@y
4378procedure out_what(@!p:pointer);
4379var j:small_number; {write stream number}
4380    @!old_setting:0..max_selector;
4381@z
4382
4383@x [53.1374] Disallow certain \openout filenames, and log results.
4384      while not a_open_out(write_file[j]) do
4385        prompt_file_name("output file name",".tex");
4386      write_open[j]:=true;
4387@y
4388      while not kpse_out_name_ok(stringcast(name_of_file+1))
4389            or not a_open_out(write_file[j]) do
4390        prompt_file_name("output file name",".tex");
4391      write_open[j]:=true;
4392      {If on first line of input, log file is not ready yet, so don't log.}
4393      if log_opened then begin
4394        old_setting:=selector;
4395        if (tracing_online<=0) then
4396          selector:=log_only  {Show what we're doing in the log file.}
4397        else selector:=term_and_log;  {Show what we're doing.}
4398        print_nl("\openout");
4399        print_int(j);
4400        print(" = `");
4401        print_file_name(cur_name,cur_area,cur_ext);
4402        print("'."); print_nl(""); print_ln;
4403        selector:=old_setting;
4404      end;
4405@z
4406
4407@x [54.1376] l.24903 - Add editor-switch variables to globals.
4408@* \[54] System-dependent changes.
4409@y
4410@* \[54/web2c] System-dependent changes for Web2c.
4411Here are extra variables for Web2c.  (This numbering of the
4412system-dependent section allows easy integration of Web2c and e-\TeX, etc.)
4413@^<system dependencies@>
4414
4415@<Glob...@>=
4416@!edit_name_start: pool_pointer; {where the filename to switch to starts}
4417@!edit_name_length,@!edit_line: integer; {what line to start editing at}
4418@!ipc_on: cinttype; {level of IPC action, 0 for none [default]}
4419@!stop_at_space: boolean; {whether |more_name| returns false for space}
4420
4421@ The |edit_name_start| will be set to point into |str_pool| somewhere after
4422its beginning if \TeX\ is supposed to switch to an editor on exit.
4423
4424@<Set init...@>=
4425edit_name_start:=0;
4426stop_at_space:=true;
4427
4428@ These are used when we regenerate the representation of the first 256
4429strings.
4430
4431@<Global...@> =
4432@!save_str_ptr: str_number;
4433@!save_pool_ptr: pool_pointer;
4434@!shellenabledp: cinttype;
4435@!restrictedshell: cinttype;
4436@!output_comment: ^char;
4437@!k,l: 0..255; {used by `Make the first 256 strings', etc.}
4438
4439@ When debugging a macro package, it can be useful to see the exact
4440control sequence names in the format file.  For example, if ten new
4441csnames appear, it's nice to know what they are, to help pinpoint where
4442they came from.  (This isn't a truly ``basic'' printing procedure, but
4443that's a convenient module in which to put it.)
4444
4445@<Basic printing procedures@> =
4446procedure print_csnames (hstart:integer; hfinish:integer);
4447var c,h:integer;
4448begin
4449  write_ln(stderr, 'fmtdebug:csnames from ', hstart, ' to ', hfinish, ':');
4450  for h := hstart to hfinish do begin
4451    if text(h) > 0 then begin {if have anything at this position}
4452      for c := str_start[text(h)] to str_start[text(h) + 1] - 1
4453      do begin
4454        put_byte(str_pool[c], stderr); {print the characters}
4455      end;
4456      write_ln(stderr, '|');
4457    end;
4458  end;
4459end;
4460
4461@ Are we printing extra info as we read the format file?
4462
4463@<Glob...@> =
4464@!debug_format_file: boolean;
4465
4466
4467@ A helper for printing file:line:error style messages.  Look for a
4468filename in |full_source_filename_stack|, and if we fail to find
4469one fall back on the non-file:line:error style.
4470
4471@<Basic print...@>=
4472procedure print_file_line;
4473var level: 0..max_in_open;
4474begin
4475  level:=in_open;
4476  while (level>0) and (full_source_filename_stack[level]=0) do
4477    decr(level);
4478  if level=0 then
4479    print_nl("! ")
4480  else begin
4481    print_nl (""); print (full_source_filename_stack[level]); print (":");
4482    if level=in_open then print_int (line)
4483    else print_int (line_stack[level+1]);
4484    print (": ");
4485  end;
4486end;
4487
4488@ To be able to determine whether \.{\\write18} is enabled from within
4489\TeX\ we also implement \.{\\eof18}.  We sort of cheat by having an
4490additional route |scan_four_bit_int_or_18| which is the same as
4491|scan_four_bit_int| except it also accepts the value 18.
4492
4493@<Declare procedures that scan restricted classes of integers@>=
4494procedure scan_four_bit_int_or_18;
4495begin scan_int;
4496if (cur_val<0)or((cur_val>15)and(cur_val<>18)) then
4497  begin print_err("Bad number");
4498@.Bad number@>
4499  help2("Since I expected to read a number between 0 and 15,")@/
4500    ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
4501  end;
4502end;
4503
4504@ Dumping the |xord|, |xchr|, and |xprn| arrays.  We dump these always
4505in the format, so a TCX file loaded during format creation can set a
4506default for users of the format.
4507
4508@<Dump |xord|, |xchr|, and |xprn|@>=
4509dump_things(xord[0], 256);
4510dump_things(xchr[0], 256);
4511dump_things(xprn[0], 256);
4512
4513@ Undumping the |xord|, |xchr|, and |xprn| arrays.  This code is more
4514complicated, because we want to ensure that a TCX file specified on
4515the command line will override whatever is in the format.  Since the
4516tcx file has already been loaded, that implies throwing away the data
4517in the format.  Also, if no |translate_filename| is given, but
4518|eight_bit_p| is set we have to make all characters printable.
4519
4520@<Undump |xord|, |xchr|, and |xprn|@>=
4521if translate_filename then begin
4522  for k:=0 to 255 do undump_things(dummy_xord, 1);
4523  for k:=0 to 255 do undump_things(dummy_xchr, 1);
4524  for k:=0 to 255 do undump_things(dummy_xprn, 1);
4525  end
4526else begin
4527  undump_things(xord[0], 256);
4528  undump_things(xchr[0], 256);
4529  undump_things(xprn[0], 256);
4530  if eight_bit_p then
4531    for k:=0 to 255 do
4532      xprn[k]:=1;
4533end;
4534
4535
4536@* \[54/web2c-string] The string recycling routines.
4537\TeX{} uses 2 upto 4 {\it new\/} strings when scanning a filename in an
4538\.{\\input}, \.{\\openin}, or \.{\\openout} operation.  These strings are
4539normally lost because the reference to them are not saved after finishing
4540the operation.  |search_string| searches through the string pool for the
4541given string and returns either 0 or the found string number.
4542
4543@<Declare additional routines for string recycling@>=
4544function search_string(@!search:str_number):str_number;
4545label found;
4546var result: str_number;
4547@!s: str_number; {running index}
4548@!len: integer; {length of searched string}
4549begin result:=0; len:=length(search);
4550if len=0 then  {trivial case}
4551  begin result:=""; goto found;
4552  end
4553else  begin s:=search-1;  {start search with newest string below |s|; |search>1|!}
4554  while s>255 do  {first 256 strings depend on implementation!!}
4555    begin if length(s)=len then
4556      if str_eq_str(s,search) then
4557        begin result:=s; goto found;
4558        end;
4559    decr(s);
4560    end;
4561  end;
4562found:search_string:=result;
4563end;
4564
4565@ The following routine is a variant of |make_string|.  It searches
4566the whole string pool for a string equal to the string currently built
4567and returns a found string.  Otherwise a new string is created and
4568returned.  Be cautious, you can not apply |flush_string| to a replaced
4569string!
4570
4571@<Declare additional routines for string recycling@>=
4572function slow_make_string : str_number;
4573label exit;
4574var s: str_number; {result of |search_string|}
4575@!t: str_number; {new string}
4576begin t:=make_string; s:=search_string(t);
4577if s>0 then
4578  begin flush_string; slow_make_string:=s; return;
4579  end;
4580slow_make_string:=t;
4581exit:end;
4582
4583
4584@* \[54/ML\TeX] System-dependent changes for ML\TeX.
4585
4586The boolean variable |mltex_p| is set by web2c according to the given
4587command line option (or an entry in the configuration file) before any
4588\TeX{} function is called.
4589
4590@<Global...@> =
4591@!mltex_p: boolean;
4592
4593@ The boolean variable |mltex_enabled_p| is used to enable ML\TeX's
4594character substitution.  It is initialised to |false|.  When loading
4595a \.{FMT} it is set to the value of the boolean |mltex_p| saved in
4596the \.{FMT} file.  Additionally it is set to the value of |mltex_p|
4597in Ini\TeX.
4598
4599@<Glob...@>=
4600@!mltex_enabled_p:boolean;  {enable character substitution}
4601
4602
4603@ @<Set init...@>=
4604mltex_enabled_p:=false;
4605
4606
4607@ The function |effective_char| computes the effective character with
4608respect to font information.  The effective character is either the
4609base character part of a character substitution definition, if the
4610character does not exist in the font or the character itself.
4611
4612Inside |effective_char| we can not use |char_info| because the macro
4613|char_info| uses |effective_char| calling this function a second time
4614with the same arguments.
4615
4616If neither the character |c| exists in font |f| nor a character
4617substitution for |c| was defined, you can not use the function value
4618as a character offset in |char_info| because it will access an
4619undefined or invalid |font_info| entry!  Therefore inside |char_info|
4620and in other places, |effective_char|'s boolean parameter |err_p| is
4621set to |true| to issue a warning and return the incorrect
4622replacement, but always existing character |font_bc[f]|.
4623@^inner loop@>
4624
4625@<Declare additional functions for ML\TeX@>=
4626function effective_char(@!err_p:boolean;
4627                        @!f:internal_font_number;@!c:quarterword):integer;
4628label found;
4629var base_c: integer; {or |eightbits|: replacement base character}
4630@!result: integer; {or |quarterword|}
4631begin result:=c;  {return |c| unless it does not exist in the font}
4632if not mltex_enabled_p then goto found;
4633if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
4634  if char_exists(orig_char_info(f)(c)) then  {N.B.: not |char_info|(f)(c)}
4635    goto found;
4636if qo(c)>=char_sub_def_min then if qo(c)<=char_sub_def_max then
4637  if char_list_exists(qo(c)) then
4638    begin base_c:=char_list_char(qo(c));
4639    result:=qi(base_c);  {return |base_c|}
4640    if not err_p then goto found;
4641    if font_ec[f]>=base_c then if font_bc[f]<=base_c then
4642      if char_exists(orig_char_info(f)(qi(base_c))) then goto found;
4643    end;
4644if err_p then  {print error and return existing character?}
4645  begin begin_diagnostic;
4646  print_nl("Missing character: There is no "); print("substitution for ");
4647@.Missing character@>
4648  print_ASCII(qo(c)); print(" in font ");
4649  slow_print(font_name[f]); print_char("!"); end_diagnostic(false);
4650  result:=qi(font_bc[f]); {N.B.: not non-existing character |c|!}
4651  end;
4652found: effective_char:=result;
4653end;
4654
4655
4656@ The function |effective_char_info| is equivalent to |char_info|,
4657except it will return |null_character| if neither the character |c|
4658exists in font |f| nor is there a substitution definition for |c|.
4659(For these cases |char_info| using |effective_char| will access an
4660undefined or invalid |font_info| entry.  See the documentation of
4661|effective_char| for more information.)
4662@^inner loop@>
4663
4664@<Declare additional functions for ML\TeX@>=
4665function effective_char_info(@!f:internal_font_number;
4666                             @!c:quarterword):four_quarters;
4667label exit;
4668var ci:four_quarters; {character information bytes for |c|}
4669@!base_c:integer; {or |eightbits|: replacement base character}
4670begin if not mltex_enabled_p then
4671  begin effective_char_info:=orig_char_info(f)(c); return;
4672  end;
4673if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
4674  begin ci:=orig_char_info(f)(c);  {N.B.: not |char_info|(f)(c)}
4675  if char_exists(ci) then
4676    begin effective_char_info:=ci; return;
4677    end;
4678  end;
4679if qo(c)>=char_sub_def_min then if qo(c)<=char_sub_def_max then
4680  if char_list_exists(qo(c)) then
4681    begin {|effective_char_info:=char_info(f)(qi(char_list_char(qo(c))));|}
4682    base_c:=char_list_char(qo(c));
4683    if font_ec[f]>=base_c then if font_bc[f]<=base_c then
4684      begin ci:=orig_char_info(f)(qi(base_c));  {N.B.: not |char_info|(f)(c)}
4685      if char_exists(ci) then
4686        begin effective_char_info:=ci; return;
4687        end;
4688      end;
4689    end;
4690effective_char_info:=null_character;
4691exit:end;
4692
4693
4694@ This code is called for a virtual character |c| in |hlist_out|
4695during |ship_out|.  It tries to built a character substitution
4696construct for |c| generating appropriate \.{DVI} code using the
4697character substitution definition for this character.  If a valid
4698character substitution exists \.{DVI} code is created as if
4699|make_accent| was used.  In all other cases the status of the
4700substituion for this character has been changed between the creation
4701of the character node in the hlist and the output of the page---the
4702created \.{DVI} code will be correct but the visual result will be
4703undefined.
4704
4705Former ML\TeX\ versions have replaced the character node by a
4706sequence of character, box, and accent kern nodes splicing them into
4707the original horizontal list.  This version does not do this to avoid
4708a)~a memory overflow at this processing stage, b)~additional code to
4709add a pointer to the previous node needed for the replacement, and
4710c)~to avoid wrong code resulting in anomalies because of the use
4711within a \.{\\leaders} box.
4712
4713@<Output a substitution, |goto continue| if not possible@>=
4714  begin
4715  @<Get substitution information, check it, goto |found|
4716  if all is ok, otherwise goto |continue|@>;
4717found: @<Print character substition tracing log@>;
4718  @<Rebuild character using substitution information@>;
4719  end
4720
4721
4722@ The global variables for the code to substitute a virtual character
4723can be declared as local.  Nonetheless we declare them as global to
4724avoid stack overflows because |hlist_out| can be called recursivly.
4725
4726@<Glob...@>=
4727@!accent_c,@!base_c,@!replace_c:integer;
4728@!ia_c,@!ib_c:four_quarters; {accent and base character information}
4729@!base_slant,@!accent_slant:real; {amount of slant}
4730@!base_x_height:scaled; {accent is designed for characters of this height}
4731@!base_width,@!base_height:scaled; {height and width for base character}
4732@!accent_width,@!accent_height:scaled; {height and width for accent}
4733@!delta:scaled; {amount of right shift}
4734
4735
4736@ Get the character substitution information in |char_sub_code| for
4737the character |c|.  The current code checks that the substition
4738exists and is valid and all substitution characters exist in the
4739font, so we can {\it not\/} substitute a character used in a
4740substitution.  This simplifies the code because we have not to check
4741for cycles in all character substitution definitions.
4742
4743@<Get substitution information, check it...@>=
4744  if qo(c)>=char_sub_def_min then if qo(c)<=char_sub_def_max then
4745    if char_list_exists(qo(c)) then
4746      begin  base_c:=char_list_char(qo(c));
4747      accent_c:=char_list_accent(qo(c));
4748      if (font_ec[f]>=base_c) then if (font_bc[f]<=base_c) then
4749        if (font_ec[f]>=accent_c) then if (font_bc[f]<=accent_c) then
4750          begin ia_c:=char_info(f)(qi(accent_c));
4751          ib_c:=char_info(f)(qi(base_c));
4752          if char_exists(ib_c) then
4753            if char_exists(ia_c) then goto found;
4754          end;
4755      begin_diagnostic;
4756      print_nl("Missing character: Incomplete substitution ");
4757@.Missing character@>
4758      print_ASCII(qo(c)); print(" = "); print_ASCII(accent_c);
4759      print(" "); print_ASCII(base_c); print(" in font ");
4760      slow_print(font_name[f]); print_char("!"); end_diagnostic(false);
4761      goto continue;
4762      end;
4763  begin_diagnostic;
4764  print_nl("Missing character: There is no "); print("substitution for ");
4765@.Missing character@>
4766  print_ASCII(qo(c)); print(" in font ");
4767  slow_print(font_name[f]); print_char("!"); end_diagnostic(false);
4768  goto continue
4769
4770
4771@ For |tracinglostchars>99| the substitution is shown in the log file.
4772
4773@<Print character substition tracing log@>=
4774 if tracing_lost_chars>99 then
4775   begin begin_diagnostic;
4776   print_nl("Using character substitution: ");
4777   print_ASCII(qo(c)); print(" = ");
4778   print_ASCII(accent_c); print(" "); print_ASCII(base_c);
4779   print(" in font "); slow_print(font_name[f]); print_char(".");
4780   end_diagnostic(false);
4781   end
4782
4783
4784@ This outputs the accent and the base character given in the
4785substitution.  It uses code virtually identical to the |make_accent|
4786procedure, but without the node creation steps.
4787
4788Additionally if the accent character has to be shifted vertically it
4789does {\it not\/} create the same code.  The original routine in
4790|make_accent| and former versions of ML\TeX{} creates a box node
4791resulting in |push| and |pop| operations, whereas this code simply
4792produces vertical positioning operations.  This can influence the
4793pixel rounding algorithm in some \.{DVI} drivers---and therefore will
4794probably be changed in one of the next ML\TeX{} versions.
4795
4796@<Rebuild character using substitution information@>=
4797  base_x_height:=x_height(f);
4798  base_slant:=slant(f)/float_constant(65536);
4799@^real division@>
4800  accent_slant:=base_slant; {slant of accent character font}
4801  base_width:=char_width(f)(ib_c);
4802  base_height:=char_height(f)(height_depth(ib_c));
4803  accent_width:=char_width(f)(ia_c);
4804  accent_height:=char_height(f)(height_depth(ia_c));
4805  @/{compute necessary horizontal shift (don't forget slant)}@/
4806  delta:=round((base_width-accent_width)/float_constant(2)+
4807            base_height*base_slant-base_x_height*accent_slant);
4808@^real multiplication@>
4809@^real addition@>
4810  dvi_h:=cur_h;  {update |dvi_h|, similar to the last statement in module 620}
4811  @/{1. For centering/horizontal shifting insert a kern node.}@/
4812  cur_h:=cur_h+delta; synch_h;
4813  @/{2. Then insert the accent character possibly shifted up or down.}@/
4814  if ((base_height<>base_x_height) and (accent_height>0)) then
4815    begin {the accent must be shifted up or down}
4816    cur_v:=base_line+(base_x_height-base_height); synch_v;
4817    if accent_c>=128 then dvi_out(set1);
4818    dvi_out(accent_c);@/
4819    cur_v:=base_line;
4820    end
4821  else begin synch_v;
4822    if accent_c>=128 then dvi_out(set1);
4823    dvi_out(accent_c);@/
4824    end;
4825  cur_h:=cur_h+accent_width; dvi_h:=cur_h;
4826  @/{3. For centering/horizontal shifting insert another kern node.}@/
4827  cur_h:=cur_h+(-accent_width-delta);
4828  @/{4. Output the base character.}@/
4829  synch_h; synch_v;
4830  if base_c>=128 then dvi_out(set1);
4831  dvi_out(base_c);@/
4832  cur_h:=cur_h+base_width;
4833  dvi_h:=cur_h {update of |dvi_h| is unnecessary, will be set in module 620}
4834
4835@ Dumping ML\TeX-related material.  This is just the flag in the
4836format that tells us whether ML\TeX{} is enabled.
4837
4838@<Dump ML\TeX-specific data@>=
4839dump_int(@"4D4C5458);  {ML\TeX's magic constant: "MLTX"}
4840if mltex_p then dump_int(1)
4841else dump_int(0);
4842
4843@ Undump ML\TeX-related material, which is just a flag in the format
4844that tells us whether ML\TeX{} is enabled.
4845
4846@<Undump ML\TeX-specific data@>=
4847undump_int(x);   {check magic constant of ML\TeX}
4848if x<>@"4D4C5458 then goto bad_fmt;
4849undump_int(x);   {undump |mltex_p| flag into |mltex_enabled_p|}
4850if x=1 then mltex_enabled_p:=true
4851else if x<>0 then goto bad_fmt;
4852
4853
4854@* \[54] System-dependent changes.
4855@z
4856
4857@x [54.1379] l.24916 - extra routines
4858@* \[55] Index.
4859@y
4860
4861@ @<Declare action procedures for use by |main_control|@>=
4862
4863procedure insert_src_special;
4864var toklist, p, q : pointer;
4865begin
4866  if (source_filename_stack[in_open] > 0 and is_new_source (source_filename_stack[in_open]
4867, line)) then begin
4868    toklist := get_avail;
4869    p := toklist;
4870    info(p) := cs_token_flag+frozen_special;
4871    link(p) := get_avail; p := link(p);
4872    info(p) := left_brace_token+"{";
4873    q := str_toks (make_src_special (source_filename_stack[in_open], line));
4874    link(p) := link(temp_head);
4875    p := q;
4876    link(p) := get_avail; p := link(p);
4877    info(p) := right_brace_token+"}";
4878    ins_list (toklist);
4879    remember_source_info (source_filename_stack[in_open], line);
4880  end;
4881end;
4882
4883procedure append_src_special;
4884var q : pointer;
4885begin
4886  if (source_filename_stack[in_open] > 0 and is_new_source (source_filename_stack[in_open]
4887, line)) then begin
4888    new_whatsit (special_node, write_node_size);
4889    write_stream(tail) := 0;
4890    def_ref := get_avail;
4891    token_ref_count(def_ref) := null;
4892    q := str_toks (make_src_special (source_filename_stack[in_open], line));
4893    link(def_ref) := link(temp_head);
4894    write_tokens(tail) := def_ref;
4895    remember_source_info (source_filename_stack[in_open], line);
4896  end;
4897end;
4898
4899@ This function used to be in pdftex, but is useful in tex too.
4900
4901@p function get_nullstr: str_number;
4902begin
4903    get_nullstr := "";
4904end;
4905
4906@* \[55] Index.
4907@z
4908