summaryrefslogtreecommitdiff
path: root/systems/unix/tex-fpc/tex.ch
diff options
context:
space:
mode:
Diffstat (limited to 'systems/unix/tex-fpc/tex.ch')
-rw-r--r--systems/unix/tex-fpc/tex.ch1425
1 files changed, 1425 insertions, 0 deletions
diff --git a/systems/unix/tex-fpc/tex.ch b/systems/unix/tex-fpc/tex.ch
new file mode 100644
index 0000000000..491307d948
--- /dev/null
+++ b/systems/unix/tex-fpc/tex.ch
@@ -0,0 +1,1425 @@
+% This is a change file of TeX, Wolfgang Helbig, Nov. 2007-Nov. 2020
+
+[0] About TeX-FPC
+Strangely, the first page is page 3
+@x
+\pageno=3
+@y
+@z
+@x
+\def\gglob{20, 26} % this should be the next two sections of "<Global...>"
+@y
+\def\gglob{20, 26} % this should be the next two sections of "<Global...>"
+\input TeXinputs/webmac-fpc
+\pagewidth=14.8 cm % Close to the original book format.
+\setpage
+
+\emergencystretch 0.6in % avoid overfull boxes
+
+\let\maybe=\iffalse % maybe -> print all, notmaybe -> print changed modules only
+
+% put a mark in the left margin. (see Exercise 14.28 in The TeXbook)
+\def\marke#1{\strut\vadjust{\kern-\dp\strutbox\vbox to 0pt{\vss
+ \llap{\bf #1\/\quad\strut}}}\ignorespaces }
+
+\def\name{\TeX}
+
+\N0\*. \[0] About \namefpc.
+\namefpc\ is an adaption of Donald~E. Knuth's \TeX82 in
+the version 3.14159265 from January 2014 to Free~Pascal (FPC) and Unix.
+To help you identify the differences of \TeX82 and
+\namefpc, the numbers of modified modules carry an asterisk. Letters
+in the left margin indicate the reason for a change. They mean:
+\medskip
+\item{\bf E} fixes an error in \TeX82
+\item{\bf F} adds a feature as suggested by Knuth
+\item{\bf P} fixes a violation of Pascal (Jensen, Wirth: {\sl Pascal
+User Manual and Report\/}, 3rd edition, 1985)
+\item{\bf X} describes an FPC extension
+\item{\bf U} necessary change in Unix
+\item{\bf u} enhances usability in a Unix enviroment
+\medskip
+\item{(1)} \marke E \TeX82\ deletes area and extension of an input
+file name and then only shows the base name of the file during error
+recovery.
+
+\item{(2)} \TeX82 prunes discardable nodes from the beginning of a
+new line until it reaches a nondiscardable node. This might leave
+you with an empty box resulting in an \.{Underfull box} warning.
+Btw, I discovered this bug while trying to prove the line breaking
+algorithm, not through by testing. In this regard, I go with Dijkstra, not
+with Knuth.
+
+\item{(3)} \TeX\ fails to respect end of file (Control-D) from
+terminal oinput during debug dialog.
+
+\item{(3)}
+Igor Liferenko reported an extra space in the transcript file and
+a missing last line terminator on terminal output after user switched
+to \.{/batchmode} during error recovery.
+
+\medskip
+\item{(1)}\marke F\namefpc\ treats the command line as the first input line;
+
+\item{(2)}\namefpc\ starts \.{vi} if the user types `\.{E}' during
+error recovery.
+
+\item{(3)}You can interrupt \namefpc\ by typing `\.{Control-C}'.
+
+\medskip
+\item{(1)}\marke P \TeX82 assumes that the terminal input file is
+positioned {\sl before\/} the first character after being opened,
+whereas \namefpc\ assumes that it is positioned {\sl at\/} the first
+character, thus complying with the Pascal standard.
+
+\item{(2)} The names of the standard text files must occur in the
+program header whenever they are used.
+
+\item{(3)} The standard text files must not be declared. Declared files
+with the name of the standard text files are new internal files.
+
+\item{(4)} The program must not open the standard text files.
+
+\medskip
+\item{(1)} \marke X FPC's extensions are needed to specify a file name
+at run time, to check the existence of files and to access the
+system date and time. Identifiers from FPC~Pascal are prefixed
+with \\{fpc\_} to help distinguish them from Pascal and \.{WEB}
+identifiers and to avoid name clashes. Furthermore all FPC~Pascal
+identifiers will appear together in the index.
+
+\medskip
+\item{(1)}\marke U The Unix file seperator is `\.{/}'
+instead of `\.{:}'.
+\medskip
+\item{(1)}\marke u On exit, \namefpc\ passes its `history' to the
+operating system. This integer is zero when everything is fine,
+one when something less serious like an overfull box was detected,
+two when an error happened like an undefined control sequence, and
+three when the program aborted because one of its tables overflowed
+or because it couldn't find an input file while running in batch
+mode.
+
+\item{(2)} Valid input characters are the 94~visible ASCII characters
+together with the three control characters horizontal tabulator,
+form~feed, and space.
+
+\item{(3)} Terminate last line on terminal. This is Unix, not DOS!
+
+\item{(4)} Teach \TeX\ and user how to end the terminal input by Control-D.
+
+\break
+Like Dijkstra,
+\.{http://www.cs.utexas.edu/users/EWD/videos/noorderlicht.mpg},
+I dislike version numbers---I consider \namefpc\ finished.
+I'd rather maintain invariants---not software.
+\address
+\fi
+@z
+
+
+% \TeX82 will emit an underfull box warning here, \namefpc\ won't.
+\setbox0=\hbox to \hsize {\hfil\ \strut}
+\noindent\box0\ \ \par
+\bigskip
+\fi
+
+[2] Change the banner line
+@x
+known as `\TeX' [cf.~Stanford Computer Science report CS1027,
+November 1984].
+
+@d banner=='This is TeX, Version 3.14159265' {printed when \TeX\ starts}
+@y
+known as `\TeX' [cf.~Stanford Computer Science report CS1027,
+November 1984].
+
+Even though \namefpc\ does not differ from \TeX\ I proudly change
+the banner! And take responsibility for any error.
+
+@d banner=='This is TeX-FPC, 2nd ed.'
+@z
+
+[4] program header
+@x
+@d mtype==t@&y@&p@&e {this is a \.{WEB} coding trick:}
+@y
+
+\marke P Pascal wants the identifiers of the standard text files
+\\{input} and \\{output} in the parameter list of the program header.
+
+@d term_in==i @& n @& p @& u @& t
+@d term_out==o @& u @& t @& p @& u @& t
+@d mtype==t @& y @& p @& e
+@z
+
+[4] program header
+@x
+program TEX; {all file names are defined dynamically}
+@y
+program TEX(@!term_in,@!term_out);
+@z
+
+[4] forward definition of signal catcher
+@x
+procedure initialize; {this procedure gets things started properly}
+@y
+procedure catch_signal(i: integer); interrupt@, forward;@t\2@>
+procedure initialize; {this procedure gets things started properly}
+@z
+
+Since @x, @y, and @z only define a change block when they begin a
+line, you deactivate a block by indenting it (shift right) and
+activate it by unindenting it (shift left). With vi set the cursor
+to the @x line and type >} or <} to (un)indent a paragraph.
+
+[7] shift left to turn debugging on, right to turn it off
+ @x debug
+ @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\.{@@\{}$' when not debugging}
+ @d gubed=={change this to `$\\{gubed}\equiv\.{@@\}}$' when not debugging}
+ @z
+
+[7] shift left to turn stats on, right to turn them off.
+ @x stats
+ @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== {change this to `$\\{stat}\equiv\.{@@\{}$' to turn off statistics}
+ @d tats== {change this to `$\\{tats}\equiv\.{@@\}}$' to turn off statistics}
+ @z
+
+
+[8] shift left to build TEX and right to build INITEX.
+ @x initex
+ @d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
+ @d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
+ @y
+ @d init==@{ {change this to `$\\{init}\equiv $' for \.{INITEX}}
+ @d tini==@t@>@} {change this to `$\\{tini}\equiv $' for \.{INITEX}}
+ @z
+
+[9] compiler directives, turn off I/O checking.
+@x
+@^overflow in arithmetic@>
+@y
+@^overflow in arithmetic@>
+
+\marke X If the first character of a \PASCAL\ comment is a dollar
+sign, Free~Pascal treats the comment as a ``compiler directive''.
+Turn off checking since the debugger might trigger a range
+check when it accesses subfields of a memory word without knowing
+what it is reading.
+Overflow is checked if the result of an integer operation overflows
+the range of 64bit |integer|.
+FPC in default mode neither provides |goto| nor the I/O
+procedures |get| and |put|, and 16-bit |integer|. The compiler
+directive MODE ISO fixes all of it.
+
+@^system dependencies@>
+@^FPC Pascal@>
+@z
+
+[9] compiler directives, turn off I/O checking, continued
+@x
+@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead}
+@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging}
+@y
+@{$MODE@,ISO@} {turn on mode ISO}
+@{$Q+@} {turn on overflow checking}
+@{$R+@} {turn on range checking}
+@!debug
+@{$Q-@}@,
+@{$R-@}@+
+gubed {turn off all checks when debugging}
+@z
+
+[10] default case branch
+@x
+\PASCAL s have, in fact, done this, successfully but not happily!)
+@:PASCAL H}{\ph@>
+
+@d othercases == others: {default for cases not listed explicitly}
+@y
+\PASCAL s have, in fact, done this, successfully but not happily!)
+@:PASCAL H}{\ph@>
+
+\marke X This is the only place I voluntarily use an FPC extension
+to Pascal.
+@^FPC Pascal@>
+
+@d othercases == @+ else {default for cases not listed explicitly}
+@z
+
+The changes headed by trip need to be made for the trip test suite.
+ For trip activate all changeblocks with the first line @x trip.
+
+ [11]
+ @x trip
+ @!mem_max=30000; {greatest index in \TeX's internal |mem| array;
+ @y
+ @!mem_max=3000; {greatest index in \TeX's internal |mem| array;
+ @z
+
+[11]
+ @x trip
+ @!mem_min=0; {smallest index in \TeX's internal |mem| array;
+ @y
+ @!mem_min=1; {smallest index in \TeX's internal |mem| array;
+ @z
+
+[11]
+ @x trip
+ @!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}
+ @y
+ @!error_line=64; {width of context lines on terminal error messages}
+ @!half_error_line=32; {width of first lines of contexts in terminal
+ error messages; should be between 30 and |error_line-15|}
+ @!max_print_line=72; {width of longest text lines output; should be at least 60}
+ @z
+
+[11] location of pool file
+@x
+@!pool_name='TeXformats:TEX.POOL ';
+@y
+@!pool_name='TeXformats/tex.pool'; { \marke U Unix filename. }
+@z
+
+
+[12]
+ @x trip
+ @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|}
+ @y
+ @d mem_bot=1 {smallest index in the |mem| array dumped by \.{INITEX};
+ must not be less than |mem_min|}
+ @d mem_top==3000 {largest index in the |mem| array dumped by \.{INITEX};
+ must be substantially larger than |mem_bot|
+ and not greater than |mem_max|}
+ @z
+
+[23] we accept horizontal tab and form feed!
+@x
+right of these assignment statements to |chr(i)|.
+@y
+right of these assignment statements to |chr(i)|.
+
+\marke u In Unix tab and form feed are valid characters.
+The plain format categorizes the tab as a spacer and form feed
+as an active character defined as \.{\\outer\\par}.
+@z
+
+[23] continued
+@x
+for i:=0 to @'37 do xchr[i]:=' ';
+@y
+for i:=0 to @'37 do xchr[i]:=' ';
+xchr[@'11] := chr(@'11); {accept horizontal tab\marke u}
+xchr[@'14] := chr(@'14); {accept form feed}
+@z
+
+[25] the type of text_files is text
+@x
+@!alpha_file=packed file of text_char; {files that contain textual data}
+@y
+@!alpha_file=t @& e @& x @& t; {\marke P the type of text files is |text|}
+@z
+
+[25] continued
+@x
+@!byte_file=packed file of eight_bits; {files that contain binary data}
+@y
+@!byte_file=packed file of eight_bits; {files that contain binary data}
+@!untyped_file=file; {untyped files for buffered output}
+@z
+
+[27]
+@x
+\TeX's file-opening procedures return |false| if no file identified by
+|name_of_file| could be opened.
+
+@d reset_OK(#)==erstat(#)=0
+@d rewrite_OK(#)==erstat(#)=0
+@y
+\marke X
+The procedure |fpc_assign| assigns an external file name to a file.
+The function |fpc_io_result| returns a nonzero value if any
+error occurred since the last invocation of |fpc_io_result|.
+The runtime system halts the program when it experiences an
+I/O error. Since \namefpc\ wants to survive while trying to open
+a nonexistence file, it turns off I/O checking for the open procedures.
+
+@^FPC Pascal@>
+@^system dependencies@>
+
+@d fpc_io_result==i @& o @& r @& e @& s @& u @& l @& t
+@d fpc_assign==a @& s @& s @& i @& g @& n
+@d reset_OK(#)==fpc_io_result=0
+@d rewrite_OK(#)==fpc_io_result=0
+@d clear_io_result==@+if fpc_io_result=0 then do_nothing
+@z
+
+[27] reset and rewrite for each of three file types
+
+@x alpha_file
+@p function a_open_in(var f:alpha_file):boolean;
+ {open a text file for input}
+begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f);
+@y
+@p
+@{@&$I-@} {turn of I/O checking}
+@#
+function a_open_in(var f:alpha_file):boolean;
+begin clear_io_result; fpc_assign(f,name_of_file); reset(f);
+a_open_in:=reset_OK(f);
+@z
+
+@x
+begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f);
+@y
+begin clear_io_result; fpc_assign(f,name_of_file); rewrite(f);
+a_open_out:=rewrite_OK(f);
+@z
+
+byte_file
+@x
+begin reset(f,name_of_file,'/O'); b_open_in:=reset_OK(f);
+@y
+begin clear_io_result; fpc_assign(f,name_of_file); reset(f);
+b_open_in:=reset_OK(f);
+@z
+
+@x
+begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f);
+@y
+begin clear_io_result; fpc_assign(f,name_of_file); rewrite(f);
+b_open_out:=rewrite_OK(f);
+@z
+
+@x word_file
+begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f);
+@y
+begin clear_io_result; fpc_assign(f,name_of_file); reset(f); w_open_in:=reset_OK(f);
+@z
+@x
+begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f);
+end;
+@y
+begin clear_io_result; fpc_assign(f,name_of_file); rewrite(f);
+w_open_out:=rewrite_OK(f);
+end;
+@#
+@{@&$I+@} {turn on I/O checking}
+@z
+
+[31] bypass eoln
+@x
+finer tuning is often possible at well-developed \PASCAL\ sites.
+@y
+finer tuning is often possible at well-developed \PASCAL\ sites.
+@^|bypass eoln|@>
+
+\marke P Standard Pascal never suppresses the first get, so |input_ln|
+must not bypass the first character of the first line. To maintain
+this rule for subsequent lines, |input_ln| is changed to bypass the
+end of line character at the end of line.
+@z
+
+[31] bypass eoln
+@x
+begin if bypass_eoln then if not eof(f) then get(f);
+@y
+begin
+@z
+
+[31] bypass eoln
+@x
+ last:=last_nonblank; input_ln:=true;
+ end;
+@y
+ last:=last_nonblank; input_ln:=true;
+ read_ln(f);
+ end;
+@z
+
+[31] re-engineered input_ln
+ @x
+ finer tuning is often possible at well-developed \PASCAL\ sites.
+ @^inner loop@>
+
+ @p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
+ {inputs the next line or returns |false|}
+ var last_nonblank:0..buf_size; {|last| with trailing blanks removed}
+ begin if bypass_eoln then if not eof(f) then get(f);
+ {input the first character of the line into |f^|}
+ last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
+ if eof(f) then input_ln:=false
+ else begin last_nonblank:=first;
+ while not eoln(f) do
+ begin if last>=max_buf_stack then
+ begin max_buf_stack:=last+1;
+ if max_buf_stack=buf_size then
+ @<Report overflow of the input buffer, and abort@>;
+ end;
+ buffer[last]:=xord[f^]; get(f); incr(last);
+ if buffer[last-1]<>" " then last_nonblank:=last;
+ end;
+ last:=last_nonblank; input_ln:=true;
+ end;
+ end;
+ @y
+ finer tuning is often possible at well-developed \PASCAL\ sites.
+ @^inner loop@>
+
+ \marke h
+ Unlike \TeX82 \namefpc\ leaves trailing spaces in the input line.
+
+ \marke N
+ Whenever |input_ln| is to read the first line of a disk file,
+ |bypass_eoln| is set to |false|, in all other cases it is set to
+ |true|. This causes |input_ln| to advance the file pointer. For
+ the first line, in ISO-Pascal and FPC-Pascal this is done by |reset()|
+ -- on terminals and disk files alike. But \TeX82 turns this off
+ for the terminal, so the old |input_line| has to advance the file
+ pointer if reading the first line from a terminal. On return, the
+ old |input_ln| leaves the file position at the end-of-line marker,
+ which is to be bypassed on next invocation.
+
+ The new |input_ln| bypasses the end-of-line marker allways at the
+ end of line and never at the beginning of line. In other words
+ |reset| establishes and |input_ln| maintains the invariant:
+
+ \centerline {The file is positioned at the first character of the
+ line or |eof|}
+
+ \marke N
+ `To hell with ``meaningful identifiers''!': The parameter |bypass_eoln|
+ does not always cause |input_ln| to bypass an end-of-line marker.
+ And the size of the buffer is not |buf_size| but |buf_size+1|. And
+ the end-of-line marker is not a start-of-line marker!
+
+ @p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;
+ {inputs the next line or returns |false|}
+ begin
+ {|f| is positioned at the first character of the line, or |eof(f)|}
+ last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
+ if eof(f) then input_ln:=false
+ else begin
+ 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 begin
+ read_ln(f); {complete the current line}
+ @<Report overflow of the input buffer, and abort@>;
+ end
+ end;
+ buffer[last]:=xord[f^]; get(f); incr(last)
+ end;
+ get(f); { advance to the first character of next line}
+ input_ln:=true
+ end
+ {|f| is positioned at the first character of the next line, or |eof(f)|}
+ end;
+ @z
+
+[32] term_in and term_out are the standard pascal files
+@x
+is considered an output file the file variable is |term_out|.
+@^system dependencies@>
+
+@<Glob...@>=
+@!term_in:alpha_file; {the terminal as an input file}
+@!term_out:alpha_file; {the terminal as an output file}
+@y
+is considered an output file the file variable is |term_out|.
+
+\marke P No need to declare standard input/output in standard Pascal.
+@z
+
+[33]
+@x
+@ Here is how to open the terminal files
+in \ph. The `\.{/I}' switch suppresses the first |get|.
+@:PASCAL H}{\ph@>
+@^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 \ph. The `\.{/I}' switch suppresses the first |get|.
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+
+\marke P In Pascal, the standard text files are openend implicitly.
+
+@d t_open_in==do_nothing {open the terminal for text input}
+@d t_open_out==do_nothing {open the terminal for text output}
+@z
+
+[34]
+@x
+some instruction to the operating system. The following macros show how
+these operations can be specified in \ph:
+@:PASCAL H}{\ph@>
+@^system dependencies@>
+@y
+some instruction to the operating system.
+
+\marke X
+In Unix, nothing needs to be done here.
+
+@^FPC Pascal@>
+@^system dependencies@>
+@z
+
+[34]
+@x
+@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
+@d fpc_flush == f@&l@&u@&s@&h
+@d update_terminal == fpc_flush(term_out) {empty the terminal output buffer}
+@d clear_terminal == do_nothing {clear the terminal input buffer}
+@d wake_up_terminal == do_nothing {cancel the user's cancellation of output}
+@z
+
+[36] command line
+@x
+not be typed immediately after~`\.{**}'.)
+
+@d loc==cur_input.loc_field {location of first unread character in |buffer|}
+
+@y
+not be typed immediately after~`\.{**}'.)
+
+\marke X
+An |@!fpc_string| is a |packed array[1..fpc_length] of
+char| with varying length.
+The function |@!fpc_length(s)| returns the length of the |fpc_string@,
+s|.
+The function |@!fpc_param_count| returns the number of
+command line arguments less one.
+The function |@!fpc_param_str(n)|
+returns the n-th argument for |0 <= n <= fpc_param_count|.
+
+\marke F This procedure puts the command line arguments separated
+by spaces into |buffer|. Like |input_ln| it updates |last| so that
+|buffer[first..last)| will contain the command line.
+
+@^FPC Pascal@>
+@^system dependencies@>
+
+@d loc==cur_input.loc_field {location of first unread character in |buffer|}
+@d fpc_string == s@& h@& o@& r@& t @& s @& t @& r @& i@& n @& g
+@d fpc_length==l @& e @& n @& g @& t @& h
+@d fpc_param_count==p @& a @& r @& a @& m @& c @& o @& u @& n @& t
+@d fpc_param_str==p @& a @& r @& a @& m @&s @& t @& r
+
+@p procedure input_command_ln; {get the command line in |buffer|}
+var argc: integer; {argument counter}
+ arg: fpc_string; {argument}
+ cc: integer; {character counter in argument}
+begin last := first; argc := 1;
+while argc <= fpc_param_count do
+ begin cc := 1; arg := fpc_param_str(argc); incr(argc);
+ while cc <= fpc_length(arg) do
+ begin
+ if last+1>=buf_size then
+ @<Report overflow of the input buffer, and abort@>;
+ buffer[last] := xord[arg[cc]]; incr(last); incr(cc)
+ end;
+ if (argc <= fpc_param_count) then begin
+ buffer[last] := " "; incr(last) {insert a space between arguments}
+ end
+ end
+end;
+@z
+
+[37] command line.
+@x
+It should be clear how to modify this routine to deal with command lines,
+if the system permits them.
+@^system dependencies@>
+
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+begin t_open_in;
+loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
+@y
+\marke F The command line is treated as the first terminal line.
+
+\marke u Tell user to end the terminal file by Control-D.
+
+@p function init_terminal:boolean; {gets the terminal input started}
+label exit;
+begin t_open_in; input_command_ln;
+loc := first;
+if loc<last then
+ begin init_terminal:=true; return; {first line is the command line}
+ end;
+loop@+begin write(term_out,'**');
+@z
+
+[37] chatty
+ @x chatty
+ write(term_out,'! End of file on the terminal... why?');
+ @.End of file on the terminal@>
+ @y
+ @z
+
+[37] hint Control-D
+@x
+ write_ln(term_out,'Please type the name of your input file.');
+@y
+ write_ln(term_out,'Please type the name of your input file or Control-D.');@/
+@z
+
+[51] leave tex.pool open
+@x
+@ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#);
+ a_close(pool_file); get_strings_started:=false; return;
+@y
+@ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#);
+ get_strings_started:=false; return;
+@z
+
+[51] TANGLE would'nt help, but update
+@x
+done: if a<>@$ then bad_pool('! TEX.POOL doesn''t match; TANGLE me again.');
+@y
+done: if a<>@$ then bad_pool('! TeXformats/tex.pool doesn''t match.');
+@z
+
+[79] start editor
+@x
+@!use_err_help:boolean; {should the |err_help| list be shown?}
+@y
+@^Editor@>
+@!use_err_help:boolean; {should the |err_help| list be shown?}
+@!want_edit: boolean; {start \.{vi}?}
+@z
+
+[80] initial value for edit arguments
+@x
+help_ptr:=0; use_err_help:=false;
+@y
+@^Editor@>
+help_ptr:=0; use_err_help:=false;@/
+want_edit := false; {\marke F don't start \.{ed}}
+@z
+
+[84] set edit_cmd
+@x
+ begin print_nl("You want to edit file ");
+@.You want to edit file x@>
+ slow_print(input_stack[base_ptr].name_field);
+ print(" at line "); print_int(line);
+ interaction:=scroll_mode; jump_out;
+ end;
+@y
+@^Editor@>
+ begin print_nl("You want to edit file ");
+@.You want to edit file x@>
+ slow_print(input_stack[base_ptr].name_field);
+ print(" at line "); print_int(line);
+ interaction:=scroll_mode;
+ want_edit := true;
+ jump_out;
+ end;
+@z
+
+[86] extra space in log and missing last line terminator on terminal
+@x
+"Q":begin print_esc("batchmode"); decr(selector);
+ end;
+@y
+"Q":print_esc("batchmode");
+{ \marke E don't turn off terminal now }
+@z
+
+[86] continued
+@x
+print("..."); print_ln; update_terminal; return;
+@y
+print("..."); print_ln; update_terminal;
+if c="Q" then decr(selector); return; { but now }
+@z
+
+[109] fpc_single for glue ratio.
+@x
+routines cited there must be modified to allow negative glue ratios.)
+@y
+routines cited there must be modified to allow negative glue ratios.)
+
+\marke X In FPC~Pascal the type |fpc_single| seems appropiate.
+@d fpc_single== s@&i@&n@&g@&l@&e
+@z
+
+@x
+@!glue_ratio=real; {one-word representation of a glue expansion factor}
+@y
+@!glue_ratio=fpc_single; {one-word representation of a glue expansion
+ factor in FPC~Pascal}
+@^FPC Pascal@>
+@z
+
+[112]
+@x
+macros are simplified in the obvious way when |min_quarterword=0|.
+@^inner loop@>@^system dependencies@>
+
+@d qi(#)==#+min_quarterword
+ {to put an |eight_bits| item into a quarterword}
+@d qo(#)==#-min_quarterword
+ {to take an |eight_bits| item out of a quarterword}
+@d hi(#)==#+min_halfword
+ {to put a sixteen-bit item into a halfword}
+@d ho(#)==#-min_halfword
+ {to take a sixteen-bit item from a halfword}
+@y
+macros are simplified in the obvious way when |min_quarterword=0|.
+\marke X Which is the case with FPC.
+@^inner loop@>@^system dependencies@>
+
+@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(#)==#
+ {to put a sixteen-bit item into a halfword}
+@d ho(#)==#
+ {to take a sixteen-bit item from a halfword}
+@z
+
+[241]
+@x
+@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
+\marke X The functions |now|, |decodedate|, and |decodetime| are provided
+by the unit |sysutils|. The command line option \.{fpc~-Fasysutils~tex.p}
+links that unit.
+@^system dependencies@>
+@^sysutils@>
+@^FPC Pascal@>
+When FPC is in ISO mode, it does not accept declaring a |unit| in the source
+file.
+@dfpc_now == now
+@dfpc_decode_date == decodedate
+@dfpc_decode_time == decodetime
+@p procedure fix_date_and_time;
+var yy,mm,dd: word;
+ hh,ss,ms: word;
+begin
+fpc_decode_date(fpc_now,yy,mm,dd); {current date}
+day := dd;
+month := mm;
+year := yy;@/
+fpc_decode_time(fpc_now,hh,mm,ss,ms); {current time}
+time := hh*60+mm; {minutes since midnight}
+end;
+@z
+
+[360] Don't print empty lines
+ @x chatty
+ @ All of the easy branches of |get_next| have now been taken care of.
+ There is one more branch.
+ @y
+ @ All of the easy branches of |get_next| have now been taken care of.
+ There is one more branch.
+
+ \marke h \TeX82 ends the current line by calling |print_ln| even
+ if the line is empty. This causes a spurious ugly empty line.
+ Calling |print_nl("")| is smarter. It ends the current
+ line only if it is not empty.
+ @z
+
+ @x chatty
+ if limit=start then {previous line was empty}
+ print_nl("(Please type a command or say `\end')");
+ @.Please type...@>
+ print_ln; first:=start;
+ @y
+ if limit=-1 then {previous line was empty}
+ print_nl("(Please type a command or say `\end')");
+ @.Please type...@>
+ print_nl(""); first:=start;
+ @z
+
+@x [514]
+|TEX_font_area|. These system area names will, of course, vary from place
+to place.
+@y
+|TEX_font_area|. These system area names will, of course, vary from place
+to place.
+
+\marke U Use the Unix file separator.
+@z
+
+[514]
+@x
+@d TEX_area=="TeXinputs:"
+@.TeXinputs@>
+@d TEX_font_area=="TeXfonts:"
+@.TeXfonts@>
+@y
+@d TEX_area=="TeXinputs/" {i.e., a subdirectory of the working directory}
+@.TeXinputs@>
+@d TEX_font_area=="TeXfonts/" {dito}
+@.TeXfonts@>
+@z
+
+[516]
+@x
+ if (c=">")or(c=":") then
+@y
+ if c="/" then {use ``/'' as a file name separator\marke U}
+@z
+
+[519]
+@x
+@d append_to_name(#)==begin c:=#; incr(k);
+@y
+
+\marke X With Free~Pascal you cannot set the length of a |packed
+array|. And with Unix, it does not help to blank out the rest of
+the |array|. But assigning the |name_of_file| to an |fpc_string|,
+setting the length of the |fpc_string| and then assigning it back
+to the |name_of_file| seems to work. @^FPC Pascal@>
+
+@d fpc_set_length==s@&e@&t@&l@&e@&n@&g@&t@&h
+
+@d append_to_name(#)==begin c:=#; incr(k);
+@z
+
+[519]
+@x
+@!j:pool_pointer; {index into |str_pool|}
+@y
+@!j:pool_pointer; {index into |str_pool|}
+@!s: fpc_string;
+@z
+
+[519] pack file name
+@x
+if k<=file_name_size then name_length:=k@+else name_length:=file_name_size;
+for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
+end;
+@y
+if k<=file_name_size then name_length:=k@+else name_length:=file_name_size;
+s := name_of_file;
+fpc_set_length(s, name_length);
+name_of_file := s;
+end;
+@z
+
+[521] Unix file separator
+@x
+TEX_format_default:='TeXformats:plain.fmt';
+@y
+TEX_format_default:='TeXformats/plain.fmt';
+ {``/'' is the Unix file name separator\marke U}
+@z
+
+[523] packed buffered name
+@x
+@!j:integer; {index into |buffer| or |TEX_format_default|}
+@y
+@^FPC Pascal@>
+@!j:integer; {index into |buffer| or |TEX_format_default|}
+s: fpc_string;
+@z
+
+[523] packed buffered name
+@x
+for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
+@y
+s := name_of_file; fpc_set_length(s, name_length); name_of_file := s;
+@z
+
+[530] Control D will help
+@x
+print_nl("Please type another "); print(s);
+@y
+print_nl("Please type another "); print(s); print(" or Control-D");
+@z
+
+[537] Editor
+@x
+@ Let's turn now to the procedure that is used to initiate file reading
+when an `\.{\\input}' command is being processed.
+
+@y
+@ Let's turn now to the procedure that is used to initiate file reading
+when an `\.{\\input}' command is being processed.
+@^Editor@>
+@^Fix@>
+
+\marke E Keep the complete file name since it might be needed to
+be passed to the system editor.
+(\TeX82 strips off area and extension to conserve string
+pool space.)
+@z
+
+[537] never flush file name
+@x
+if name=str_ptr-1 then {we can conserve string pool space now}
+ begin flush_string; name:=cur_name;
+ end;
+@y
+@^Editor@>
+@z
+
+[575] Don't check eof (fpc bug: eof off by one)
+@x
+if eof(tfm_file) then abort;
+@y
+@^FPC-EOF@>
+@z
+
+[597] buffered write
+@x
+output an array of words with one system call.
+@y
+output an array of words with one system call.
+@^FPC-buffer@>
+
+\marke P The procedure |fpc_blockwrite| takes a file, the first
+byte in a buffer and the number of bytes to be written as parameters
+and writes all bytes with one system call. This in fact speeds up
+\namefpc.
+
+@d fpc_blockwrite == b @& l @& o @& c @& k @& w @& r @& i @& t @& e
+@z
+
+[597] use buffered i/o to speed up TeX
+@x
+var k:dvi_index;
+begin for k:=a to b do write(dvi_file,dvi_buf[k]);
+@y
+begin fpc_blockwrite(dvi_file, dvi_buf[a], b-a+1);
+@z
+
+[816] save pointer to penalty_node
+@x
+same number of |mem|~words.
+@^data structure assumptions@>
+@y
+same number of |mem|~words.
+@^data structure assumptions@>
+@^\TeX-Bug@>
+
+\marke E
+\TeX82 prunes discardable nodes from the beginning of a new line until
+it reaches a nondiscardable node. Now, if the last line of a paragraph
+contains discardables only, the \.{\\parfillskip} glue at the end of the
+paragraph will also be removed, since it is a discardable. This will
+give you an empty \.{\\hbox}. Finally \TeX\ appends \.{\\rightskip} glue.
+This gives you a nonempty \.{\\hbox}, raising a \.{Underfull \\hbox}
+warning.
+
+To avoid this happening, \namefpc\ saves a pointer to the node
+immediately preceding the \.{\\parfillskip} node and quits pruning
+when it encounters this node several procedures later.
+@^Underfull \\hbox...@>
+@z
+
+@x
+link(tail):=new_param_glue(par_fill_skip_code);
+@y
+non_prunable_p := tail; {points to the node immediately before
+\.{\\parfillskip}}
+link(tail):=new_param_glue(par_fill_skip_code);
+@z
+
+[862] declare non_prunable_p
+@x
+The following declarations provide for a few other local variables that are
+used in special calculations.
+
+@y
+The following declarations provide for a few other local variables that are
+used in special calculations.
+
+\marke E Declare the |non_prunable_p| pointer.
+@z
+
+@x
+@!auto_breaking:boolean; {is node |cur_p| outside a formula?}
+@y
+@!auto_breaking:boolean; {is node |cur_p| outside a formula?}
+non_prunable_p:pointer; {pointer to the node before \.{\\parfillskip}}
+@z
+
+[876] pass non_prunable_p
+@x
+(By introducing this subprocedure, we are able to keep |line_break|
+from getting extremely long.)
+@y
+(By introducing this subprocedure, we are able to keep |line_break|
+from getting extremely long.)
+
+\marke E Pass |non_prunable_p| to the |post_line_break|~procedure.
+@z
+
+@x
+post_line_break(final_widow_penalty)
+@y
+post_line_break(final_widow_penalty, non_prunable_p)
+@z
+
+[877] declare non_prunable_p
+@x
+of their new significance.) Then the lines are justified, one by one.
+
+@y
+of their new significance.) Then the lines are justified, one by one.
+
+\marke E Declare another parameter. It holds the pointer to the node
+immediately preceding \.{\\parfillskip}.
+@z
+
+@x
+procedure post_line_break(@!final_widow_penalty:integer);
+@y
+procedure post_line_break(@!final_widow_penalty:integer;
+ non_prunable_p:pointer);
+@z
+
+[879]
+@x
+are computed for non-discretionary breakpoints.
+@y
+are computed for non-discretionary breakpoints.
+
+\marke E The pointer |non_prunable_p| references the node immediately
+preceding the \.{\\parfillskip} node at the end of the paragraph.
+Stop pruning at this node.
+@z
+
+[879]
+@x
+ if non_discardable(q) then goto done1;
+@y
+ if non_discardable(q) then goto done1;
+ if q = non_prunable_p then goto done1; {retain \.{\\parfillskip} glue}
+@z
+
+ [1265] empty line after change of interaction mode
+ @x chatty
+ begin print_ln;
+ @y
+ begin print_nl(""); { print new line only if current line not empty \marke h}
+ @z
+
+[1327] eof is broken
+@x
+if (x<>69069)or eof(fmt_file) then goto bad_fmt
+@y
+if (x<>69069) then goto bad_fmt
+@^FPC-EOF@>
+@z
+
+[1332]
+@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@>
+@y
+The initial test involving |ready_already| should be deleted if the
+\PASCAL\ runtime system is smart enough to detect such a ``mistake.''
+@^system dependencies@>
+
+\marke X The procedure |@!fpc_halt| terminates the program and passes its
+parameter to the shell.
+
+@^system dependencies@>
+@^FPC Pascal@>
+@^Unix@>
+
+@d fpc_halt == h@&a@&l@&t
+@z
+
+[1332] simulate tex, not virtex
+ @x
+ start_of_TEX: @<Initialize the output routines@>;
+ @y
+ start_of_TEX:
+ @<Preload the default format file@>;
+ @<Initialize the output routines@>;
+ @z
+
+[1332]
+@x
+final_end: ready_already:=0;
+@y
+final_end:
+if want_edit then exec_editor; {user typed `\.{E}' \marke F}
+fpc_halt(history);
+ {pass |history| as the exit value to the system\marke u}
+@z
+
+[1333] print last end-of-line marker if needed
+@x
+This program doesn't bother to close the input files that may still be open.
+@y
+This program doesn't bother to close the input files that may still be open.
+\marke u
+Terminate the last line on the terminal.
+@z
+
+[1333] print last end-of-line marker if needed
+@x
+ slow_print(log_name); print_char(".");
+@y
+ slow_print(log_name); print_char("."); print_ln;
+@z
+
+[1338] return if eof.
+@x
+program below. (If |m=13|, there is an additional argument, |l|.)
+@.debug \#@>
+
+@y
+program below. (If |m=13|, there is an additional argument, |l|.)
+@.debug \#@>
+
+\marke P A Pascal program must not read from the standard text file
+if the end of file is reached. Even in this respect, Unix and Pascal
+treat terminals and disk files alike.
+@z
+
+@x
+ read(term_in,m);
+@y
+ if eof(term_in) then return; {\marke P never |read| at |eof|}
+ read(term_in,m);
+@z
+
+[1338] return if eof
+@x
+ else begin read(term_in,n);
+@y
+ else begin if eof(term_in) then return; {\marke P never |read| at |eof|}
+ read(term_in,n);
+@z
+
+[1339] return if eof
+@x
+13: begin read(term_in,l); print_cmd_chr(n,l);
+@y
+13: begin if eof(term_in) then return; {\marke P never |read| at |eof| }
+read(term_in,l); print_cmd_chr(n,l);
+@z
+
+[1379 and modules added for TeX-FPC]
+@x
+itself will get a new section number.
+@^system dependencies@>
+@y
+itself will get a new section number.
+
+@ \marke F If the user typed |'E'| to edit a file after confronted
+with an error message, \TeX\ will clean up and then call |edit|
+as its last feat.
+@^Editor@>
+
+This procedure must not print error messages, since all files are already
+closed.
+
+Beware of using any \.{WEB} strings like \.{"vi +"} since that
+would change the string pool file and you'll need to rebuild all
+format files with the new string pool in case you disagree which
+editor is the system editor.
+
+An overflow of |name_of_file| cannot happen, since |name_of_file|
+kept the file name while the file was being opened.
+/marke F
+The procedure @!|exec_edit| starts \.{vi} passing line number and
+file name.
+
+\marke X
+This procedure executes the Unix system editor, which is \.{ed} of course.
+@^Editor@>
+In case you disagree, modify all four definitions of |ed|, |de|, |vi|, |iv|
+to select code that executes \.{vi} instead. This not just changes
+the name of the system editor, but it adds one argument that contains the
+line number to the argument vector.
+The argument vector for the system editor has two entries:
+
+\indent \.{ed file-name}
+
+\noindent And the argument vector for the west coast editor three:
+
+\indent\.{vi +line file-name}
+
+The system call @!|fpc_fp_exec_vp| expects two parameters, namely
+the name of the editor to be loaded and the argument vector, an
+|array| of the arguments to be passed to the editor. Unix replaces
+the code of \TeX\ by the code of the editor without forking a new
+process. On success this procedure does not return.
+
+The type @!|fpc_pchar| is a pointer to a character. An argument is
+a null-terminated |packed array of char|. The \.{@@}-operator applied
+to an argument evaluates to the address of the first entry, i.e
+a pointer to a character.
+
+The function |fpc_fp_exec_vp| wants the argument vector to be passed
+as a pointer to a pointer to a character. An |array|~parameter is
+always passed as the address of its first entry. Therefore we must
+not apply the \.{@@}-operator to the parameters of |fpc_fp_exec_vp|.
+
+Note that the name of the binary is passed twice, namely as the
+first parameter and as the first entry of the second argument.
+|fpc_fp_exec_vp| searches for the binary in the \.{PATH}. And then
+it seems to replace |argv[0]| by the full name of the editor. At
+least this is what \.{ps -f} shows and might be a bug.
+
+The procedure |fpc_fp_exec_vp| is provided by the |unit@,unix|.
+@^|unit unix|@> The command line option \.{-Faunix} links to that
+unit. @^unix@>
+
+@^FPC Pascal@>
+@^system dependencies@>
+
+@d fpc_fp_exec_vp == fp_exec_vp
+@d fpc_pchar == pchar
+@d edit_file == input_stack[base_ptr].name_field
+@#
+@d vi==@{ {change this to `$\\{vi}\equiv\null$' when you think \.{vi}
+is the system editor}
+@d iv==@t@>@} {change this to `$\\{iv}\equiv\null$' when you think \.{vi}
+is the sytem editor}
+@f vi == begin
+@f iv == end
+@d ed== {change this to `$\\{ed}\equiv\.{@@\{}$' when you think \.{vi}
+is the system editor}
+@d de== {change this to `$\\{de}\equiv\.{@@\}}$' when you think \.{vi}
+is the system editor}
+@f ed == begin
+@f de == end
+
+@<Last-minute...@>=
+procedure exec_editor;
+const arg_size = 100; {maximal size of each of the arguments}
+ vi editor = 'vi'; {name of the binary to be started}
+ iv
+ @#
+ ed editor = 'ed'; {name of the binary to be started}
+ de
+ @#
+ editor_length = 2; {length of the name}
+var i, l: integer; {index into args}
+ j: pool_pointer; {index into |str_pool|}
+ s: str_number; {string to hold line number}
+ sel: integer; {save selector}
+ editor_arg, line_arg, file_arg : array[1..arg_size] of char; {arguments}
+ argv: array [0..3] of fpc_pchar; {vector of arguments}
+begin
+ l := editor_length;
+ for j := 1 to l do editor_arg[j] := editor[j];
+ editor_arg[l+1] := chr(0);@/
+ sel := selector;
+ selector := new_string;
+ print_int(line);
+ selector := sel;
+ s := make_string;
+ line_arg[1] := '+';
+ j := str_start[s];
+ l := length(s)+1;
+ for i := 2 to l do begin line_arg[i] := xchr[str_pool[j]]; incr(j) end;
+ line_arg[l+1] := chr(0);
+ @#
+ j := str_start[edit_file];
+ l := length(edit_file);
+ if l+1 > arg_size then begin
+ write_ln('File name longer than 100 bytes! Nice try!');
+ halt(100);
+ end;
+ for i := 1 to l do
+ begin file_arg[i] := xchr[str_pool[j]]; incr(j)
+ end;
+ file_arg[l+1] := chr(0);
+ @#
+ argv[0] := @@editor_arg;
+ vi
+ argv[1] := @@line_arg;
+ argv[2] := @@file_arg;
+ argv[3] := nil;
+ iv
+ @#
+ ed
+ argv[1] := @@file_arg;
+ argv[2] := nil;
+ de
+ @#
+ fpc_fp_exec_vp(editor, argv);
+ write_ln('Sorry, executing the editor failed.');
+end;
+
+@ \marke X
+A signal handler is a procedure that takes one |integer| parameter.
+The procedure |fpc_fp_signal| takes two parameter, an integer and
+a signal handler. The integer is the number of the signal. When
+the program receives a signal with the designated number, the signal
+handler gets invoked.
+
+The integer |fpc_SIGINT| is the number of the interrupt signal.
+The system interrupts the program, when the user types \.{\^C}.
+
+If |fpc_fp_get_errno| returns an integer that is not zero, an error
+occurred.
+
+The identifier |fpc_signal_handler| denotes the |type| of a
+pointer to a signal handler. Since this is foreign to Pascal,
+we use the type cast to |fpc_signal_handler| as a kludge.
+
+The functions related to installing a signal handler are provided
+by the |unit@,baseunix|. @^|baseunix|@>
+The command line option \.{-Fabaseunix} links to that unit.
+@^FPC Pascal@>
+@^system dependencies@>
+
+@d fpc_signal_handler == signal@&ha@&ndler
+@d fpc_fp_signal == fp_signal
+@d fpc_SIGINT == SIGINT
+@d fpc_fp_get_errno ==f@&p@&g@&e@&t@&e@&r@&r@&n@&o
+
+@<Set initial values ...@>+=
+
+fpc_fp_signal(fpc_SIGINT, fpc_signal_handler(catch_signal));
+if fpc_fp_get_errno <> 0 then
+ write_ln('Could not install signal handler:', fpc_fp_get_errno);
+
+@ \marke X The signal handler has the modifier |interrupt|. Modifiers
+are an extension of FPC Pascal. This one makes the compiler generate
+code suitable for a signal handler, which must not return to the
+caller, i.e. the system, but to the instruction where the program
+was interrupted.
+
+@^FPC Pascal@>
+@^dirty \PASCAL@>
+@^system dependencies@>
+
+@<Error handling ...@>+=
+procedure catch_signal; interrupt;
+begin
+ interrupt := i;
+end;
+@z