summaryrefslogtreecommitdiff
path: root/macros/text1/texix/txt1v293.cmschan
diff options
context:
space:
mode:
Diffstat (limited to 'macros/text1/texix/txt1v293.cmschan')
-rw-r--r--macros/text1/texix/txt1v293.cmschan2000
1 files changed, 2000 insertions, 0 deletions
diff --git a/macros/text1/texix/txt1v293.cmschan b/macros/text1/texix/txt1v293.cmschan
new file mode 100644
index 0000000000..8f6bbe5a16
--- /dev/null
+++ b/macros/text1/texix/txt1v293.cmschan
@@ -0,0 +1,2000 @@
+TEX.CMS-CHAN - WEB change file for TeX 2.0 for VM/CMS and Pascal/VS.
+Copyright (C) 1984 by David Fuchs. All rights are reserved.
+
+External references: TERMATTN, ATTN202, USESTACK. Assembled
+ text decks of these routines must be linked into module.
+
+Changes to this file since 1.0 version (at SLAC):
+
+ Added increased mem size params etc from VMS-CHAN,
+ XEDIT hook, change ".log" to ".texlog". 11 Feb 84
+ Fixed filemode specifier so you can "\input fn.ft.fm". 9 Mar 84
+ Update line number references from TeX 1.0 to TeX 1.1. 20 Mar 84
+ Increase |buf_size| parameter from 500 to 1024. 24 Apr 84
+ Add CMS hook to send string to CMS using "\write15". 24 Apr 84
+ Various small changes in comments in TeX. 12 Jul 84
+ Change |pool_name| from "TEX.POOL" to "TEX.POOL.*". 21 Aug 84
+ File mode "*" added to |prompt_file_name| on input. 23 Aug 84
+ Allow tab and formfeed characters in input. 23 Aug 84
+ Increase |pool_size| to 40000. 23 Aug 84
+ ONERROR message deleted. 23 Aug 84
+ DVI block size changed to 1024. 24 Aug 84
+ SLAC character translates (hex): 4F->4A, 6A->4F, A1->5F. 27 Sep 84
+ Add SLAC routines for logging use data. 27 Sep 84
+ Update for TeX 1.4. 24 Feb 86
+ Remove |ready_already| as per Klaus Thull's recommendation. 24 Feb 86
+ Increase |hash_size| to 3000. 26 Feb 86
+ Update for TeX 2.0. 10 Mar 86
+ Add Chris Thompson's changes for large arrays, |use_stack|,
+ and do simple array asignments for |do_all_six|. 25 Mar 86
+ Add code in |close_files_and_terminate| to explicitly close
+ all input files. Avoids Pascal/VS loop in AMPXIO. 6 May 86
+ Allow |mem| array to start at negative index. 8 May 86
+ Increase |pool_size| to 50000. 9 May 86
+ Move |ret_code| from |end_of_TEX:| to |final_end:| and make
+ |history|:=|fatal_error_stop| if |bad_fmt|. 15 May 86
+ Remove SLAC-specific routines and character translates
+ to conform to TeX Project (hex): 5F->A1, 4A->5F. 4 Jun 86
+ Change |tfm_file| reading routine to read multiple 1024-byte
+ records. All TeX/MF data files are now RECFM F LRECL 1024. 2 Jul 86
+
+ Changes for TEXT1 by Dean Guenther 20 Aug 86
+ Banner now reflects TEXT1 at WEB line 148
+ DVI size changes to 2048 (4096) WEB line 345
+ Variable tfm_buf_size added at WEB line 345
+ (init'd at 1024)
+ tfm_buf_size replaces len_byte_block in system dependent
+ procedure fget in WEB code at line 23949
+ Square brackets around the page numbers changed to
+ angle brackets at WEB line 12302
+ Module's name changed to TXT1V2M0 at WEB line 212
+ buf_size changed from 1024 to 2048
+
+ Changes by Dean Guenther 20 Dec 86
+ Changes added to make \printindex a TeX primative. Refer to Web
+ lines 23602-23725 below.
+ Module's name changed to TXT1V2M1 at WEB line 212
+
+ Changes by Brian Harvey
+ Module's name is changed to TXT1V212 at WEB line 212
+ Banner line changed "TEXT1 (TEX 2.1)" 16 June 87
+
+ Changes by Dean Guenther
+ Installed fixes for TeX 2.2, 2.3, 2.4, 2.5, 2.6 & 2.7 25 Nov 87
+ Module is named TXT1V271 for TeX 2.7, mod 1
+ Installed fixes for TeX 2.8 & 2.9 11 Jan 88
+ Installed fixes for TeX 2.91, 2.92, & 2.93 2 Sep 88
+ Now using 1k dvi files instead of 2k
+ Module is named TXT1V293 for TeX 2.93
+
+TeX 2.0 WEB source line 34
+@x limbo
+\def\ph{\hbox{Pascal-H}}
+@y
+\def\ph{\hbox{Pascal-H}}
+\def\pvs{\hbox{Pascal/VS}}
+@z
+
+TeX 2.0 WEB source line 60
+@x limbo
+\pageno=3
+@y
+\pageno=3
+\let\maybe=\iffalse % to TeX only the changed sections after WEAV'ing
+\def\title{\TeX\ changes for VM/CMS}
+@z
+
+TeX 2.0 WEB source line 148
+@x
+@d banner=='This is TeX, Version 2.93' {printed when \TeX\ starts}
+@y
+The VM/CMS port of \TeX\ is a combination of efforts of many people.
+\.{WEB} change files for preliminary versions of \TeX\ were brought to
+the \TeX\ Users Group meeting in August 1983 and
+given to David Fuchs, of Stanford
+University Computer Science Department, who combined them into a
+definitive version on the VM system at Stanford Linear Accelerator
+Center. The original change files were supplied by Roger Chaffee of
+SLAC (now at Metaphor), Craig Platt of the University of Manitoba, and
+Peter M.~Sih of IBM Palo Alto Scientific Center. Bernd Schulze of the
+University of Bonn contributed his experience from bringing up a
+preliminary \TeX\ under CMS and has since sent many
+further improvements including the Metafont change file used in this
+implementation and other CMS change files.
+Other CMS change files and suggestions were made by Klaus Thull.
+All of this work was based on preliminary
+work adapting \TeX\ to MVS by Eagle Berns and Susan Plass of Stanford
+University. Peter Sih has donated countless hours of his expertise
+and contributed the device support for the IBM 4250 and APA6670 (and
+3800 model 3) printers. Many valuable revisions and additions to this
+work were made by Robert J.~Creasy.
+Alan Spragens at SLAC coordinated
+communication among the CMS sites and made some enhancements to the
+implementation while revising the CMS change file for \TeX\ versions
+1.1 and 2.0. Significant improvements were contributed for version
+2.0 by Chris Thompson of the University of Cambridge; they are
+described in the ``System-dependent Changes'' section.
+@d banner=='TEXT1 (TEX 2.93)'
+ {printed when \TeX\ starts}
+@d term_in==tty_in
+@d term_out==tty_out
+@d string_length==len @& gth {IBM length function}
+@d string_index ==ind @& ex {IBM index function}
+@z
+
+
+TeX 2.0 WEB source line 212
+@x
+program TEX; {all file names are defined dynamically}
+@y
+program TXT1V293; {all file names are defined dynamically}
+@z
+
+TeX 2.0 WEB source line 218
+@x
+procedure initialize; {this procedure gets things started properly}
+@y
+@<Large array variables@>@/
+@<VM/CMS procedures@>@/
+@#
+procedure initialize; {this procedure gets things started properly}
+@z
+
+TeX 2.0 WEB source line 261
+@x
+@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
+@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
+@y
+@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
+@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
+@z
+
+TeX 2.0 WEB source line 266
+@x
+@d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering
+ usage statistics}
+@d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering
+ usage statistics}
+@y
+@d stat==
+@d tats==
+@z
+
+TeX 2.0 WEB source line 281
+@x
+@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
+@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
+@y virtex: init==@{ tini==@} initex: init== tini==
+@d init==@{
+@d tini==@}
+@z
+
+TeX 2.0 WEB source line 333
+@x
+@d othercases == others: {default for cases not listed explicitly}
+@y
+@d othercases == otherwise {default for cases not listed explicitly}
+@z
+
+TeX 2.0 WEB source line 345
+@x
+@!mem_max=30000; {greatest index in \TeX's internal |mem| array;
+ must be strictly less than |max_halfword|;
+ must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
+@!mem_min=0; {smallest index in \TeX's internal |mem| array;
+ must be |min_halfword| or more;
+ must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
+@!buf_size=500; {maximum number of characters simultaneously present in
+ current lines of open files and in control sequences between
+ \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
+@!error_line=72; {width of context lines on terminal error messages}
+@!half_error_line=42; {width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|}
+@!max_print_line=79; {width of longest text lines output; should be at least 60}
+@!stack_size=200; {maximum number of simultaneous input sources}
+@!max_in_open=6; {maximum number of input files and error insertions that
+ can be going on simultaneously}
+@!font_max=75; {maximum internal font number; must not exceed |max_quarterword|
+ and must be at most |font_base+256|}
+@!font_mem_size=20000; {number of words of |font_info| for all fonts}
+@!param_size=60; {maximum number of simultaneous macro parameters}
+@!nest_size=40; {maximum number of semantic levels simultaneously active}
+@!max_strings=3000; {maximum number of strings; must not exceed |max_halfword|}
+@!string_vacancies=8000; {the minimum number of characters that should be
+ available for the user's control sequences and font names,
+ after \TeX's own error messages are stored}
+@!pool_size=32000; {maximum number of characters in strings, including all
+ error messages and help texts, and the names of all fonts and
+ control sequences; must exceed |string_vacancies| by the total
+ length of \TeX's own strings, which is currently about 23000}
+@!save_size=600; {space for saving values outside of current group; must be
+ at most |max_halfword|}
+@!trie_size=8000; {space for hyphenation patterns; should be larger for
+ \.{INITEX} than it is in production versions of \TeX}
+@!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8}
+@!file_name_size=40; {file names shouldn't be longer than this}
+@!pool_name='TeXformats:TEX.POOL ';
+ {string of length |file_name_size|; tells where the string pool appears}
+@.TeXformats@>
+@y
+@!mem_max=32766; {greatest index in \TeX's internal |mem| array;
+ must be strictly less than |max_halfword|;
+ must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|}
+@!mem_min=-32768; {smallest index in \TeX's internal |mem| array;
+ must be |min_halfword| or more;
+ must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|}
+@!buf_size=2048; {maximum number of characters simultaneously present in
+ current lines of open files and in control sequences between
+ \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|}
+@!error_line=79; {width of context lines on terminal error messages}
+@!half_error_line=50; {width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|}
+@!max_print_line=79; {width of longest text lines output; should be at least 60}
+@!stack_size=200; {maximum number of simultaneous input sources}
+@!max_in_open=6; {maximum number of input files and error insertions that
+ can be going on simultaneously}
+@!font_max=120; {maximum internal font number; must not exceed |max_quarterword|
+ and must be at most |font_base+256|}
+@!font_mem_size=30000; {number of words of |font_info| for all fonts}
+@!param_size=60; {maximum number of simultaneous macro parameters}
+@!nest_size=40; {maximum number of semantic levels simultaneously active}
+@!max_strings=5000; {maximum number of strings; must not exceed |max_halfword|}
+@!string_vacancies=26000; {the minimum number of characters that should be
+ available for the user's control sequences and font names,
+ after \TeX's own error messages are stored}
+@!pool_size=50000; {maximum number of characters in strings, including all
+ error messages and help texts, and the names of all fonts and
+ control sequences; must exceed |string_vacancies| by the total
+ length of \TeX's own strings, which is currently about 23000}
+@!save_size=600; {space for saving values outside of current group; must be
+ at most |max_halfword|}
+@!trie_size=8000; {space for hyphenation patterns; should be larger for
+ \.{INITEX} than it is in production versions of \TeX}
+@!dvi_buf_size=2048; {size of the output buffer; must be a multiple of 8}
+@!len_byte_block=1024; {must be half of |dvi_buf_size|}
+@!tfm_buf_size=1024;
+@!len_word_block=256; {format file buffer length}
+@!file_name_size=40; {file names shouldn't be longer than this}
+@!pool_name='TEX.POOl.* ';
+ {string of length |file_name_size|; tells where the string pool appears}
+@.TeXformats@>
+@z
+
+TeX 2.0 WEB source line 395
+@x
+@d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX};
+ must not be less than |mem_min|}
+@d mem_top==30000 {largest index in the |mem| array dumped by \.{INITEX};
+ must be substantially larger than |mem_bot|
+ and not greater than |mem_max|}
+@d font_base=0 {smallest internal font number; must not be less
+ than |min_quarterword|}
+@d hash_size=2100 {maximum number of control sequences; it should be at most
+ about |(mem_max-mem_min)/10|, but 2100 is already quite generous}
+@d hash_prime=1777 {a prime number equal to about 85\% of |hash_size|}
+@d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions}
+@^system dependencies@>
+@y
+@d mem_bot==-32768 {smallest index in the |mem| array dumped by \.{INITEX};
+ must not be less than |mem_min|}
+@d mem_top==32766 {largest index in the |mem| array dumped by \.{INITEX};
+ must be substantially larger than |mem_bot|
+ and not greater than |mem_max|}
+@d font_base=0 {smallest internal font number; must not be less
+ than |min_quarterword|}
+@d hash_size=3000 {maximum number of control sequences; it should be at most
+ about |(mem_max-mem_min)/10|, but 2100 is already quite generous}
+@d hash_prime=2549 {a prime number equal to about 85\% of |hash_size|}
+@d hyph_size=307 {another prime; the number of \.{\\hyphenation} exceptions}
+@^system dependencies@>
+@z
+
+TeX 2.0 WEB source line 503
+@x
+@!ASCII_code=0..127; {seven-bit numbers}
+@y
+@!ASCII_code=packed 0..127; {seven-bit numbers}
+@z
+
+TeX 2.0 WEB source line 533
+@x
+@d last_text_char=127 {ordinal number of the largest element of |text_char|}
+@y
+@d last_text_char=255 {ordinal number of the largest element of |text_char|}
+@z
+
+TeX 2.0 WEB source line 689
+@x [2] System-dependent character set changes:
+@^character set dependencies@>
+@^system dependencies@>
+
+@<Set init...@>=
+for i:=1 to @'37 do xchr[i]:=' ';
+@y
+For \pvs\ we allow |form_feed| and |tab| characters in input.
+@^character set dependencies@>
+@^system dependencies@>
+
+@d form_feed=@'14
+@d tab=@'05
+
+@<Set initial values...@>=
+for i:=1 to @'37 do xchr[i]:=' ';
+xchr[form_feed]:=chr(form_feed);
+xchr[tab]:=chr(tab);
+@z
+
+TeX 2.0 WEB source line 737
+@x
+for us to specify simple operations on word files before they are defined.
+
+@<Types...@>=
+@!eight_bits=0..255; {unsigned one-byte quantity}
+@!alpha_file=packed file of text_char; {files that contain textual data}
+@!byte_file=packed file of eight_bits; {files that contain binary data}
+@y
+for us to specify simple operations on word files before they are defined.
+
+@d alpha_file==@= TEXT@>
+@d ccat==@=||@>
+
+@<Types...@>=
+@!eight_bits=packed 0..255; {unsigned one-byte quantity}
+@z
+
+TeX 2.0 WEB source line 790
+@x
+begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f);
+@y
+begin okstatus; reset(f,'NAME='ccat@, trim(str(name_of_file)));
+ a_open_in:=status;
+@z
+
+TeX 2.0 WEB source line 795
+@x
+begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f);
+@y
+var buf_string:string(4);
+begin okstatus;
+writestr(buf_string,buf_size:4);
+rewrite(f,'NAME='ccat@, trim(str(name_of_file))
+ccat ',LRECL=' ccat buf_string);
+ a_open_out:=status;
+@z
+
+TeX 2.0 WEB source line 800
+@x
+begin reset(f,name_of_file,'/O'); b_open_in:=reset_OK(f);
+@y
+begin okstatus; reset(f,'NAME='ccat@, trim(str(name_of_file) ccat'.*'));
+ b_open_in:=status;
+@z
+
+TeX 2.0 WEB source line 805
+@x
+begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f);
+@y
+begin okstatus; rewrite(f,'NAME='ccat@, trim(str(name_of_file)));
+ b_open_out:=status;
+@z
+
+TeX 2.0 WEB source line 810
+@x
+begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f);
+@y
+begin okstatus; reset(f,'NAME='ccat@, trim(str(name_of_file) ccat'.*'));
+ w_open_in:=status;
+@z
+
+TeX 2.0 WEB source line 815
+@x
+begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f);
+@y
+begin okstatus; rewrite(f,'NAME='ccat@, trim(str(name_of_file)));
+ w_open_out:=status;
+@z
+
+TeX 2.0 WEB source line 855
+@x
+@<Glob...@>=
+@!buffer:array[0..buf_size] of ASCII_code; {lines of characters being read}
+@y
+@d LA_buffer==
+@!buffer:array[0..buf_size] of ASCII_code; {lines of characters being read}
+
+@<Glob...@>=
+@z
+
+TeX 2.0 WEB source line 901
+@x
+@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
+ {inputs the next line or returns |false|}
+var last_nonblank:0..buf_size; {|last| with trailing blanks removed}
+begin if bypass_eoln then if not eof(f) then get(f);
+ {input the first character of the line into |f^|}
+last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
+if eof(f) then input_ln:=false
+else begin last_nonblank:=first;
+ while not eoln(f) do
+ begin if last>=max_buf_stack then
+ begin max_buf_stack:=last+1;
+ if max_buf_stack=buf_size then
+ overflow("buffer size",buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+ end;
+ buffer[last]:=xord[f^]; get(f); incr(last);
+ if buffer[last-1]<>" " then last_nonblank:=last;
+ end;
+ last:=last_nonblank; input_ln:=true;
+ end;
+end;
+@y
+@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
+ {inputs the next line or returns |false|}
+var last_nonblank:0..buf_size; {|last| with trailing blanks removed}
+begin if bypass_eoln then if not eof(f) then get(f);
+ {input the first character of the line into |f^|}
+last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
+if eof(f) then input_ln:=false
+else begin last_nonblank:=first;
+ while not eoln(f) do
+ begin if last>=max_buf_stack then
+ begin max_buf_stack:=last+1;
+ if max_buf_stack=buf_size then
+ overflow("buffer size",buf_size);
+@:TeX capacity exceeded buffer size}{\quad buffer size@>
+ end;
+ buffer[last]:=xord[f@@]; get(f); incr(last); {@@ is \pvs\ pointer notation}
+ if buffer[last-1]<>" " then last_nonblank:=last;
+ end;
+ last:=last_nonblank; input_ln:=true;
+ end;
+end;
+@z
+
+TeX 2.0 WEB source line 933
+@x
+@ Here is how to open the terminal files
+in \ph. The `\.{/I}' switch suppresses the first |get|.
+@^system dependencies@>
+
+@d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input}
+@d t_open_out==rewrite(term_out,'TTY:','/O') {open the terminal for text output}
+@y
+@ Here is how to open the terminal files
+in \pvs. There is no need to do a |reset| or |rewrite| or suppress
+the first |get| as with \ph.
+@d t_open_in==@= TERMIN@>(term_in) {open the terminal for text input}
+@d t_open_out==@= TERMOUT@>(term_out); {open the terminal for text output}
+@z
+
+TeX 2.0 WEB source line 949
+@x
+some instruction to the operating system. The following macros show how
+these operations can be specified in \ph:
+@^system dependencies@>
+
+@d update_terminal == break(term_out) {empty the terminal output buffer}
+@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer}
+@d wake_up_terminal == do_nothing {cancel the user's cancellation of output}
+@y
+some instructions to the operating system. The following macros were
+used to specify these operations in \ph\ but have been made into
+``no-ops'' for \pvs.
+@d update_terminal == do_nothing
+@d clear_terminal == do_nothing
+@d wake_up_terminal == do_nothing
+@z
+
+TeX 2.0 WEB source line 1011
+@x
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+begin t_open_in;
+loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
+@y
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+var i,j,k: integer;
+ l: string(256);
+begin t_open_in;
+ l:=parms;
+ if l<>'' then begin
+ i:=@=LENGTH@>(l);
+ j:=min(i,buf_size-first); {this much will fit}
+ if j>0 then for k:=0 to j-1 do buffer[first+k]:=xord[l[k+1]];
+ last:=first+j;
+ max_buf_stack:=max(max_buf_stack,last);
+ loc:=first;
+ init_terminal:=true;
+ return
+ end;
+loop@+begin wake_up_terminal; write_ln(term_out,'**'); update_terminal;
+@z
+
+TeX 2.0 WEB source line 1072
+@x
+@ @<Glob...@>=
+@!str_pool:packed array[pool_pointer] of ASCII_code; {the characters}
+@!str_start : array[str_number] of pool_pointer; {the starting pointers}
+@y
+@ @d LA_string==
+@!str_pool:packed array[pool_pointer] of ASCII_code; {the characters}
+@!str_start : array[str_number] of pool_pointer; {the starting pointers}
+
+@<Glob...@>=
+@z
+
+The following change is to use \write15 to send stuff to CMS
+TeX 2.0 WEB source line 1373
+@x
+@ To end a line of text output, we call |print_ln|.
+
+@<Basic print...@>=
+procedure print_ln; {prints an end-of-line}
+begin case selector of
+term_and_log: begin wterm_cr; wlog_cr;
+ term_offset:=0; file_offset:=0;
+ end;
+log_only: begin wlog_cr; file_offset:=0;
+ end;
+term_only: begin wterm_cr; term_offset:=0;
+ end;
+no_print,pseudo,new_string: do_nothing;
+othercases write_ln(write_file[selector])
+endcases;@/
+end; {|tally| is not affected}
+@y
+@ To end a line of text output, we call |print_ln|.
+In CMS \TeX\ we also use |print_ln| to send a message
+to the operating system using the \.{\\write15} stream.
+
+@<Basic print...@>=
+procedure print_ln; {prints an end-of-line}
+var i:integer;
+begin case selector of
+term_and_log: begin wterm_cr; wlog_cr;
+ term_offset:=0; file_offset:=0;
+ end;
+log_only: begin wlog_cr; file_offset:=0;
+ end;
+term_only: begin wterm_cr; term_offset:=0;
+ end;
+no_print,pseudo,new_string: do_nothing;
+15: begin cms(trim(str(cms_buf)), irc); {send \.{\\write15} to CMS}
+ for i:=1 to cms_ptr do cms_buf[i]:=' ';
+ cms_ptr:=1; end;
+othercases write_ln(write_file[selector])
+endcases;@/
+end; {|tally| is not affected}
+@z
+
+The following change is to use \write15 to send stuff to CMS
+TeX 2.0 WEB source line 1394
+@x
+@<Basic printing...@>=
+procedure print_char(@!s:ASCII_code); {prints a single character}
+label exit;
+begin if @<Character |s| is the current new-line character@> then
+ if selector<pseudo then
+ begin print_ln; return;
+ end;
+case selector of
+term_and_log: begin wterm(xchr[s]); wlog(xchr[s]);
+ incr(term_offset); incr(file_offset);
+ if term_offset=max_print_line then
+ begin wterm_cr; term_offset:=0;
+ end;
+ if file_offset=max_print_line then
+ begin wlog_cr; file_offset:=0;
+ end;
+ end;
+log_only: begin wlog(xchr[s]); incr(file_offset);
+ if file_offset=max_print_line then print_ln;
+ end;
+term_only: begin wterm(xchr[s]); incr(term_offset);
+ if term_offset=max_print_line then print_ln;
+ end;
+no_print: do_nothing;
+pseudo: if tally<trick_count then trick_buf[tally mod error_line]:=s;
+new_string: begin if pool_ptr<pool_size then append_char(s);
+ end; {we drop characters if the string space is full}
+othercases write(write_file[selector],xchr[s])
+endcases;@/
+incr(tally);
+exit:end;
+@y
+@<Basic printing...@>=
+procedure print_char(@!s:ASCII_code); {prints a single character}
+label exit;
+begin if @<Character |s| is the current new-line character@> then
+ if selector<pseudo then
+ begin print_ln; return;
+ end;
+case selector of
+term_and_log: begin wterm(xchr[s]); wlog(xchr[s]);
+ incr(term_offset); incr(file_offset);
+ if term_offset=max_print_line then
+ begin wterm_cr; term_offset:=0;
+ end;
+ if file_offset=max_print_line then
+ begin wlog_cr; file_offset:=0;
+ end;
+ end;
+log_only: begin wlog(xchr[s]); incr(file_offset);
+ if file_offset=max_print_line then print_ln;
+ end;
+term_only: begin wterm(xchr[s]); incr(term_offset);
+ if term_offset=max_print_line then print_ln;
+ end;
+no_print: do_nothing;
+pseudo: if tally<trick_count then trick_buf[tally mod error_line]:=s;
+new_string: begin if pool_ptr<pool_size then append_char(s);
+ end; {we drop characters if the string space is full}
+15: begin cms_buf[cms_ptr]:=xchr[s]; incr(cms_ptr); end;
+othercases write(write_file[selector],xchr[s])
+endcases;@/
+incr(tally);
+exit:end;
+@z
+
+The following change is to use \write15 to send stuff to CMS
+TeX 2.0 WEB source line 1623
+@x
+if not input_ln(term_in,true) then fatal_error("End of file on the terminal!");
+@y
+write_ln(term_out);
+if not input_ln(term_in,true) then fatal_error("End of file on the terminal!");
+@z
+
+TeX 2.0 WEB source line 1814
+@x
+wizardry, so the present implementation simply types out what file should be
+edited and the relevant line number.
+@^system dependencies@>
+
+There is a secret `\.D' option available when the debugging routines have
+not been commented out.
+@^debugging@>
+
+@<Interpret code |c| and |return| if done@>=
+case c of
+"0","1","2","3","4","5","6","7","8","9": if deletions_allowed then
+ @<Delete |c-"0"| tokens and |goto continue|@>;
+@t\4\4@>@;@+@!debug "D": begin debug_help; goto continue;@+end;@+gubed@/
+"E": if base_ptr>0 then
+ begin print_nl("You want to edit file ");
+@.You want to edit file x@>
+ print(input_stack[base_ptr].name_field);
+ print(" at line "); print_int(line);
+ interaction:=scroll_mode; jump_out;
+ end;
+"H": @<Print the help information and |goto continue|@>;
+"I":@<Introduce new material from the terminal and |return|@>;
+"Q","R","S":@<Change the interaction level and |return|@>;
+"X":begin interaction:=scroll_mode; jump_out;
+ end;
+othercases do_nothing
+endcases;@/
+@<Print the menu of available options@>
+@y
+wizardry, so the standard implementation simply types out what file should be
+edited and the relevant line number.
+The CMS implementation uses an external assembly routine |attn202| to
+invoke XEDIT with ``:|line|'' in the
+program stack.
+@^system dependencies@>
+
+There is a secret `\.D' option available when the debugging routines have
+not been commented out.
+@^debugging@>
+
+@<Interpret code |c| and |return| if done@>=
+case c of
+"0","1","2","3","4","5","6","7","8","9": if deletions_allowed then
+ @<Delete |c-"0"| tokens and |goto continue|@>;
+@t\4\4@>@;@+@!debug "D": begin debug_help; goto continue;@+end;@+gubed@/
+"E": if base_ptr>0 then
+ begin print_nl("You want to edit file ");
+@.You want to edit file x@>
+ print(input_stack[base_ptr].name_field);
+ print(" at line "); print_int(line);
+ inp_line:='XEDIT ';
+ s1:=selector;
+ tally:=0; selector:=pseudo;
+ print(input_stack[base_ptr].name_field);
+ for s2:=0 to tally-1 do inp_line[s2+7]:=xchr[trick_buf[s2]];
+ s2:=string_index(inp_line,'.'); if s2>0 then inp_line[s2]:=' ';
+ s2:=string_index(inp_line,'.'); if s2>0 then inp_line[s2]:=' ';
+ attn202('FIFO ',inp_line);
+ tally:=0; inp_line:=' ';
+ print_int(line);
+ inp_line[1]:=':';
+ for s2:=0 to tally-1 do inp_line[s2+2]:=xchr[trick_buf[s2]];
+ attn202('FIFO ',inp_line);
+ ret_code(12);
+ selector:=s1;
+ interaction:=scroll_mode; jump_out;
+ end;
+"H": @<Print the help information and |goto continue|@>;
+"I":@<Introduce new material from the terminal and |return|@>;
+"Q","R","S":@<Change the interaction level and |return|@>;
+"X":begin interaction:=scroll_mode; jump_out;
+ end;
+othercases do_nothing
+endcases;@/
+@<Print the menu of available options@>
+@z
+
+TeX 2.0 WEB source line 2030
+@x
+interrupt:=0; OK_to_interrupt:=true;
+@y
+interrupt:=0; OK_to_interrupt:=true;
+term_attn(interrupt);
+@z
+
+TeX 2.0 WEB source line 2277
+@x
+@!glue_ratio=real; {one-word representation of a glue expansion factor}
+@y
+@!glue_ratio=shortreal; {are there any other reals in the program?}
+@z
+
+TeX 2.0 WEB source line 2330
+@x
+@d min_quarterword=0 {smallest allowable value in a |quarterword|}
+@d max_quarterword=255 {largest allowable value in a |quarterword|}
+@d min_halfword==0 {smallest allowable value in a |halfword|}
+@d max_halfword==65535 {largest allowable value in a |halfword|}
+@y
+@d min_quarterword=0 {smallest allowable value in a |quarterword|}
+@d max_quarterword=255 {largest allowable value in a |quarterword|}
+@d min_halfword==-32768 {smallest allowable value in a |halfword|}
+@d max_halfword==32767 {largest allowable value in a |halfword|}
+@z
+
+TeX 2.0 WEB source line 2363
+@x
+@d qi(#)==#+min_quarterword
+ {to put an |eight_bits| item into a quarterword}
+@d qo(#)==#-min_quarterword
+ {to take an |eight_bits| item out of a quarterword}
+@d hi(#)==#+min_halfword
+ {to put a sixteen-bit item into a halfword}
+@d ho(#)==#-min_halfword
+ {to take a sixteen-bit item from a halfword}
+@y
+@d qi(#)==#
+ {to put an |eight_bits| item into a quarterword}
+@d qo(#)==#
+ {to take an |eight_bits| item out of a quarterword}
+@d hi(#)==#+min_halfword
+ {to put a sixteen-bit item into a halfword}
+@d ho(#)==#-min_halfword
+ {to take a sixteen-bit item from a halfword}
+@z
+
+TeX 2.0 WEB source line 2378
+@x
+@!quarterword = min_quarterword..max_quarterword; {1/4 of a word}
+@!halfword=min_halfword..max_halfword; {1/2 of a word}
+@!two_choices = 1..2; {used when there are two variants in a record}
+@!four_choices = 1..4; {used when there are four variants in a record}
+@y
+@!quarterword = packed min_quarterword..max_quarterword; {1/4 of a word}
+@!halfword=packed min_halfword..max_halfword; {1/2 of a word}
+@!two_choices=packed 1..2; {used when there are two variants in a record}
+@!four_choices=packed 1..4; {when there are four variants in a record}
+@z
+
+TeX 2.0 WEB source line 2401
+@x
+@!word_file = file of memory_word;
+@y
+@!word_block = packed array [0..len_word_block-1] of memory_word;
+@!word_file = packed file of word_block;
+@!byte_block = packed array [0..len_byte_block-1] of quarterword;
+@!byte_file = packed file of byte_block;
+@z
+
+TeX 2.0 WEB source line 2466
+@x
+deallocating them after their use.
+
+@<Glob...@>=
+@!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area}
+@y
+deallocating them after their use.
+
+For \pvs\ we have declared the big |mem| array in the ``large array
+variables'' module. It is defined here in terms of a macro expanded
+near the end of the program. All such ``large array'' macros begin
+with ``|LA_|.''
+
+@d LA_mem==
+@!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area}
+
+@<Glob...@>=
+@z
+
+TeX 2.0 WEB source line 3268
+@x
+been included. (You may want to decrease the size of |mem| while you
+@^debugging@>
+are debugging.)
+
+@<Glob...@>=
+@!debug @!free: packed array [mem_min..mem_max] of boolean; {free cells}
+@t\hskip1em@>@!was_free: packed array [mem_min..mem_max] of boolean;
+ {previously free cells}
+@t\hskip1em@>@!was_mem_end,@!was_lo_max,@!was_hi_min: pointer;
+@y
+been included. (You may want to decrease the size of |mem| while you
+@^debugging@>
+are debugging.)
+
+@d LA_mem_debug==
+@!free: packed array [mem_min..mem_max] of boolean; {free cells}
+@!was_free: packed array [mem_min..mem_max] of boolean;
+ {previously free cells}
+
+@<Glob...@>=
+@!debug @!was_mem_end,@!was_lo_max,@!was_hi_min: pointer;
+@z
+
+TeX 2.0 WEB source line 3653
+@x
+ if abs(mem[p+glue_offset].int)<@'4000000 then print("?.?")
+@y
+ if false then print("?.?") {no need to check value in 370 architecture}
+@z
+
+TeX 2.0 WEB source line 4218
+@x
+@<Glob...@>=
+@!nest:array[0..nest_size] of list_state_record;
+@y
+@d LA_nest==
+@!nest:array[0..nest_size] of list_state_record;
+
+@<Glob...@>=
+@z
+
+TeX 2.0 WEB source line 5085
+@x
+is needed. The program here simply specifies July 4, 1776, at noon; but
+users probably want a better approximation to the truth.
+
+@p procedure fix_date_and_time;
+begin time:=12*60; {minutes since midnight}
+day:=4; {fourth day of the month}
+month:=7; {seventh month of the year}
+year:=1776; {Anno Domini}
+end;
+@y
+is needed. The standard program
+here simply specified July 4, 1776, at noon; but
+we want a better approximation to the truth.
+
+@p procedure fix_date_and_time;
+var date,tod:alfa; hour, minute:integer;
+begin datetime(date,tod);
+readstr(str(date),month:3,day:3,year);
+year:=year+1900;{Bug next century}
+readstr(str(tod),hour:3,minute); time:=hour*60+minute;
+end;
+@z
+
+TeX 2.0 WEB source line 5289
+@x
+called |xeq_level|.
+
+@<Glob...@>=
+@!eqtb:array[active_base..eqtb_size] of memory_word;
+@!xeq_level:array[int_base..eqtb_size] of quarterword;
+@y
+called |xeq_level|.
+
+@d LA_eqtb==
+@!eqtb:array[active_base..eqtb_size] of memory_word;
+@!xeq_level:array[int_base..eqtb_size] of quarterword;
+@z
+
+TeX 2.0 WEB source line 5336
+@x
+@d hash_is_full == (hash_used=hash_base) {test if all positions are occupied}
+@d font_id_text(#) == text(font_id_base+#) {a frozen font identifier's name}
+
+@<Glob...@>=
+@!hash: array[hash_base..undefined_control_sequence-1] of two_halves;
+ {the hash table}
+@y
+@d hash_is_full == (hash_used=hash_base) {test if all positions are occupied}
+@d font_id_text(#) == text(font_id_base+#) {a frozen font identifier's name}
+@#
+@d LA_hash==
+@!hash: array[hash_base..undefined_control_sequence-1] of two_halves;
+ {the hash table}
+
+@<Glob...@>=
+@z
+
+TeX 2.0 WEB source line 5721
+@x
+@ @<Glob...@>=
+@!save_stack : array[0..save_size] of memory_word;
+@y
+@ @d LA_save_stack==
+@!save_stack : array[0..save_size] of memory_word;
+
+@<Glob...@>=
+@z
+
+TeX 2.0 WEB source line 6277
+@x
+@ @<Glob...@>=
+@!input_stack : array[0..stack_size] of in_state_record;
+@y
+@ @d LA_input_stack==
+@!input_stack : array[0..stack_size] of in_state_record;
+
+@<Glob...@>=
+@z
+
+TeX 2.0 WEB source line 6543
+@x
+rate from the others.
+
+@<Glob...@>=
+@!param_stack:array [0..param_size] of pointer;
+ {token list pointers for parameters}
+@y
+rate from the others.
+
+@d LA_param_stack==
+@!param_stack:array [0..param_size] of pointer;
+ {token list pointers for parameters}
+
+@<Glob...@>=
+@z
+
+TeX 2.0 WEB source line 9736
+@x
+@d TEX_area=="TeXinputs:"
+@.TeXinputs@>
+@d TEX_font_area=="TeXfonts:"
+@.TeXfonts@>
+@y
+@d TEX_area==".*"
+@.TeXinputs@>
+@d TEX_font_area==""
+@.TeXfonts@>
+@z
+
+TeX 2.0 WEB source line 9751
+@x
+@p function more_name(@!c:ASCII_code):boolean;
+begin if c=" " then more_name:=false
+else begin if (c=">")or(c=":") then
+ begin area_delimiter:=pool_ptr; ext_delimiter:=0;
+ end
+ else if (c=".")and(ext_delimiter=0) then ext_delimiter:=pool_ptr;
+ str_room(1); append_char(c); {contribute |c| to the current string}
+ more_name:=true;
+ end;
+end;
+@y
+@p function more_name(@!c:ASCII_code):boolean;
+var ret:boolean;
+begin
+if c=" " then ret:=false
+else begin ret:=true;
+ if (c=".")then if ext_delimiter=0 then ext_delimiter:=pool_ptr
+ else if area_delimiter=0 then area_delimiter:=pool_ptr
+ else ret:=false;
+ if ret then begin {contribute |c| to the current string}
+ str_room(1); append_char(c); end;
+ end;
+more_name:=ret;
+end;
+@z
+
+TeX 2.0 WEB source line 9769
+@x
+if area_delimiter=0 then cur_area:=""
+else begin cur_area:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=area_delimiter+1;
+ end;
+if ext_delimiter=0 then
+ begin cur_ext:=""; cur_name:=make_string;
+ end
+else begin cur_name:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=ext_delimiter; cur_ext:=make_string;
+ end;
+end;
+@y
+if ext_delimiter=0 then begin cur_area:=""; cur_ext:="";
+ cur_name:=make_string; end
+else begin cur_name:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=ext_delimiter;
+ if area_delimiter=0 then
+ begin cur_area:=""; cur_ext:=make_string;
+ end
+ else begin cur_ext:=str_ptr; incr(str_ptr);
+ str_start[str_ptr]:=area_delimiter; cur_area:=make_string;
+ end;
+ end;
+end;
+@z
+
+TeX 2.0 WEB source line 9788
+@x
+begin print(a); print(n); print(e);
+@y
+begin print(n); print(e); print(a);
+@z
+
+TeX 2.0 WEB source line 9800
+@x
+@p procedure pack_file_name(@!n,@!a,@!e:str_number);
+@y
+@p procedure pack_file_name(@!a,@!e,@!n:str_number);
+@z
+
+TeX 2.0 WEB source line 9818
+@x
+@d format_default_length=20 {length of the |TEX_format_default| string}
+@d format_area_length=11 {length of its area part}
+@y
+@d format_default_length=9 {length of the |TEX_format_default| string}
+@d format_area_length=0 {length of its area part}
+@z
+
+TeX 2.0 WEB source line 9826
+@x
+TEX_format_default:='TeXformats:plain.fmt';
+@y
+TEX_format_default:='plain.fmt';
+@z
+
+TeX 2.0 WEB source line 9998
+@x
+clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
+if cur_ext="" then cur_ext:=e;
+pack_cur_name;
+@y
+clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>;
+if cur_ext="" then cur_ext:=e;
+if (s="input file name") and (cur_area="") then cur_area:=TEX_area;
+pack_cur_name;
+@z
+
+TeX 2.0 WEB source line 10034
+@x
+@p procedure open_log_file;
+var old_setting:0..max_selector; {previous |selector| setting}
+@!k:0..buf_size; {index into |months| and |buffer|}
+@!l:0..buf_size; {end of first input line}
+@!months:packed array [1..36] of char; {abbreviations of month names}
+begin old_setting:=selector;
+if job_name=0 then job_name:="texput";
+@.texput@>
+pack_job_name(".log");
+while not a_open_out(log_file) do @<Try to get a different log file name@>;
+log_name:=a_make_name_string(log_file);
+selector:=log_only;
+@y
+@p procedure open_log_file;
+var old_setting:0..max_selector; {previous |selector| setting}
+@!k:0..buf_size; {index into |months| and |buffer|}
+@!l:0..buf_size; {end of first input line}
+@!months:packed array [1..36] of char; {abbreviations of month names}
+begin old_setting:=selector;
+if job_name=0 then job_name:="texput";
+@.texput@>
+pack_job_name(".texlog");
+while not a_open_out(log_file) do @<Try to get a different log file name@>;
+log_name:=a_make_name_string(log_file);
+selector:=log_only;
+@z
+
+TeX 2.0 WEB source line 10089
+@x
+@p procedure start_input; {\TeX\ will \.{\\input} something}
+label done;
+begin scan_file_name; {set |cur_name| to desired file name}
+if cur_ext="" then cur_ext:=".tex";
+pack_cur_name;
+loop@+ begin begin_file_reading; {set up |cur_file| and new level of input}
+ if a_open_in(cur_file) then goto done;
+ if cur_area="" then
+ begin pack_file_name(cur_name,TEX_area,cur_ext);
+ if a_open_in(cur_file) then goto done;
+ end;
+ end_file_reading; {remove the level that didn't work}
+ prompt_file_name("input file name",".tex");
+ end;
+done: name:=a_make_name_string(cur_file);
+if job_name=0 then
+ begin job_name:=cur_name; open_log_file;
+@y
+@p procedure start_input; {\TeX\ will \.{\\input} something}
+label done;
+begin scan_file_name; {set |cur_name| to desired file name}
+if cur_ext="" then cur_ext:=".tex";
+if cur_area="" then cur_area:=TEX_area;
+pack_cur_name;
+loop@+ begin begin_file_reading; {set up |cur_file| and new level of input}
+ if a_open_in(cur_file) then goto done;
+ end_file_reading; {remove the level that didn't work}
+ prompt_file_name("input file name",".tex");
+ end;
+done: name:=a_make_name_string(cur_file);
+if job_name=0 then
+ begin job_name:=cur_name; open_log_file;
+@z
+
+|flush_string| removed--spoils XEDIT invocation
+TeX 2.0 WEB source line 10110
+@x
+print_char("("); print(name); update_terminal; state:=new_line;
+if name=str_ptr-1 then {we can conserve string pool space now}
+ begin flush_string; name:=cur_name;
+ end;
+@<Read the first line of the new file@>;
+end;
+@y
+print_char("("); print(name); update_terminal; state:=new_line;
+@<Read the first line of the new file@>;
+end;
+@z
+
+TeX 2.0 WEB source line 10399
+@x
+@ Here now is the (rather formidable) array of font arrays.
+
+@<Glob...@>=
+@!font_info:array[0..font_mem_size] of memory_word;
+ {the big collection of font data}
+@!fmem_ptr:0..font_mem_size; {first unused word of |font_info|}
+@!font_ptr:internal_font_number; {largest internal font number in use}
+@!font_check:array[internal_font_number] of four_quarters; {check sum}
+@!font_size:array[internal_font_number] of scaled; {``at'' size}
+@!font_dsize:array[internal_font_number] of scaled; {``design'' size}
+@!font_params:array[internal_font_number] of halfword; {how many font
+ parameters are present}
+@!font_name:array[internal_font_number] of str_number; {name of the font}
+@!font_area:array[internal_font_number] of str_number; {area of the font}
+@!font_bc:array[internal_font_number] of eight_bits;
+ {beginning (smallest) character code}
+@!font_ec:array[internal_font_number] of eight_bits;
+ {ending (largest) character code}
+@!font_glue:array[internal_font_number] of pointer;
+ {glue specification for interword space, |null| if not allocated}
+@!font_used:array[internal_font_number] of boolean;
+ {has a character from this font actually appeared in the output?}
+@!hyphen_char:array[internal_font_number] of integer;
+ {current \.{\\hyphenchar} values}
+@!skew_char:array[internal_font_number] of integer;
+ {current \.{\\skewchar} values}
+@y
+@ Here now is the (rather formidable) array of font arrays.
+
+@d LA_font1==
+@!font_info:array[0..font_mem_size] of memory_word;
+ {the big collection of font data}
+@!font_check:array[internal_font_number] of four_quarters; {check sum}
+@!font_size:array[internal_font_number] of scaled; {``at'' size}
+@!font_dsize:array[internal_font_number] of scaled; {``design'' size}
+@!font_params:array[internal_font_number] of halfword; {how many font
+ parameters are present}
+@!font_name:array[internal_font_number] of str_number; {name of the font}
+@!font_area:array[internal_font_number] of str_number; {area of the font}
+@!font_bc:array[internal_font_number] of eight_bits;
+ {beginning (smallest) character code}
+@!font_ec:array[internal_font_number] of eight_bits;
+ {ending (largest) character code}
+@!font_glue:array[internal_font_number] of pointer;
+ {glue specification for interword space, |null| if not allocated}
+@!font_used:array[internal_font_number] of boolean;
+ {has a character from this font actually appeared in the output?}
+@!hyphen_char:array[internal_font_number] of integer;
+ {current \.{\\hyphenchar} values}
+@!skew_char:array[internal_font_number] of integer;
+ {current \.{\\skewchar} values}
+
+@<Glob...@>=
+@!fmem_ptr:0..font_mem_size; {first unused word of |font_info|}
+@!font_ptr:internal_font_number; {largest internal font number in use}
+@z
+
+TeX 2.0 WEB source line 10435
+@x
+@<Glob...@>=
+@y
+@d LA_font2==
+@z
+
+TeX 2.0 WEB source line 10639
+@x
+@ @<Open |tfm_file| for input@>=
+@y
+@ @<Open |tfm_file| for input@>=
+tfm_count:=0;
+@z
+
+TeX 2.0 WEB source line 10654
+@x
+@d fget==get(tfm_file)
+@d fbyte==tfm_file^
+@y
+@ In CMS we know that \.{TFM} files have a logical record length of
+1024 bytes, so we do one |get(tfm_file)| per CMS record. Then, since
+|tfm_file| is a |byte_file| which is a |file of byte_block| which are
+arrays of 1024 bytes, we refer to each byte in the record while it is
+in the file buffer, avoiding the need to |get(tfm_file)| for each byte.
+Note that |fget| procedure is defined at the end of the program.
+@d fbyte==tfm_file@@[tfm_count] {@@ is \pvs\ pointer notation}
+@z
+
+TeX 2.0 WEB source line 11527
+@x
+@ Some systems may find it more efficient to make |dvi_buf| a |packed|
+array, since output of four bytes at once may be facilitated.
+@^system dependencies@>
+@y
+@ We play a trick with variant records so that we can fill up the
+|dvi_buf| array byte by byte, but write it out in one swell foop.
+@^system dependencies@>
+@d dvi_buf==d_buffer.b {buffer for \.{DVI} output}
+@z
+
+TeX 2.0 WEB source line 11531
+@x
+@!dvi_buf:array[dvi_index] of eight_bits; {buffer for \.{DVI} output}
+@y
+@!d_buffer: packed record
+ case boolean of
+ false:(b:packed array [dvi_index] of eight_bits);
+ true: (l:byte_block; r:byte_block);
+ end;
+@z
+
+TeX 2.0 WEB source line 11547
+@x
+@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
+|write_dvi(a,b)|. For best results, this procedure should be optimized to
+run as fast as possible on each particular system, since it is part of
+\TeX's inner loop. It is safe to assume that |a| and |b+1| will both be
+multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on
+many machines to use efficient methods to pack four bytes per word and to
+output an array of words with one system call.
+@^system dependencies@>
+@^inner loop@>
+@^defecation@>
+
+@p procedure write_dvi(@!a,@!b:dvi_index);
+var k:dvi_index;
+begin for k:=a to b do write(dvi_file,dvi_buf[k]);
+end;
+@y
+@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
+|write| on the other variant of the |dvi_buf| record. Thus, we had
+better be sure things line up properly.
+many machines to use efficient methods to pack four bytes per word and to
+output an array of words with one system call.
+@^system dependencies@>
+@^inner loop@>
+@^defecation@>
+
+@<Check the ``const...@>=
+if dvi_buf_size<>2*len_byte_block then bad:=223;
+@z
+
+TeX 2.0 WEB source line 11572
+@x
+ begin write_dvi(0,half_buf-1); dvi_limit:=half_buf;
+@y
+ begin write(dvi_file,d_buffer.l); dvi_limit:=half_buf;
+@z
+
+TeX 2.0 WEB source line 11575
+@x
+else begin write_dvi(half_buf,dvi_buf_size-1); dvi_limit:=dvi_buf_size;
+@y
+else begin write(dvi_file,d_buffer.r); dvi_limit:=dvi_buf_size;
+@z
+
+TeX 2.0 WEB source line 11584
+@x
+if dvi_limit=half_buf then write_dvi(half_buf,dvi_buf_size-1);
+if dvi_ptr>0 then write_dvi(0,dvi_ptr-1)
+@y
+if dvi_limit=half_buf then write(dvi_file,d_buffer.r);
+for k:=dvi_ptr to dvi_buf_size do dvi_buf[k]:=223; {bug is |k| ok?}
+if dvi_ptr>0 then write(dvi_file,d_buffer.l);
+if dvi_ptr>half_buf then write(dvi_file,d_buffer.r);
+@z
+
+TeX 1.1 WEB source line 12302
+@x
+print_char("["); j:=9;
+while (count(j)=0)and(j>0) do decr(j);
+for k:=0 to j do
+ begin print_int(count(k));
+ if k<j then print_char(".");
+ end;
+update_terminal;
+if tracing_output>0 then
+ begin print_char("]");
+ begin_diagnostic; show_box(p); end_diagnostic(true);
+ end;
+@<Ship box |p| out@>;
+if tracing_output<=0 then print_char("]");
+@y
+print_char("<"); j:=9;
+while (count(j)=0)and(j>0) do decr(j);
+for k:=0 to j do
+ begin print_int(count(k));
+ if k<j then print_char(".");
+ end;
+update_terminal;
+if tracing_output>0 then
+ begin print_char(">");
+ begin_diagnostic; show_box(p); end_diagnostic(true);
+ end;
+@<Ship box |p| out@>;
+if tracing_output<=0 then print_char(">");
+@z
+
+TeX 2.0 WEB source line 15720
+@x
+@d delta_node=2 {|type| field in a delta node}
+@y
+@d delta_node=2 {|type| field in a delta node}
+
+@<Types...@>=
+@!delta_array=array[1..6] of scaled;
+@z
+
+TeX 2.0 WEB source line 15735
+@x
+@d do_all_six(#)==#(1);#(2);#(3);#(4);#(5);#(6)
+
+@<Glo...@>=
+@!active_width:array[1..6] of scaled;
+ {distance from first active node to~|cur_p|}
+@!cur_active_width:array[1..6] of scaled; {distance from current active node}
+@!background:array[1..6] of scaled; {length of an ``empty'' line}
+@!break_width:array[1..6] of scaled; {length being computed after current break}
+@y
+In standard \TeX\ the |do_all_six| macro is sometimes used just to copy one
+of these arrays to another. In this version, that uses \pvs, these have been
+converted to simple array assignments. This not only produces faster code,
+it decreases the size of the generated procedure: which is important, for
+|try_break| is very nearly too large for \pvs.
+
+@d do_all_six(#)==#(1);#(2);#(3);#(4);#(5);#(6)
+
+@<Glo...@>=
+@!active_width:delta_array; {distance from first active node to~|cur_p|}
+@!cur_active_width:delta_array; {distance from current active node}
+@!background:delta_array; {length of an ``empty'' line}
+@!break_width:delta_array; {length being computed after current break}
+@z
+
+TeX 2.0 WEB source line 15874
+@x
+@<Other local variables for |try_break|@>@;
+@y
+@<Other local variables for |try_break|@>@;
+
+procedure print_new_break; begin
+@<Print a symbolic description of the new break node@>
+end;
+
+procedure print_feasible_break; begin
+ @<Print a symbolic description of this feasible break@>;
+end;
+@z
+
+TeX 2.0 WEB source line 15877
+@x
+do_all_six(copy_to_cur_active);
+@y
+cur_active_width:=active_width; {\pvs\ for |do_all_six(copy_to_cur_active)|}
+@z
+
+TeX 2.0 WEB source line 16020
+@x
+begin no_break_yet:=false; do_all_six(set_break_width_to_background);
+@y
+begin no_break_yet:=false; break_width:=background;
+ {\pvs\ for |do_all_six(set_break_width_to_background)|}
+@z
+
+TeX 2.0 WEB source line 16122
+@x
+ begin do_all_six(store_break_width);
+@y
+ begin active_width:=break_width; {\pvs\ for |do_all_six(store_break_width)|}
+@z
+
+TeX 2.0 WEB source line 16158
+@x
+ @<Print a symbolic description of the new break node@>;
+@y
+ print_new_break;
+@z
+
+TeX 2.0 WEB source line 16343
+@x
+ @<Print a symbolic description of this feasible break@>;
+@y
+ print_feasible_break;
+@z
+
+TeX 2.0 WEB source line 16448
+@x
+ do_all_six(copy_to_cur_active);
+@y
+ cur_active_width:=active_width; {\pvs\ for |do_all_six(copy_to_cur_active)|}
+@z
+
+TeX 2.0 WEB source line 16523
+@x
+do_all_six(store_background);@/
+@y
+active_width:=background; {\pvs\ for |do_all_six(store_background)|}
+@z
+
+TeX 2.0 WEB source line 17394
+@x
+@!trie_pointer=0..trie_size; {an index into |trie|}
+@y
+@!trie_pointer=packed 0..trie_size; {an index into |trie|}
+@z
+
+TeX 2.0 WEB source line 17398
+@x
+@d trie_op(#)==trie[#].b0 {program for hyphenation at this trie location}
+
+@<Glob...@>=
+@y
+@d trie_op(#)==trie[#].b0 {program for hyphenation at this trie location}
+@#
+@d LA_trie==
+@z
+
+TeX 2.0 WEB source line 17457
+@x
+@!hyph_pointer=0..hyph_size; {an index into the ordered hash table}
+
+@ @<Glob...@>=
+@!hyph_word:array[hyph_pointer] of str_number; {exception words}
+@!hyph_list:array[hyph_pointer] of pointer; {list of hyphen positions}
+@y
+@!hyph_pointer=packed 0..hyph_size; {an index into the ordered hash table}
+
+@ @d LA_hyph==
+@!hyph_word:array[hyph_pointer] of str_number; {exception words}
+@!hyph_list:array[hyph_pointer] of pointer; {list of hyphen positions}
+
+@<Glob...@>=
+@z
+
+TeX 2.0 WEB source line 17665
+@x
+@d trie_op_hash_size=quarterword_diff+quarterword_diff {double}
+
+@<Glob...@>=
+@!init@! trie_op_hash:array[0..trie_op_hash_size] of quarterword;
+ {trie op codes for triples}
+tini@;@/
+@t\hskip1em@>@!trie_op_ptr:quarterword; {highest |trie_op| assigned}
+@y
+@d trie_op_hash_size=quarterword_diff+quarterword_diff {double}
+@#
+@d LA_trie_init1==
+@! trie_op_hash:array[0..trie_op_hash_size] of quarterword;
+ {trie op codes for triples}
+
+@<Glob...@>=
+@!trie_op_ptr:quarterword; {highest |trie_op| assigned}
+@z
+
+TeX 2.0 WEB source line 17717
+@x
+@d trie_root==trie_l[0] {root of the linked trie}
+
+@<Glob...@>=
+@!init @!trie_c:packed array[trie_pointer] of ASCII_code; {characters to match}
+@t\hskip1em@>@!trie_o:packed array[trie_pointer] of quarterword;
+ {operations to perform}
+@t\hskip1em@>@!trie_l:packed array[trie_pointer] of trie_pointer;
+ {left subtrie links}
+@t\hskip1em@>@!trie_r:packed array[trie_pointer] of trie_pointer;
+ {right subtrie links}
+@t\hskip1em@>@!trie_ptr:trie_pointer; {the number of nodes in the trie}
+@y
+@d trie_root==trie_l[0] {root of the linked trie}
+@#
+@d LA_trie_init2==
+@!trie_c:packed array[trie_pointer] of ASCII_code; {characters to match}
+@t\hskip1em@>@!trie_o:packed array[trie_pointer] of quarterword;
+ {operations to perform}
+@t\hskip1em@>@!trie_l:packed array[trie_pointer] of trie_pointer;
+ {left subtrie links}
+@t\hskip1em@>@!trie_r:packed array[trie_pointer] of trie_pointer;
+ {right subtrie links}
+
+@<Glob...@>=
+@!init @!trie_ptr:trie_pointer; {the number of nodes in the trie}
+@z
+
+TeX 2.0 WEB source line 17734
+@x
+initialized to zero.
+
+@<Glob...@>=
+@!init @!trie_hash:packed array[trie_pointer] of trie_pointer;
+tini {to identify equivalent subtries}
+@y
+initialized to zero.
+
+@d LA_trie_init3==
+@!trie_hash:packed array[trie_pointer] of trie_pointer;
+ {to identify equivalent subtries}
+@z
+
+TeX 2.0 WEB source line 17809
+@x
+@d trie_back(#)==trie[#].lh {backward links in |trie| holes}
+
+@<Glob...@>=
+@!init@!trie_taken:packed array[trie_pointer] of boolean;
+ {does a family start here?}
+@t\hskip1em@>@!trie_min:trie_pointer;
+@y
+@d trie_back(#)==trie[#].lh {backward links in |trie| holes}
+@#
+@d LA_trie_init4==
+@!trie_taken:packed array[trie_pointer] of boolean;
+ {does a family start here?}
+
+@<Glob...@>=
+@!init @!trie_min:trie_pointer;
+@z
+
+TeX 2.0 WEB source line 22573
+@x
+ if cur_ext="" then cur_ext:=".tex";
+@y
+ if cur_ext="" then cur_ext:=".tex";
+ if cur_area="" then cur_area:=TEX_area;
+@z
+
+TeX 2.0 WEB source line 22865
+@x
+bad_fmt: wake_up_terminal;
+ wterm_ln('(Fatal format file error; I''m stymied)');
+@.Fatal format file error@>
+load_fmt_file:=false;
+exit:end;
+@y
+bad_fmt: wake_up_terminal;
+ wterm_ln('(Fatal format file error; I''m stymied)');
+@.Fatal format file error@>
+history:=fatal_error_stop;
+load_fmt_file:=false;
+exit:end;
+@z
+
+TeX 2.0 WEB source line 22885
+@x
+@d dump_wd(#)==begin fmt_file^:=#; put(fmt_file);@+end
+@d dump_int(#)==begin fmt_file^.int:=#; put(fmt_file);@+end
+@d dump_hh(#)==begin fmt_file^.hh:=#; put(fmt_file);@+end
+@d dump_qqqq(#)==begin fmt_file^.qqqq:=#; put(fmt_file);@+end
+
+@<Glob...@>=
+@y
+@d fmt_word==fmt_file@@[fmt_count]
+
+@d dump_wd(#)==begin fmt_word:=#; put_fmt;@+end
+@d dump_int(#)==begin fmt_word.int:=#; put_fmt;@+end
+@d dump_hh(#)==begin fmt_word.hh:=#; put_fmt;@+end
+@d dump_qqqq(#)==begin fmt_word.qqqq:=#; put_fmt;@+end
+
+@<Glob...@>=
+@!fmt_count:integer;
+@z
+
+TeX 2.0 WEB source line 22897
+@x
+@d undump_wd(#)==begin get(fmt_file); #:=fmt_file^;@+end
+@d undump_int(#)==begin get(fmt_file); #:=fmt_file^.int;@+end
+@d undump_hh(#)==begin get(fmt_file); #:=fmt_file^.hh;@+end
+@d undump_qqqq(#)==begin get(fmt_file); #:=fmt_file^.qqqq;@+end
+@y
+@d undump_wd(#)==begin get_fmt; #:=fmt_word;@+end
+@d undump_int(#)==begin get_fmt; #:=fmt_word.int;@+end
+@d undump_hh(#)==begin get_fmt; #:=fmt_word.hh;@+end
+@d undump_qqqq(#)==begin get_fmt; #:=fmt_word.qqqq;@+end
+@z
+
+TeX 2.0 WEB source line 22912
+@x
+@<Dump constants for consistency check@>=
+@y
+@<Dump constants for consistency check@>=
+fmt_count:=0;
+@z;
+
+TeX 2.0 WEB source line 22927
+@x
+x:=fmt_file^.int;
+@y
+fmt_count:=0;
+x:=fmt_word.int;
+@z
+
+TeX 2.0 WEB source line 23224
+@x
+dump_int(interaction); dump_int(format_ident); dump_int(69069);
+@y
+dump_int(interaction); dump_int(format_ident); dump_int(69069);
+while fmt_count<>0 do dump_int(0); {flush out the buffer}
+@z
+
+TeX 2.0 WEB source line 23309
+@x
+The initial test involving |ready_already| should be deleted if the
+\PASCAL\ runtime system is smart enough to detect such a ``mistake.''
+@^system dependencies@>
+
+@p begin @!{|start_here|}
+history:=fatal_error_stop; {in case we quit during initialization}
+t_open_out; {open the terminal for output}
+if ready_already=314159 then goto start_of_TEX;
+@y
+The initial test involving |ready_already| has been deleted here
+since the
+CMS storage management is not smart enough to clean up properly.
+We also declare the procedure |use_stack| which is explained in
+its definition.
+@^system dependencies@>
+
+@p @<Declare the procedure |use_stack|@> @;
+@#
+begin @!{|start_here|}
+use_stack;
+history:=fatal_error_stop; {in case we quit during initialization}
+t_open_out; {open the terminal for output}
+@z
+
+TeX 2.0 WEB source line 23319
+@x
+ begin wterm_ln('Ouch---my internal constants have been clobbered!',
+ '---case ',bad:1);
+@y
+ begin wterm_ln('Ouch---my internal constants have been clobbered!',
+ '---case ',bad:1);
+ ret_code(100+bad);
+@z
+
+TeX 2.0 WEB source line 23328
+@x
+ready_already:=314159;
+start_of_TEX: @<Initialize the output routines@>;
+@<Get the first line of input and prepare to start@>;
+init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/
+history:=spotless; {ready to go!}
+main_control; {come to life}
+final_cleanup; {prepare for death}
+end_of_TEX: close_files_and_terminate;
+final_end: ready_already:=0;
+@y
+do_nothing; {remove |ready_already:=314159;|}
+start_of_TEX: @<Initialize the output routines@>;
+@<Get the first line of input and prepare to start@>;
+init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/
+history:=spotless; {ready to go!}
+main_control; {come to life}
+final_cleanup; {prepare for death}
+end_of_TEX: close_files_and_terminate;
+final_end: ret_code(history*4);
+interrupt:=-1;
+term_attn(interrupt);
+@z
+
+TeX 2.0 WEB source line 23348
+@x
+but that can't cause infinite recursion.
+
+@<Last-minute...@>=
+procedure close_files_and_terminate;
+var k:integer; {all-purpose index}
+begin @<Finish the extensions@>;
+@!stat if tracing_stats>0 then @<Output statistics about this job@>;@;@+tats@/
+wake_up_terminal; @<Finish the \.{DVI} file@>;
+if job_name>0 then
+ begin wlog_cr; a_close(log_file); selector:=selector-2;
+@y
+but that can't cause infinite recursion.
+
+For \pvs\ we explicitly close all text input files, which standard
+\TeX\ leaves open, because \pvs\ sometimes(!) cannot manage
+to close them
+after a |jump_out| from an inner-level input file containing a
+\TeX\ error.
+It is (currently) okay to close files that are not open in \pvs.
+
+@<Last-minute...@>=
+procedure close_files_and_terminate;
+var k:integer; {all-purpose index}
+begin @<Finish the extensions@>;
+@!stat if tracing_stats>0 then @<Output statistics about this job@>;@;@+tats@/
+wake_up_terminal; @<Finish the \.{DVI} file@>;
+if job_name>0 then
+ begin wlog_cr; a_close(log_file);
+ for k:=1 to max_in_open do a_close(input_file[k]); {close input files}
+ selector:=selector-2;
+@z
+
+Web line 23602, add index code
+@x
+@d special_node=3 {|subtype| in whatsits that represent \.{\\special} things}
+@y
+@d special_node=3 {|subtype| in whatsits that represent \.{\\special} things}
+@d ix_print_node=5
+{|subtype| in whatsits that represent \.{\\printindex} things}
+@z
+The following change is to use \write15 to send stuff to CMS
+TeX 2.0 WEB source line 23619
+@x
+@ @<Set init...@>=
+for k:=0 to 17 do write_open[k]:=false;
+@y
+@ @<Set init...@>=
+for k:=0 to 17 do write_open[k]:=false;
+write_open[15]:=true; {hack open \.{\\write15} stream for sending
+ messages to CMS}
+cms_ptr:=1; {initialize |cms_buf| pointer and array}
+for k:=1 to buf_size do cms_buf[k]:=' ';
+@z
+
+Web line 23635, index code
+@x
+primitive("special",extension,special_node);@/
+@!@:special_}{\.{\\special} primitive@>
+@y
+primitive("special",extension,special_node);@/
+@!@:special_}{\.{\\special} primitive@>
+primitive("printindex",extension,ix_print_node);@/
+@!@:printindex_}{\.{\\printindex} primitive@>
+@z
+
+Web line 23651, index code
+@x
+ special_node:print_esc("special");
+@y
+ special_node:print_esc("special");
+ ix_print_node:print_esc("printindex");
+@z
+
+Web line 23671, index code
+@x
+special_node:@<Implement \.{\\special}@>;
+@y
+special_node:@<Implement \.{\\special}@>;
+ix_print_node:@<Implement \.{\\printindex}@>;
+@z
+
+Web line 23725, index code
+@x
+@<Implement \.{\\special}@>=
+begin new_whatsit(special_node,write_node_size); write_stream(tail):=null;
+p:=scan_toks(false,true); write_tokens(tail):=def_ref;
+end
+@y
+@<Implement \.{\\special}@>=
+begin new_whatsit(special_node,write_node_size); write_stream(tail):=null;
+p:=scan_toks(false,true); write_tokens(tail):=def_ref;
+end
+@ This is an extension to call TEXIX, the index building and sorting
+program.
+
+@<Implement \.{\\printindex}@>=
+begin scan_int;
+if (cur_val<1) or (cur_val>3)
+then begin
+print_err("Invalid index number");
+help2("Since I expected to read a number between 1 and 3,")
+("I changed this one to 1.");
+int_error(cur_val);
+cur_val:=1;
+end;
+texix(chr(cur_val+ord('0')));
+end
+
+@ The next procedure calls the Pascal/VS module TEXIX to build the
+sorted index. TEXIX calls
+the PL/1 procedure PLSORT, which calls the CASORT procedure to sort
+the index file.
+
+@<Declare procedures needed in |do_ext...@>=
+procedure texix(@!ix:char); external;
+
+@z
+
+TeX 2.0 WEB source line 23949
+@x
+This section should be replaced, if necessary, by changes to the program
+that are necessary to make \TeX\ work at a particular installation.
+It is usually best to design your change file so that all changes to
+previous sections preserve the section numbering; then everybody's version
+will be consistent with the published program. More extensive changes,
+which introduce new sections, can be inserted here; then only the index
+itself will get a new section number.
+@^system dependencies@>
+@y
+The following sections, as recommended, contain the changes necessary to
+make \TeX\ work under \pvs\ and CMS.
+
+@ The following two sections of code and comment are from Chris Thompson
+of Cambridge University Computing Service:
+
+One of the unfortunate features of the \pvs\ compiler (and, indeed, of
+all known \PASCAL\ compilers for the IBM/370 architecture) is that variables
+in a stack frame are allocated strictly in the order they were declared.
+If the stack frame is more than 4096 bytes long, access to the later variables
+is less efficient, as \pvs\ must generate code to add a suitable multiple
+of 4096 to the base register for the stack frame. If many different multiples
+of 4096 are involved, the situation is correspondingly worse.
+
+Unfortunately, this effect is particularly acute for programs like \TeX.
+The order of the global variable declarations in the program generated by
+\.{TANGLE} is the order they actually occur in the source of \TeX. This order
+is oriented towards a structured exposition of the program. In particular,
+arrays (some of them rather large) and simple variables are mixed up; thus
+some of the most heavily used global variables in \TeX\ not only are not
+assigned addresses in the first 4096 bytes of the global stack frame, but
+even occur in many different 4096-byte sections of that frame, causing
+\pvs\ to have to assign many registers to point at them.
+
+There are many possible ways in which this situation could be improved.
+In this version of \TeX\ the declarations of the largest arrays have been
+removed from the module ``Global variables'' and added to a new one called
+``Large array variables'' which is inserted at the end of the declarations.
+The object is to make the space allocated to the variables left in the first
+module no more than 4096 bytes. Many of the smaller arrays have been left in
+the first module; after all, they too can gain from being directly addressable.
+
+As the individual sections of ``Global variables'' often contain declarations
+of both simple and array variables, the latter have been converted to
+\.{TANGLE} macros which are expanded here, rather than building up
+``Large array variables'' on the way.
+This would also enable us to change the order of
+these arrays on the global stack frame if desired.
+
+@<Large array...@>=
+ LA_buffer @; LA_string @;
+ LA_mem @; debug LA_mem_debug gubed @;
+ LA_nest @; LA_eqtb @; LA_hash @; LA_save_stack @;
+ LA_input_stack @; LA_param_stack @;
+ LA_font1 @; LA_font2 @;
+ LA_trie @; LA_hyph @;
+ init LA_trie_init1 @; LA_trie_init2 @; LA_trie_init3 @; LA_trie_init4 tini
+
+@ Another unfortunate feature of the \pvs\ compiler (this time unique to it)
+is the way it manages the \PASCAL\ stack. Rather than allocating the whole
+stack area at once, it uses \.{GETMAIN} system calls to obtain chunks of store
+for it on demand. If stack overflow is detected on a routine call (i.e., the
+current chunk is not big enough; which, in particular, always happens when
+the main program is called from the runtime system) then a new chunk is made
+current. This is taken from a chain of spare chunks if any of them is big
+enough; if not, a new chunk is obtained, of size
+$$\lceil\max(\hbox{new stack frame}, d)\rceil\quad\hbox{Kbytes}$$
+where $d$ is specified by a runtime option, defaulting to 12\thinspace Kbytes.
+A special dummy procedure is
+placed between the caller and callee. When the callee returns, this procedure
+switches back to the old chunk, placing the new one on the spare list.
+
+Now, consider the case of \TeX. Most of the stack frames are not much larger
+than the \pvs\ minimum of 144 bytes, because they do not contain arrays;
+on the other hand, the global stack frame is enormous. The chunk obtained
+by \pvs\ for the main program will have between 0~and 1\thinspace Kbytes
+left after the global stack frame itself---and exactly how much will be
+quite impossible to keep control of as \TeX\ is altered. This is not
+enough for very many nested routine calls, and \TeX\ will soon use it up
+and obtain a new chunk of 12\thinspace Kbytes; this will suffice for
+nearly all \TeX\ applications (and if it didn't, we could change the
+runtime option).
+
+Some routines will have their stack frames very near the end of the
+first chunk. On every routine call they make, a switch will have to be
+made to the second chunk, and on each return to them a switch back again.
+Although this part of the \pvs\ runtime system is written in assembler,
+this is still a heavy overhead. If the routine involved is one that calls
+many other routines (the worst case may be |main_control|) then this will
+observably degrade the whole performance of \TeX. Experiments have shown
+variations due to this cause in the CPU time used by \TeX\ of 10\% in
+normal applications, and more than that in special cases.
+
+The possible solutions here range from altering the algorithm in \pvs\ to
+use a chunk size of
+$$\lceil\hbox{new stack frame} + d\rceil\quad\hbox{Kbytes}$$
+(which would work quite well for \TeX) to arranging to always specify a
+runtime system \.{STACK=d} option comfortably larger than the global
+stack frame (but then one could hardly hope ever to get another chunk
+if the first one {\sl did} run out). The solution adopted in this version
+of \TeX\ is to use an assembler routine |use_stack| which arranges that
+its caller's stack frame will subsequently be judged by \pvs\ to be as
+high as possible in the current chunk---to do this it has to know more
+than is good for it about the internals of \pvs, of course!
+
+Ideally, this routine would be used as follows. The main program would
+consist of a call of |use_stack|, followed by a call of
+ \\{do\_everything\_else};
+then only one call-return pair gets the overhead. This is awkward for \TeX,
+though, because of the labels in the main program, especially |end_of_TEX|.
+Almost as good is to insert a call of |use_stack| near the beginning of the
+existing main program, and this is what we do here. It works because the
+main program doesn't actually call many other routines, and has no loops---we
+can hope it will stay that way!
+
+@<Declare the procedure |use_stack|@>=
+procedure use_stack; external;
+
+@ Extra type needed for CMS message
+@<Types...@>=
+
+@!cms_buf_type=packed array[1..buf_size] of char;
+
+@ Here are extra global variables for VM/CMS routines
+@<Glob...@>=
+
+@!inp_line:string(255);
+@!cms_buf:cms_buf_type;
+@!cms_ptr:1..buf_size;
+@!irc:integer;
+@!tfm_count:integer;
+@!status: boolean; {did the last |reset| or |rewrite| succeed?}
+
+@ @<VM/CMS...@>=
+procedure term_attn(var interrupt: integer); fortran;
+procedure cms(const s:string; var rc:integer); external;
+procedure attn202(const lifofifo:alfa; const cmd:string); external;
+procedure okstatus; begin status:=true; end;
+@/@\@=%INCLUDE ONERROR;@>@\
+@#
+procedure onerror; begin
+if @= FERROR @> in [41,48] then begin
+ status:=false;
+ @= FACTION@>:=[@=XDECERR@>]; end;
+if @= FERROR@>=30 then interrupt:=1;
+end;
+
+procedure fget; begin {no check done for eof}
+ incr(tfm_count);
+ if tfm_count=tfm_buf_size then
+ begin get(tfm_file); tfm_count:=0;
+ end;
+ end;
+
+procedure put_fmt; begin
+ incr(fmt_count);
+ if fmt_count=len_word_block then
+ begin put(fmt_file); fmt_count:=0;
+ end;
+ end;
+
+procedure get_fmt; begin
+ incr(fmt_count);
+ if fmt_count=len_word_block then begin
+ get(fmt_file); fmt_count:=0;
+ end;
+ end;
+@z