file: TeX.changes
Written by Michael Plass, September 27, 1985 9:12:40 am PDT.
Modified by Lyle Ramshaw, February 5, 1984 5:38 pm
Last changed by Pavel on May 23, 1985 1:13:13 pm PDT
December 3, 1984: Pavel changed hi←mem�se back to 13000 from 25000, since the lower half of memory didn't seem to need more room and the upper half certainly did. The removed change was marked UNUSED and commented out, in case anybody wants to put it back the way it was. I also changed the banner line for version 1.2.
December 3, 1984: Pavel changed that part back because it appears that the earlier referred to statistics have lied to us. Therefore, the hi-mem-base has been moved back to it's old value of 25000 and the mem←max change from 58000 to 65000. Sigh.
December 14, 1984: Pavel upgraded to version 1.3. This involved changing the banner and removing the hi←mem�se changes altogether.
December 28, 1984: Pavel finished the upgrade to 1.3. This involved setting mem𡤋ot and mem←top to always be equal to mem←min and mem←max respectively since they must be so for IniTeX and we don't have a separate version. This does mean that the format file length will go up by about 35000 words, but it doesn't seem to be able to be helped. Sigh.
February 4, 1985: Pavel added a fix so that TeX would close all of its input files when it ends.
February 12, 1985: Pavel removed the call to ``register←tex𡤌ommands'' in the main program. Command registration is now done differently.
September 27, 1985: Michael added a missing semicolon before press𡤌lose𡤏ile call.
006776: Add "Cedar" to the banner line.
@x
@d banner=='This is TeX, Version 1.3' {printed when \TeX\ starts}
@y
@d banner=='This is TeX 1.3 for Cedar 6.0' {printed when \TeX\ starts}
@z
009786: Define macros for read←ln and write←ln that expand without the underscores.
@x
@f type==true {but `|type|' will not be treated as a reserved word}
@y
@f type==true {but `|type|' will not be treated as a reserved word}
@d write←ln==writeln {since our Tangle doesn't strip out "←"}
@d read←ln==readln {since our Tangle doesn't strip out "←"}
@z
010090: Add external procedure declarations for things implemented in Cedar
@x
procedure initialize; {this procedure gets things started properly}
@y
@<External procedure declarations for things implemented directly in Cedar@>@/
procedure initialize; {this procedure gets things started properly}
@z
012024: Turn on debug code.
@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==
@d gubed==
@z
012201: Turn on statistics code.
@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
013080: Only initialize the table entries if we are to start←like←initex.
@x
@!init @<Initialize table entries (done by \.{INITEX} only)@>@;@+tini
@y
if start←like←initex then
begin
@<Initialize table entries (done by \.{INITEX} only)@>
end;
@z
015849: TRIP: Set mem←max for the trip test.
@x
@!mem←max=30000; {greatest index in \TeX's internal |mem| array,
@y
@!mem←max=3000; {greatest index in \TeX's internal |mem| array,
@z
015849: Set mem←max to a reasonable production value. If you change this, be sure to change mem←top, below.
@x
@!mem←max=30000; {greatest index in \TeX's internal |mem| array;
@y
@!mem←max=65000; {greatest index in \TeX's internal |mem| array;
@z
015959: Up the buf←size, so that long input lines don't cause errors.
@x
@!buf←size=500; {maximum number of characters simultaneously present in
@y
@!buf←size=7500; {maximum number of characters simultaneously present in
@z
016162: TRIP: Set error←line, half𡤎rror←line, max←print←line for the trip test.
@x
@!error←line=72; {width of context lines on terminal error messages}
@!half𡤎rror←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𡤎rror←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
016162: Set error←line and half𡤎rror←line small, but max←print←line very large.
@x
@!error←line=72; {width of context lines on terminal error messages}
@!half𡤎rror←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𡤎rror←line=32; {width of first lines of contexts in terminal
error messages; should be between 30 and |error←line-15|}
@!max←print←line=30000; {width of longest text lines output; should be at least 60}
@z
016613: Up the font←max and font←mem←size for LaTeX and other greedy users.
@x
@!font←max=75; {maximum internal font number; must not exceed |max←quarterword|
and must be at most |font�se+256|}
@!font←mem←size=20000; {number of words of |font←info| for all fonts}
@y
@!font←max=100; {maximum internal font number; must not exceed |max←quarterword|
and must be at most |font�se+256|}
@!font←mem←size=25000; {number of words of |font←info| for all fonts}
@z
016943: Up the max←strings, string←vacancies, and pool←size for LaTeX and other greedy folk.
@x
@!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}
@y
@!max←strings=4400; {maximum number of strings; must not exceed |max←halfword|}
@!string←vacancies=15000; {the minimum number of characters that should be
available for the user's control sequences and font names,
after \TeX's own error messages are stored}
@!pool←size=48000; {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}
@z
017775: Up the file←name←size to 127, enough for FS including version numbers.
@x
@!file←name←size=40; {file names shouldn't be longer than this}
@y
@!file←name←size=127; {file names shouldn't be longer than this}
@z
017839: Delete pool name, since that initialization will be done by an external proc.
@x
@!pool←name='TeXformats:TEX.POOL ';
@y
@z
000000: Set mem𡤋ot and mem←top to mem←min and mem←max respectively.
@x
@d mem𡤋ot=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𡤋ot|
and not greater than |mem←max|}
@y
@d mem𡤋ot=0 {smallest index in the |mem| array dumped by \.{INITEX};
must not be less than |mem←min|}
@d mem←top==65000 {largest index in the |mem| array dumped by \.{INITEX};
must be substantially larger than |mem𡤋ot|
and not greater than |mem←max|}
@z
018878: Up the hash←size and hash←prime for greedy users.
@x
@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|}
@y
@d hash←size=2500 {maximum number of control sequences; it should be at most
about |(mem←max-mem←min)/10|, but 2100 is already quite generous}
@d hash←prime=2129 {a prime number equal to about 85\% of |hash←size|}
@z
025470: Allow for eight-bit characters
@x
@d last←text𡤌har=127 {ordinal number of the largest element of |text𡤌har|}
@y
@d last←text𡤌har=255 {ordinal number of the largest element of |text𡤌har|}
@z
030172: Set up the character-code mapping to be the identity for now.
@x
for i:=1 to @'37 do xchr[i]:=' ';
@y
for i:=1 to @'37 do xchr[i]:=chr(i);
@z
034917: Replace Pascal-H extended file routines with external calls.
@x
@d reset←OK(#)==erstat(#)=0
@d rewrite←OK(#)==erstat(#)=0
@p function a←open←in(var f:alpha𡤏ile):boolean;
{open a text file for input}
begin reset(f,name←of𡤏ile,'/O'); a←open←in:=reset←OK(f);
end;
@#
function a←open←out(var f:alpha𡤏ile):boolean;
{open a text file for output}
begin rewrite(f,name←of𡤏ile,'/O'); a←open←out:=rewrite←OK(f);
end;
@#
function b←open←in(var f:byte𡤏ile):boolean;
{open a binary file for input}
begin reset(f,name←of𡤏ile,'/O'); b←open←in:=reset←OK(f);
end;
@#
function b←open←out(var f:byte𡤏ile):boolean;
{open a binary file for output}
begin rewrite(f,name←of𡤏ile,'/O'); b←open←out:=rewrite←OK(f);
end;
@#
function w←open←in(var f:word𡤏ile):boolean;
{open a word file for input}
begin reset(f,name←of𡤏ile,'/O'); w←open←in:=reset←OK(f);
end;
@#
function w←open←out(var f:word𡤏ile):boolean;
{open a word file for output}
begin rewrite(f,name←of𡤏ile,'/O'); w←open←out:=rewrite←OK(f);
end;
@y
@p function a←open←in(var f:alpha𡤏ile):boolean; external;
{open a text file for input}
@#
function a←open←out(var f:alpha𡤏ile):boolean; external;
{open a text file for output}
@#
function b←open←in(var f:byte𡤏ile):boolean; external;
{open a binary file for input}
@#
function b←open←out(var f:byte𡤏ile):boolean; external;
{open a binary file for output}
@#
function w←open←in(var f:word𡤏ile):boolean; external;
{open a word file for input}
@#
function w←open←out(var f:word𡤏ile):boolean; external;
{open a word file for output}
@z
036219: Also make close-operations external.
@x
@p procedure a𡤌lose(var f:alpha𡤏ile); {close a text file}
begin close(f);
end;
@#
procedure b𡤌lose(var f:byte𡤏ile); {close a binary file}
begin close(f);
end;
@#
procedure w𡤌lose(var f:word𡤏ile); {close a word file}
begin close(f);
end;
@y
@p procedure a𡤌lose(var f:alpha𡤏ile); external; {close a text file}
@#
procedure b𡤌lose(var f:byte𡤏ile); external; {close a binary file}
@#
procedure w𡤌lose(var f:word𡤏ile); external; {close a word file}
@z
041190: Terminal files are also external.
@x
@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
@d t←open←in==reset←term←in(term←in) {open the terminal for text input}
@d t←open←out==rewrite←term←out(term←out) {open the terminal for text output}
@z
042174: Remove break←in from clear←terminal
@x
@d clear←terminal == break←in(term←in,true) {clear the terminal input buffer}
@y
@d clear←terminal == {clear the terminal input buffer}
@z
045051: Read the tail of the command line as the first line of input
@x
begin t←open←in;
@y
const cmd𡤋lank = 0;
cmd←ok = 1;
cmd←overflow = -1;
var cmd←status:integer;
begin t←open←in;
cmd←status:=stuff←on𡤌md←line;
if cmd←status=cmd←overflow then overflow("buffer size",buf←size);
if cmd←status=cmd←ok then begin init←terminal:=true; return end;
@z
054024: This is where to change if you want to print the extended character set to the terminal.
054715: Set up pool←name properly, filling out with blanks.
@x
name←of𡤏ile:=pool←name; {we needn't set |name←length|}
@y
set←pool←name;
@z
075294: Set process priority back up to normal for error handling interactions
@x
if interaction=error←stop←mode then @<Get user's advice and |return|@>;
@y
if interaction=error←stop←mode then
begin set←normal←priority; @<Get user's advice and |return|@>; end;
@z
075593: But set it back down to background when the interaction is over
@x
exit:end;
@y
exit: set�kground←priority; end;
@z
076701: In Cedar, character counts are more useful than line numbers. My basic plan is to store character counts of the beginning of the lines in Knuth's "line" variables. To avoid confusion with zero, which Knuth uses as a special flag, I shall actually store (charPos+1) instead. This works out wonderfully, since the Position button in Tioga starts counting characters from one instead of from zero anyway.
@x
print(" at line "); print←int(line);
@y
print(" near character "); print←int(line);
@z
085725: Eliminate big subrange of INT.
@x
@!nonnegative←integer=0..@'17777777777; {$0\L x<2^{31}$}
@y
@!nonnegative←integer=integer; {$0\L x<2^{31}$}
@z
096364: Make max←halfword a little smaller to allow more effiencient index arithmetic.
@x
@d max←halfword==65535 {largest allowable value in a |halfword|}
@y
@d max←halfword==65515 {largest allowable value in a |halfword|}
@z
097561: Make life easy on the compiler, given that min←halfword=min←quarterword=0
@x
@d qi(#)==#+min←quarterword
{to put an |eight𡤋its| item into a quarterword}
@d qo(#)==#-min←quarterword
{to take an |eight𡤋its| 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𡤋its| item into a quarterword}
@d qo(#)==#
{to take an |eight𡤋its| 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
098142: Change tag fields in variant records to enumerated types.
@x
@!two𡤌hoices = 1..2; {used when there are two variants in a record}
@!four𡤌hoices = 1..4; {used when there are four variants in a record}
@!two←halves = packed record@;@/
@!rh:halfword;
case two𡤌hoices of
1: (@!lh:halfword);
2: (@!b0:quarterword; @!b1:quarterword);
end;
@!four←quarters = packed record@;@/
@!b0:quarterword;
@!b1:quarterword;
@!b2:quarterword;
@!b3:quarterword;
end;
@!memory←word = record@;@/
case four𡤌hoices of
1: (@!int:integer);
2: (@!gr:glue←ratio);
3: (@!hh:two←halves);
4: (@!qqqq:four←quarters);
end;
@y
@!two𡤌hoices = (c1of2, c2of2);
{used when there are two variants in a record}
@!four𡤌hoices = (c1of4, c2of4, c3of4, c4of4);
{used when there are four variants in a record}
@!two←halves = packed record@;@/
@!rh:halfword;
case two𡤌hoices of
c1of2: (@!lh:halfword);
c2of2: (@!b0:quarterword; @!b1:quarterword);
end;
@!four←quarters = packed record@;@/
@!b0:quarterword;
@!b1:quarterword;
@!b2:quarterword;
@!b3:quarterword;
end;
@!memory←word = record@;@/
case four𡤌hoices of
c1of4: (@!int:integer);
c2of4: (@!gr:glue←ratio);
c3of4: (@!hh:two←halves);
c4of4: (@!qqqq:four←quarters);
end;
@z
178496: Fix up character count versus line number
@x
print(" entered at line "); print←int(abs(nest[p].ml𡤏ield));
@y
print(" entered in line at c. "); print←int(abs(nest[p].ml𡤏ield));
@z
216323: Fix up fix�te𡤊nd←time
@x
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
begin read←the𡤌lock(time,day,month,year);
end;
@z
252194: Add flag that chooses Press output format
@x
@!mag←set:integer; {if nonzero, this magnification should be used henceforth}
@y
@!mag←set:integer; {if nonzero, this magnification should be used henceforth}
@!use←press𡤏ormat:boolean; {the user has requested that Press format be used}
@z
252400: Set flag by inquiring of the user profile
@x
@p procedure prepare←mag;
begin if (mag←set>0)and(mag<>mag←set) then
@y
@p procedure prepare←mag;
var @!user←wants←press:boolean;
begin user←wants←press:=profile𡤊sks𡤏or←press;
if (mag←set>0)and(mag<>mag←set) then
@z
252865: Complain about a tardy attempt to change the output format
@x
if (mag<=0)or(mag>32768) then
@y
if (mag←set>0)and(use←press𡤏ormat<>user←wants←press) then
begin print𡤎rr("Tardy attempt to select Press print file format is being ignored");
error;
user←wants←press:=use←press𡤏ormat;
end;
if (mag<=0)or(mag>32768) then
@z
253126: Irrevocably decide on the output format
@x
mag←set:=mag;
@y
mag←set:=mag;
use←press𡤏ormat:=user←wants←press;
@z
282012: Report error locations by character count rather than line number. In this particular case, I adjust the value of line in order to indicate the exact character at which the error happened.
@x
else begin print←nl("l."); print←int(line);
@y
else begin print←nl("c."); print←int(line+(loc-start));
@z
294981: Change message from "line" to "character"
@x
print("; all text was ignored after line "); print←int(skip←line);
@y
print("; all text was ignored after line at c. "); print←int(skip←line);
@z
309157: Set "line" to character count rather than line number. Remember that we want to store (charPos+1) in "line", but the offset of plus one comes for free, since Pascal has read the first character of the new line behind our backs.
@x
begin incr(line); first:=start;
@y
begin line:=file←get←pos(cur𡤏ile); first:=start;
@z
361891: Eliminate large subrange of INT.
@x
@!num,@!denom:1..65536; {conversion ratio for the scanned units}
@y
@!num,@!denom:integer; {conversion ratio for the scanned units}
@z
402772: Default file directories
@x
@d TEX𡤊rea=="TeXinputs:"
@.TeXinputs@>
@d TEX𡤏ont𡤊rea=="TeXfonts:"
@.TeXfonts@>
@y
@<Glob...@>=
@!TEX𡤊rea:str←number;
@.TeXinputs@>
@!TEX𡤏ont𡤊rea:str←number;
@.TeXfonts@>
@z
403170: Adjust parsing of file names.
@x
else begin if (c=">")or(c=":") then
begin area�limiter:=pool←ptr; ext�limiter:=0;
end
else if (c=".")and(ext�limiter=0) then ext�limiter:=pool←ptr;
@y
else begin if (c=">")or(c="/")or(c="]") then
area�limiter:=pool←ptr
else if (c=".") then ext�limiter:=pool←ptr;
@z
405257: We shall generate format file names in Cedar, working from the default name in the user profile. Hence, we here replace three modules by dummies (to keep the numbering the same).
@x
@ A messier routine is also needed, since format file names must be scanned
before \TeX's string mechanism has been initialized. We shall use the
global variable |TEX𡤏ormat�ult| to supply the text for default system areas
and extensions related to format files.
@^system dependencies@>

@d format�ult←length=20 {length of the |TEX𡤏ormat�ult| string}
@d format𡤊rea←length=11 {length of its area part}
@d format𡤎xt←length=4 {length of its `\.{.fmt}' part}

@<Glob...@>=
@!TEX𡤏ormat�ult:packed array[1..format�ult←length] of char;

@ @<Set init...@>=
TEX𡤏ormat�ult:='TeXformats:PLAIN.fmt';
@.TeXformats@>
@.PLAIN@>
@^system dependencies@>

@ @<Check the ``constant'' values for consistency@>=
if format�ult←length>file←name←size then bad:=31;
@y
@ This module is a dummy. The default name of the format file is dealt with
directly in Cedar.

@ So is this one.

@ This one too.
@z
406537: Pack𡤋uffered←name in Pascal is replaced by three external relatives.
@x
@p procedure pack𡤋uffered←name(@!n:small←number;@!a,@!b:integer);
var k:integer; {number of positions filled in |name←of𡤏ile|}
@!c: ASCII𡤌ode; {character being packed}
@!j:integer; {index into |buffer| or |TEX𡤏ormat�ult|}
begin if n+b-a+1+format𡤎xt←length>file←name←size then
b:=a+file←name←size-n-1-format𡤎xt←length;
k:=0;
for j:=1 to n do append←to←name(xord[TEX𡤏ormat�ult[j]]);
for j:=a to b do append←to←name(buffer[j]);
for j:=format�ult←length-format𡤎xt←length+1 to format�ult←length do
append←to←name(xord[TEX𡤏ormat�ult[j]]);
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𡤏ile[k]:=' ';
end;
@y
@p procedure pack𡤋uffered←name(@!a,@!b:integer); external;
procedure pack�ult𡤊rea(@!a,@!b:integer); external;
procedure pack𡤊ll�ult; external;
@z
407921: Change first call on pack𡤋uffered←name to a call on an external.
@x
pack𡤋uffered←name(0,loc,j-1); {try first without the system file area}
@y
pack𡤋uffered←name(loc,j-1); {try first without the system file area}
@z
408066: Change second call on pack𡤋uffered←name to a call on an external.
@x
pack𡤋uffered←name(format𡤊rea←length,loc,j-1);
@y
pack�ult𡤊rea(loc,j-1);
@z
408247: Change message to indicate that PLAIN isn't necessarily the default format file.
@x
wterm←ln('Sorry, I can''t find that format;',' will try PLAIN.');
@y
wterm←ln('Sorry, I can''t find that format;',' will try your default.');
@z
408415: Change third call on pack𡤋uffered←name to a call on an external.
@x
pack𡤋uffered←name(format�ult←length-format𡤎xt←length,1,0);
@y
pack𡤊ll�ult;
@z
408538: Change another message to indicate that PLAIN isn't necessarily the default format file.
@x
wterm←ln('I can''t find the PLAIN format file!');
@y
wterm←ln('I can''t find your default format file!');
@z
409289: Report full names of open files by calls to system dependent externals.
@x
function a←make←name←string(var f:alpha𡤏ile):str←number;
begin a←make←name←string:=make←name←string;
end;
function b←make←name←string(var f:byte𡤏ile):str←number;
begin b←make←name←string:=make←name←string;
end;
function w←make←name←string(var f:word𡤏ile):str←number;
begin w←make←name←string:=make←name←string;
end;
@y
function a←make←name←string(var f:alpha𡤏ile):str←number; external;
function b←make←name←string(var f:byte𡤏ile):str←number; external;
function w←make←name←string(var f:word𡤏ile):str←number; external;
function press←make←name←string:str←number; external;
@z
413111: Open either press or DVI as appropriate.
@x
@d ensure𡤍vi←open==if output𡤏ile←name=0 then
@y
@d ensure←press←open==if output𡤏ile←name=0 then
begin if job←name=0 then open←log𡤏ile;
pack←job←name(".press");
while not press←open←out do
prompt𡤏ile←name("file name for output",".press");
output𡤏ile←name:=press←make←name←string;
end;
@d ensure𡤍vi←open==if output𡤏ile←name=0 then
@z
417246: No change here, since it happens that 1 is correct value of (charPos+1) at the start of a file.
@x
first:=limit+1; loc:=start; line:=1;
@y
first:=limit+1; loc:=start; line:=1;
@z
431785: Add arrays for Press font parameters.
@x
@!skew𡤌har:array[internal𡤏ont←number] of integer;
{current \.{\\skewchar} values}
@y
@!skew𡤌har:array[internal𡤏ont←number] of integer;
{current \.{\\skewchar} values}
@!font�mily:array[internal𡤏ont←number] of str←number;
{the Press family name}
@!font�:array[internal𡤏ont←number] of eight𡤋its;
{the Press face code}
@!font←pype𡤌ode:array[internal𡤏ont←number] of cedar←nat;
{once font←used is true, holds the SirPress pyping font code}
@z
438943: Add two new local variables to read𡤏ont←info
@x
@!f:internal𡤏ont←number; {the new font's number}
@y
@!i,@!fam←len:halfword; {new temporaries}
@!f:internal𡤏ont←number; {the new font's number}
@z
439273: Declare inner procedure for reading header, to make read𡤏ont←info shorter.
@x
begin g:=null𡤏ont;@/
@y
procedure read←the←tfm←header;
@<Read the {\.{TFM}} header@>;
begin g:=null𡤏ont;@/
@z
440837: Call the new inner procedure.
@x
@<Read the {\.{TFM}} header@>;
@y
read←the←tfm←header;
@z
443721: Change old header-reading code into body of the new inner procedure.
@x
@ Only the first two words of the header are needed by \TeX82.

@<Read the {\.{TFM}} header@>=
begin if lh<2 then abort;
store𡤏our←quarters(font𡤌heck[f]);
fget; read←sixteen(z); {this rejects a negative design size}
fget; z:=z*@'400+fbyte; fget; z:=(z*@'20)+(fbyte div@'20);
if z<unity then abort;
while lh>2 do
begin fget;fget;fget;fget;decr(lh); {ignore the rest of the header}
end;
font𡤍size[f]:=z;
if s<>-1000 then
if s>=0 then z:=s
else z:=xn←over𡤍(z,-s,1000);
font←size[f]:=z;
end
@y
@ Normally, \TeX82 only needs to read the first two words of the
header. But we must read more, in order to handle Press output.

@<Read the {\.{TFM}} header@>=
begin if lh<18 then abort;
store𡤏our←quarters(font𡤌heck[f]);
fget; read←sixteen(z); {this rejects a negative design size}
fget; z:=z*@'400+fbyte; fget; z:=(z*@'20)+(fbyte div@'20);
if z<unity then abort;
for i:=1 to 10 do begin fget;fget;fget;fget end; {ignore character coding scheme}
fget; {read the length of the font family name}
fam←len:=fbyte;
str←room(fam←len);
for i:=1 to fam←len do begin fget; append𡤌har(fbyte) end;
for i:=fam←len+1 to 19 do fget;
font�mily[f]:=make←string;
fget; fget; fget; fget; font�[f]:=fbyte;
while lh>18 do
begin fget;fget;fget;fget;decr(lh); {ignore the rest of the header}
end;
font𡤍size[f]:=z;
if s<>-1000 then
if s>=0 then z:=s
else z:=xn←over𡤍(z,-s,1000);
font←size[f]:=z;
end
@z
482739: Make write𡤍vi external also.
@x
@p procedure write𡤍vi(@!a,@!b:dvi←index);
var k:dvi←index;
begin for k:=a to b do write(dvi𡤏ile,dvi𡤋uf[k]);
end;
@y
@p procedure write𡤍vi(@!a,@!b:dvi←index); external;
@z
498097: Add new global variable for use by hlist←press←out;
@x
@!cur←s:integer; {current depth of output box nesting}
@y
@!cur←s:integer; {current depth of output box nesting}
@!press←h←ok:boolean; {while pyping, tells if SirPress has the correct x-coordinate}
@z
498257: Ship←out must firm up the selection between Press and DVI, and then initialize the appropriate one.
@x
cur←s:=-1; ensure𡤍vi←open;
@y
cur←s:=-1;
prepare←mag; {now the Press/DVI die is cast}
if use←press𡤏ormat then
begin
ensure←press←open;
if total←pages=0 then
do←nothing; {nothing special needs to be done before the first page}
end
else
begin
ensure𡤍vi←open;
@z
498873: Close off new block that the 498257 change opened inside ship←out.
@x
pool←ptr:=str←start[str←ptr]; {flush the current string}
end
@y
pool←ptr:=str←start[str←ptr]; {flush the current string}
end;
end
@z
499328: Declare hlist←press←out and vlist←press←out.
@x
@p procedure@?vlist←out; forward; {|hlist←out| and |vlist←out| are mutually
recursive}
@y
@p procedure@?vlist←out; forward; {|hlist←out| and |vlist←out| are mutually
recursive}
procedure@?hlist←press←out; forward;
procedure@?vlist←press←out; forward;
@z
499418: Perform the identity change on the output code, to warn us of any future changes. If something changes here, the corresponding change should be made to the Press analogues of hlist←out and vlist←out, which appear at the end of this change file.
@x
@ The recursive procedures |hlist←out| and |vlist←out| each have local variables
|save←h| and |save←v| to hold the values of |dvi←h| and |dvi←v| just before
entering a new level of recursion. In effect, the values of |save←h| and
|save←v| on \TeX's run-time stack correspond to the values of |h| and |v|
that a \.{DVI}-reading program will push onto its coordinate stack.

@d move←past=13 {go to this label when advancing past glue or a rule}
@d fin←rule=14 {go to this label to finish processing a rule}
@d next←p=15 {go to this label when finished with node |p|}

@p @t\4@>@<Declare procedures needed in |hlist←out|, |vlist←out|@>@t@>@/
procedure hlist←out; {output an |hlist←node| box}
label reswitch, move←past, fin←rule, next←p;
var base←line: scaled; {the baseline coordinate for this box}
@!left�ge: scaled; {the left coordinate for this box}
@!save←h,@!save←v: scaled; {what |dvi←h| and |dvi←v| should pop to}
@!this𡤋ox: pointer; {pointer to containing box}
@!g←order: glue←ord; {applicable order of infinity for glue}
@!g←sign: normal..shrinking; {selects type of glue}
@!p:pointer; {current position in the hlist}
@!save←loc:integer; {\.{DVI} byte location upon entry}
@!leader𡤋ox:pointer; {the leader box being replicated}
@!leader←wd:scaled; {width of leader box being replicated}
@!lx:scaled; {extra space between leader boxes}
@!outer𡤍oing←leaders:boolean; {were we doing leaders?}
@!edge:scaled; {left edge of sub-box, or right edge of leader space}
begin this𡤋ox:=temp←ptr; g←order:=glue←order(this𡤋ox);
g←sign:=glue←sign(this𡤋ox); p:=list←ptr(this𡤋ox);
incr(cur←s);
if cur←s>0 then dvi←out(push);
if cur←s>max←push then max←push:=cur←s;
save←loc:=dvi←offset+dvi←ptr; base←line:=cur←v; left�ge:=cur←h;
while p<>null do @<Output node |p| for |hlist←out| and move to the next node,
maintaining the condition |cur←v=base←line|@>;
prune←movements(save←loc);
if cur←s>0 then dvi←pop(save←loc);
decr(cur←s);
end;

@ We ought to give special care to the efficiency of one part of |hlist←out|,
since it belongs to \TeX's inner loop. When a |char←node| is encountered,
we save a little time by processing several nodes in succession until
reaching a non-|char←node|. The program uses the fact that |set𡤌har𡤀=0|.
@^inner loop@>

@<Output node |p| for |hlist←out|...@>=
reswitch: if is𡤌har←node(p) then
begin synch←h; synch←v;
repeat f:=font(p); c:=character(p);
if f<>dvi𡤏 then @<Change font |dvi𡤏| to |f|@>;
if c<qi(128) then dvi←out(qo(c))
else begin dvi←out(set1); dvi←out(qo(c));
end;
cur←h:=cur←h+char←width(f)(char←info(f)(c));
p:=link(p);
until not is𡤌har←node(p);
dvi←h:=cur←h;
end
else @<Output the non-|char←node| |p| for |hlist←out|
and move to the next node@>

@ @<Change font |dvi𡤏| to |f|@>=
begin if not font←used[f] then
begin dvi𡤏ont�(f); font←used[f]:=true;
end;
if f<=64+font�se then dvi←out(f-font�se-1+fnt←num𡤀)
else begin dvi←out(fnt1); dvi←out(f-font�se-1);
end;
dvi𡤏:=f;
end

@ @<Output the non-|char←node| |p| for |hlist←out|...@>=
begin case type(p) of
hlist←node,vlist←node:@<Output a box in an hlist@>;
rule←node: begin rule←ht:=height(p); rule𡤍p:=depth(p); rule←wd:=width(p);
goto fin←rule;
end;
whatsit←node: @<Output the whatsit node |p| in an hlist@>;
glue←node: @<Move right or output leaders@>;
kern←node,math←node:cur←h:=cur←h+width(p);
ligature←node: @<Make node |p| look like a |char←node| and |goto reswitch|@>;
othercases do←nothing
endcases;@/
goto next←p;
fin←rule: @<Output a rule in an hlist@>;
move←past: cur←h:=cur←h+rule←wd;
next←p:p:=link(p);
end

@ @<Output a box in an hlist@>=
if list←ptr(p)=null then cur←h:=cur←h+width(p)
else begin save←h:=dvi←h; save←v:=dvi←v;
cur←v:=base←line+shift𡤊mount(p); {shift the box down}
temp←ptr:=p; edge:=cur←h;
if type(p)=vlist←node then vlist←out@+else hlist←out;
dvi←h:=save←h; dvi←v:=save←v;
cur←h:=edge+width(p); cur←v:=base←line;
end

@ @<Output a rule in an hlist@>=
if is←running(rule←ht) then rule←ht:=height(this𡤋ox);
if is←running(rule𡤍p) then rule𡤍p:=depth(this𡤋ox);
rule←ht:=rule←ht+rule𡤍p; {this is the rule thickness}
if (rule←ht>0)and(rule←wd>0) then {we don't output empty rules}
begin synch←h; cur←v:=base←line+rule𡤍p; synch←v;
dvi←out(set←rule); dvi𡤏our(rule←ht); dvi𡤏our(rule←wd);
cur←v:=base←line; dvi←h:=dvi←h+rule←wd;
end

@ @<Move right or output leaders@>=
begin g:=glue←ptr(p); rule←wd:=width(g);
if g←sign<>normal then
begin if g←sign=stretching then
begin if stretch←order(g)=g←order then
rule←wd:=rule←wd+round(float(glue←set(this𡤋ox))*stretch(g));
@^real multiplication@>
end
else begin if shrink←order(g)=g←order then
rule←wd:=rule←wd-round(float(glue←set(this𡤋ox))*shrink(g));
end;
end;
if subtype(p)>=a←leaders then
@<Output leaders in an hlist, |goto fin←rule| if a rule
or to |next←p| if done@>;
goto move←past;
end

@ @<Output leaders in an hlist...@>=
begin leader𡤋ox:=leader←ptr(p);
if type(leader𡤋ox)=rule←node then
begin rule←ht:=height(leader𡤋ox); rule𡤍p:=depth(leader𡤋ox);
goto fin←rule;
end;
leader←wd:=width(leader𡤋ox);
if (leader←wd>0)and(rule←wd>0) then
begin edge:=cur←h+rule←wd; lx:=0;
@<Let |cur←h| be the position of the first box, and set |leader←wd+lx|
to the spacing between corresponding parts of boxes@>;
while cur←h+leader←wd<=edge do
@<Output a leader box at |cur←h|,
then advance |cur←h| by |leader←wd+lx|@>;
cur←h:=edge; goto next←p;
end;
end

@ The calculations related to leaders require a bit of care. First, in the
case of |a←leaders| (aligned leaders), we want to move |cur←h| to
|left�ge| plus the smallest multiple of |leader←wd| for which the result
is not less than the current value of |cur←h|; i.e., |cur←h| should become
$|left�ge|+|leader←wd|\times\lceil
(|cur←h|-|left�ge|)/|leader←wd|\rceil$. The program here should work in
all cases even though some implementations of \PASCAL\ give nonstandard
results for the |div| operation precisely, and even when |cur←h| is less
than |left�ge|.

In the case of |c←leaders| (centered leaders), we want to increase |cur←h|
by half of the excess space not occupied by the leaders; and in the case of
case of |x←leaders| (expanded leaders) we increase |cur←h|
by $1/(q+1)$ of this excess space, where $q$ is the number of times the
leader box will be replicated. Slight inaccuracies in the division might
accumulate; half of this rounding error is placed at each end of the leaders.

@<Let |cur←h| be the position of the first box, ...@>=
if subtype(p)=a←leaders then
begin save←h:=cur←h;
cur←h:=left�ge+leader←wd*((cur←h-left�ge)@!div leader←wd);
if cur←h<save←h then cur←h:=cur←h+leader←wd;
end
else begin lq:=rule←wd div leader←wd; {the number of box copies}
lr:=rule←wd mod leader←wd; {the remaining space}
if subtype(p)=c←leaders then cur←h:=cur←h+(lr div 2)
else begin lx:=(2*lr+lq+1) div (2*lq+2); {round|(lr/(lq+1))|}
cur←h:=cur←h+((lr-(lq-1)*lx) div 2);
end;
end

@ The `\\{synch}' operations here are intended to decrease the number
of bytes needed to specify horizontal and vertical motion in the \.{DVI} output.

@<Output a leader box at |cur←h|, ...@>=
begin cur←v:=base←line+shift𡤊mount(leader𡤋ox); synch←v; save←v:=dvi←v;@/
synch←h; save←h:=dvi←h; temp←ptr:=leader𡤋ox;
outer𡤍oing←leaders:=doing←leaders; doing←leaders:=true;
if type(leader𡤋ox)=vlist←node then vlist←out@+else hlist←out;
doing←leaders:=outer𡤍oing←leaders;
dvi←v:=save←v; dvi←h:=save←h; cur←v:=save←v;
cur←h:=save←h+leader←wd+lx;
end

@ The |vlist←out| routine is similar to |hlist←out|, but a bit simpler.

@p procedure vlist←out; {output a |vlist←node| box}
label move←past, fin←rule, next←p;
var left�ge: scaled; {the left coordinate for this box}
@!top�ge: scaled; {the top coordinate for this box}
@!save←h,@!save←v: scaled; {what |dvi←h| and |dvi←v| should pop to}
@!this𡤋ox: pointer; {pointer to containing box}
@!g←order: glue←ord; {applicable order of infinity for glue}
@!g←sign: normal..shrinking; {selects type of glue}
@!p:pointer; {current position in the vlist}
@!save←loc:integer; {\.{DVI} byte location upon entry}
@!leader𡤋ox:pointer; {the leader box being replicated}
@!leader←ht:scaled; {height of leader box being replicated}
@!lx:scaled; {extra space between leader boxes}
@!outer𡤍oing←leaders:boolean; {were we doing leaders?}
@!edge:scaled; {bottom boundary of leader space}
begin this𡤋ox:=temp←ptr; g←order:=glue←order(this𡤋ox);
g←sign:=glue←sign(this𡤋ox); p:=list←ptr(this𡤋ox);
incr(cur←s);
if cur←s>0 then dvi←out(push);
if cur←s>max←push then max←push:=cur←s;
save←loc:=dvi←offset+dvi←ptr; left�ge:=cur←h; cur←v:=cur←v-height(this𡤋ox);
top�ge:=cur←v;
while p<>null do @<Output node |p| for |vlist←out| and move to the next node,
maintaining the condition |cur←h=left�ge|@>;
prune←movements(save←loc);
if cur←s>0 then dvi←pop(save←loc);
decr(cur←s);
end;

@ @<Output node |p| for |vlist←out|...@>=
begin if is𡤌har←node(p) then confusion("vlistout")
@:this can't happen vlistout}{\quad vlistout@>
else @<Output the non-|char←node| |p| for |vlist←out|@>;
next←p:p:=link(p);
end

@ @<Output the non-|char←node| |p| for |vlist←out|@>=
begin case type(p) of
hlist←node,vlist←node:@<Output a box in a vlist@>;
rule←node: begin rule←ht:=height(p); rule𡤍p:=depth(p); rule←wd:=width(p);
goto fin←rule;
end;
whatsit←node: @<Output the whatsit node |p| in a vlist@>;
glue←node: @<Move down or output leaders@>;
kern←node:cur←v:=cur←v+width(p);
othercases do←nothing
endcases;@/
goto next←p;
fin←rule: @<Output a rule in a vlist, |goto next←p|@>;
move←past: cur←v:=cur←v+rule←ht;
end

@ The |synch←v| here allows the \.{DVI} output to use one-byte commands
for adjusting |v| in most cases, since the baselineskip distance will
usually be constant.

@<Output a box in a vlist@>=
if list←ptr(p)=null then cur←v:=cur←v+height(p)+depth(p)
else begin cur←v:=cur←v+height(p); synch←v;
save←h:=dvi←h; save←v:=dvi←v;
cur←h:=left�ge+shift𡤊mount(p); {shift the box right}
temp←ptr:=p;
if type(p)=vlist←node then vlist←out@+else hlist←out;
dvi←h:=save←h; dvi←v:=save←v;
cur←v:=save←v+depth(p); cur←h:=left�ge;
end

@ @<Output a rule in a vlist...@>=
if is←running(rule←wd) then rule←wd:=width(this𡤋ox);
rule←ht:=rule←ht+rule𡤍p; {this is the rule thickness}
cur←v:=cur←v+rule←ht;
if (rule←ht>0)and(rule←wd>0) then {we don't output empty rules}
begin synch←h; synch←v;
dvi←out(put←rule); dvi𡤏our(rule←ht); dvi𡤏our(rule←wd);
end;
goto next←p

@ @<Move down or output leaders@>=
begin g:=glue←ptr(p); rule←ht:=width(g);
if g←sign<>normal then
begin if g←sign=stretching then
begin if stretch←order(g)=g←order then
rule←ht:=rule←ht+round(float(glue←set(this𡤋ox))*stretch(g));
@^real multiplication@>
end
else begin if shrink←order(g)=g←order then
rule←ht:=rule←ht-round(float(glue←set(this𡤋ox))*shrink(g));
end;
end;
if subtype(p)>=a←leaders then
@<Output leaders in a vlist, |goto fin←rule| if a rule
or to |next←p| if done@>;
goto move←past;
end

@ @<Output leaders in a vlist...@>=
begin leader𡤋ox:=leader←ptr(p);
if type(leader𡤋ox)=rule←node then
begin rule←wd:=width(leader𡤋ox); rule𡤍p:=0;
goto fin←rule;
end;
leader←ht:=height(leader𡤋ox)+depth(leader𡤋ox);
if (leader←ht>0)and(rule←ht>0) then
begin edge:=cur←v+rule←ht; lx:=0;
@<Let |cur←v| be the position of the first box, and set |leader←ht+lx|
to the spacing between corresponding parts of boxes@>;
while cur←v+leader←ht<=edge do
@<Output a leader box at |cur←v|,
then advance |cur←v| by |leader←ht+lx|@>;
cur←v:=edge; goto next←p;
end;
end

@ @<Let |cur←v| be the position of the first box, ...@>=
if subtype(p)=a←leaders then
begin save←v:=cur←v;
cur←v:=top�ge+leader←ht*((cur←v-top�ge)@!div leader←ht);
if cur←v<save←v then cur←v:=cur←v+leader←ht;
end
else begin lq:=rule←ht div leader←ht; {the number of box copies}
lr:=rule←ht mod leader←ht; {the remaining space}
if subtype(p)=c←leaders then cur←v:=cur←v+(lr div 2)
else begin lx:=(2*lr+lq+1) div (2*lq+2); {round|(lr/(lq+1))|}
cur←v:=cur←v+((lr-(lq-1)*lx) div 2);
end;
end

@ When we reach this part of the program, |cur←v| indicates the top of a
leader box, not its baseline.

@<Output a leader box at |cur←v|, ...@>=
begin cur←h:=left�ge+shift𡤊mount(leader𡤋ox); synch←h; save←h:=dvi←h;@/
cur←v:=cur←v+height(leader𡤋ox); synch←v; save←v:=dvi←v;
temp←ptr:=leader𡤋ox;
outer𡤍oing←leaders:=doing←leaders; doing←leaders:=true;
if type(leader𡤋ox)=vlist←node then vlist←out@+else hlist←out;
doing←leaders:=outer𡤍oing←leaders;
dvi←v:=save←v; dvi←h:=save←h; cur←h:=save←h;
cur←v:=save←v-height(leader𡤋ox)+leader←ht+lx;
end
@y
@ The recursive procedures |hlist←out| and |vlist←out| each have local variables
|save←h| and |save←v| to hold the values of |dvi←h| and |dvi←v| just before
entering a new level of recursion. In effect, the values of |save←h| and
|save←v| on \TeX's run-time stack correspond to the values of |h| and |v|
that a \.{DVI}-reading program will push onto its coordinate stack.

@d move←past=13 {go to this label when advancing past glue or a rule}
@d fin←rule=14 {go to this label to finish processing a rule}
@d next←p=15 {go to this label when finished with node |p|}

@p @t\4@>@<Declare procedures needed in |hlist←out|, |vlist←out|@>@t@>@/
procedure hlist←out; {output an |hlist←node| box}
label reswitch, move←past, fin←rule, next←p;
var base←line: scaled; {the baseline coordinate for this box}
@!left�ge: scaled; {the left coordinate for this box}
@!save←h,@!save←v: scaled; {what |dvi←h| and |dvi←v| should pop to}
@!this𡤋ox: pointer; {pointer to containing box}
@!g←order: glue←ord; {applicable order of infinity for glue}
@!g←sign: normal..shrinking; {selects type of glue}
@!p:pointer; {current position in the hlist}
@!save←loc:integer; {\.{DVI} byte location upon entry}
@!leader𡤋ox:pointer; {the leader box being replicated}
@!leader←wd:scaled; {width of leader box being replicated}
@!lx:scaled; {extra space between leader boxes}
@!outer𡤍oing←leaders:boolean; {were we doing leaders?}
@!edge:scaled; {left edge of sub-box, or right edge of leader space}
begin this𡤋ox:=temp←ptr; g←order:=glue←order(this𡤋ox);
g←sign:=glue←sign(this𡤋ox); p:=list←ptr(this𡤋ox);
incr(cur←s);
if cur←s>0 then dvi←out(push);
if cur←s>max←push then max←push:=cur←s;
save←loc:=dvi←offset+dvi←ptr; base←line:=cur←v; left�ge:=cur←h;
while p<>null do @<Output node |p| for |hlist←out| and move to the next node,
maintaining the condition |cur←v=base←line|@>;
prune←movements(save←loc);
if cur←s>0 then dvi←pop(save←loc);
decr(cur←s);
end;

@ We ought to give special care to the efficiency of one part of |hlist←out|,
since it belongs to \TeX's inner loop. When a |char←node| is encountered,
we save a little time by processing several nodes in succession until
reaching a non-|char←node|. The program uses the fact that |set𡤌har𡤀=0|.
@^inner loop@>

@<Output node |p| for |hlist←out|...@>=
reswitch: if is𡤌har←node(p) then
begin synch←h; synch←v;
repeat f:=font(p); c:=character(p);
if f<>dvi𡤏 then @<Change font |dvi𡤏| to |f|@>;
if c<qi(128) then dvi←out(qo(c))
else begin dvi←out(set1); dvi←out(qo(c));
end;
cur←h:=cur←h+char←width(f)(char←info(f)(c));
p:=link(p);
until not is𡤌har←node(p);
dvi←h:=cur←h;
end
else @<Output the non-|char←node| |p| for |hlist←out|
and move to the next node@>

@ @<Change font |dvi𡤏| to |f|@>=
begin if not font←used[f] then
begin dvi𡤏ont�(f); font←used[f]:=true;
end;
if f<=64+font�se then dvi←out(f-font�se-1+fnt←num𡤀)
else begin dvi←out(fnt1); dvi←out(f-font�se-1);
end;
dvi𡤏:=f;
end

@ @<Output the non-|char←node| |p| for |hlist←out|...@>=
begin case type(p) of
hlist←node,vlist←node:@<Output a box in an hlist@>;
rule←node: begin rule←ht:=height(p); rule𡤍p:=depth(p); rule←wd:=width(p);
goto fin←rule;
end;
whatsit←node: @<Output the whatsit node |p| in an hlist@>;
glue←node: @<Move right or output leaders@>;
kern←node,math←node:cur←h:=cur←h+width(p);
ligature←node: @<Make node |p| look like a |char←node| and |goto reswitch|@>;
othercases do←nothing
endcases;@/
goto next←p;
fin←rule: @<Output a rule in an hlist@>;
move←past: cur←h:=cur←h+rule←wd;
next←p:p:=link(p);
end

@ @<Output a box in an hlist@>=
if list←ptr(p)=null then cur←h:=cur←h+width(p)
else begin save←h:=dvi←h; save←v:=dvi←v;
cur←v:=base←line+shift𡤊mount(p); {shift the box down}
temp←ptr:=p; edge:=cur←h;
if type(p)=vlist←node then vlist←out@+else hlist←out;
dvi←h:=save←h; dvi←v:=save←v;
cur←h:=edge+width(p); cur←v:=base←line;
end

@ @<Output a rule in an hlist@>=
if is←running(rule←ht) then rule←ht:=height(this𡤋ox);
if is←running(rule𡤍p) then rule𡤍p:=depth(this𡤋ox);
rule←ht:=rule←ht+rule𡤍p; {this is the rule thickness}
if (rule←ht>0)and(rule←wd>0) then {we don't output empty rules}
begin synch←h; cur←v:=base←line+rule𡤍p; synch←v;
dvi←out(set←rule); dvi𡤏our(rule←ht); dvi𡤏our(rule←wd);
cur←v:=base←line; dvi←h:=dvi←h+rule←wd;
end

@ @<Move right or output leaders@>=
begin g:=glue←ptr(p); rule←wd:=width(g);
if g←sign<>normal then
begin if g←sign=stretching then
begin if stretch←order(g)=g←order then
rule←wd:=rule←wd+round(float(glue←set(this𡤋ox))*stretch(g));
@^real multiplication@>
end
else begin if shrink←order(g)=g←order then
rule←wd:=rule←wd-round(float(glue←set(this𡤋ox))*shrink(g));
end;
end;
if subtype(p)>=a←leaders then
@<Output leaders in an hlist, |goto fin←rule| if a rule
or to |next←p| if done@>;
goto move←past;
end

@ @<Output leaders in an hlist...@>=
begin leader𡤋ox:=leader←ptr(p);
if type(leader𡤋ox)=rule←node then
begin rule←ht:=height(leader𡤋ox); rule𡤍p:=depth(leader𡤋ox);
goto fin←rule;
end;
leader←wd:=width(leader𡤋ox);
if (leader←wd>0)and(rule←wd>0) then
begin edge:=cur←h+rule←wd; lx:=0;
@<Let |cur←h| be the position of the first box, and set |leader←wd+lx|
to the spacing between corresponding parts of boxes@>;
while cur←h+leader←wd<=edge do
@<Output a leader box at |cur←h|,
then advance |cur←h| by |leader←wd+lx|@>;
cur←h:=edge; goto next←p;
end;
end

@ The calculations related to leaders require a bit of care. First, in the
case of |a←leaders| (aligned leaders), we want to move |cur←h| to
|left�ge| plus the smallest multiple of |leader←wd| for which the result
is not less than the current value of |cur←h|; i.e., |cur←h| should become
$|left�ge|+|leader←wd|\times\lceil
(|cur←h|-|left�ge|)/|leader←wd|\rceil$. The program here should work in
all cases even though some implementations of \PASCAL\ give nonstandard
results for the |div| operation precisely, and even when |cur←h| is less
than |left�ge|.

In the case of |c←leaders| (centered leaders), we want to increase |cur←h|
by half of the excess space not occupied by the leaders; and in the case of
case of |x←leaders| (expanded leaders) we increase |cur←h|
by $1/(q+1)$ of this excess space, where $q$ is the number of times the
leader box will be replicated. Slight inaccuracies in the division might
accumulate; half of this rounding error is placed at each end of the leaders.

@<Let |cur←h| be the position of the first box, ...@>=
if subtype(p)=a←leaders then
begin save←h:=cur←h;
cur←h:=left�ge+leader←wd*((cur←h-left�ge)@!div leader←wd);
if cur←h<save←h then cur←h:=cur←h+leader←wd;
end
else begin lq:=rule←wd div leader←wd; {the number of box copies}
lr:=rule←wd mod leader←wd; {the remaining space}
if subtype(p)=c←leaders then cur←h:=cur←h+(lr div 2)
else begin lx:=(2*lr+lq+1) div (2*lq+2); {round|(lr/(lq+1))|}
cur←h:=cur←h+((lr-(lq-1)*lx) div 2);
end;
end

@ The `\\{synch}' operations here are intended to decrease the number
of bytes needed to specify horizontal and vertical motion in the \.{DVI} output.

@<Output a leader box at |cur←h|, ...@>=
begin cur←v:=base←line+shift𡤊mount(leader𡤋ox); synch←v; save←v:=dvi←v;@/
synch←h; save←h:=dvi←h; temp←ptr:=leader𡤋ox;
outer𡤍oing←leaders:=doing←leaders; doing←leaders:=true;
if type(leader𡤋ox)=vlist←node then vlist←out@+else hlist←out;
doing←leaders:=outer𡤍oing←leaders;
dvi←v:=save←v; dvi←h:=save←h; cur←v:=save←v;
cur←h:=save←h+leader←wd+lx;
end

@ The |vlist←out| routine is similar to |hlist←out|, but a bit simpler.

@p procedure vlist←out; {output a |vlist←node| box}
label move←past, fin←rule, next←p;
var left�ge: scaled; {the left coordinate for this box}
@!top�ge: scaled; {the top coordinate for this box}
@!save←h,@!save←v: scaled; {what |dvi←h| and |dvi←v| should pop to}
@!this𡤋ox: pointer; {pointer to containing box}
@!g←order: glue←ord; {applicable order of infinity for glue}
@!g←sign: normal..shrinking; {selects type of glue}
@!p:pointer; {current position in the vlist}
@!save←loc:integer; {\.{DVI} byte location upon entry}
@!leader𡤋ox:pointer; {the leader box being replicated}
@!leader←ht:scaled; {height of leader box being replicated}
@!lx:scaled; {extra space between leader boxes}
@!outer𡤍oing←leaders:boolean; {were we doing leaders?}
@!edge:scaled; {bottom boundary of leader space}
begin this𡤋ox:=temp←ptr; g←order:=glue←order(this𡤋ox);
g←sign:=glue←sign(this𡤋ox); p:=list←ptr(this𡤋ox);
incr(cur←s);
if cur←s>0 then dvi←out(push);
if cur←s>max←push then max←push:=cur←s;
save←loc:=dvi←offset+dvi←ptr; left�ge:=cur←h; cur←v:=cur←v-height(this𡤋ox);
top�ge:=cur←v;
while p<>null do @<Output node |p| for |vlist←out| and move to the next node,
maintaining the condition |cur←h=left�ge|@>;
prune←movements(save←loc);
if cur←s>0 then dvi←pop(save←loc);
decr(cur←s);
end;

@ @<Output node |p| for |vlist←out|...@>=
begin if is𡤌har←node(p) then confusion("vlistout")
@:this can't happen vlistout}{\quad vlistout@>
else @<Output the non-|char←node| |p| for |vlist←out|@>;
next←p:p:=link(p);
end

@ @<Output the non-|char←node| |p| for |vlist←out|@>=
begin case type(p) of
hlist←node,vlist←node:@<Output a box in a vlist@>;
rule←node: begin rule←ht:=height(p); rule𡤍p:=depth(p); rule←wd:=width(p);
goto fin←rule;
end;
whatsit←node: @<Output the whatsit node |p| in a vlist@>;
glue←node: @<Move down or output leaders@>;
kern←node:cur←v:=cur←v+width(p);
othercases do←nothing
endcases;@/
goto next←p;
fin←rule: @<Output a rule in a vlist, |goto next←p|@>;
move←past: cur←v:=cur←v+rule←ht;
end

@ The |synch←v| here allows the \.{DVI} output to use one-byte commands
for adjusting |v| in most cases, since the baselineskip distance will
usually be constant.

@<Output a box in a vlist@>=
if list←ptr(p)=null then cur←v:=cur←v+height(p)+depth(p)
else begin cur←v:=cur←v+height(p); synch←v;
save←h:=dvi←h; save←v:=dvi←v;
cur←h:=left�ge+shift𡤊mount(p); {shift the box right}
temp←ptr:=p;
if type(p)=vlist←node then vlist←out@+else hlist←out;
dvi←h:=save←h; dvi←v:=save←v;
cur←v:=save←v+depth(p); cur←h:=left�ge;
end

@ @<Output a rule in a vlist...@>=
if is←running(rule←wd) then rule←wd:=width(this𡤋ox);
rule←ht:=rule←ht+rule𡤍p; {this is the rule thickness}
cur←v:=cur←v+rule←ht;
if (rule←ht>0)and(rule←wd>0) then {we don't output empty rules}
begin synch←h; synch←v;
dvi←out(put←rule); dvi𡤏our(rule←ht); dvi𡤏our(rule←wd);
end;
goto next←p

@ @<Move down or output leaders@>=
begin g:=glue←ptr(p); rule←ht:=width(g);
if g←sign<>normal then
begin if g←sign=stretching then
begin if stretch←order(g)=g←order then
rule←ht:=rule←ht+round(float(glue←set(this𡤋ox))*stretch(g));
@^real multiplication@>
end
else begin if shrink←order(g)=g←order then
rule←ht:=rule←ht-round(float(glue←set(this𡤋ox))*shrink(g));
end;
end;
if subtype(p)>=a←leaders then
@<Output leaders in a vlist, |goto fin←rule| if a rule
or to |next←p| if done@>;
goto move←past;
end

@ @<Output leaders in a vlist...@>=
begin leader𡤋ox:=leader←ptr(p);
if type(leader𡤋ox)=rule←node then
begin rule←wd:=width(leader𡤋ox); rule𡤍p:=0;
goto fin←rule;
end;
leader←ht:=height(leader𡤋ox)+depth(leader𡤋ox);
if (leader←ht>0)and(rule←ht>0) then
begin edge:=cur←v+rule←ht; lx:=0;
@<Let |cur←v| be the position of the first box, and set |leader←ht+lx|
to the spacing between corresponding parts of boxes@>;
while cur←v+leader←ht<=edge do
@<Output a leader box at |cur←v|,
then advance |cur←v| by |leader←ht+lx|@>;
cur←v:=edge; goto next←p;
end;
end

@ @<Let |cur←v| be the position of the first box, ...@>=
if subtype(p)=a←leaders then
begin save←v:=cur←v;
cur←v:=top�ge+leader←ht*((cur←v-top�ge)@!div leader←ht);
if cur←v<save←v then cur←v:=cur←v+leader←ht;
end
else begin lq:=rule←ht div leader←ht; {the number of box copies}
lr:=rule←ht mod leader←ht; {the remaining space}
if subtype(p)=c←leaders then cur←v:=cur←v+(lr div 2)
else begin lx:=(2*lr+lq+1) div (2*lq+2); {round|(lr/(lq+1))|}
cur←v:=cur←v+((lr-(lq-1)*lx) div 2);
end;
end

@ When we reach this part of the program, |cur←v| indicates the top of a
leader box, not its baseline.

@<Output a leader box at |cur←v|, ...@>=
begin cur←h:=left�ge+shift𡤊mount(leader𡤋ox); synch←h; save←h:=dvi←h;@/
cur←v:=cur←v+height(leader𡤋ox); synch←v; save←v:=dvi←v;
temp←ptr:=leader𡤋ox;
outer𡤍oing←leaders:=doing←leaders; doing←leaders:=true;
if type(leader𡤋ox)=vlist←node then vlist←out@+else hlist←out;
doing←leaders:=outer𡤍oing←leaders;
dvi←v:=save←v; dvi←h:=save←h; cur←h:=save←h;
cur←v:=save←v-height(leader𡤋ox)+leader←ht+lx;
end
@z
512274: Here is where we shall stick the procedures that do Press output, right before ship←out.
@x
@p procedure ship←out(@!p:pointer); {output the box |p|}
@y
@p @t\4@>@<Declare procedures for Press output@>@t@>@/
procedure ship←out(@!p:pointer); {output the box |p|}
@z
513940: Ship out page in either Press or DVI format.
@x
page←loc:=dvi←offset+dvi←ptr;
dvi←out(bop);
for k:=0 to 9 do dvi𡤏our(count(k));
dvi𡤏our(last𡤋op); last𡤋op:=page←loc;
cur←v:=height(p)+v←offset; temp←ptr:=p;
if type(p)=vlist←node then vlist←out@+else hlist←out;
dvi←out(eop); incr(total←pages);
done:
@y
if use←press𡤏ormat then
begin
cur←v:=height(p)+v←offset; temp←ptr:=p;
if type(p)=vlist←node then vlist←press←out@+else hlist←press←out;
press←write←page;
incr(total←pages);
end
else begin
page←loc:=dvi←offset+dvi←ptr;
dvi←out(bop);
for k:=0 to 9 do dvi𡤏our(count(k));
dvi𡤏our(last𡤋op); last𡤋op:=page←loc;
cur←v:=height(p)+v←offset; temp←ptr:=p;
if type(p)=vlist←node then vlist←out@+else hlist←out;
dvi←out(eop); incr(total←pages);
end;
done:
@z
515424: Close off print format output file, either Press or DVI
@x
else begin dvi←out(post); {beginning of the postamble}
@y
else if use←press𡤏ormat then
begin
print←nl("Output written on "); print(output𡤏ile←name);
@.Output written on x@>
print(" ("); print←int(total←pages); print(" page");
if total←pages<>1 then print𡤌har("s");
print(").");
press𡤌lose𡤏ile;
end
else begin dvi←out(post); {beginning of the postamble}
@z
527348: Change first half of illfull hbox error message from "line" to "character"
@x
begin if pack�gin←line>0 then print(") in paragraph at lines ")
else print(") in alignment at lines ");
@y
begin if pack�gin←line>0 then print(") in paragraph at cc. ")
else print(") in alignment at cc. ");
@z
527520: Change the other half of the hbox message.
@x
else print(") detected at line ");
@y
else print(") detected at c. ");
@z
533523: Change first half of illfull vbox message as well.
@x
begin print(") in alignment at lines ");
@y
begin print(") in alignment at cc. ");
@z
533630: Change the other half of the vbox message.
@x
else print(") detected at line ");
@y
else print(") detected at c. ");
@z
636439: Declare the new procedure fin𡤊lign←inner.
@x
@!rule←save:scaled; {temporary storage for |overfull←rule|}
@y
@!rule←save:scaled; {temporary storage for |overfull←rule|}
procedure fin𡤊lign←inner;
begin
@<Set the glue in all the unset boxes of the current list@>;
end;
@z
637074: Invoke the new procedure fin𡤊lign←inner.
@x
@<Set the glue in all the unset boxes of the current list@>;
@y
fin𡤊lign←inner;
@z
649303: Declare inner procedure line𡤋reak←inner, and call it.
@x
var @<Local variables for line breaking@>@;
begin pack�gin←line:=mode←line; {this is for over/underfull box messages}
@<Get ready to start line breaking@>;
@y
var @<Local variables for line breaking@>@;
procedure line𡤋reak←inner;
begin
@<Get ready to start line breaking@>;
end;
begin pack�gin←line:=mode←line; {this is for over/underfull box messages}
line𡤋reak←inner;
@z
664669: Remove a label from try𡤋reak, since it now appears in try𡤋reak←inner.
@x
label exit,done,done1,continue,deactivate;
@y
label exit,done1,continue,deactivate;
@z
664949: Declare the new procedure try𡤋reak←inner.
@x
@<Other local variables for |try𡤋reak|@>@;
@y
@<Other local variables for |try𡤋reak|@>@;
procedure try𡤋reak←inner;
label done;
begin
@<Create new active nodes for the best feasible breaks
just found@>;
end;
@z
669277: Call the new procedure try𡤋reak←inner;
@x
((old←l<>easy←line)or(r=last�tive)) then
@<Create new active nodes for the best feasible breaks
just found@>;
@y
((old←l<>easy←line)or(r=last�tive)) then
try𡤋reak←inner;
@z
941047: Dump the Press font information to the format file.
@x
dump←int(skew𡤌har[k]);@/
@y
dump←int(skew𡤌har[k]);@/
dump←int(font�mily[k]);
dump←int(font�[k]);@/
@z
941943: Undump the Press font information from the format file.
@x
undump←int(skew𡤌har[k]);@/
@y
undump←int(skew𡤌har[k]);@/
undump(0)(str←ptr)(font�mily[k]);
undump(0)(255)(font�[k]);@/
@z
947272: Replace ready𡤊lready by the new boolean initing
@x
@!ready𡤊lready:integer; {a sacrifice of purity for economy}
@y
@!start←like←initex:boolean; {otherwise, we start up like TeX}
@z
947551: Wrap up the main code into a procedure body.
@x
@p begin @!{|start←here|}
@y
@p procedure the←real←tex;
begin @!{|start←here|}
@z
947687: Delete test on ready𡤊lready; instead, set process priority down to background.
@x
if ready𡤊lready=314159 then goto start←of←TEX;
@y
set�kground←priority;
@z
948004: Only intialize strings and primitives if we are to start←like←initex; else, reading the format will take care of these initializations.
@x
@!init if not get←strings←started then goto final𡤎nd;
init←prim; {call |primitive| for each primitive}
tini@/
@y
if start←like←initex then
begin
if not get←strings←started then goto final𡤎nd;
init←prim; {call |primitive| for each primitive}
end;
@z
948115: Delete set of ready𡤊lready.
@x
ready𡤊lready:=314159;
@y
@z
948429: Delete set of ready𡤊lready; instead, set process priority back up to normal.
@x
final𡤎nd: ready𡤊lready:=0;
@y
final𡤎nd: set←normal←priority;
@z
948458: End the new procedure the←real←tex, and put in a null main body.
@x
end.
@y
end;
begin
end.
@z
953085: Close all of the input files at the end.
@x
begin @<Finish the extensions@>;
@y
begin @<Finish the extensions@>;
for k := 1 to in←open do
begin
a𡤌lose(input𡤏ile[k]);
print𡤌har(")");
end;
@z
953422: Add a final carriage-return to the terminal output.
@x
print(log←name); print𡤌har(".");
@y
print(log←name); print𡤌har("."); print𡤌har(carriage←return);
@z
951454: Fix up one last (line number)←(character position) point.
@x
begin print(" on line "); print←int(if←line);
@y
begin print(" on line at c. "); print←int(if←line);
@z
953143: Read the default directories from the user profile; strings must be started by now, and we can't wait any longer since the next line might call start←input
@x
if (loc<limit)and(cat𡤌ode(buffer[loc])<>escape) then start←input;
@y
read←profile𡤏or𡤍irectories;
if (loc<limit)and(cat𡤌ode(buffer[loc])<>escape) then start←input;
@z
971877: All the new modules go here, so that other modules would not be renumbered. Most of our new modules are concerned with Press output; the final one declares as external the procedures that are implemented directly in Cedar.
@x
itself will get a new section number.
@^system dependencies@>
@y
itself will get a new section number.
@^system dependencies@>


@ @<Declare procedures for Press output@>=

@<Declare external procedures for Press output@>
@<Declare extension-related procedures for Press output@>
@<Declare hlist←press←out@>
@<Declare vlist←press←out@>

@ The actual work of writing the Press file is done by the SirPress
package in Cedar. The following procedures provide access to
this package from Pascal. The final function is a little different:
its job it to provide access to our procedures from Cedar.

@<Declare external procedures for Press output@>=
function get←pype𡤌ode(f: internal𡤏ont←number; at←size←in←hnm:integer): cedar←nat;
external;
procedure press←set𡤏ont(c: cedar←nat); external;
procedure press←show𡤌har(c: quarterword); external;
procedure press←set←x(x: scaled); external;
procedure press←set←y(y: scaled); external;
procedure press←show←rule(xstart, ystart, xlen, ylen: scaled); external;
procedure flush←pype; external;
procedure press←write←page; external;
procedure press𡤌lose𡤏ile; external;

@ The procedure hlist←press←out is very similar to hlist←out. Note that
hlist←press←out makes no use of dvi←h, dvi←v, or cur←s. Instead, we make
use of the global booleans press←h←ok; if we are pyping, this
boolean tells us that there is no need to do a PipePosition before the
next PipeChar.

We shall first add a macro definition for the number of micas in
11 inches, since Press has it's vertical axis running up instead of down.
Also, a macro for the number of hectonanometers (meters*e^-7) in 11
inches, since sometimes we will be computing in them. They correspond
to SirPress.unit=100.

In addition, the origin of the DVI page is actually shifted by one inch in
both h and v. We also add macros for these distances.

@d page←height←in←mica==27940 {micas in 11 inches}
@d page←height←in←hnm==2794000 {hnm in 11 inches}

@d h←marg←in←mica==2540
@d h←marg←in←hnm==254000
@d v←marg←in←mica==2540
@d v←marg←in←hnm==254000


@<Declare hlist←press←out@>=

procedure hlist←press←out; {output an |hlist←node| box}
label reswitch, move←past, fin←rule, next←p;
var base←line: scaled; {the baseline coordinate for this box}
@!base←in←mica: scaled; {baseline in micas}
@!left�ge: scaled; {the left coordinate for this box}
@!save←h,@!save←v: scaled; {still used in leaders calculations}
@!this𡤋ox: pointer; {pointer to containing box}
@!g←order: glue←ord; {applicable order of infinity for glue}
@!g←sign: normal..shrinking; {selects type of glue}
@!p:pointer; {current position in the hlist}
@!leader𡤋ox:pointer; {the leader box being replicated}
@!leader←wd:scaled; {width of leader box being replicated}
@!lx:scaled; {extra space between leader boxes}
@!outer𡤍oing←leaders:boolean; {were we doing leaders?}
@!edge:scaled; {left edge of sub-box, or right edge of leader space}
begin this𡤋ox:=temp←ptr; g←order:=glue←order(this𡤋ox);
g←sign:=glue←sign(this𡤋ox); p:=list←ptr(this𡤋ox);
base←line:=cur←v; left�ge:=cur←h;
base←in←mica:=page←height←in←mica - v←marg←in←mica
- x←over←n(xn←over𡤍(base←line, mag, 18647),100);
while p<>null do @<Press: Output node |p| for |hlist←press←out| and move to the
next node, maintaining the condition |cur←v=base←line|@>;
end;


@ @<Press: Output node |p| for |hlist←press←out| ...@>=
reswitch: if is𡤌har←node(p) then
begin press←set←y(base←in←mica);
f:=font(p);
if f<>dvi𡤏 then @<Press: Change font |dvi𡤏| to |f|@>;
press←set←x(h←marg←in←mica + x←over←n(xn←over𡤍(cur←h, mag, 18647),100));
repeat
c:=character(p);
press←show𡤌har(c);
cur←h:=cur←h+char←width(f)(char←info(f)(c));
p:=link(p);
until (not is𡤌har←node(p))or(font(p)<>dvi𡤏);
end
else @<Press: Output the non-|char←node| |p| for |hlist←press←out|
and move to the next node@>

@ @<Press: Change font |dvi𡤏| to |f|@>=
begin if not font←used[f] then
begin
font←pype𡤌ode[f]:=get←pype𡤌ode(f, xn←over𡤍(font←size[f],mag,18647));
font←used[f]:=true;
end;
press←set𡤏ont(font←pype𡤌ode[f]);
dvi𡤏:=f;
end

@ @<Press: Output the non-|char←node| |p| for |hlist←press←out| ...@>=
begin case type(p) of
hlist←node,vlist←node:@<Press: Output a box in an hlist@>;
rule←node: begin rule←ht:=height(p); rule𡤍p:=depth(p); rule←wd:=width(p);
goto fin←rule;
end;
whatsit←node: @<Press: Output the whatsit node |p| in an hlist@>;
glue←node: @<Press: Move right or output leaders@>;
kern←node,math←node:cur←h:=cur←h+width(p);
ligature←node: @<Make node |p| look like a |char←node| and |goto reswitch|@>;
othercases do←nothing
endcases;@/
goto next←p;
fin←rule: @<Press: Output a rule in an hlist@>;
move←past: cur←h:=cur←h+rule←wd;
next←p:p:=link(p);
end

@ @<Press: Output a box in an hlist@>=
if list←ptr(p)=null then cur←h:=cur←h+width(p)
else begin cur←v:=base←line+shift𡤊mount(p); {shift the box down}
temp←ptr:=p; edge:=cur←h;
if type(p)=vlist←node then vlist←press←out@+else hlist←press←out;
cur←h:=edge+width(p); cur←v:=base←line;
end

@ @<Press: Output a rule in an hlist@>=
if is←running(rule←ht) then rule←ht:=height(this𡤋ox);
if is←running(rule𡤍p) then rule𡤍p:=depth(this𡤋ox);
rule←ht:=rule←ht+rule𡤍p; {this is the rule thickness}
if (rule←ht>0)and(rule←wd>0) then {we don't output empty rules}
begin press←show←rule(h←marg←in←hnm + xn←over𡤍(cur←h,mag,18647),
page←height←in←hnm - v←marg←in←hnm
- xn←over𡤍(base←line+rule𡤍p,mag,18647),
xn←over𡤍(rule←wd,mag,18647),
xn←over𡤍(rule←ht,mag,18647));
cur←v:=base←line;
end

@ @<Press: Move right or output leaders@>=
begin g:=glue←ptr(p); rule←wd:=width(g);
if g←sign<>normal then
begin if g←sign=stretching then
begin if stretch←order(g)=g←order then
rule←wd:=rule←wd+round(float(glue←set(this𡤋ox))*stretch(g));
@^real multiplication@>
end
else begin if shrink←order(g)=g←order then
rule←wd:=rule←wd-round(float(glue←set(this𡤋ox))*shrink(g));
end;
end;
if subtype(p)>=a←leaders then
@<Press: Output leaders in an hlist, |goto fin←rule| if a rule
or to |next←p| if done@>;
goto move←past;
end

@ @<Press: Output leaders in an hlist...@>=
begin leader𡤋ox:=leader←ptr(p);
if type(leader𡤋ox)=rule←node then
begin rule←ht:=height(leader𡤋ox); rule𡤍p:=depth(leader𡤋ox);
goto fin←rule;
end;
leader←wd:=width(leader𡤋ox);
if (leader←wd>0)and(rule←wd>0) then
begin edge:=cur←h+rule←wd; lx:=0;
@<Let |cur←h| be the position of the first box, and set |leader←wd+lx|
to the spacing between corresponding parts of boxes@>;
while cur←h+leader←wd<=edge do
@<Press: Output a leader box at |cur←h|,
then advance |cur←h| by |leader←wd+lx|@>;
cur←h:=edge; goto next←p;
end;
end

@ @<Press: Output a leader box at |cur←h|, ...@>=
begin cur←v:=base←line+shift𡤊mount(leader𡤋ox); save←v:=cur←v;@/
save←h:=cur←h; temp←ptr:=leader𡤋ox;
outer𡤍oing←leaders:=doing←leaders; doing←leaders:=true;
if type(leader𡤋ox)=vlist←node then vlist←press←out@+else hlist←press←out;
doing←leaders:=outer𡤍oing←leaders;
cur←v:=save←v;
cur←h:=save←h+leader←wd+lx;
end

@ @<Declare vlist←press←out@>=

procedure vlist←press←out; {output a |vlist←node| box}
label move←past, fin←rule, next←p;
var left�ge: scaled; {the left coordinate for this box}
@!top�ge: scaled; {the top coordinate for this box}
@!save←h,@!save←v: scaled; {what |dvi←h| and |dvi←v| should pop to}
@!this𡤋ox: pointer; {pointer to containing box}
@!g←order: glue←ord; {applicable order of infinity for glue}
@!g←sign: normal..shrinking; {selects type of glue}
@!p:pointer; {current position in the vlist}
@!leader𡤋ox:pointer; {the leader box being replicated}
@!leader←ht:scaled; {height of leader box being replicated}
@!lx:scaled; {extra space between leader boxes}
@!outer𡤍oing←leaders:boolean; {were we doing leaders?}
@!edge:scaled; {bottom boundary of leader space}
begin this𡤋ox:=temp←ptr; g←order:=glue←order(this𡤋ox);
g←sign:=glue←sign(this𡤋ox); p:=list←ptr(this𡤋ox);
left�ge:=cur←h; cur←v:=cur←v-height(this𡤋ox);
top�ge:=cur←v;
while p<>null do @<Press: Output node |p| for |vlist←press←out| and move
to the next node, maintaining the condition |cur←h=left�ge|@>;
end;

@ @<Press: Output node |p| for |vlist←press←out|...@>=
begin if is𡤌har←node(p) then confusion("vlistout")
@:this can't happen vlistout}{\quad vlistout@>
else @<Press: Output the non-|char←node| |p| for |vlist←press←out|@>;
next←p:p:=link(p);
end

@ @<Press: Output the non-|char←node| |p| for |vlist←press←out|@>=
begin case type(p) of
hlist←node,vlist←node:@<Press: Output a box in a vlist@>;
rule←node: begin rule←ht:=height(p); rule𡤍p:=depth(p); rule←wd:=width(p);
goto fin←rule;
end;
whatsit←node: @<Press: Output the whatsit node |p| in a vlist@>;
glue←node: @<Press: Move down or output leaders@>;
kern←node:cur←v:=cur←v+width(p);
othercases do←nothing
endcases;@/
goto next←p;
fin←rule: @<Press: Output a rule in a vlist, |goto next←p|@>;
move←past: cur←v:=cur←v+rule←ht;
end

@ @<Press: Output a box in a vlist@>=
if list←ptr(p)=null then cur←v:=cur←v+height(p)+depth(p)
else begin cur←v:=cur←v+height(p);
save←v:=cur←v;
cur←h:=left�ge+shift𡤊mount(p); {shift the box right}
temp←ptr:=p;
if type(p)=vlist←node then vlist←press←out@+else hlist←press←out;
cur←v:=save←v+depth(p); cur←h:=left�ge;
end

@ @<Press: Output a rule in a vlist...@>=
if is←running(rule←wd) then rule←wd:=width(this𡤋ox);
rule←ht:=rule←ht+rule𡤍p; {this is the rule thickness}
cur←v:=cur←v+rule←ht;
if (rule←ht>0)and(rule←wd>0) then {we don't output empty rules}
begin press←show←rule(h←marg←in←hnm + xn←over𡤍(cur←h,mag,18647),
page←height←in←hnm - v←marg←in←hnm
- xn←over𡤍(cur←v,mag,18647),
xn←over𡤍(rule←wd,mag,18647),
xn←over𡤍(rule←ht,mag,18647));
end;
goto next←p

@ @<Press: Move down or output leaders@>=
begin g:=glue←ptr(p); rule←ht:=width(g);
if g←sign<>normal then
begin if g←sign=stretching then
begin if stretch←order(g)=g←order then
rule←ht:=rule←ht+round(float(glue←set(this𡤋ox))*stretch(g));
@^real multiplication@>
end
else begin if shrink←order(g)=g←order then
rule←ht:=rule←ht-round(float(glue←set(this𡤋ox))*shrink(g));
end;
end;
if subtype(p)>=a←leaders then
@<Press: Output leaders in a vlist, |goto fin←rule| if a rule
or to |next←p| if done@>;
goto move←past;
end

@ @<Press: Output leaders in a vlist...@>=
begin leader𡤋ox:=leader←ptr(p);
if type(leader𡤋ox)=rule←node then
begin rule←wd:=width(leader𡤋ox); rule𡤍p:=0;
goto fin←rule;
end;
leader←ht:=height(leader𡤋ox)+depth(leader𡤋ox);
if (leader←ht>0)and(rule←ht>0) then
begin edge:=cur←v+rule←ht; lx:=0;
@<Let |cur←v| be the position of the first box, and set |leader←ht+lx|
to the spacing between corresponding parts of boxes@>;
while cur←v+leader←ht<=edge do
@<Press: Output a leader box at |cur←v|,
then advance |cur←v| by |leader←ht+lx|@>;
cur←v:=edge; goto next←p;
end;
end

@ @<Press: Output a leader box at |cur←v|, ...@>=
begin cur←h:=left�ge+shift𡤊mount(leader𡤋ox); save←h:=cur←h;@/
cur←v:=cur←v+height(leader𡤋ox); save←v:=cur←v;
temp←ptr:=leader𡤋ox;
outer𡤍oing←leaders:=doing←leaders; doing←leaders:=true;
if type(leader𡤋ox)=vlist←node then vlist←press←out@+else hlist←press←out;
doing←leaders:=outer𡤍oing←leaders;
cur←h:=save←h;
cur←v:=save←v-height(leader𡤋ox)+leader←ht+lx;
end

@ @<Declare extension-related procedures for Press output@>=
procedure press←out←what(@!p:pointer);
begin case subtype(p) of
open←node,write←node,close←node:out←what(p);
special←node:do←nothing; {specials not implemented for Press output}
othercases confusion("ext4")
@:this can't happen ext4}{\quad ext4@>
endcases;
end;

@ @<Press: Output the whatsit node |p| in an hlist@>=
press←out←what(p)

@ @<Press: Output the whatsit node |p| in a vlist@>=
press←out←what(p)


@ We want to refer to the type of SirPress font codes from with Pascal, so we
do the following.

@<Types...@>=
@!cedar←nat=0..32767;
@ Here, finally, are the external procedure declarations.
@<External procedure declarations for things implemented directly in Cedar@>=
procedure reset←term←in(var f: alpha𡤏ile); external;
 {set up for input from terminal}
procedure rewrite←term←out(var f: alpha𡤏ile); external;
 {set up for output to terminal}
function profile𡤊sks𡤏or←press: boolean; external;
function press←open←out: boolean; external;
procedure read←the𡤌lock(var ttime,dday,mmonth,yyear:integer); external;
function file←get←pos(var f: alpha𡤏ile):integer; external; {return character count}
procedure set←pool←name; external;
procedure read←profile𡤏or𡤍irectories; external;
procedure set←normal←priority; external;
procedure set�kground←priority; external;
function stuff←on𡤌md←line:integer; external;
@z