\font\twelvept=cmbx12
\font\tentex=cmr10
\def\topofcontents{\null\vfill\eject
   \def\titlepage{T}
   \centerline{{\twelvept The \TeX 8600 Driver}}
   \vskip15pt
   \centerline{Version 2.2, June 1988}
   \hbox{\vbox{\hsize\the\hsize This work is
  protected as an unpublished work under U.S. copyright laws.
  Copyright $\copyright$ 1986 by WSUCSC.  All rights Reserved.}}
  \vskip18pt
   \hbox{\vbox{\hsize\the\hsize This software is furnished under a
   license for
   use only on a single computer system and may be copied only
 with the inclusion of the above copyright notice.
This software, or any other copies
thereof, may not be provided or otherwise made available to any
other person except for use on such system and to one who agrees to
these license terms.  Title to and ownership of the software shall
at all times remain in WSUCSC.}}
   \vfill}

@* Introduction.
This program takes a \TeX\ DVI file and converts it into CG 8600
Universal Slave Mode commands. Five bytes have been added to each
record. These five bytes are stripped off by the Datum 5095 tape
drive as it passes the file onto the 8600.

The \TeX 8600 program is written in WEB. You will need the TANGLE
and WEAVE programs to make changes. The WEB code was written
originally for IBM Pascal/VS on VM/CMS.

If you have a CG font that is not one of the ones on the \TeX 8600
distribution tape, you need to modify the SAMPLE.FONTINFO file for
that font and process it through FONTTEX.

@ Following are a  few macros and definitions used throughout program:

@d incr(#) == # := # + 1
@d decr(#) == # := # - 1
@d do_nothing == begin; end
@d ccat==@=||@>
@f static == var
@f value == var

@ The beginning of the program.

@p program tex8600(dumpout,sysprint,addrline,setfile,cgfonts,infofile);
const
@<Global Constants@>@/
type
@<Global Types@>@/
var
@<Global Variables@>@/
static@/
@!com_table       :packed array[0..18] of string(7);@/
value@/
   com_table[0] := 'HDR';    {Header Record}@/
   com_table[1] := 'CHWIDTH';{Character Width}@/
   com_table[2] := 'RT';     {Reverse Type}@/
   com_table[3] := 'PS';     {Point Size}@/
   com_table[4] := 'SS';     {Set Size}@/
   com_table[5] := 'VMF';    {Vertical Move Forward}@/
   com_table[6] := 'VMR';    {Vertical Move Reverse}@/
   com_table[7] := 'RW';     {Rule Width}@/
   com_table[8] := 'RD';     {Rule Depth}@/
   com_table[9] := 'IR';     {Insert Rule}@/
   com_table[10] := 'SL';    {Slant Mode}@/
   com_table[11] := 'RTWT';  {Reverse Type Window Top}@/
   com_table[12] := 'RTWB';  {Reverse Type Window Bottom}@/
   com_table[13] := 'AU';    {Auxiliary Character Set}@/
   com_table[14] := 'F';     {Change Fonts}@/
   com_table[15] := 'HMR';   {Horizontal Move Right}@/
   com_table[16] := 'HML';   {Horizontal Move Left}@/
   com_table[17] := 'TTS';   {8600 character, in decimal}@/
   com_table[18] := 'MAXCMD';@/
@<CMS Includes@>

@ This is a collection of arrays for converting ASCII to EBCDIC.

@<CMS Includes@>=
@{This is a very long comment. It is designed to force a break@}
%include pasclib(asciicvt);

@ This is a collection of arrays for converting ASCII to EBCDIC.

@<CMS Includes@>=
@{This is a very long comment. It is designed to force a break@}
%include cms;
@{This is a very long comment. It is designed to force a break@}

@* Beginning section.
This section includes some basic functions for reading the DVI file
as well as a couple of procedures, like error and allcaps. Nothing
tricky or noteworthy in these.

@<Global Variables@>=
@!count : integer;
@!fileend :boolean;

@ The function for reading a byte of information from the DVI file.

@p function getbyte:integer;
var c    :integer;
   byte :char;
begin
   read(byte);
   getbyte := ord(byte);
   c := count mod pv_dvi_lrecl;
   if (c=(pv_dvi_lrecl-1)) and not (eof(input))
        then get(input)
        else if (c=(pv_dvi_lrecl-1)) and eof(input)
             then fileend:=true;
   end;

@ This is necessary because tangle doesn't let us get away with
using RETCODE by itself in more than one spot.

@p procedure setretcode(rc:integer);
begin retcode(rc); end;

@  This converts the byte to an integer, for further evaluation by
the program.

@p function readinteger(length :integer):integer;
var
   inx       :integer;
   int       :integer;
begin
   if (length<1) or (length>4)
        then begin;
             trace(output);
             halt;
             end;
   int:=0;
   for inx := 1 to length do begin
        int := int * 256 + getbyte;
                         {check for cvt to negative...}
        if (inx = 1) and (length > 1) and (int >= 128)
             then int := int - 256;
        incr(count);
        end;
   readinteger := int;
   end;      {readinteger}

@ This function receives an integer value and converts it to its
hex value and returns that value as a string.

@^system dependencies@>
@p function hex(int   :integer) :string(2);
var
   i              :integer;
   j              :integer;
   stri           :string(2);
static
   hexarray       :array[0..15] of string(1);
value
   hexarray[0]  := '0';
   hexarray[1]  := '1';
   hexarray[2]  := '2';@/
   hexarray[3]  := '3';
   hexarray[4]  := '4';
   hexarray[5]  := '5';@/
   hexarray[6]  := '6';
   hexarray[7]  := '7';
   hexarray[8]  := '8';@/
   hexarray[9]  := '9';
   hexarray[10] := 'A';
   hexarray[11] := 'B';@/
   hexarray[12] := 'C';
   hexarray[13] := 'D';
   hexarray[14] := 'E';
   hexarray[15] := 'F';
begin
   stri := '';
   i := int;
   if i >= 16
        then begin
             j := i div 16;
             stri := hexarray[j];
             i := i - (j * 16);
             end
        else stri := '0';
   stri := stri  ccat hexarray[i];@/
   hex := stri;
   end;

@
@<Global Variables@>=
@! savecount :integer;
@^system dependencies@>
@! filename  :string(8);
@^system dependencies@>
@! errstr :string(256);

@ The error procedure. When a byte is read that does not jive with
what the program was expecting, it goes to this procedure with a
return code of some kind and an appropriate message is printed to user.

@p procedure error(number  :integer;
               critical:boolean;
               intval  :integer);
begin
   case number of
   1    :writeln('Error in file ',filename,', no header record');
   2    :writeln('Error in file ',filename,', the highest 8600 ',
                 'command has a value of ',ord(MAXCMD):3,' but ',
                 intval,' was read instead');
   3    :writeln('Expected a font command and got "',
                 com_table[intval],'" instead');
   4    :writeln('Expected a character width definition and got "',
                 com_table[intval],'" instead in file ',filename);
   5    :writeln('File ',filename,' is out of order for character ',
                 intval:3,' (',chrx[intval],')');
   6    :writeln('Error in file ',filename,', the value of byte ',
                 intval,' is >= 218 and <= 255 at byte ',savecount);
   7    :writeln('Expected a Slantmode command and got ',
                 com_table[intval],' instead');
   10   :writeln('No address information given');
   28   :writeln('Unidentified input option "',errstr,'"');
   otherwise writeln('Unidentified error ',number);
   end; {case}
   if critical then begin
        writeln('TeX8600 run aborted; See your consultant');
        trace(output);
        halt;
        end;
   writeln('Tape will not be sent to operator');
   setretcode(32);
   end; {error}

@ Finally, a function that will convert whatever is passed to it into
all capital letters. It translates lower case letters into upper case
letters.  All  other  characters   outside   of   the   range
a$<$=character$<$=z are returned as their original value.

@^system dependencies@>
@p function allcaps(instring    :string(40))   :string(40);
var
   i              :integer;
   character      :char;
   buildit        :string(40);
static@/
   chtable        :packed array['81'xc..'e9'xc] of char;@/
value@/
   chtable['81'xc] := 'A';
   chtable['82'xc] := 'B';
   chtable['83'xc] := 'C';
   chtable['84'xc] := 'D';@/
   chtable['85'xc] := 'E';
   chtable['86'xc] := 'F';
   chtable['87'xc] := 'G';
   chtable['88'xc] := 'H';@/
   chtable['89'xc] := 'I';
   chtable['91'xc] := 'J';
   chtable['92'xc] := 'K';
   chtable['93'xc] := 'L';@/
   chtable['94'xc] := 'M';
   chtable['95'xc] := 'N';
   chtable['96'xc] := 'O';
   chtable['97'xc] := 'P';@/
   chtable['98'xc] := 'Q';
   chtable['99'xc] := 'R';
   chtable['a2'xc] := 'S';
   chtable['a3'xc] := 'T';@/
   chtable['a4'xc] := 'U';
   chtable['a5'xc] := 'V';
   chtable['a6'xc] := 'W';@/
   chtable['a7'xc] := 'X';
   chtable['a8'xc] := 'Y';
   chtable['a9'xc] := 'Z';
begin
   buildit := '';
   for i := 1 to length(instring) do begin
        readstr(substr(instring,i,1),character);
        if character in ['a'..'z']
             then buildit := buildit  ccat str(chtable[character])
             else buildit := buildit  ccat str(character);
        end;
   allcaps := buildit;
   end;

@* Font Related Procedures.
This first font procedure reads the font matrix information for the
current font from an outside file called cginfo defined as cgfonts.

@<Global Constants@>=
@!    maxfunctions = 15;@/
@!    maxChar=127;@/
@!    fatal = true;@/
@!    fontsperrun = 76;@/
@!    maxFont=256;@/

@
@<Global Types@>=
@!    oneoftwo = packed 1..2;
   command        = (HDR,CHWIDTH,RT,PS,SS,VMF,VMR,RW,RD,IR,SL,
                     RTWT,RTWB,AU,F,HMR,HML,TTS,MAXCMD);@/
@!    storerec = packed record
        comcode    :packed -128..127;
        case oneoftwo of
        1    :(argument       :integer);
        2    :(real_argument  :shortreal);
        end;
@!    charrec = packed record
        num            :-1..maxfunctions;
        charwidth      :shortreal;
        comarray   :packed array[0..maxfunctions] of storerec;
        end;
@!    driverrec      = record
        cmd       :integer;
        case oneoftwo of
             1      :(param  :shortreal);
             2      :(code   :integer);
        end;
@!    font_def       = packed record
       pointsize    : 0..255;
       designsize   : 0..255;
       fontindex    : 0..255;
       end;
@^system dependencies@>
@!    fontrec        = record
       fontno8600   : 0..2550;
       name         : string(8);
       a8600chars   : packed array[0..maxChar] of charrec;
       end;

@
@<Global Variables@>=
@!currfont : -1..maxFont;
@!a8600fontrec : packed array[1..fontsperrun] of fontrec;
@!fontcode : driverrec;
@^system dependencies@>
@!fontname : string(8);
@!dumpin : boolean;
@!fontenviron : packed array[-1..maxFont] of font_def;

@ A new font is being used so it must have its font metrics read; this
procedure does just that.

@p procedure readfontinfo(fontnum,a8600index:integer);
var
   auxiliary      :boolean;
   cgfonts        :file of driverrec;
   changefont     :boolean;
   charmult       :shortreal;
   i,j,rc,
   numcommands    :integer;
begin
@<open cginfo file@>
@<read beginning info@>
@<read character info@>
@<close cginfo file@>
end;

@ First open the cginfo file

@<open cginfo file@>=
 fontenviron[fontnum].fontindex := a8600index;
 a8600fontrec[a8600index].name:= fontname;
 cms('ESTATE 'ccat fontname ccat ' CGINFO *',rc);
 if rc = 0
   then reset(cgfonts,'NAME='  ccat fontname  ccat '.CGINFO.*')
   else begin
      reset(cgfonts,'NAME=ETR.CGINFO.*');
      writeln('Error!! Font ',fontname,' is not on the 8600');
      writeln('You will not be able to continue');
      setretcode(8);
      end;

@ Now read the first few records that give overall font info.

@<read beginning info@>=
   fontcode := cgfonts@@;{Read the first record of the file}
   get(cgfonts);@/
   with fontcode do begin
        if cmd <> ord(HDR) then error(1,fatal,0);
        if code <> ord(MAXCMD) then error(2,fatal,code);
        end; {with..begin}
   fontcode := cgfonts@@; {read the second record of the file}
   get(cgfonts);@/
   with fontcode do begin
        if cmd <> ord(F) then error(3,fatal,cmd); {Must be font cmnd}
 a8600fontrec[a8600index].fontno8600 := code;
        end; {with..begin}
   fontcode := cgfonts@@;
   get(cgfonts);
   with fontcode do begin
        if cmd <> ord(CHWIDTH) then error(4,fatal,cmd); {charac mult}
        charmult := param;
        end; {with..begin}
             {Each character (maxChar) has one header record (HDR)
              and one character width record. The number of records
              for each character that follows the width record is
              contained as "code" in the header record. Each
              character will have at least one record.}
   fontcode := cgfonts@@; {slantmode option no longer used}
   get(cgfonts);
   with fontcode do begin
        if cmd <> ord(SL) then error(7,fatal,cmd);
        end;
   if dumpin
       then with a8600fontrec[fontenviron[fontnum].fontindex]
         do begin
          writeln(dumpout,
          '          The character width multiplier for ',
                     filename,' is ',charmult:5:2);
          writeln(dumpout,
          '          The 8600 font number is ',fontno8600:3);
          end;

@ The individual character heights, depths, widths and positions
come next.

@<read character info@>=
   for i := 0 to maxChar do begin
        with a8600fontrec[a8600index].a8600chars[i]
do begin
             fontcode := cgfonts@@;
             get(cgfonts);
             with fontcode do begin
                  if cmd <> ord(HDR) then error(5,fatal,i);
                  numcommands := code; {number for this character}
                  end; {with..begin}
             num := -1;
             @<read character width@>
             auxiliary := false;
             changefont := false;
             for j := 0 to numcommands do begin
             @<read next command@>
                  end;
             if auxiliary then begin
                  @<Auxiliary change@>
                  end;
             if changefont then begin
                  @<Font change@>
                  end;
             end;
        end;

@ Font is all read and safely tucked into appropriate places to
be used later, so close the door and shut off the lights on the
way out.

@<close cginfo file@>=
   close(cgfonts);

@
 @<read character width@>=
 fontcode := cgfonts@@; {read the character width}
 get(cgfonts);
 with fontcode do begin
     if cmd <> ord(CHWIDTH) then error(5,fatal,i);
     charwidth := param * charmult;
     end; {with..begin}

@
 @<read next command@>=
 fontcode := cgfonts@@;
 get(cgfonts);
 num := num + 1; {increment number of commands}
 with fontcode, comarray[num] do begin
      if ((cmd >= 5) and (cmd <= 8)) or
         (cmd = 11) or (cmd = 12) or (cmd = 16)
         then real_argument := param
         else argument := code;
         case cmd of
             2  :comcode := 3; {reverse type}
             3  :comcode := 7; {Point Size Change}
             4  :comcode := 8; {Set Size Change}
             5  :comcode := 9; {Vertical Move Forward}
             6  :comcode := 10; {Vertical Move Reverse}
             7  :comcode := 12; {Rule Width}
             8  :comcode := 13; {Rule Depth}
             9  :comcode := 14; {Insert Rule}
             10  :comcode := 15; {Slant Mode}
             11  :comcode := 16; {Reverse Window Top}
             12  :comcode := 17; {Reverse Window Bot}
             13  :begin
                    @<Change to Auxiliary Characters@>
                  end;
             14  :begin
                    @<Change Font@>
                    end;
             15  :comcode := 27; {Horiz. Move Right}
             16  :comcode := 28; {Horiz. Move Left}
             17  :comcode := -1; {Decimal Char Code}
             otherwise begin
                    @<Invalid Command Number@>
                    end;
             end;
      end;

@
@<Auxiliary change@>=
num := num + 1;
with comarray[num] do begin
    comcode := 20;
    argument := 1;
    end;

@
@<Font change@>=
num := num + 1;
with comarray[num] do begin
    comcode := 25;
    argument := -1; {for quick ID in font changes}
    end;

@
@<Change to Auxiliary Characters@>=
comcode := 20;
if auxiliary
then begin
     argument := 1;
     auxiliary := false;
     end
else begin
     argument := 2;
     auxiliary := true;
     end;

@
@<Change Font@>=
comcode := 25;
if code <> fontnum
   then changefont := true;
argument := code * 10;

@
 @<Invalid Command Number@>=
 writeln('Invalid 8600 Command Number ', cmd);
 error(5,fatal,cmd);

@ This procedure checks to see if the current font has been
 previously defined. If it has, it returns to the main program,
 if it hasn't, |readfontinfo| is called.

@p procedure checkfont;
var
   i              :integer;
static
   in_count       :integer;
value
   in_count      := 0;
begin
@<check fonts@>
readfontinfo(currfont,in_count);
   end;

@ Each time a font is encountered in the DVI file, one is added to
the |in_count|. The following section checks to see if the |curr_font|
has ever been used before in this file. If it has, nothing is done and
it returns to main program. If it is a new file, it continues on in
procedure to read the new font metrics.

@<check fonts@>=
   incr(in_count);
   for i := 1 to in_count do begin
      if a8600fontrec[i].name = fontname
         then begin
            fontenviron[currfont].fontindex := i;
            return;
            end;
       end;

@ This procedure reads the DVI file to get all pertinent information
for the |MAIN| program.

@<Global Constants@>=
@!  SPsPerPt = 65536;@/
@!  pc_dvi_lrecl=1024;

@
@<Global Variables@>=
@!checksumtest : integer;
@!pv_dvi_lrecl :integer;

@
@p procedure fontinfo;
var
  fnlength : integer;
  temp : integer;
  temp2 : integer;
  inx : integer;
begin
  with fontenviron[currfont] do begin
       checksumtest := readinteger(4);{check sum}
       temp := readinteger(4);{scale}
       temp2:= readinteger(4);{design size}
       pointsize := temp2 * (temp div temp2) div SPsPerPt;
       designsize := temp2 div SPsPerPt;
       end; {WITH..begin}
  temp := readinteger(1);{font name area}
  fnlength := readinteger(1);{file length}
  fnlength := fnlength + temp;
  fontname := '';
  for inx := 1 to fnlength do begin
       temp := readinteger(1);
       fontname := fontname  ccat allcaps(str(chrx[temp]));
       end;
  checkfont;
end;

@* Tape-writing functions and procedures.
These next few functions and procedures prepare or write information
to a tape file

@  This function converts an integer to a string or something like that

@^system dependencies@>
@p function strconv(intnum : integer): string(5);
var
   hdrec          :string(5);
   j              :integer;
   k10            :integer;
   temphdr        :integer;
begin
   hdrec := '';
   k10 := 10000;
   temphdr := intnum;
   repeat
        if temphdr >= k10 then begin
             j := temphdr div k10;
             hdrec := hdrec  ccat str(chr(j + ord('0')));
             temphdr := temphdr - (j * k10);
             end;
        k10 := k10 div 10;
        until k10 = 1;
   hdrec := hdrec  ccat str(chr(temphdr + ord('0')));
   if length(hdrec) < 5
        then hdrec := substr('00000',1,5-length(hdrec))  ccat hdrec;
   strconv := hdrec;
   end;

@ This procedure is to add the 5 bytes at the beginning
 of each record that will be read by the 5095 tape
 drive. It should be noted that these 5 bytes are
discarded by the 5095 before it sends the rest of the record to the 8600.

@<Global Constants@>=
@!  maxbuffer = 1029;@/

@
@<Global Variables@>=
@!doingpages : boolean;
@!setfile : text;
@!dumpout : text;
@!bufferlen : 0..maxbuffer;
@!headernum : integer;

@
@p procedure writeheader; {only needed when using Datum 5095}
var
   hdrec               :string(5);
begin
   if doingpages = true
   then begin
      hdrec := strconv(headernum);
      write(setfile,hdrec);
      bufferlen := 5;
      end; {then..begin}
   end; {writeheader}

@
@<Global Constants@>=
@!  allzeros = '00'xc;@/

@
@<Global Variables@>=
@!postam_found : boolean;

@ This procedure is used to write the tape file for the  5095
drive on the 8600

@p @^system dependencies@>
procedure write8600rec(codes      :string(17));
var
   i              :integer;
   codesize       :integer;
begin
   codesize := length(codes);
   if doingpages=true
   then begin
     if bufferlen + codesize < maxbuffer
        then begin
             @<record length less than maximum@>
             end {then..begin}
        else if bufferlen + codesize = maxbuffer
             then begin
             @<record length equal to maximum@>
                  end  {then..begin}
             else begin
             @<record length greater than maximum@>
                  end; {else..begin}
      end; {then..begin}
   end; {write8600rec}

@
@<record length less than maximum@>=
write(setfile,codes);
bufferlen := bufferlen + codesize;
if postam_found then begin
    while bufferlen < maxbuffer do begin
        write(setfile,allzeros);
        codesize := length(allzeros);
        bufferlen := bufferlen + codesize;
        end; {while..begin}
    end; {then..begin}

@
@<record length equal to maximum@>=
writeln(setfile,codes);
if not postam_found then writeheader;

@
@<record length greater than maximum@>=
i := maxbuffer - bufferlen;
                  writeln(setfile,substr(codes,1,i));
                  writeheader;
                  write(setfile,substr(codes,i+1,codesize-i));
                  bufferlen := bufferlen + codesize - i;
                  if postam_found then begin
                     while bufferlen < maxbuffer do begin
                        write(setfile,allzeros);
                        codesize := length(allzeros);
                        bufferlen := bufferlen + codesize;
                        end; {while..begin}
                     end; {then..begin}

@
@<Global Variables@>=
@!print_hmove : boolean;

@ This function,
given amount in scale points, converts it to floating-point
points and print it.

@p function getpts(amt    :integer)  :real;
var
   temp           :real;
begin
   temp := float(amt) / SPsPerPt;
  if dumpin and print_hmove then write(dumpout,temp:4:1,' pts.');
   getpts := temp;
   end;

@* Main tape-writing procedures.
These next few procedures are the main ones for writing information
to the tape file.

@
@<Global Constants@>=
@!    high1 = '8000'@&x;@/
@!    SPsPer8th = 8192;@/
@!    SPsPer18th = 3640.8888;@/

@
@<Global Type...@>=
@!    valrec = packed record case oneoftwo of
        1         :(hexcode      :char;
                    argument     :packed -32768..32767);
        2         :(byte1        :packed 0..255;
                    byte2        :packed 0..255;
                    byte3        :packed 0..255)
        end;
@!    stackrec = packed record
        H         :integer;
        V         :integer;
        W         :integer;
        X         :integer;
        Y         :integer;
        Z         :integer;
        end;

@
@<Global Variables@>=
@!stack : packed array[1..50] of stackrec;
@!stacktop : integer;
@!outrec : valrec;
@!in_reverse_type : boolean;
@!in_slant_mode  : boolean;

@ This procedure is called to format the output record
 in a 1 or 3 byte word to be added to the 8600 output
 record buffer. Each command used by the slave mode
 is represented here by their appropriate code number
 assigned by Compugraphics. The code "-1" was not
 assigned by them. It was assigned to denote the use
  of a character in the current font.

@p @^system dependencies@>
procedure writecommand(codenum    :integer;
                      inargument :real);
var
   temp           :string(3);
   realtemp       :real;
begin
   with outrec do begin
        case codenum of
        -2 :@<long character form@>@/
        -1 :@<individual character code@>@/
         0 :@<start of take@>@/
         1 :@<end of take@>@/
         2 :@<change reverse type@>@/
         7 :@<change point size@>@/
         8 :@<change set size@>@/
         9 :@<forward vertical move@>@/
        10 :@<reverse vertical move@>@/
        11 :@<absolute horizontal positioning@>@/
        12 :@<rule width@>@/
        13 :@<rule depth@>@/
        14 :@<insert rule@>@/
        15 :@<slant mode@>@/
        16 :@<reverse type window top@>@/
        17 :@<reverse type window bottom@>@/
        20 :@<change auxiliary character set@>@/
        25 :@<change fonts@>@/
        27 :@<right horizontal move@>@/
        28 :@<left horizontal move@>@/
        otherwise @<all other cases@>
             end; {case}
        byte2 := byte2 + '10000000'B;
        temp := str(chr(byte1)) ccat
                str(chr(byte2)) ccat str(chr(byte3));
        write8600rec(temp);
        end; {with..begin}
   end;      {writecommand}

@
@<long character...@>=
 begin
 hexcode := chr(trunc(inargument)+high1);
 argument := round(getpts(stack[stacktop].H) * 18);
 temp := str(chr(byte1))  ccat str(chr(byte2));
 temp := temp  ccat str(chr(byte3));
 write8600rec(temp);
 return;
 end;

@
@<individual character code@>=
             begin
                      {change inargument into a one character
                       string (hex) value}
                  argument := trunc(inargument);
                  write8600rec(str(chr(byte3)));
                  return;
                  end;
@
@<start of take@>=
              begin
                  hexcode := '80'xc;
                  argument := trunc(inargument);
                  end;

@
@<end of take@>=
              begin
                  hexcode := '81'xc;
                  argument := trunc(inargument);
                  end;

@
@<change reverse type@>=
              begin
                  if not in_reverse_type and (inargument = 0)
                       then return; {8600 warning if you try to
                                     turn it off when its already off}
                  if inargument = 0
                       then in_reverse_type := false
                       else in_reverse_type := true;
                  if in_reverse_type then begin
                       realtemp :=     {76\% of the current leading}
                         (fontenviron[currfont].pointsize + 2)*0.76;
                       writecommand(16,realtemp); {window top}
                       realtemp :=     {30\% of the current leading}
                         (fontenviron[currfont].pointsize + 2)*0.30;
                       writecommand(17,realtemp); {window bottom}
                       end; {then..begin}
                  hexcode := '83'xc;
                  argument := trunc(inargument);
                  end;

@
@<change point size@>=
              begin
                  hexcode := '87'xc;
                  argument := round(inargument*2) * 4; {in eighths}
                  end;

@
@<change set size@>=
              begin
                  hexcode := '88'xc;
                  argument := round((fontenviron[currfont].pointsize*
                       (inargument/100.0)) * 2) * 4; {in eighths}
                  end;

@
@<forward vertical move@>=
              begin
                  if inargument = 0 then return; {0 invalid on 8600}
                  hexcode := '89'xc;
                            {in sixteenths}
                  argument := round(inargument / SPsPer8th) * 2;
                  end;

@
@<reverse vertical move@>=
             begin
                  if inargument = 0 then return; {0 invalid on 8600}
                  hexcode := '8a'xc;
                            {in sixteenths}
                  argument := round(inargument / SPsPer8th) * 2;
                  end;

@
@<absolute horizontal positioning@>=
             begin
                  hexcode := '8b'xc;
                            {eighteenths}
                  if inargument < -72.27 then begin
                       if dumpin then writeln(dumpout,
                                           '  HP less than zero');
                       inargument := 0;
                       end;
                  argument := round(inargument / SPsPer18th);
                  end;

@
@<rule width@>=
             begin
                  if inargument = 0 then return; {0 invalid on 8600}
                  hexcode := '8c'xc;
                  argument := round(inargument * 18);
                  end;

@
@<rule depth@>=
             begin
                  if inargument = 0 then return; {0 invalid on 8600}
                  hexcode := '8d'xc;
                  argument := round(inargument * 8) * 2;
                  end;

@
@<insert rule@>=
             begin
                  hexcode := '8e'xc;
                  if inargument < 0 then begin
                       if dumpin then writeln(dumpout,
                                    '  IR less than zero');
                       inargument := 0;
                       end;
                  argument := round(inargument / SPsPer18th);
                  end;

@
@<slant mode@>=
             begin
                  hexcode := '8f'xc;
                  argument := trunc(inargument);
                  if argument = 0
                       then in_slant_mode := false
                       else in_slant_mode := true;
                  end;

@
@<reverse type window top@>=
             begin
                  hexcode := '90'xc;
                  argument := round(inargument*8) * 2; {in sixteenths}
                  end;

@
@<reverse type window bottom@>=
             begin
                  hexcode := '91'xc;
                  argument := round(inargument*8) * 2; {in sixteenths}
                  end;

@
@<change auxiliary character set@>=
             begin
                  hexcode := '94'xc;
                  argument := trunc(inargument);
                  end;

@
@<change fonts@>=
             begin
                  hexcode := '99'xc;
                  argument := trunc(inargument);
                  end;

@
@<right horizontal move@>=
             begin
                  if inargument = 0 then return; {if no move}
                  hexcode := '9b'xc;
                            {eighteenths}
                  argument := round(inargument / SPsPer18th);
                  end;

@
@<left horizontal move@>=
             begin
                  if inargument = 0 then return; {if no move}
                  hexcode := '9c'xc;
                            {eighteenths}
                  argument := round(inargument / SPsPer18th);
                  end;

@
@<all other cases@>=
              begin
                  writeln('Invalid 8600 command code = ',codenum);
                  error(5,fatal,codenum);
                  end; {otherwise}

@* Billing and identification information procedures.

@ The first procedure is the one that writes out all the resource-type
information. It first checks to see if the character it is about to
write out is one of several special characters, if it is the hex code
is changed.

@^system dependencies@>
@p procedure writeinfo(info:string(30));
  var
    inx : integer;
  begin
    for inx := 1 to length(info)
       do begin
          if info[inx] = ' '
             then write8600rec('1F'xc)
             else if info[inx] = '('
                then write8600rec('3A'xc)
             else if info[inx] = ')'
                then write8600rec('3B'xc)
             else if info[inx] = '*'
                then write8600rec('5C'xc)
             else if info[inx] = '_'
                then begin
                   writecommand(20,2); {aux. char. set}
                   write8600rec('50'xc);
                   writecommand(20,1); {back to primary}
                   end {then..begin}
            else write8600rec(str(chr(ordx[info[inx]])));
          end; {do..begin}
    end; {writeinfo}

@
@<Global Variables@>=
@^system dependencies@>
@!job_len_conv : string(5);
@!job_length : integer;
@^system dependencies@>
@!parmvalue : string(80);
@^system dependencies@>
@!pages_conv : string(5);
@!pages_set  : integer;
@!galley_length : real;
@^system dependencies@>
@!real_filename : string(8);

@ The following procedure writes the information within the accounting
box at the end of each job.

@p @^system dependencies@>
   procedure setaccountbox (infoname       :string(30);
                            infophone      :string(14);
                            infodelivery   :string(8);
                            infozip        :string(10);
                            infobin        :string(8);
                            infoid         :string(22));
   var
      inx            :integer;
   begin
    @<set constant values@>@/
    @<draw accounting box@>@/
    @<write name in box@>@/
    @<write phone number in box@>@/
    @<write delivery method in box@>@/
    @<write zipcode in box@>@/
    @<write center bin in box@>@/
    @<write user id in box@>@/
    @<write job length in box@>@/
    @<write file name in box@>@/
    @<write number of pages set, in box@>@/
    @<write tape number in box@>@/
        galley_length := galley_length + 140;
   end; {setaccountbox}

@
@<set constant...@>=
      different_setsize := false;
      in_slant_mode := false;
      in_reverse_type := false;

@
@<draw account...@>=
      writecommand(12,410);          {rule width in points}
      writecommand(13,8);            {rule depth in points}
      writecommand(14,0);            {set top rule}
      writecommand(12,8);            {rule width in points}
      writecommand(13,84);           {rule depth in points}
      writecommand(14,402*SPsPerPt); {set left rule}
      writecommand(14,0);            {set right rule}
      writecommand(9,83.8*SPsPerPt); {VMF to bottom in pts}
      writecommand(12,410);          {rule width in points}
      writecommand(13,8);            {rule depth in points}
      writecommand(14,0);            {set bottom rule}
      writecommand(11,32*SPsPerPt);  {32pt indent}
      writecommand(10,56*SPsPerPt);  {Move back up}
      writecommand(25,320);          {define bold font}
      writecommand(7,11);            {11pt size}

@
@<write name...@>=
      write8600rec('4e616d65231e'xc); {'Name: '}
      writecommand(25,330);           {change to Bold Ital}
      writeinfo(infoname);
      writecommand(11,265*SPsPerPt);  {265pt Indent}
      writecommand(25,320);           {Bold}

@
@<write phone...@>=
      write8600rec('50686f6e65231e'xc); {'Phone: '}
      writecommand(25,330);             {Bold Italic}
      writeinfo(infophone);

@
@<write delivery meth...@>=
        writecommand(11,50*SPsPerPt);   {50pt indent}
        writecommand(9,16*SPsPerPt);    {VMF 16pt}
        writecommand(25,320);           {Bold}
        write8600rec('44656c6976657279231e'xc);  {'Delivery: '}
        writecommand(25,330);           {Bold Italic}
        writeinfo(infodelivery);

@
@<write zipcode...@>=
        if infozip <> 'NA'
              then begin
                 writecommand(11,190*SPsPerPt);   {190pt indent}
                 writecommand(25,320);            {Bold}
                 write8600rec('5a6970636f6465231e'xc);  {'Zipcode: '}
                 writecommand(25,330);            {Bold Italic}
                 writeinfo(infozip);
                 end;

@
@<write center...@>=
        if infobin <> 'NA'
              then begin
                 writecommand(11,284*SPsPerPt);   {284pt indent}
                 writecommand(25,320);            {Bold}
                 write8600rec('42696e231e'xc);    {'Bin: '}
                 writecommand(25,330);            {Bold Italic}
                 writeinfo(infobin);
                 end; {then..begin}

@
@<write user id...@>=
        writecommand(9,14*SPsPerPt);              {VMF 14pt}
        if infoid <> 'NA'
              then begin
                 writecommand(11,30*SPsPerPt);    {30pt indent}
                 writecommand(25,320);            {Bold}
                 write8600rec('4944231e'xc);      {'ID: '}
                 writecommand(25,330);            {Bold Italic}
                 writeinfo(infoid);
                 end; {then..begin}
@
@<write job length...@>=
        writecommand(11,250*SPsPerPt);      {indent for job length}
        writecommand(25,320);               {BOLD}
        write8600rec('4a6f621e'xc);         {'Job '}
        write8600rec('4c656e677468231e'xc); {'Length: '}
        writecommand(25,330);               {Bold Italic}
        job_len_conv := strconv(job_length);
              for inx := 1 to 5
                 do write8600rec(str(chr
                     (ordx[job_len_conv[inx]])));
        write8600rec('1e696e63686573'xc);   {' inches'}
        writecommand(11,20*SPsPerPt);       {get ready for DSN}

@
@<write file name...@>=
        writecommand(9,16*SPsPerPt);   {VMF 16pt}
        writecommand(25,320);          {Bold}
        write8600rec('46696c656e616d65231f'xc);  {'Filename: '}
        writecommand(25,330);          {Bold Italic}
        parmvalue := real_filename;
        writeinfo(parmvalue);

@
@<write number of...@>=
        writecommand(11,155*SPsPerPt);   {155pt indent}
        writecommand(25,320);            {Bold}
        write8600rec('50616765731e'xc);  {'Pages '}
        write8600rec('536574231e1e'xc);  {'Set: '}
        writecommand(25,330);            {Bold Italic}
        pages_conv := strconv(pages_set);
              for inx := 1 to 5
                 do write8600rec(str(chr(ordx
                     [pages_conv[inx]])));
        writecommand(11,265*SPsPerPt);   {get ready for Tape \#}

@
@<write tape numb...@>=
        writecommand(25,320);            {Bold}
        write8600rec('546170651e'xc);    {'Tape '}
        writecommand(20,2);              {aux. char. set}
        write8600rec('72'xc);              {'\#'}
        writecommand(20,1);              {pri. char. set}
        write8600rec('231e1e1e1e'xc);      {': '}
        postam_found := true;
        writecommand(25,330);            {bold italic}


@ The information procedure reads the billing information from an outside
file called the |addrfile|, and sends that information to the
|setaccountbox| procedure. It also writes the information to another file
called the |infofile|.

@<Global Constants@>=
@!    notfatal = false;@/

@
@<Global Variables@>=
@!addrline : text;
@!infofile : text;
@^system dependencies@>
@!resource_info : string(256);
@^system dependencies@>
@!str1 : string(256);
@^system dependencies@>
@!str2 : string(256);
@!minimum_width  : integer;@/

@
@p @^system dependencies@>
procedure information;
   var
      int            :integer;
      inx            :integer;
      infoname       :string(30);
      infophone      :string(14);
      infodelivery   :string(10);
      infozip        :string(10);
      infobin        :string(8);
      infoid         :string(22);
      infoprocedure  :string(4);
      infobudget     :string(20);
      tempbool       :boolean;
begin
 @<set initial values for strings@>
 @<open address file and read and close@>@/
 @<parse info from address file@>
 @<send info to accounting procedure and write infofile@>
end; {information}

@
@<set initial values...@>=
   infozip := 'NA';
   infoid := 'NA';
   infobin := 'NA';
   infoprocedure := 'NA';
   infobudget := 'NA';

@
@<open address...@>=
   termin(addrline);
   readln(addrline,resource_info);
   close(addrline);

@
@<parse info...@>=
   rewrite(infofile,'NAME='  ccat filename  ccat '.INFOFILE.*');
   while length(resource_info) > 0 do begin
       inx := index(resource_info,':');
       if inx < 1
          then begin
               errstr := resource_info;
               error(28,notfatal,0);
               end
          else begin
               str1 := substr(resource_info,1,inx-1);
               resource_info := ltrim(substr(resource_info,inx+1));
               inx := index(resource_info,':');
               if inx = 0
                  then begin
                       str2 := resource_info;
                       resource_info := '';
                       end
                  else begin
                       int := inx - 1; {no sense starting at a colon:}
                       tempbool := false;
                       repeat
                         if substr(resource_info,int,1) = ' '
                              then tempbool := true
                              else int := int - 1;
                         until tempbool; {which means we found a blank}
                       str2 := trim(substr(resource_info,1,int-1));
                       resource_info := substr(resource_info,int+1);
                       end;
               str1 := allcaps(ltrim(trim(str1)));
               str2 := allcaps(ltrim(trim(str2)));
               if str1 = 'NAME' then
                    infoname := str2
                  else if str1 = 'PHONE' then
                    infophone := str2
                  else if str1 = 'PROCEDURE_NUMBER'
                    then infoprocedure := str2
                  else if str1 = 'BUDGET_PROJECT'
                    then infobudget := str2
                  else if str1 = 'PICKUP' then
                    infodelivery := str2
                  else if str1 = 'CAMPUS_ZIP' then
                    infozip := str2
                  else if str1 = 'BIN' then
                    infobin := str2
                  else if str1 = 'ID' then
                    infoid := str2
                  else begin
                         errstr := resource_info;
                         error(28,notfatal,0);
                         end
               end;
               end;

@
@<send info...@>=
   setaccountbox(infoname,infophone,infodelivery,infozip,
                 infobin,infoid);
   writeln(infofile,infoname);
   writeln(infofile,infophone);
   writeln(infofile,infoprocedure);
   writeln(infofile,infobudget);
   writeln(infofile,infodelivery);
   writeln(infofile,infozip);
   writeln(infofile,infoid);
   writeln(infofile,infobin);
   writeln(infofile,job_length);
   writeln(infofile,pages_set);
   writeln(infofile,minimum_width);
   writeln(infofile,real_filename);

@* End of File procedures.
At the end of the \TeX DVI file is a postamble command, when that
command is encountered |readpostamble| and |post_amble| are called.

@ The second procedure called but first listed is the |post_amble|
procedure, it calls the |information| procedure and writes the job
length and number of pages to the terminal.

@<Global Variables@>=
@!num_of_pages : integer;
@^system dependencies@>
@!job_type : string(6);

@
@p procedure post_amble;
       begin
         @<prepare and write information info@>
         @<give job length to user on terminal@>@/
         @<set final values for galleylength, etc.@>
       end; {Postamble}

@
@<prepare and write...@>=
             if dumpin then writeln(dumpout,
                             'PST -- post-amble: End of Run');
             doingpages := true;
             writecommand(11,0);      {Move to left col.}
             writecommand(9,30.0*SPsPerPt);    {VMF 30 pts}
             information;

@
@<give job length...@>=
             writeln;
             writeln('Total length of run = ',
                       galley_length:9:1,' pts.');
             writeln('                    = ',
                       galley_length/72.0:9:1,' inches.');
             writeln('                    = ',
                       num_of_pages:9,' pages.');

@
@<set final...@>=
             job_length := round(galley_length/72.0);
             pages_set := num_of_pages;
             job_type := 'TeX';

@ This second procedure is called first and reads the final job
information for the file. Things like job length, widest page,
tallest page are set and the information sent to |post_amble|.

@<Global Variables@>=
@!byte : integer;@/
@!width  : real;@/
@!even_page_margin : real;@/
@!odd_page_margin : real;@/
@!totalpg : integer;@/

@
@p procedure readpostamble;
var
   int            :integer;@/
   inx            :integer;@/
begin
   job_length := round(galley_length / 72.0);@/
   pages_set  := num_of_pages;@/
   for inx := 1 to 3 do byte := readinteger(4);
   byte := readinteger(4); {Get magnification}@/
   if dumpin
         then writeln(dumpout,
                  '** Font magnification = ',byte/1000.0:3:1);
   writeln;
   writeln('Tallest page is ',readinteger(4)/SPsPerPt/72.0:2:1,
           ' inches.');
   width := readinteger(4) / SPsPerPt / 72.27;
   width := max(width,put_width,even_page_margin/72.27,
   odd_page_margin/72.27);
   writeln('Widest page is ',width:2:1,' inches.');@/
   width := width + 0.31;   {5/16" on the left that cannot be used.}
   if width < 8.0 then int := 8
             else int := 12;
   minimum_width := int;
   writeln('The smallest paper you can use is ',int:2,'"');
   totalpg := 9999;
   post_amble;
   if galley_length = 0 then begin
      writeln('Error!! No pages set. ');
      setretcode(12);
      end;
   end; {readpostamble}

@* Conversion Functions.
The following two functions will convert strings to integers
(|whole_value|) or to real numbers (|decimal_value|).

@^system dependencies@>
@p function whole_value(str1 :string(10)) :integer;
var
    inx, inz : integer;@/
    divisor  : real;@/
    number   : real;@/
begin
    number := 0;
    inx := index(str1,'-');
    if inx > 0
        then begin
            divisor := (-1 * 0.1);
            str1 := substr(str1,2);
            end {then..begin}
        else divisor := 0.1;
   for inz := 0 to (length(str1)-1) do begin
       divisor := divisor * 10.0;
       number := number + ((ordx[str1[length(str1) - inz]] -
             ordx['0']) * divisor);
       end;
   whole_value := round(number);
end; {|whole_value|}

@
@^system dependencies@>
@p function decimal_value(str2 :string(40)): real;
var
    inx, inz : integer;
    divisor  : real;
    str3     : string(30);
    number   : real;
begin
    number := 0.0;
    inx := index(str2, '.');@/
    @<value with decimal, but nothing to right@>
    @<value with decimal, and something to right@>@/
    @<value without decimal@>
   decimal_value := number;
   end;   {|decimal_value|}

@
@<value with decimal, but...@>=
    if inx = length(str2) then begin {read left side of decimal}
        str2 := substr(str2,1,inx-1);
        end
@
@<value with decimal, and...@>=
        else begin
        if inx > 0 then begin
        str3 := substr(str2,inx+1);
            divisor := 1.0;
            for inz := inx+1 to length(str3) do begin
               divisor := divisor * 0.1;
               number := number +
                (ordx[str3[inz]] - ordx['0'] * divisor);
               end;
        if inx = 1 then return;
       str2 := substr(str2,1,inx-1);
       end;
       end;

@
@<value without...@>=
   divisor := 0.1;
   for inz := 0 to (length(str2)-1) do begin
       divisor := divisor * 10.0;
       number := number + ((ordx[str2[length(str2) - inz]] -
             ordx['0']) * divisor);
       end;
@* Parm-reading procedure.
This procedure reads and parses the parameters entered with the
call to this program; it is expecting the following form of some
sort:

\centerline{\tt tex8600 fn ft (1stpg \#ofpgs) realfn lrecl}

@<Global Variables@>=
@^system dependencies@>
@!filetype : string(8);
@!firstpg : integer;

@
@p @^system dependencies@>
procedure readparms;
var
   namepage : string(256);
   temp     : integer;
   temp2    : integer;
   temp3    : integer;
   str1     : string(10);
   lrecl    : string(8);

begin
   namepage := ltrim(trim(parms));
   @<file name and real filename@>
   @<file type not supplied@>
   @<file type supplied@>
   end; {readparms}

@
   @<file name and real filename@>=
   temp := index(namepage,' ');
   temp2 := index(namepage,')');
   if temp2 > 0
      then @<parse real name and lrecl@>
      else error(10,fatal,0);
   filename := substr(namepage,1,temp-1);

@
   @<parse real name and lrecl@>=
      begin
      temp3 := index(substr(namepage,temp2+2),' ');
      if temp3 = 0
       then begin
         real_filename := substr(namepage,temp2 + 2);
         lrecl := '';
         end
       else begin
         real_filename := substr(namepage,temp2 + 2,temp3-1);
         lrecl := substr(namepage,temp2+2+temp3);
         end;
    if lrecl = ''
       then pv_dvi_lrecl := pc_dvi_lrecl
       else readstr(lrecl,pv_dvi_lrecl);
    end

@
   @<file type not...@>=
   namepage := substr(namepage,temp+1,(temp2-temp));
   temp := index(namepage,'(');
   if temp = 1
      then begin
         filetype := 'DVI';
         if length(namepage) > 1
            then begin
               namepage := substr(namepage,temp+2);
               temp := index(namepage,' ');
               if temp > 0
                  then begin
                     str1 := substr(namepage,1,temp-1);
                     firstpg := whole_value(str1);
                     str1 := substr(namepage,temp+1);
                     if length(str1) > 0 then
                        totalpg := whole_value(str1);
                     end {then..begin}
                  else begin
                     str1 := substr(namepage,1);
                     firstpg := whole_value(str1);
                     end {ELSE..begin}
               end {then..begin}
         end {then..begin}

@
   @<file type supplied...@>=
      else begin
         filetype := substr(namepage,1,temp-2);
         namepage := ltrim(substr(namepage,temp+1));
         temp := index(namepage,')');
         if temp > 1
            then begin
               temp2 := index(namepage,' ');
               str1 := substr(namepage,1,temp2-1);
               if str1='*'
                  then firstpg := -99999
                  else firstpg := whole_value(str1);
               str1 := substr(namepage,temp2+1,(temp-temp2)-2);
               if str1='*'
                  then totalpg := 99999
                  else totalpg := whole_value(str1);
               end; {then..begin}
         end; {ELSE..begin}

@* Print Position Procedures.
The next three procedures are called whenever there is to be a
vertical or horizontal move of any kind.

@
@<Global Type...@>=
@!movetype = (horiz,vert);

@ This procedure will print the horizontal or vertical
 distance that the 8600 is to move the paper.

@p procedure figuredir(typ  :movetype;
                  amt  :integer);
var
   temp           :real;
begin
  if dumpin and print_hmove then begin
        writeln(dumpout);
        write(dumpout,'          *** move ');
        end;
   @<horizontal move@>
      @<move right@>
      @<move left@>
   @<vertical move@>
      @<move down@>
      @<move up@>
   if dumpin and print_hmove
        then temp := getpts(abs(amt));
   end; {FigureDir}

@
@<horizontal move@>=
  if typ = horiz
     then if amt >= 0

@
@<move right@>=
        then begin
             if dumpin and print_hmove then write(dumpout,'right ');
             writecommand(11,stack[stacktop].H);
             end

@
@<move left@>=
        else begin
             if dumpin and print_hmove then write(dumpout,'left ');
             writecommand(11,stack[stacktop].H);
             end

@
   @<vertical move@>=
        else if amt >= 0

@
      @<move down@>=
             then begin
                  if dumpin then write(dumpout,'down ');
                  writecommand(9,amt);
                  end

@
      @<move up@>=
             else begin
                  if dumpin then write(dumpout,'up ');
                  writecommand(10,abs(amt));
                  end;

@
@<Global Variables@>=
@!hmove_pending : boolean;
@!hmove_amt : integer;
@!vmove_pending : boolean;
@!vmove_amt : integer;
@!length_of_take : real;

@ This procedure is invoked in the main program each
 time something is actually to be set (such as a
 character). If there is a vertical or horizontal
 move pending, they will be set here, before continuing
 on to the next set command (such as set character).

@p procedure checkmoves;
var
   tempbool       :boolean;
begin
   if hmove_pending then begin
        figuredir(horiz,hmove_amt);
        hmove_amt := 0;
        hmove_pending := false;
        print_hmove := true;
        end; {then..begin}
   if vmove_pending then begin
        figuredir(vert,vmove_amt);
        tempbool := dumpin;
        dumpin := false;
        if doingpages=true
          then begin
            galley_length := galley_length + getpts(vmove_amt);
            length_of_take := length_of_take + getpts(vmove_amt);
            end;
        dumpin := tempbool;
        vmove_amt := 0;
        vmove_pending := false;
        end; {then..begin}
   end;      {checkmoves}

@
@<Global Variables@>=
@!font8600 : 0..2550;
@!ptsize : 0..255;
@!different_setsize : boolean;
@!setsize : 0..255;

@ This procedure sets the page environment to be that of ``font"

@p procedure establish_font_parameters(font  :integer);
begin
  @<new font name@>
  @<new font size@>
  @<new set size@>
end; {|establish_font_parameters|}

@
@<new font name@>=
   with a8600fontrec[fontenviron[font].fontindex]
        do begin
           if (fontno8600 <> font8600) and (fontno8600 <> 0)
              then begin
                writecommand(25,float(fontno8600));
                font8600 := fontno8600;
                end; {then..begin}
        end; {WITH..begin}

@
@<new font size@>=
   if fontenviron[font].pointsize <> ptsize
        then begin
           ptsize := fontenviron[font].pointsize;
           writecommand(7,float(ptsize));
        end; {then..begin}

@
@<new set size@>=
   if different_setsize
        then writecommand(8,float(setsize));


@* ``Special'' Procedures.
The next few procedures enable the 8600 to do ``special'' things
like setting line footnotes, or slant type, or expanded type, etc.

@
@<Global Constants@>=
@!    maxNote = 100;@/

@ This procedure establishes the line number reference in
|footnote_line_array| with the line number in which a line note was
called.

@<Global Variables@>=
@!foot_area_ref : 0..255;
@!footnote_line_array : packed array[0..maxNote] of 0..255;
@!foot_line_ref : 0..255;
@!line_note_pending : boolean;
@!line_ref_pend_seq : 0..255;
@!counting_lines : boolean;
@!number_of_lines : integer;

@
@p procedure line_footnote_reference;
begin
   if not counting_lines then begin
       incr(foot_area_ref);
       line_note_pending := true;
       line_ref_pend_seq := 1;
       end
   else begin
       incr(foot_line_ref);
       footnote_line_array[foot_line_ref] := number_of_lines + 1;
       end;
   end; {|line_footnote_reference|}

@
@<Global Constants@>=
@!    linefont = 256;@/
@!    linenumfont = 76;@/

@
@<Global Variables@>=
@^system dependencies@>
@!special : string(40);
@!line_interval : 0..255;
@!margin_note : boolean;
@!numbering_lines : boolean;
@!printing_numbers : boolean;
@!pop_level : integer;

@ This procedure reads and interprets all the \\special commands
entered in the \TeX\ file. Its primary purpose is for reading the
the instructions pertaining to linenotes.

@p @^system dependencies@>
procedure readspecials;
var
   int : integer;
   inx : integer;
  temp : string(40);
 temp2 : string(40);
 temp3 : string(40);
 temp4 : string(40);

begin
 @<read special command@>
         if temp = 'EVEN_PAGE_MARGIN'
            then begin
              temp := (substr(temp2, 1, length(temp2)-2));
              even_page_margin := decimal_value(temp);
            end
         else if temp = 'ODD_PAGE_MARGIN'
            then begin
              temp := (substr(temp2, 1, length(temp2)-2));
              odd_page_margin := decimal_value(temp);
            end
         else if temp = 'LINE_NUMBER_FONT'
             @<linenumber font@>
         else if temp = 'POP_LEVEL'
             then pop_level := whole_value(temp2)
         else if temp = 'LINE_INTERVAL'
             then line_interval := whole_value(temp2)
         else if temp = 'NUMBERING_LINES'
             then begin
                  @<boolean value@>
                  then numbering_lines := true
                  else numbering_lines := false;
             end {then..begin}
         else if temp = 'COUNTING_LINES'
             then begin
                  @<boolean value@>
                  then counting_lines := true
                  else counting_lines := false;
              end {then..begin}
         else if (temp = 'MARGINNOTE')
             then margin_note := true
         else if temp = 'PRINTING_NUMBERS'
              then begin
                  @<boolean value@>
                  then printing_numbers := true
                  else printing_numbers := false;
               end {then..begin}
         else if temp = 'LINE_FOOTNOTE_REFERENCE'
               then line_footnote_reference;
         end; {then..begin}
   end; {ReadSpecials}

@ This gives default values for even and odd page margins that
will be reset if the user specified them in his file. It also reads
the special command.

@<read special command@>=
   int := index(special, '=');
   if int > 0
      then begin
         temp := trim(ltrim(substr(special, 1, int-1)));
         temp2 := substr(special, int+1);

@ If the special command is a Line Number Font, the command must
be further broken down to find the point size, as well as the name.

 @<linenumber font@>=
              then begin
                 int := index(temp2, ' ');
                 if int > 0
                 then begin
                 @<point size given@>
                    end
                 else  begin
                 @<no point size given@>
                    end;
                 fontname := allcaps(temp3);
                 readfontinfo(linefont,linenumfont);
                 end

@ A point size is given and that size must be sent along with the
name to the |readfontinfo| procedure.

@<point size given...@>=
 temp3 := trim(ltrim(substr(temp2, 1, int-1)));
 temp4 := substr(temp2, int+1);
 with fontenviron[linefont] do begin
      inx := whole_value(temp4);
      pointsize := inx;
      designsize := inx;
      end;

@ No point size is given, so the default point size will be used
(ten-point).

@<no point size...@>=
 temp3 := trim(ltrim(substr(temp2, 1, int-1)));
 inx := 10;
 with fontenviron[linefont] do begin
      pointsize := inx;
      designsize := inx;
      end;

@ The boolean value module is used when the response to the
special command is true or false.

@<boolean value@>=
       temp2 := allcaps(ltrim(trim(temp2)));
       if temp2 = 'TRUE'

@ This procedure is used in conjunction with the 0 font and
handles the special functions codes like slant,
reverse type, set size, etc.

@p procedure call_specials_routine(funcname         :integer);
var
   inx            :integer;
   num            :integer;
begin
   if dumpin then writeln(dumpout,'Function [',funcname:3,'] ');
   if funcname = 10
       then counting_lines := true
   else if funcname = 11
       then counting_lines := false
   else if funcname = 12
       then printing_numbers := true
   else if funcname = 13
       then printing_numbers := false
   else if funcname = 14
      then line_footnote_reference;
   if (funcname=14) or (funcname=13) or (funcname=12) or
       (funcname=11) or (funcname=10) then return;
 with stack[stacktop],
      a8600fontrec[fontenviron[currfont].fontindex],
      fontenviron[currfont] do begin
      with a8600chars[funcname] do begin
              for inx := 0 to num
              do with comarray[inx]
                  do writecommand(comcode,float(argument));
           end; {DO..begin}
        end; {DO..begin}
   end; {|call_specials_routine|}

@* Set the characters procedures.
The first procedure is called from the second one if a line
number is to be printed.
The second procedure actually sets an individual character.
First it checks
to make sure the character is a real one and not from the zero or
specials' font, then
it checks to see if a move needs to be made before the character is
printed. It makes the move and then
checks to see if a line number is to be printed; if it does, it prints
the line number, if it doesn't it sets the character.

@<Global Variables@>=
@!points : real;
@!we_add_the_character_width : boolean;

@ When \TeX\  formats the footnotes entered with a linenote reference
command, it simply inserts two zeros for the linenumber. This procedure
replaces those two zeros with the line number in which the linenote
reference was called.

@p procedure setline_footnote_ref(font            :integer);
var
   temp           :integer;
   inx            :integer;
   tempreal       :real;
   return_ps      :boolean;
   return_ss      :boolean;
begin
@<determine correct line number@>
@<print line number@>
@<reset line number values@>
end; {|setline_footnote_ref|}

@
@<determine correct line number@>=
   if line_ref_pend_seq = 1
      then temp := footnote_line_array[foot_area_ref] div 10
      else temp := footnote_line_array[foot_area_ref] mod 10;
   with fontenviron[font], stack[stacktop] do
          H := H + round(pointsize *
               a8600fontrec[fontindex].a8600chars[48].charwidth
               * SPsPerPt);
   if (line_ref_pend_seq = 1) and (temp = 0) then begin
      hmove_pending := true;
      line_ref_pend_seq := 2;
      return;
      end;

@
@<print line number@>=
 with stack[stacktop], a8600fontrec[fontenviron[font].fontindex],
    fontenviron[font] do begin
      with a8600chars[48 + temp] do begin
          @<set character commands@>
    end; {WITH..begin}
      end; {WITH..begin}

@
@<reset line number values@>=
   if line_ref_pend_seq = 1 then begin
      line_ref_pend_seq := 2;
      return; end
      else begin
          line_ref_pend_seq := 0;
            line_note_pending := false;
            return; end;
    if line_note_pending
       then begin
            line_note_pending := false;
            return;
            end;

@ The |setcharacter| procedure is the main procedure for setting
any and all characters, except the |line_footnote| references.

@p procedure setcharacter(character       :integer;
                         font            :integer);
var
   inx            :integer;
   tempreal       :real;
   temppt         :integer;
   tempbool       :boolean;
   return_ps      :boolean;
   return_ss      :boolean;
begin
   @<specials font or dumpin@>
   checkmoves;
   @<linenote-footnote@>
   @<debug info@>
   @<begin character@>
   end; {setcharacter}

@
@<specials font or dumpin@>=
if font8600 = 0 then begin
  call_specials_routine(character);
  return;
  end;  {then..begin}
if dumpin and (hmove_pending or vmove_pending)
  then tempbool := true
  else tempbool := false;

@
@<linenote-footnote@>=
  if line_note_pending and (character = 48)
     then begin
        setline_footnote_ref(font);
        return;
        end;

@
@<debug info@>=
  if dumpin and tempbool then writeln(dumpout);
  if dumpin
      then if (character >= 32) and (character < 127)
          then write(dumpout,chrx[character])
          else write(dumpout,'?<',character:3,'>');

@
@<begin character@>=
   return_ps := false;
   return_ss := false;
   with stack[stacktop], a8600fontrec[fontenviron[font].fontindex],
        fontenviron[font] do begin
        with a8600chars[character] do begin
              if different_setsize
                  then temppt := trunc(float(setsize) /
                          100.0 * pointsize)
                  else  temppt := pointsize;
              if we_add_the_character_width
                  then H := H + round(temppt * charwidth * SPsPerPt);
              @<set character commands@>
          end; {WITH..begin}
    end; {WITH..begin}

@
@<set character commands@>=
for inx := 0 to num do
   with comarray[inx] do
       if (comcode = 25) and (argument = -1)
          then writecommand(25,fontno8600)
                        {Some commands need to be scaled by
                             the set size factor}
           else if (comcode=9) or (comcode=10) or
                    (comcode = 27) or (comcode = 28)
                then begin
                     points := float(pointsize) *
                                      SPsPerPt * real_argument;
                     writecommand(comcode,points);
                     end {then..begin}
           else if (comcode = 12) or (comcode = 13)
                then begin
                     points :=float(pointsize) * real_argument;
                     writecommand(comcode,points);
                     end {then..begin}
           else if comcode = 14
                then begin
                     tempreal := SPsPerPt * (getpts(H) +
                              (real_argument * pointsize));
                     if we_add_the_character_width
                          then tempreal := tempreal -
                                  round(pointsize*charwidth*SPsPerPt);
                     writecommand(14,tempreal);
                     end
           else if comcode = 7
                then begin
                     writecommand(7,pointsize+float(argument));
                     return_ps := true;
                     end
           else if comcode = 8
                then begin
                     writecommand(8,designsize+float(argument));
                     return_ss := true;
                     end
           else writecommand(comcode,float(argument));
       if return_ss then writecommand(8,designsize);
       if return_ps then writecommand(7,pointsize);

@
@<Global Variables@>=
@!size : integer;

@ This next procedure sets the line number if that option is used.
It will print the line number according to
|odd_page_margin| or |even_page_margin|. The number will
be set in the |line_number_font|. The line numbers
will print every five lines by default or according to
|line_interval|, and begin at 1 on each page.

@p procedure print_line_number;
var
   j         :integer;
begin
   incr(number_of_lines);
   if not printing_numbers then return;
   if (number_of_lines <> ((number_of_lines div
         line_interval) * line_interval))
        then return; {If this is not a line number divisible by
                      |line_interval|}
   size := headernum div 2;
   size := size * 2;
   if even_page_margin = 0 then
   even_page_margin := 50.8;
   if odd_page_margin = 0 then
   odd_page_margin := 407.7;
   if size = headernum
        then writecommand(11,even_page_margin*SPsPerPt)  {H position}
        else writecommand(11,odd_page_margin*SPsPerPt);  {H position}
   establish_font_parameters(linefont);
   size := number_of_lines;
   if dumpin then begin
        writeln;
        write(dumpout,'*** set line number ');
        end;
   we_add_the_character_width := false;
   if size >= 10
        then begin
             j := size div 10;
             setcharacter(j+48,linefont); {set 1st digit}
             size := size -(j * 10);
             end
        else with
a8600fontrec[fontenviron[linefont].fontindex].a8600chars[48]
             do       {set nothing, but move the width of a "0"}
             writecommand(27, fontenviron[linefont].pointsize *
                  charwidth * SPsPerPt);
   setcharacter(size+48,linefont); {+48 for ASCII code}
   we_add_the_character_width := true;
   if dumpin then writeln(dumpout);
   establish_font_parameters(currfont); {return to active font}
   end; {|print_line_number|}

@* Initialization procedures.
These next few procedures, get the whole thing started by assigning
values to all necessary items.

@<Global Constants@>=
@!    version = 2;@/
@!    level = 7;@/

@
@<Global Variables@>=
@!takenum : integer;
@!currpage : integer;
@!prevpage : integer;

@
@p @^system dependencies@>
procedure initialize8600;
begin
   @<page-setting values@>
   @<setting output/input values@>
   @<line-numbering font values@>@/
   @<page and font values@>
   @<line numbering values@>
   @<miscellaneous values@>
   end; {initialize8600}

@
   @<page-setting values@>=
   firstpg := -99999;
   totalpg := 99999;
   doingpages := false;

@
   @<setting output/input values@>=
   termout(output);
   readparms;
   reset(input,'NAME='  ccat filename  ccat '.'  ccat filetype  ccat '.*');
   writeln('******* tex8600 Version ',version:2,' Level ',
        level:3,' *******');
   rewrite(setfile,'LRECL=1029,RECFM=F,NAME='  ccat filename  ccat
'.TAPEFILE.*');

@
   @<line-numbering font values@>=
   with fontenviron[-1] do begin
        pointsize := 10;
        designsize   := 1;
        fontindex := 0;
        end; {WITH..begin}

@
@<page and font values@>=
   currfont := -1;
   currpage := 0;
   prevpage := -99999;
   ptsize := 0;
   setsize := 100;

@
@<line numbering values@>=
   counting_lines := false;
   margin_note := false;
   numbering_lines := false;
   printing_numbers := false;
   line_note_pending := false;
   line_ref_pend_seq := 0;
   even_page_margin := 0.0;
   odd_page_margin := 0.0;
   line_interval := 5;
   pop_level := 3;
   bufferlen := 0;

@
@<miscellaneous values@>=
   takenum := -1;
   num_of_pages := 0;
   length_of_take := 0;
   dumpin := false;

@ This procedure initializes values that pertain to the overall run.

@<Global Variables@>=
@!last_command : 0..255;
@!outputpending : boolean;
@!page_counter : integer;
@!second_to_last_cmnd : 0..255;

@
@p procedure init_run;
begin
   initialize8600;
   @<debugging statements@>
   count          := 0;
   fileend        := false;
   galley_length  := 0;
   hmove_amt      := 0;
   hmove_pending  := false;
   last_command   := 0;
   outputpending  := false;
   page_counter   := 0;
   postam_found   := false;
   put_width      := 0.0;
   print_hmove    := true;
   second_to_last_cmnd := 0;
   stacktop       := 1;    {initialize stack}
   vmove_amt      := 0;
   vmove_pending  := false;
   we_add_the_character_width := true;
   @<initialize job's main record--stack@>
   end; {|init_run|}

@
   @<debugging statements@>=
   if dumpin then begin
        writeln(dumpout);
        writeln(dumpout);
        writeln(dumpout,'********************************************');
        writeln(dumpout,'byte:code meaning');
        writeln(dumpout);
        end;

@
@<initialize job's main record--stack@>=
   with stack[stacktop] do begin
        H := 0;
        V := 0;
        W := 0;
        X := 0;
        Y := 0;
        Z := 0;
        end;  {WITH loop}

@* Rule-setting Procedures.
The |setrule| procedure is called when the horizontal position
is to be advanced. |putrule| is called when the horizontal position
is not to be advanced.

@ This procedure sets a rule.

@<Global Variables@>=
@!ruleht : integer;
@!rulewidth : integer;
@!height : real;
@!fudge : real;

@
@p procedure drawrule;
begin
   checkmoves;
   points := getpts(ruleht);
   height := points * SPsPerPt;
   if points <> 0 then begin
      writecommand(13,points);
      points := getpts(rulewidth);
      writecommand(12,points);
      if points <> 0 then begin
          writecommand(10,height); {Move back the rule height}
          writecommand(14,stack[stacktop].H); {set it}
          writecommand(9,height); {move down after setting}
          writecommand(11,stack[stacktop].H); {set it}
          end; {then...begin}
      end;{then..begin}
end;

@ Rule and increase the value of H (horizontal position).

@p procedure setrule;
begin
    drawrule;
    hmove_amt := rulewidth;
    hmove_pending := true;
    stack[stacktop].H := stack[stacktop].H + rulewidth;
end;  {setrule}

@ Rule and do not increase the value of H (horizontal position).

@p procedure putrule;
begin
   drawrule;
end; {putrule}

@* Page procedures.
The |doendofpage| procedure is called at the end of each page and the
|dobeginningofpage| procedure at the beginning of each page.

@ This procedure is entirely for the user's information. It prints
out to the terminal the number of pages set in the job. If there are
are more than 8 page numbers a carriage return is thrown.

@p procedure doendofpage;
begin
    incr(page_counter);
    if page_counter >= 8 then begin
         writeln;
         page_counter := 0;
         end;
    if doingpages=true
       then begin
         decr(totalpg);
         if totalpg = 0
            then begin
               writeln('<',currpage:1,'> ');
               return;
               end {then..begin}
            else write('<',currpage:1,'> ');
         end;
    end;

@ This procedure does all of the 8600 initialization
              for the start of each new page.

@<Global Constants@>=
@!    indent='                 ';@/
@!    nullstring = '00000000000000000000'xc;@/

@
@<Global Variables@>=
@!int : integer;
@!newtake : boolean;

@
@p procedure dobeginningofpage;
var
inx       :integer;
begin
   @<general initializations@>
   @<read first page number@>
   @<determine if current page is to be set@>
   @<read counters@>
   if doingpages=true
      then begin
        if (currpage = firstpg) or (int = -1)
           or (length_of_take >= 5184)
          then begin
             @<first page or 6 feet in film canister@>
             end {then..begin}
          else begin
             @<any other page@>
             end;  {ELSE..begin}
          with fontenviron[currfont] do begin
             if int = -1 then begin
             @<first page font environment@>
                 end
             else begin
                 @<all other pages font environment@>
                 @<print end of page rule@>
                 end; {ELSE..begin}
          end;{WITH..begin}
      incr(num_of_pages);
      end; {then..begin}
end; {DoBeginningOfPage}

@
@<general initializations@>=
   foot_line_ref := 0;
   foot_area_ref := 0;
   number_of_lines := 0;
   newtake := false;
   with stack[stacktop] do begin
      H := 4718592;
      V := 0; {start 1" over and 1" down}
vmove_amt := 4718592;
vmove_pending := true;
hmove_pending := true;
      end;      {WITH ... do begin}

@
@<read first page number@>=
   int := readinteger(4);
   if dumpin then writeln(dumpout,'BOP -- Beginning Of Page ',int);
   headernum := int;
       prevpage := currpage;
   currpage := int;

@
@<determine if current...@>=
if (firstpg = -99999)
  then
     doingpages := true;
if not doingpages
then
  if ((firstpg >= 0) and (firstpg <= currpage))
     or ((firstpg < 0) and (firstpg >= currpage))
     then
        doingpages := true;
if (totalpg < 1)
 then
   doingpages := false;

@
@<read counters@>=
   for inx := 1 to 9 do begin
        int := readinteger(4);
        if dumpin then writeln(dumpout,'Counter ',inx:1,' = ',int);
        end;      {FOR ... do begin}
   int := readinteger(4);
   if dumpin
      then writeln(dumpout,indent,'previous page pointer = ',int);

@
@<first page or 6 feet in film canister@>=
             incr(takenum);
             length_of_take := 0;
             if (int = -1) or (currpage = firstpg) {On first page}
                  then writeheader
                  else begin
                       inx := headernum;
                       headernum := 88888;
                       repeat  {pad end of record with hex FF}
                            write8600rec(allzeros);
                            until bufferlen <= 5;
                       headernum := inx;
                       writecommand(1,0.0); {End of Take}
                       repeat  {pad record with '00'xc}
                            write8600rec(allzeros);
                            until bufferlen <= 5;
                       end;
             write8600rec(nullstring); {10 hex zeros}
             writecommand(0,takenum); {Start of Take}
             newtake := true;

@
@<any other page@>=
                repeat  {pad end of record with hex FF}
                  write8600rec(allzeros);
                  until bufferlen <= 5;

@
@<first page font environment@>=
                 different_setsize := false;
                 in_slant_mode := false;
                 in_reverse_type := false;

@
@<all other pages font environment@>=
                 writecommand(25,font8600);
                 writecommand(7,pointsize);
                 if different_setsize
                    then writecommand(8,float(setsize));
                 if in_slant_mode
                    then writecommand(15,48);
                 if in_reverse_type
                    then writecommand(3,1);

@
@<print end of page rule@>=
                 writecommand(11,0);      {Move to left col.}
                 writecommand(9,12.0*SPsPerPt);    {VMF 12 pts}
                 writecommand(12,30.0);   {set width of rule}
                 writecommand(13,1.5);    {set depth of rule}
                 writecommand(14,0);      {page separator}
                 writecommand(11,0);      {quad left}
                 writecommand(9,12.0*SPsPerPt);    {VMF 12 pts}
                 galley_length := galley_length + 24;

@* MAIN PROGRAM.

@<Global Variables@>=
@!tempstack : stackrec;
@!inx : integer;
@!temp : integer;
@!temp2 : integer;
@!put_width : real;
@!realtemp : real;

@
@p begin {MAIN}
                    {=== Initialize ===}
   init_run;
   while not postam_found do begin
        savecount := count;     {don't change it in readinteger}
        byte := readinteger(1); {1-byte code}
        if printing_numbers
             then if ((byte > 128) and (byte < 218)) then begin
                  second_to_last_cmnd := last_command;
                  last_command := byte;
                  end; {then..begin}
        if byte < 128 then begin {This is a character}
             outputpending := true;
             setcharacter(byte,currfont);
             end  {then..begin}
             else if (byte>=250) and (byte<=255)
                  then error(6,fatal,byte)
     else case byte of
   128: @<set horizontal character1@>@/
   129: @<set horizontal character2@>@/
   130: @<set horizontal character3@>@/
   131: @<set horizontal character4@>@/
   132: @<set a rule@>@/
   133: @<put horizontal character1@>@/
   134: @<put horizontal character2@>@/
   135: @<put horizontal character3@>@/
   136: @<put horizontal character4@>@/
   137: @<put a rule@>@/
   138: do_nothing; {NOP}
   139: dobeginningofpage;{BOP}
   140: doendofpage; {EOP}
   141: @<push@>@/
   142: @<pop@>@/
   143: @<right1 move@>@/
   144: @<right2 move@>@/
   145: @<right3 move@>@/
   146: @<right4 move@>@/
   147: @<``W'' horizontal move@>@/
   148..151: @<``W''1-4 horizontal move@>@/
   152: @<``X'' horizontal move@>@/
   153..156: @<``X''1-4 horizontal move@>@/
   157..160: @<down1@>@/
   161: @<``Y'' vertical move@>@/
   162..165:@<``Y''1-4 vertical move@>@/
   166: @<``Z'' vertical move@>@/
   167..170: @<``Z''1-4 vertical move@>@/
   171..234: @<set font@>@/
   235: @<font1 set@>@/
   236: @<font2 set@>@/
   237: @<font3 set@>@/
   238: @<font4 set@>@/
   239: @<nop1@>@/
   240: @<nop2@>@/
   241: @<nop3@>@/
   242: @<nop4@>@/
   243: @<font1 def $0<k<64$@>@/
   244: @<font2 def $0<k<65536$@>@/
   245: @<font3 def $0<k<2^{24}$@>@/
   246: @<font4 def $-2^{31}<k<2{30}$@>@/
   247: @<preamble@>@/
   248: readpostamble; {Post-amble}@/
   249: do_nothing; {Post-post-amble}
  otherwise writeln('oops...forgot about ',byte:12);
     end;{CASE}
  end;{while}
end.

@
@<set horizontal character1@>=
  begin
             int := readinteger(1);
             we_add_the_character_width := true;
             hmove_pending := true;
             setcharacter(int,currfont);
             end;

@
@<set horizontal character2@>=
begin
             int := readinteger(2);
             we_add_the_character_width := true;
             hmove_pending := true;
             setcharacter(int,currfont);
             end;

@
@<set horizontal character3@>=
begin
             int := readinteger(3);
             we_add_the_character_width := true;
             hmove_pending := true;
             setcharacter(int,currfont);
             end;

@
@<set horizontal character4@>=
begin
             int := readinteger(4);
             we_add_the_character_width := true;
             hmove_pending := true;
             setcharacter(int,currfont);
             end;

@
@<set a rule@>=
begin
             ruleht := readinteger(4);
             rulewidth := readinteger(4);
             setrule;
            end;

@
@<put horizontal character1@>=
begin
             int := readinteger(1);
             we_add_the_character_width := false;
             hmove_pending := true;
             setcharacter(int,currfont);
             we_add_the_character_width := true;
             end;

@
@<put horizontal character2@>=
begin
             int := readinteger(2);
             we_add_the_character_width := false;
             hmove_pending := true;
             setcharacter(int,currfont);
             we_add_the_character_width := true;
             end;

@
@<put horizontal character3@>=
begin
             int := readinteger(3);
             we_add_the_character_width := false;
             hmove_pending := true;
             setcharacter(int,currfont);
             we_add_the_character_width := true;
             end;

@
@<put horizontal character4@>=
begin {Put Horizontal Character}
             int := readinteger(4);
             we_add_the_character_width := false;
             hmove_pending := true;
             setcharacter(int,currfont);
             we_add_the_character_width := true;
             end;

@
@<put a rule@>=
begin
             ruleht := readinteger(4);
             rulewidth := readinteger(4);
             realtemp := rulewidth / SPsPerPt / 72.27;
             putrule;
            end;

@
@<push@>=
begin
             tempstack := stack[stacktop];
             stacktop := stacktop + 1;
             stack[stacktop] := tempstack;
             with stack[stacktop] do begin
                  end; {WITH..begin}
             end;

@
@<pop@>=
begin
             tempstack := stack[stacktop];
             inx := stacktop;
             stacktop := stacktop - 1;
             with stack[stacktop] do begin
                  hmove_pending := false;
                  hmove_amt     := 0;
                  print_hmove := true;
                  vmove_amt := vmove_amt + V - tempstack.V;
                  vmove_pending := true;
                  if margin_note and counting_lines
                     then margin_note := false
                     else if numbering_lines and counting_lines
                     and (inx = pop_level)
                        then print_line_number;
                  writecommand(11,H); {HPOS to left margin}
                  end;           {WITH .. do begin}
with tempstack do begin
if put_width = 12.0 then
else if H / SPsPerPt > 554 then
put_width := 12.0;
end;
             end;                {POP}

@
@<right1 move@>=
begin
        int := readinteger(1);
        with stack[stacktop] do begin
          hmove_amt := hmove_amt + int;
          hmove_pending := true;
          h := h + int;
          end; {DO..begin}
        end;

@
@<right2 move@>=
begin
        int := readinteger(2);
        with stack[stacktop] do begin
          hmove_amt := hmove_amt + int;
          hmove_pending := true;
          h := h + int;
          end; {DO..begin}
        end;

@
@<right3 move@>=
begin
        int := readinteger(3);
        with stack[stacktop] do begin
          hmove_amt := hmove_amt + int;
          hmove_pending := true;
          h := h + int;
          end; {DO..begin}
        end;

@
@<right4 move@>=
begin
        int := readinteger(4);
        with stack[stacktop] do begin
          hmove_amt := hmove_amt + int;
          hmove_pending := true;
          h := h + int;
          end; {DO..begin}
        end;

@
@<``W'' horizontal move@>=
begin
             with stack[stacktop] do begin
                  hmove_amt := hmove_amt + W;
                  hmove_pending := true;
                  H := H + W;
                  end; {WITH..begin}
             end;      {"W" amount change}

@
@<``W''1-4 horizontal move@>=
        begin
             size := 4 + (byte - 151);
             int := readinteger(size);
             points := getpts(int);
             hmove_amt := hmove_amt + int;
             hmove_pending := true;
             with stack[stacktop] do begin
                  W := int;       {int is in scalepts}
                  H := H + W;
                  end;      {WITH..begin}
             end;           {"W" change}

@
@<``X'' horizontal move@>=
begin
             with stack[stacktop] do begin
                  hmove_amt := hmove_amt + X;
                  hmove_pending := true;
                  H := H + X;
                  end; {WITH..begin}
             end;      {"X" amount move}

@
@<``X''1-4 horizontal move@>=
        begin
             size := 4 + (byte - 156);
             int := readinteger(size);
             points := getpts(int);
             hmove_amt := hmove_amt + int;
             hmove_pending := true;
             with stack[stacktop] do begin
                  X := int;      ; {saveamt.}
                  H := H + X;    {record the move}
                  end;                {WITH..begin}
             end;                     {"X" amount change}

@
@<down1@>=
begin
             size := 4 + (byte - 160);
             int := readinteger(size);
             points := getpts(int);
             with stack[stacktop] do begin
                  vmove_amt := vmove_amt + int;
                  vmove_pending := true;
                  V := V + int;
                  end; {WITH..begin}
             end;      {"Down" amount move}

@
@<``Y'' vertical move@>=
begin
             with stack[stacktop] do begin
                  vmove_amt := vmove_amt + Y;
                  vmove_pending := true;
                  V := V + Y;
                  end; {WITH..begin}
             end;      {"Y" amount move}

@
@<``Y''1-4 vertical move@>=
        begin
             size := 4 + (byte - 165);
             int := readinteger(size);
             points := getpts(int);
             vmove_amt := vmove_amt + int;
             vmove_pending := true;
             with stack[stacktop] do begin
                  Y := int;          {save amt.}
                  V := V + Y;
                  end;      {WITH..DO begin}
             end; {"Y" amount move}

@
@<``Z'' vertical move@>=
begin
             with stack[stacktop] do begin
                  vmove_amt := vmove_amt + Z;
                  vmove_pending := true;
                  V := V + Z;
                  end; {WITH..begin}
             end; {"Z" amount move}

@
@<``Z''1-4 vertical move@>=
        begin
             size := 4 + (byte - 170);
             int := readinteger(size);
             points := getpts(int);
             vmove_amt := vmove_amt + int;
             vmove_pending := true;
             with stack[stacktop] do begin
                  Z := int;           {save amt.}
                  V := V + Z;
                  end;      {WITH..begin}
             end; {"Z" amount move}

@
@<set font@>=
        begin
        currfont := byte - 171;
        establish_font_parameters(currfont);
        end;

@
@<font1 set@>=
begin
        currfont := readinteger(1);
        establish_font_parameters(currfont);
        end;

@
@<font2 set@>=
begin
        currfont := readinteger(2);
        establish_font_parameters(currfont);
        end;

@
@<font3 set@>=
begin
        currfont := readinteger(3);
{       |establish_font_parameters(currfont);|}
        end;

@
@<font4 set@>=
begin
        currfont := readinteger(4);
{       |establish_font_parameters(currfont);|}
        end;

@
@<nop1@>=
begin
        int := readinteger(1);
        special := '';
        for inx := 1 to int do begin
           temp := readinteger(1);
           special := special  ccat allcaps(str(chrx[temp]));
          end; {DO..begin}
        readspecials;
        end;

@
@<nop2@>=
begin
        int := readinteger(2);
        special := '';
        for inx := 1 to int do begin
           temp := readinteger(1);
           special := special  ccat allcaps(str(chrx[temp]));
          end; {DO..begin}
        readspecials;
        end;

@
@<nop3@>=
begin
        int := readinteger(3);
        special := '';
        for inx := 1 to int do begin
           temp := readinteger(1);
           special := special  ccat allcaps(str(chrx[temp]));
          end; {DO..begin}
        readspecials;
        end;

@
@<nop4@>=
begin
        int := readinteger(4);
        special := '';
        for inx := 1 to int do begin
           temp := readinteger(1);
           special := special  ccat allcaps(str(chrx[temp]));
          end; {DO..begin}
        readspecials;
        end;

@
@<font1 def...@>=
begin
        currfont := readinteger(1);
        fontinfo;
        end;

@
@<font2 def...@>=
begin
        currfont := readinteger(2);
        fontinfo;
        end;

@
@<font3 def...@>=
begin
        currfont := readinteger(3);
        fontinfo;
end;

@
@<font4 def...@>=
begin
        currfont := readinteger(4);
        fontinfo;
        end;

@
@<preamble@>=
begin
        int := readinteger(1);
        int := readinteger(4);
        temp := readinteger(4);
        temp2 := readinteger(4);
        temp := readinteger(1);
        for int := 1 to temp do
           inx := readinteger(1);
        end;

@* INDEX.