GFtoDVI change file for Vax/VMS
Jane Colman, Lawrence Berkeley Laboratory
19 Nov 84

@x
\pageno=\contentspagenumber \advance\pageno by 1
@y
\pageno=\contentspagenumber \advance\pageno by 1
\let\maybe=\iftrue
\def\title{GFtoDVI changes for Vax/VMS}
@z

@x
@d banner=='This is GFtoDVI, Version 1.7' {printed when the program starts}
@y
@d banner=='This is GFtoDVI, Vax/VMS Version 1.7'
@z

@x
@d othercases == others: {default for cases not listed explicitly}
@y
@d othercases == otherwise {default for cases not listed explicitly}
@z

@x
@d print(#)==write(#)
@d print_ln(#)==write_ln(#)
@d print_nl(#)==begin write_ln; write(#);
  end

@p program GF_to_DVI(@!output);
@y
@d crlf==chr(13),chr(10)
@d print(#)==write(#)
@d print_ln(#)==write_ln(#,crlf)
@d print_nl(#)==begin write_ln(crlf); write(#);
  end
@d VAX_carriage_control==@= carriage_control @>
@d VAX_none==@= none @>
@d real==double

@p @=[inherit('sys$library:starlet')]@>@\
 {allows us to use system symbols and routines}
program GF_to_DVI(@!input,@!output,@!gf_file,@!tfm_file,@!dvi_file);
@z

@x
procedure initialize; {this procedure gets things started properly}
  var @!i,@!j,@!m,@!n:integer; {loop indices for initializations}
  begin print_ln(banner);@/
@y
@<Vax/VMS procedures@>@/
procedure initialize; {this procedure gets things started properly}
  var @!i,@!j,@!m,@!n:integer; {loop indices for initializations}
  begin
    open(output,'SYS$OUTPUT',VAX_carriage_control:=VAX_none);
    rewrite(output);
    out_FAB:=@=PAS$FAB@>(output);
    out_RAB:=@=PAS$RAB@>(output);
    print_ln(banner);@/
@z

@x
@<Constants...@>=
@!max_labels=2000; {maximum number of labels and dots per character}
@!pool_size=10000; {maximum total length of labels and other strings}
@!max_strings=1100; {maximum number of labels and other strings}
@!terminal_line_length=150; {maximum number of characters input in a single
  line of input from the terminal}
@!file_name_size=50; {a file name shouldn't be longer than this}
@!font_mem_size=1000; {space for font metric data}
@!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8}
@!widest_row=8192; {maximum number of pixels per row}
@y
@<Constants...@>=
@!max_labels=2000; {maximum number of labels and dots per character}
@!pool_size=10000; {maximum total length of labels and other strings}
@!max_strings=1100; {maximum number of labels and other strings}
@!terminal_line_length=150; {maximum number of characters input in a single
  line of input from the terminal}
@!file_name_size=50; {a file name shouldn't be longer than this}
@!font_mem_size=1000; {space for font metric data}
@!dvi_buf_size=1024; {size of the output buffer;
	must be twice |VAX_block_length|}
@!widest_row=8192; {maximum number of pixels per row}
@z

@x
@d update_terminal == break(output) {empty the terminal output buffer}

@<Glob...@>=
@!buffer:array[0..terminal_line_length] of 0..255;
@!term_in:text_file; {the terminal, considered as an input file}
@y
@d update_terminal == write_ln(output) {empty the terminal output buffer}
@d term_in == input {the terminal, considered as an input file}

@<Glob...@>=
@!buffer:array[0..terminal_line_length] of 0..255;
@z

@x
begin update_terminal; reset(term_in);
if eoln(term_in) then read_ln(term_in);
line_length:=0;
while (line_length<terminal_line_length)and not eoln(term_in) do
  begin buffer[line_length]:=xord[term_in^]; incr(line_length); get(term_in);
  end;
@y
begin update_terminal;
line_length:=0;
while (line_length<terminal_line_length)and not eoln(term_in) do
  begin buffer[line_length]:=xord[term_in^]; incr(line_length); get(term_in);
  end;
buffer[line_length]:=" "; read_ln(term_in);
@z

@x
@!byte_file=packed file of eight_bits; {files that contain binary data}
@y
{later we'll define files that contain binary data}
@z

@x
@!gf_file:byte_file; {the character data we are reading}
@!dvi_file:byte_file; {the typesetting instructions we are writing}
@!tfm_file:byte_file; {a font metric file}
@y
@!gf_file:packed file of byte_block; {the character data we are reading}
@!dvi_file:packed file of byte_block;
	{the typesetting instructions we are writing}
@!tfm_file:packed file of byte_block; {a font metric file}
@!gf_count:integer; {number of bytes read from current block of |gf_file|}
@!dvi_count:integer; {number of bytes read from current block of |dvi_file|}
@!tfm_count:integer; {number of bytes read from current block of |tfm_file|}
@z

@x
begin reset(gf_file,name_of_file);
@y
begin open(gf_file,name_of_file,@=old,error:=continue@>);
reset(gf_file,@=error:=continue@>); gf_count:=0;
@z

@x
begin reset(tfm_file,name_of_file);
@y
begin close(tfm_file,@=error:=continue@>);
  open(tfm_file,name_of_file,@=old,error:=continue@>);
  reset(tfm_file,@=error:=continue@>); tfm_count:=0;
@z

@x
begin rewrite(dvi_file,name_of_file);
@y
begin open(dvi_file,name_of_file,@=new,error:=continue@>);
rewrite(dvi_file); dvi_count:=0;
@z

@x
@p procedure read_tfm_word;
begin read(tfm_file,b0); read(tfm_file,b1);
read(tfm_file,b2); read(tfm_file,b3);
end;
@y
@d read_tfm_file(#) ==
    begin if tfm_count=VAX_block_length then begin
      get(tfm_file,@=error:=continue@>); tfm_count:=0;
    end;
    #:=tfm_file^[tfm_count]; incr (tfm_count);
    end

@p procedure read_tfm_word;
begin read_tfm_file(b0); read_tfm_file(b1);
read_tfm_file(b2); read_tfm_file(b3);
end;
@z

@x
@p function get_byte:integer; {returns the next byte, unsigned}
var b:eight_bits;
begin if eof(gf_file) then get_byte:=0
else  begin read(gf_file,b); incr(cur_loc); get_byte:=b;
  end;
end;
@#
function get_two_bytes:integer; {returns the next two bytes, unsigned}
var a,@!b:eight_bits;
begin read(gf_file,a); read(gf_file,b);
cur_loc:=cur_loc+2;
get_two_bytes:=a*256+b;
end;
@#
function get_three_bytes:integer; {returns the next three bytes, unsigned}
var a,@!b,@!c:eight_bits;
begin read(gf_file,a); read(gf_file,b); read(gf_file,c);
cur_loc:=cur_loc+3;
get_three_bytes:=(a*256+b)*256+c;
end;
@#
function signed_quad:integer; {returns the next four bytes, signed}
var a,@!b,@!c,@!d:eight_bits;
begin read(gf_file,a); read(gf_file,b); read(gf_file,c); read(gf_file,d);
cur_loc:=cur_loc+4;
if a<128 then signed_quad:=((a*256+b)*256+c)*256+d
else signed_quad:=(((a-256)*256+b)*256+c)*256+d;
end;
@y
@d read_gf_file(#) ==
    begin if gf_count=VAX_block_length then begin
      get(gf_file,@=error:=continue@>); gf_count:=0;
    end;
    #:=gf_file^[gf_count]; incr(gf_count);
    end

@p function get_byte:integer; {returns the next byte, unsigned}
var b:eight_bits;
begin if eof(gf_file) then get_byte:=0
else  begin read_gf_file(b); incr(cur_loc); get_byte:=b;
  end;
end;
@#
function get_two_bytes:integer; {returns the next two bytes, unsigned}
var a,@!b:eight_bits;
begin read_gf_file(a); read_gf_file(b);
cur_loc:=cur_loc+2;
get_two_bytes:=a*256+b;
end;
@#
function get_three_bytes:integer; {returns the next three bytes, unsigned}
var a,@!b,@!c:eight_bits;
begin read_gf_file(a); read_gf_file(b); read_gf_file(c);
cur_loc:=cur_loc+3;
get_three_bytes:=(a*256+b)*256+c;
end;
@#
function signed_quad:integer; {returns the next four bytes, signed}
var a,@!b,@!c,@!d:eight_bits;
begin read_gf_file(a); read_gf_file(b); read_gf_file(c); read_gf_file(d);
cur_loc:=cur_loc+4;
if a<128 then signed_quad:=((a*256+b)*256+c)*256+d
else signed_quad:=(((a-256)*256+b)*256+c)*256+d;
end;
@z

@x
@d qi(#)==#+min_quarterword
  {to put an |eight_bits| item into a quarterword}
@d qo(#)==#-min_quarterword
@y
@d qi(#)==#
  {to put an |eight_bits| item into a quarterword}
@d qo(#)==#
@z

@x
following structure:  If the name contains `\.>' or `\.:', the file area
@y
following structure:  If the name contains `\.]' or `\.:', the file area
@z

@x
@!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any}
@y
@!area_delimiter:pool_pointer; {the most recent `\.]' or `\.:', if any}
@z

@x
to place. The program here sets it to `\.{TeXfonts:}'.
@^system dependencies@>
@.TeXfonts@>

@<Initialize the strings@>=
l:=9; init_str9("T")("e")("X")("f")("o")("n")("t")("s")(":")(home_font_area);@/
@y
to place. The program here sets it to `\.{TeX$fonts:}'.
@^system dependencies@>
@.TeX$fonts@>

@<Initialize the strings@>=
l:=10; init_str10("T")("e")("X")("$")("f")("o")("n")("t")("s")(":")
	(home_font_area);@/
@z

@x
else  begin if (c=">")or(c=":") then
@y
else  begin if (c="]")or(c=":") then
@z

@x
Although this routine is system-independent, it should probably be
modified to take the file name from the command line (without an initial
prompt), on systems that permit such things.

@p procedure start_gf;
label found,done;
begin loop@+begin print_nl('GF file name: '); input_ln;
@.GF file name@>
  buf_ptr:=0; buffer[line_length]:="?";
  while buffer[buf_ptr]=" " do incr(buf_ptr);
  if buf_ptr<line_length then
    begin @<Scan the file name in the buffer@>;
    if cur_ext=null_string then cur_ext:=gf_ext;
    pack_file_name(cur_name,cur_area,cur_ext); open_gf_file;
    if not eof(gf_file) then goto found;
    print_nl('Oops... I can''t find file '); print(name_of_file);
@.Oops...@>
@.I can't find...@>
    end;
  end;
@y
On Vax/VMS this routine has been
modified to take the file name from the command line (without an initial
prompt).

@d VAX_volatile==@=volatile@>
@d VAX_aligned==@=aligned@>
@d VAX_immed==@=%immed @>
@d VAX_external==@=external@>
@d VAX_stdescr==@=%stdescr @>
@d VAX_lib_get_foreign==@= lib$get_foreign@>

@p procedure start_gf;
label found,done;
var
@!i,j:integer;
begin
i:=0; j:=VAX_lib_get_foreign(command_line,,cmd_len,i);
i:=1; buf_ptr:=0;
while i<=cmd_len do
  begin buffer[buf_ptr]:=xord[command_line[i]];
    incr(buf_ptr); incr(i);
  end;
line_length:=buf_ptr;
loop@+begin
  buf_ptr:=0; buffer[line_length]:="?";
  while buffer[buf_ptr]=" " do incr(buf_ptr);
  if buf_ptr<line_length then
    begin @<Scan the file name in the buffer@>;
    if cur_ext=null_string then cur_ext:=gf_ext;
    pack_file_name(cur_name,cur_area,cur_ext); open_gf_file;
    if not eof(gf_file) then goto found;
    print_nl('Oops... I can''t find file '); print_ln(name_of_file);
@.Oops...@>
@.I can't find...@>
    end;
 print('GF file name: '); input_ln;
@.GF file name@>
  end;
@z

@x
@ Some systems may find it more efficient to make |dvi_buf| a |packed|
array, since output of four bytes at once may be facilitated.
@^system dependencies@>

@<Glob...@>=
@!dvi_buf:array[dvi_index] of eight_bits; {buffer for \.{DVI} output}
@y
@ Some systems may find it more efficient to make |dvi_buf| a |packed|
array, since output of four bytes at once may be facilitated.
On Vax/VMS, we get even more complicated than that, for efficiency.
@^system dependencies@>

@d dvi_buf==d_buffer.b {buffer for \.{DVI} output}

@<Glob...@>=
@!d_buffer: [VAX_volatile,VAX_aligned(9)] packed record
    case boolean of
        false: (b:packed array[dvi_index] of eight_bits);
        true:  (l:byte_block; r:byte_block; j:eight_bits);
    end;
@z

@x
@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
|write_dvi(a,b)|. It is safe to assume that |a| and |b+1| will both be
multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on
many machines to use efficient methods to pack four bytes per word and to
output an array of words with one system call.
@^system dependencies@>

@p procedure write_dvi(@!a,@!b:dvi_index);
var k:dvi_index;
begin for k:=a to b do write(dvi_file,dvi_buf[k]);
end;
@y
@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
|write| on the other variant of the |dvi_buf| record.
@^system dependencies@>
@z

@x
  begin write_dvi(0,half_buf-1); dvi_limit:=half_buf;
@y
  begin write(dvi_file,d_buffer.l); dvi_limit:=half_buf;
@z

@x
else  begin write_dvi(half_buf,dvi_buf_size-1); dvi_limit:=dvi_buf_size;
@y
else  begin write(dvi_file,d_buffer.r); dvi_limit:=dvi_buf_size;
@z

@x
if dvi_limit=half_buf then write_dvi(half_buf,dvi_buf_size-1);
if dvi_ptr>0 then write_dvi(0,dvi_ptr-1)
@y
if dvi_limit=half_buf then write(dvi_file,d_buffer.r);
for k:=dvi_ptr to dvi_buf_size do dvi_buf[k]:=223;
if dvi_ptr>0 then write(dvi_file,d_buffer.l);
if dvi_ptr>half_buf then write(dvi_file,d_buffer.r);
@z

@x
This section should be replaced, if necessary, by changes to the program
that are necessary to make \.{GFtoDVI} work at a particular installation.
It is usually best to design your change file so that all changes to
previous sections preserve the section numbering; then everybody's version
will be consistent with the printed program. More extensive changes,
which introduce new sections, can be inserted here; then only the index
itself will get a new section number.
@^system dependencies@>
@y
Here are the remaining changes to the program that are necessary to
make \.{GFtoDVI} work on Vax/VMS.
@^system dependencies@>

@<Constants...@>=
VAX_block_length=512;

@ @<Types ...@>=
byte_block=packed array[0..VAX_block_length-1] of 0..255;
sixteen_bits=0..65535;

@ @<Glob...@>=
@!command_line: packed array[1..terminal_line_length] of char;
@!cmd_len:sixteen_bits;

@ Here is the library procedure that gets the user's command line.

@<Vax/VMS procedures@>=
[VAX_external]
function VAX_lib_get_foreign(VAX_stdescr cmdlin:[VAX_volatile]
packed array[$l1..$u1:integer]of char:=VAX_immed 0;
VAX_stdescr prompt:[VAX_volatile]packed array[$l2..$u2:integer]
of char:=VAX_immed 0;
var len:[VAX_volatile]sixteen_bits:=VAX_immed 0;
var flag:[VAX_volatile]integer:=VAX_immed 0):integer;extern;

@ Here is the stuff for magic file operations.
@<Types ...@>=
unsafe_file = [unsafe] file of char;
FAB_ptr = ^@=FAB$TYPE@>;
RAB_ptr = ^@=RAB$TYPE@>;

@ @<Vax/VMS procedures@>=
function@= PAS$FAB@>(var foobar:unsafe_file):FAB_ptr; extern;
function@= PAS$RAB@>(var foobar:unsafe_file):RAB_ptr; extern;

@ @<Glob...@>=
out_FAB: FAB_ptr;
out_RAB: RAB_ptr;
@z