%%%  WEB Change File for METAFONT (Win32 version)
%%%  Time-stamp: "97/01/31 11:37:49 cschenk"
%%%
%%%  Copyright (C) 1991, 92, 93, 94, 95, 96, 97
%%%	Christian Schenk  <cschenk@berlin.snafu.de>
%%%
%%%  This file is part of MiKTeX.
%%%
%%%  MiKTeX is free software; you can redistribute it and/or
%%%  modify it under the terms of the GNU General Public License as
%%%  published by the Free Software Foundation; either version 2, or (at
%%%  your option) any later version.
%%%  
%%%  MiKTeX is distributed in the hope that it will be useful, but
%%%  WITHOUT ANY WARRANTY; without even the implied warranty of
%%%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
%%%  General Public License for more details.
%%%  
%%%  You should have received a copy of the GNU General Public License
%%%  along with MiKTeX; if not, write to the Free Software
%%%  Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
%%%  USA.

@x
\def\title{{\eightlogo METAFONT}}
@y
\def\MiKTeX{MiK\TeX}
\def\title{{\eightlogo METAFONT} for Win32 (\MiKTeX\ 1.06)}
@z

%% **     4  ******************************************************************

@x
@t\4@>@<Basic printing procedures@>@/
@y
@t\4@>@<External C routines@>@/
@t\4@>@<Basic printing procedures@>@/
@z

%% **     6  ******************************************************************

@x
@d start_of_MF=1 {go here when \MF's variables are initialized}
@d end_of_MF=9998 {go here to close files and terminate gracefully}
@d final_end=9999 {this label marks the ending of the program}
@y
@d start_of_MF=1 {go here when \MF's variables are initialized}
@d end_of_MF=9998 {go here to close files and terminate gracefully}
@d final_end=9999 {this label marks the ending of the program}
@d goto_fin_end==c4p_longjmp(fin_buf,1)
@d goto_eof_MF==c4p_longjmp(eo_MF_buf,1)
@z

%% **     7  ******************************************************************

@x debug
@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
@f debug==begin
@f gubed==end
@y debug
@d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging}
@d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging}
@f debug==begin
@f gubed==end
@z debug

%% **     7  ******************************************************************

@x stat
@d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering
  usage statistics}
@d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering
  usage statistics}
@y stat
@d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering
  usage statistics}
@d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering
  usage statistics}
@z stat

%% **     8  ******************************************************************

@x init
@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
@y init
@d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version}
@d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version}
@z init

%% **    11  ******************************************************************

@x mem_max
@!mem_max=30000; {greatest index in \MF's internal |mem| array;
  must be strictly less than |max_halfword|;
  must be equal to |mem_top| in \.{INIMF}, otherwise |>=mem_top|}
@y mem_max
@!mem_max=262136; {greatest index in \MF's internal |mem| array;
  must be strictly less than |max_halfword|;
  must be equal to |mem_top| in \.{INIMF}, otherwise |>=mem_top|}
@z mem_max

@x
@!max_internal=100; {maximum number of internal quantities}
@y
@!max_internal=300; {maximum number of internal quantities}
@z

@x
@!buf_size=500; {maximum number of characters simultaneously present in
  current lines of open files; must not exceed |max_halfword|}
@y
@!buf_size=3000; {maximum number of characters simultaneously present in
  current lines of open files; must not exceed |max_halfword|}
@z

@x error_line
@!error_line=72; {width of context lines on terminal error messages}
@y error_line
@!error_line=72; {width of context lines on terminal error messages}
@z error_line

@x half_error_line
@!half_error_line=42; {width of first lines of contexts in terminal
  error messages; should be between 30 and |error_line-15|}
@y half_error_line
@!half_error_line=42; {width of first lines of contexts in terminal
  error messages; should be between 30 and |error_line-15|}
@z half_error_line

@x max_print_line
@!max_print_line=79; {width of longest text lines output; should be at least 60}
@y max_print_line
@!max_print_line=72; {width of longest text lines output; should be at least 60}
@z max_print_line

@x screen_width
@!screen_width=768; {number of pixels in each row of screen display}
@y screen_width
@!screen_width=768; {number of pixels in each row of screen display}
@z screen_width

@x screen_depth
@!screen_depth=1024; {number of pixels in each column of screen display}
@y screen_depth
@!screen_depth=1024; {number of pixels in each column of screen display}
@z screen_depth

@x
@!stack_size=30; {maximum number of simultaneous input sources}
@y
@!stack_size=300; {maximum number of simultaneous input sources}
@z

@x
@!max_strings=2000; {maximum number of strings; must not exceed |max_halfword|}
@y
@!max_strings=7500; {maximum number of strings; must not exceed |max_halfword|}
@z

@x
@!string_vacancies=8000; {the minimum number of characters that should be
  available for the user's identifier names and strings,
  after \MF's own error messages are stored}
@y
@!string_vacancies=74000; {the minimum number of characters that should be
  available for the user's identifier names and strings,
  after \MF's own error messages are stored}
@z

@x
@!pool_size=32000; {maximum number of characters in strings, including all
  error messages and help texts, and the names of all identifiers;
  must exceed |string_vacancies| by the total
  length of \MF's own strings, which is currently about 22000}
@y
@!pool_size=100000; {maximum number of characters in strings, including all
  error messages and help texts, and the names of all identifiers;
  must exceed |string_vacancies| by the total
  length of \MF's own strings, which is currently about 22000}
@z

@x
@!move_size=5000; {space for storing moves in a single octant}
@y
@!move_size=20000; {space for storing moves in a single octant}
@z

@x
@!max_wiggle=300; {number of autorounded points per cycle}
@y
@!max_wiggle=1000; {number of autorounded points per cycle}
@z

@x gf_buf_size
@!gf_buf_size=800; {size of the output buffer, must be a multiple of 8}
@y gf_buf_size
@!gf_buf_size=8192; {size of the output buffer, must be a multiple of 8}
@z gf_buf_size

@x
@!file_name_size=40; {file names shouldn't be longer than this}
@y
@!file_name_size=256; {file names shouldn't be longer than this}
@!fil_name_size=257;
@z

@x
@!pool_name='MFbases:MF.POOL                         ';
  {string of length |file_name_size|; tells where the string pool appears}
@.MFbases@>
@y
@!pool_name='[METAFONT]Base Dirs:mf.pool';
  {name of the pool file; tells where the string pool appears}
@z

@x
@!path_size=300; {maximum number of knots between breakpoints of a path}
@y
@!path_size=1000; {maximum number of knots between breakpoints of a path}
@z

@x
@!bistack_size=785; {size of stack for bisection algorithms;
  should probably be left at this value}
@y
@!bistack_size=1500; {size of stack for bisection algorithms;
  should probably be left at this value}
@z

@x
@!header_size=100; {maximum number of \.{TFM} header words, times~4}
@y
@!header_size=100; {maximum number of \.{TFM} header words, times~4}
@z

@x
@!lig_table_size=5000; {maximum number of ligature/kern steps, must be
  at least 255 and at most 32510}
@y
@!lig_table_size=15000; {maximum number of ligature/kern steps, must be
  at least 255 and at most 32510}
@z

@x
@!max_kerns=500; {maximum number of distinct kern amounts}
@y
@!max_kerns=2500; {maximum number of distinct kern amounts}
@z

@x
@!max_font_dimen=50; {maximum number of \&{fontdimen} parameters}
@y
@!max_font_dimen=50; {maximum number of \&{fontdimen} parameters}
@z

%% **    12  ******************************************************************

@x
@d mem_min=0 {smallest index in the |mem| array, must not be less
  than |min_halfword|}
@y
@d mem_min=0 {smallest index in the |mem| array, must not be less
  than |min_halfword|}
@z

@x mem_top
@d mem_top==30000 {largest index in the |mem| array dumped by \.{INIMF};
  must be substantially larger than |mem_min|
  and not greater than |mem_max|}
@y mem_top
@d mem_top==262136 {largest index in the |mem| array dumped by \.{INIMF};
  must be substantially larger than |mem_min|
  and not greater than |mem_max|}
@z mem_top

@x
@d hash_size=2100 {maximum number of symbolic tokens,
  must be less than |max_halfword-3*param_size|}
@y
@d hash_size=9500 {maximum number of symbolic tokens,
  must be less than |max_halfword-3*param_size|}
@z

@x
@d hash_prime=1777 {a prime number equal to about 85\pct! of |hash_size|}
@y
@d hash_prime=7919 {a prime number equal to about 85\pct! of |hash_size|}
@z

@x
@d max_in_open=6 {maximum number of input files and error insertions that
  can be going on simultaneously}
@y
@d max_in_open=20 {maximum number of input files and error insertions that
  can be going on simultaneously}
@z

@x
@d param_size=150 {maximum number of simultaneous macro parameters}
@^system dependencies@>
@y
@d param_size=150 {maximum number of simultaneous macro parameters}
@^system dependencies@>
@z

%% **    19  ******************************************************************

@x
@d text_char == char {the data type of characters in text files}
@d first_text_char=0 {ordinal number of the smallest element of |text_char|}
@d last_text_char=255 {ordinal number of the largest element of |text_char|}
@y
@d text_char == char {the data type of characters in text files}
@d first_text_char=-128 {ordinal number of the smallest element of |text_char|}
@d last_text_char=127 {ordinal number of the largest element of |text_char|}
@^signed characters@>
@d tabulator=9
@d form_feed=12
@z

%% **    22  ******************************************************************

@x
Appropriate changes to \MF's |char_class| table should then be made.
(Unlike \TeX, each installation of \MF\ has a fixed assignment of category
codes, called the |char_class|.) Such changes make portability of programs
more difficult, so they should be introduced cautiously if at all.
@^character set dependencies@>
@^system dependencies@>

@<Set init...@>=
for i:=0 to @'37 do xchr[i]:=' ';
for i:=@'177 to @'377 do xchr[i]:=' ';
@y
Appropriate changes to \MF's |char_class| table should then be made.
(Unlike \TeX, each installation of \MF\ has a fixed assignment of category
codes, called the |char_class|.) Such changes make portability of programs
more difficult, so they should be introduced cautiously if at all.
@^character set dependencies@>
@^system dependencies@>

@<Set init...@>=
for i:=0 to @'37 do xchr[i]:=chr(i);
for i:=@'177 to @'377 do xchr[i]:=chr(i);
@z

%% **    25  ******************************************************************

@x
@!name_of_file:packed array[1..file_name_size] of char;@;@/
  {on some systems this may be a \&{record} variable}
@!name_length:0..file_name_size;@/{this many characters are actually
  relevant in |name_of_file| (the rest are blank)}
@y
@!name_of_file:packed array[1..fil_name_size] of char;@;@/
  {on some systems this may be a \&{record} variable}
@!name_length:0..file_name_size;@/{this many characters are actually
  relevant in |name_of_file|}
@z

%% **    26  ******************************************************************

@x
@ The \ph\ compiler with which the present version of \MF\ was prepared has
extended the rules of \PASCAL\ in a very convenient way. To open file~|f|,
we can write
$$\vbox{\halign{#\hfil\qquad&#\hfil\cr
|reset(f,@t\\{name}@>,'/O')|&for input;\cr
|rewrite(f,@t\\{name}@>,'/O')|&for output.\cr}}$$
The `\\{name}' parameter, which is of type `\ignorespaces|packed
array[@t\<\\{any}>@>] of text_char|', stands for the name of
the external file that is being opened for input or output.
Blank spaces that might appear in \\{name} are ignored.

The `\.{/O}' parameter tells the operating system not to issue its own
error messages if something goes wrong. If a file of the specified name
cannot be found, or if such a file cannot be opened for some other reason
(e.g., someone may already be trying to write the same file), we will have
|@!erstat(f)<>0| after an unsuccessful |reset| or |rewrite|.  This allows
\MF\ to undertake appropriate corrective action.
@:PASCAL H}{\ph@>
@^system dependencies@>

\MF's file-opening procedures return |false| if no file identified by
|name_of_file| could be opened.

@d reset_OK(#)==erstat(#)=0
@d rewrite_OK(#)==erstat(#)=0

@p function a_open_in(var @!f:alpha_file):boolean;
  {open a text file for input}
begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f);
end;
@#
function a_open_out(var @!f:alpha_file):boolean;
  {open a text file for output}
begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f);
end;
@#
function b_open_out(var @!f:byte_file):boolean;
  {open a binary file for output}
begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f);
end;
@#
function w_open_in(var @!f:word_file):boolean;
  {open a word file for input}
begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f);
end;
@#
function w_open_out(var @!f:word_file):boolean;
  {open a word file for output}
begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f);
end;

@ Files can be closed with the \ph\ routine `|close(f)|', which
@^system dependencies@>
should be used when all input or output with respect to |f| has been completed.
This makes |f| available to be opened again, if desired; and if |f| was used for
output, the |close| operation makes the corresponding external file appear
on the user's area, ready to be read.

@p procedure a_close(var @!f:alpha_file); {close a text file}
begin close(f);
end;
@#
procedure b_close(var @!f:byte_file); {close a binary file}
begin close(f);
end;
@#
procedure w_close(var @!f:word_file); {close a word file}
begin close(f);
end;
@y
@ We can use the routine |@!c4p_try_fopen()| for file opening:
$$\vbox{\halign{#\hfil\qquad&#\hfil\cr
|c4p_try_fopen(f,@t\\{name}@>,@!c4p_r_mode);|&input;\cr
|c4p_try_fopen(f,@t\\{name}@>,@!c4p_w_mode);|&output;\cr
|c4p_try_fopen(f,@t\\{name}@>,@!c4p_rb_mode);|&binary input;\cr
|c4p_try_fopen(f,@t\\{name}@>,@!c4p_wb_mode);|&binary output.\cr}}$$
The `\\{name}' parameter, which is of type `{\bf packed array
$[\langle\\{any}\rangle]$ of \\{char}}', stands for the name of
the external file that is being opened for input or output. It must
be zero terminated.
@^system dependencies@>

\MF's file-opening procedures return |false| if no file identified by
|name_of_file| could be opened.

@d a_open_out(#)==c4p_try_fopen(#,name_of_file,c4p_w_mode)
  {open a text file for output}
@d b_open_out(#)==c4p_try_fopen(#,name_of_file,c4p_wb_mode)
  {open a byte file for output}
@d w_open_out(#)==c4p_try_fopen(#,name_of_file,c4p_wb_mode)
  {open a word file for output}

@p function a_open_in(var f:alpha_file):boolean;
  {open a text file for input}
begin if not mt_open_input_file(f) then a_open_in:=false
   else begin a_open_in:=true; end;
end;

@ Files can be closed with the routine `|@!c4p_fclose(f)|', which
@^system dependencies@>
should be used when all input or output with respect to |f| has been completed.
This makes |f| available to be opened again, if desired; and if |f| was used for
output, the |close| operation makes the corresponding external file appear
on the user's area, ready to be read.

These procedures should not generate error messages if a file is
being closed before it has been successfully opened.

@d a_close(#)==c4p_fclose(#) {close a text file}
@d b_close(#)==c4p_fclose(#) {close a binary file}
@d w_close(#)==c4p_fclose(#) {close a word file}
@z

%% **    30  ******************************************************************

@x
@p function input_ln(var @!f:alpha_file;@!bypass_eoln:boolean):boolean;
  {inputs the next line or returns |false|}
var @!last_nonblank:0..buf_size; {|last| with trailing blanks removed}
begin if bypass_eoln then if not eof(f) then get(f);
  {input the first character of the line into |f^|}
last:=first; {cf.\ Matthew 19\thinspace:\thinspace30}
if eof(f) then input_ln:=false
else  begin last_nonblank:=first;
  while not eoln(f) do
    begin if last>=max_buf_stack then
      begin max_buf_stack:=last+1;
      if max_buf_stack=buf_size then
        @<Report overflow of the input buffer, and abort@>;
      end;
    buffer[last]:=xord[f^]; get(f); incr(last);
    if buffer[last-1]<>" " then last_nonblank:=last;
    end;
  last:=last_nonblank; input_ln:=true;
  end;
end;
@y
@p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean;forward;
@z

%% **    32  ******************************************************************

@x
@ Here is how to open the terminal files
in \ph. The `\.{/I}' switch suppresses the first |get|.
@^system dependencies@>

@d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input}
@d t_open_out==rewrite(term_out,'TTY:','/O') {open the terminal for text output}
@y
@ Here we open the terminal files.
@^system dependencies@>

@d t_open_in==term_in:=i@&nput
@d t_open_out==term_out:=output
@z

%% **    33  ******************************************************************

@x
some instruction to the operating system.  The following macros show how
these operations can be specified in \ph:
@^system dependencies@>

@d update_terminal == break(term_out) {empty the terminal output buffer}
@d clear_terminal == break_in(term_in,true) {clear the terminal input buffer}
@d wake_up_terminal == do_nothing {cancel the user's cancellation of output}
@y
some instruction to the operating system.
@^system dependencies@>

@d update_terminal == break(term_out) {empty the terminal output buffer}
@d clear_terminal == break(term_in) {clear the terminal input buffer}
@d wake_up_terminal == do_nothing {cancel the user's cancellation of output}
@z

%% **    34  ******************************************************************

@x
  begin write_ln(term_out,'Buffer size exceeded!'); goto final_end;
@y
  begin write_ln('Buffer size exceeded!'); goto_fin_end;
@z

%% **    36  ******************************************************************

@x
@ The following program does the required initialization
without retrieving a possible command line.
It should be clear how to modify this routine to deal with command lines,
if the system permits them.
@^system dependencies@>

@p function init_terminal:boolean; {gets the terminal input started}
label exit;
begin t_open_in;
loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal;
@.**@>
  if not input_ln(term_in,true) then {this shouldn't happen}
    begin write_ln(term_out);
    write(term_out,'! End of file on the terminal... why?');
@.End of file on the terminal@>
    init_terminal:=false; return;
    end;
  loc:=first;
@y
@ The following program does the required initialization.

@p function init_terminal:boolean; {gets the terminal input started}
label exit;
begin t_open_in;
loop@+begin if (c4p_plen > 0) then
  begin
  loc:=0; last:=c4p_plen;
  c4p_memcpy(buffer,c4p_pline,c4p_plen);
  c4p_plen:=0;
  end else begin wake_up_terminal; write(term_out,'**'); update_terminal;
@.**@>
    if not input_ln(term_in,true) then {this shouldn't happen}
      begin write_ln(term_out);
      write(term_out,'! End of file on the terminal... why?');
@.End of file on the terminal@>
      init_terminal:=false; return;
      end;
  end;
  loc:=first;
@z

%% **    51  ******************************************************************

@x
name_of_file:=pool_name; {we needn't set |name_length|}
if a_open_in(pool_file) then
@y
c4p_strcpy(name_of_file, pool_name); {we needn't set |name_length|}
if mt_open_pool_file(pool_file) then
@z

%% **    61  ******************************************************************

@x
wterm(banner);
if base_ident=0 then wterm_ln(' (no base preloaded)')
else  begin slow_print(base_ident); print_ln;
  end;
@y
wterm(banner);
miktex_banner(term_out);
if base_ident=0 then print_ln {|wterm_ln(' (no base preloaded)')|}
else  begin slow_print(base_ident); print_ln;
  end;
@z

%% **    76  ******************************************************************

@x
`|close_files_and_terminate|;\thinspace' followed by a call on some system
procedure that quietly terminates the program.

@<Error hand...@>=
procedure jump_out;
begin goto end_of_MF;
end;
@y
`|close_files_and_terminate|;\thinspace' followed by a call on some system
procedure that quietly terminates the program.

@<Error hand...@>=
procedure jump_out;
begin goto_eof_MF;
end;
@z

%% **   153  ******************************************************************

@x min_quarterword
@d min_quarterword=0 {smallest allowable value in a |quarterword|}
@d max_quarterword=255 {largest allowable value in a |quarterword|}
@d min_halfword==0 {smallest allowable value in a |halfword|}
@d max_halfword==65535 {largest allowable value in a |halfword|}
@y min_quarterword
@d min_quarterword=0 {smallest allowable value in a |quarterword|}
@d max_quarterword=1023 {largest allowable value in a |quarterword|}
@d min_halfword==0 {smallest allowable value in a |halfword|}
@d max_halfword==@"3FFFFFFF {largest allowable value in a |halfword|}
@z min_quarterword

%% **   194  ******************************************************************

@x
Since standard \PASCAL\ cannot provide such information, something special
is needed. The program here simply specifies July 4, 1776, at noon; but
users probably want a better approximation to the truth.

Note that the values are |scaled| integers. Hence \MF\ can no longer
be used after the year 32767.

@p procedure fix_date_and_time;
begin internal[time]:=12*60*unity; {minutes since midnight}
internal[day]:=4*unity; {fourth day of the month}
internal[month]:=7*unity; {seventh month of the year}
internal[year]:=1776*unity; {Anno Domini}
end;
@y
Note that the values are |scaled| integers. Hence \MF\ can no longer
be used after the year 32767.

@p procedure fix_date_and_time;
begin internal[time]:=(c4p_hour*60+c4p_minute)*unity; {minutes since midnight}
internal[day]:=c4p_day*unity; {day of month}
internal[month]:=c4p_month*unity; {month of year}
internal[year]:=c4p_year*unity; {Anno Domini}
end;
@z

%% **   199  ******************************************************************

@x
for k:=0 to " "-1 do char_class[k]:=invalid_class;
for k:=127 to 255 do char_class[k]:=invalid_class;
@y
for k:=0 to " "-1 do char_class[k]:=invalid_class;
for k:=127 to 255 do char_class[k]:=invalid_class;
char_class[tabulator]:=space_class;
char_class[form_feed]:=space_class;
@z

%% **   564  ******************************************************************

@x init_screen
begin init_screen:=false;
@y init_screen
begin init_screen:=false;
@z init_screen

%% **   768  ******************************************************************

@x
@ The file names we shall deal with for illustrative purposes have the
following structure:  If the name contains `\.>' or `\.:', the file area
consists of all characters up to and including the final such character;
otherwise the file area is null.  If the remaining file name contains
`\..', the file extension consists of all such characters from the first
remaining `\..' to the end, otherwise the file extension is null.
@^system dependencies@>

We can scan such file names easily by using two global variables that keep track
of the occurrences of area and extension delimiters:

@<Glob...@>=
@!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any}
@!ext_delimiter:pool_pointer; {the relevant `\..', if any}

@ Input files that can't be found in the user's area may appear in a standard
system area called |MF_area|.
This system area name will, of course, vary from place to place.
@^system dependencies@>

@d MF_area=="MFinputs:"
@.MFinputs@>
@y
@ File names have the
following structure:  If the name contains `\./', the file area
consists of all characters up to and including the final `\./';
otherwise the file area is null.  If the remaining file name contains
`\..', the file extension consists of all such characters from the first
remaining `\..' to the end, otherwise the file extension is null.
@^system dependencies@>

We can scan such file names easily by using two global variables that keep track
of the occurrences of area and extension delimiters:

@<Glob...@>=
@!area_delimiter:pool_pointer; {the most recent `\./', if any}
@!ext_delimiter:pool_pointer; {the relevant `\..', if any}

@ Input files that can't be found in the user's area may appear in a standard
system area called |MF_area|.
This system area name will, of course, vary from place to place.
@^system dependencies@>

@d MF_area=="[METAFONT]Input Dirs:"
@.[METAFONT]Input Dirs:@>
@z

%% **   771  ******************************************************************

@x
begin if c=" " then more_name:=false
else  begin if (c=">")or(c=":") then
@y
begin if c=" " or c=tabulator then more_name:=false
else  begin if (c="/") then
@z

%% **   774  ******************************************************************

@x
for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
@y
name_of_file[ name_length + 1 ]:= chr(0);
@z

%% **   775  ******************************************************************

@x
@ A messier routine is also needed, since base file names must be scanned
before \MF's string mechanism has been initialized. We shall use the
global variable |MF_base_default| to supply the text for default system areas
and extensions related to base files.
@^system dependencies@>

@d base_default_length=18 {length of the |MF_base_default| string}
@d base_area_length=8 {length of its area part}
@d base_ext_length=5 {length of its `\.{.base}' part}
@d base_extension=".base" {the extension, as a \.{WEB} constant}

@<Glob...@>=
@!MF_base_default:packed array[1..base_default_length] of char;

@ @<Set init...@>=
MF_base_default:='MFbases:plain.base';
@.MFbases@>
@.plain@>
@^system dependencies@>
@y
@ We shall use the
global variable |MF_base_default| to supply the text for default names
and extensions related to base files.
@^system dependencies@>

@d base_default_length=10 {length of the |MF_base_default| string}
@d base_defaultz_length=base_default_length+1
@d base_ext_length=5 {length of its `\.{.base}' part}
@d base_extension=".base" {the extension, as a \.{WEB} constant}

@<Glob...@>=
@!MF_base_default:packed array[1..base_defaultz_length] of char;

@ @<Set init...@>=
c4p_strcpy(MF_base_default,'plain.base');
@.plain@>
@^system dependencies@>
@z

%% **   778  ******************************************************************

@x
@ Here is the messy routine that was just mentioned. It sets |name_of_file|
from the first |n| characters of |MF_base_default|, followed by
|buffer[a..b]|, followed by the last |base_ext_length| characters of
|MF_base_default|.

We dare not give error messages here, since \MF\ calls this routine before
the |error| routine is ready to roll. Instead, we simply drop excess characters,
since the error will be detected in another way when a strange file name
isn't found.
@^system dependencies@>

@p procedure pack_buffered_name(@!n:small_number;@!a,@!b:integer);
var @!k:integer; {number of positions filled in |name_of_file|}
@!c: ASCII_code; {character being packed}
@!j:integer; {index into |buffer| or |MF_base_default|}
begin if n+b-a+1+base_ext_length>file_name_size then
  b:=a+file_name_size-n-1-base_ext_length;
k:=0;
for j:=1 to n do append_to_name(xord[MF_base_default[j]]);
for j:=a to b do append_to_name(buffer[j]);
for j:=base_default_length-base_ext_length+1 to base_default_length do
  append_to_name(xord[MF_base_default[j]]);
if k<=file_name_size then name_length:=k@+else name_length:=file_name_size;
for k:=name_length+1 to file_name_size do name_of_file[k]:=' ';
end;

@ Here is the only place we use |pack_buffered_name|. This part of the program
becomes active when a ``virgin'' \MF\ is trying to get going, just after
the preliminary initialization, or when the user is substituting another
base file by typing `\.\&' after the initial `\.{**}' prompt.  The buffer
contains the first line of input in |buffer[loc..(last-1)]|, where
|loc<last| and |buffer[loc]<>" "|.

@<Declare the function called |open_base_file|@>=
function open_base_file:boolean;
label found,exit;
var @!j:0..buf_size; {the first space after the file name}
begin j:=loc;
if buffer[loc]="&" then
  begin incr(loc); j:=loc; buffer[last]:=" ";
  while buffer[j]<>" " do incr(j);
  pack_buffered_name(0,loc,j-1); {try first without the system file area}
  if w_open_in(base_file) then goto found;
  pack_buffered_name(base_area_length,loc,j-1);
    {now try the system base file area}
  if w_open_in(base_file) then goto found;
  wake_up_terminal;
  wterm_ln('Sorry, I can''t find that base;',' will try PLAIN.');
@.Sorry, I can't find...@>
  update_terminal;
  end;
  {now pull out all the stops: try for the system \.{plain} file}
pack_buffered_name(base_default_length-base_ext_length,1,0);
if not w_open_in(base_file) then
  begin wake_up_terminal;
  wterm_ln('I can''t find the PLAIN base file!');
@.I can't find PLAIN...@>
@.plain@>
  open_base_file:=false; return;
  end;
found:loc:=j; open_base_file:=true;
exit:end;
@y
@

@ This part of the program
becomes active when a ``virgin'' \MF\ is trying to get going, just after
the preliminary initialization, or when the user is substituting another
base file by typing `\.\&' after the initial `\.{**}' prompt.  The buffer
contains the first line of input in |buffer[loc..(last-1)]|, where
|loc<last| and |buffer[loc]<>" "|.

@<Declare the function called |open_base_file|@>=
function open_base_file:boolean;
label found,exit;
var @!j:0..buf_size; {the first space after the file name}
begin j:=loc;
if buffer[loc]="&" then
  begin incr(loc); j:=loc; buffer[last]:=" ";
  while buffer[j]<>" " do incr(j);
  c4p_memcpy(name_of_file,c4p_ptr(buffer[loc]),j-loc);
  c4p_strcpy(c4p_ptr(name_of_file[j-loc+1]),
    c4p_ptr(MF_base_default[base_default_length-base_ext_length+1]));
  if mt_open_base_file(base_file)
         then goto found;
  wake_up_terminal;
  wterm_ln('Sorry, I can''t find that base;',' will try PLAIN.');
@.Sorry, I can't find...@>
  update_terminal;
  end;
  {now pull out all the stops: try for the system \.{plain} file}
c4p_strcpy(name_of_file,MF_base_default);
if not mt_open_base_file(base_file) then
  begin wake_up_terminal;
  wterm_ln('I can''t find the PLAIN base file!');
@.I can't find PLAIN...@>
@.plain@>
  open_base_file:=false; return;
  end;
found:loc:=j; open_base_file:=true;
exit:end;
@z

%% **   780  ******************************************************************

@x
@p function make_name_string:str_number;
var @!k:1..file_name_size; {index into |name_of_file|}
begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings) then
  make_name_string:="?"
else  begin for k:=1 to name_length do append_char(xord[name_of_file[k]]);
  make_name_string:=make_string;
  end;
end;
function a_make_name_string(var @!f:alpha_file):str_number;
begin a_make_name_string:=make_name_string;
end;
function b_make_name_string(var @!f:byte_file):str_number;
begin b_make_name_string:=make_name_string;
end;
function w_make_name_string(var @!f:word_file):str_number;
begin w_make_name_string:=make_name_string;
end;
@y
@d a_make_name_string(#)==make_name_string
@d b_make_name_string(#)==make_name_string
@d w_make_name_string(#)==make_name_string

@p function make_name_string:str_number;
var @!k:1..file_name_size; {index into |name_of_file|}
begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings) then
  make_name_string:="?"
else  begin for k:=1 to name_length do append_char(xord[name_of_file[k]]);
  make_name_string:=make_string;
  end;
end;
@z

%% **   790  ******************************************************************

@x
begin wlog(banner);
slow_print(base_ident); print("  ");
print_int(round_unscaled(internal[day])); print_char(" ");
months:='JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC';
@y
begin wlog(banner);
miktex_banner(log_file);
slow_print(base_ident); print("  ");
print_int(round_unscaled(internal[day])); print_char(" ");
c4p_arrcpy(months,'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC');
@z

%% **   793  ******************************************************************

%@x
    begin pack_file_name(cur_name,MF_area,cur_ext);
    if a_open_in(cur_file) then goto done;
%@y
    begin pack_file_name(cur_name,MF_area,cur_ext);
    if a_open_in(cur_file) then goto done;
%@z

%% **  1154  ******************************************************************

@x
@ The actual output of |gf_buf[a..b]| to |gf_file| is performed by calling
|write_gf(a,b)|. It is safe to assume that |a| and |b+1| will both be
multiples of 4 when |write_gf(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@>

@<Declare generic font output procedures@>=
procedure write_gf(@!a,@!b:gf_index);
var k:gf_index;
begin for k:=a to b do write(gf_file,gf_buf[k]);
end;
@y
@ The actual output of |gf_buf[a..b]| to |gf_file| is performed by calling
|write_gf(a,b)|. It is safe to assume that |a| and |b+1| will both be
multiples of 4 when |write_gf(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@>

@<Declare generic font output procedures@>=
procedure write_gf(@!a,@!b:gf_index);
begin c4p_buf_write(gf_file,c4p_ptr(gf_buf[a]),b-a+1);
end;
@z

%% **  1204  ******************************************************************

@x
The initial test involving |ready_already| should be deleted if the
\PASCAL\ runtime system is smart enough to detect such a ``mistake.''
@^system dependencies@>

@p begin @!{|start_here|}
@y
The initial test involving |ready_already| should be deleted if the
\PASCAL\ runtime system is smart enough to detect such a ``mistake.''
@^system dependencies@>

@p begin @!{|start_here|}
if c4p_setjmp (eo_MF_buf) <> 0 then goto end_of_MF;
if c4p_setjmp (fin_buf) <> 0 then goto final_end;
mt_first_word;
mt_get_options;
@z

@x
ready_already:=314159;
@y
ready_already:=314159;
mt_after_init;
@z

@x
final_end: ready_already:=0;
@y
final_end: ready_already:=0;
mt_last_word;
if (history = error_message_issued) or (history = fatal_error_stop) then
begin
  c4p_exit (1);
end;
@z

%% **  1205  ******************************************************************

@x
@.Transcript written...@>
    slow_print(log_name); print_char(".");
    end;
  end;
@y
@.Transcript written...@>
    slow_print(log_name); print_char(".");
    end;
  end;
print_ln;
@z

%% **  1214  ******************************************************************

@x
itself will get a new section number.
@^system dependencies@>
@y
itself will get a new section number.
@^system dependencies@>

@ @<External C routines@>=

procedure mt_first_word; forward;
procedure mt_after_init; forward;
procedure mt_last_word; forward;
procedure mt_get_options; forward;
function mt_open_base_file (var f:word_file) : boolean; forward;
function mt_open_pool_file (var f:alpha_file) : boolean; forward;
function mt_open_input_file (var f:alpha_file) : boolean; forward;
procedure miktex_banner (var f:alpha_file); forward;

@ @<Global variables@>=
@!eo_MF_buf, @!fin_buf : c4p_jmp_buf;
@z
