1% vptovf.ch for C compilation with web2c.
2
3@x [0] WEAVE: print changes only.
4\pageno=\contentspagenumber \advance\pageno by 1
5@y
6\pageno=\contentspagenumber \advance\pageno by 1
7\let\maybe=\iffalse
8\def\title{VP$\,$\lowercase{to}$\,$VF changes for C}
9@z
10
11@x [1] Define my_name
12@d banner=='This is VPtoVF, Version 1.6' {printed when the program starts}
13@y
14@d my_name=='vptovf'
15@d banner=='This is VPtoVF, Version 1.6' {printed when the program starts}
16@z
17
18@x [2] Print all terminal output on stderr.
19@d print(#)==write(#)
20@d print_ln(#)==write_ln(#)
21@y
22@d print(#)==write(stderr,#)
23@d print_ln(#)==write_ln(stderr,#)
24@z
25
26@x [2] Print the banner later.
27procedure initialize; {this procedure gets things started properly}
28  var @<Local variables for initialization@>@/
29  begin print_ln(banner);@/
30@y
31@<Define |parse_arguments|@>
32procedure initialize; {this procedure gets things started properly}
33  var @<Local variables for initialization@>@/
34  begin kpse_set_program_name (argv[0], my_name);
35  parse_arguments;
36@z
37
38@x [3] Increase constants.
39@!buf_size=60; {length of lines displayed in error messages}
40@!max_header_bytes=100; {four times the maximum number of words allowed in
41  the \.{TFM} file header block, must be 1024 or less}
42@!vf_size=10000; {maximum length of |vf| data, in bytes}
43@!max_stack=100; {maximum depth of simulated \.{DVI} stack}
44@!max_param_words=30; {the maximum number of \.{fontdimen} parameters allowed}
45@!max_lig_steps=5000;
46  {maximum length of ligature program, must be at most $32767-257=32510$}
47@!max_kerns=500; {the maximum number of distinct kern values}
48@!hash_size=5003; {preferably a prime number, a bit larger than the number
49  of character pairs in lig/kern steps}
50@y
51@!buf_size=3000; {length of lines displayed in error messages}
52@!max_header_bytes=1000; {four times the maximum number of words allowed in
53  the \.{TFM} file header block, must be 1024 or less}
54@!vf_size=100000; {maximum length of |vf| data, in bytes}
55@!max_stack=100; {maximum depth of simulated \.{DVI} stack}
56@!max_param_words=254; {the maximum number of \.{fontdimen} parameters allowed}
57@!max_lig_steps=32510;
58  {maximum length of ligature program, must be at most $32767-257=32510$}
59@!max_kerns=5000; {the maximum number of distinct kern values}
60@!hash_size=32579; {preferably a prime number, a bit larger than the number
61  of character pairs in lig/kern steps}
62@z
63
64@x [6] Open VPL file.
65reset(vpl_file);
66@y
67reset (vpl_file, vpl_name);
68if verbose then begin
69  print (banner);
70  print_ln (version_string);
71end;
72@z
73
74@x [22] Open output files.
75@ On some systems you may have to do something special to write a
76packed file of bytes. For example, the following code didn't work
77when it was first tried at Stanford, because packed files have to be
78opened with a special switch setting on the \PASCAL\ that was used.
79@^system dependencies@>
80
81@<Set init...@>=
82rewrite(vf_file); rewrite(tfm_file);
83@y
84@ On some systems you may have to do something special to write a
85packed file of bytes.
86@^system dependencies@>
87
88@<Set init...@>=
89rewritebin (vf_file, vf_name);
90rewritebin (tfm_file, tfm_name);
91@z
92
93@x [24] Pascal Web's char
94@d first_ord=0 {ordinal number of the smallest element of |char|}
95@y
96@d char == 0..255
97@d first_ord=0 {ordinal number of the smallest element of |char|}
98@z
99
100@x [31] Non-zero return code in case of problems.
101@!chars_on_line:0..8; {the number of characters printed on the current line}
102@y
103@!chars_on_line:0..8; {the number of characters printed on the current line}
104@!perfect:boolean; {was the file free of errors?}
105@z
106
107@x [32] Non-zero return code in case of problems.
108chars_on_line:=0;
109@y
110chars_on_line:=0;
111perfect:=true; {innocent until proved guilty}
112@z
113
114@x [33] Non-zero return code in case of problems.
115chars_on_line:=0;
116@y
117chars_on_line:=0;
118perfect:=false;
119@z
120
121% [89] `index' is not a good choice for an identifier on Unix systems.
122% Neither is `class', on AIX.
123%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124@x
125|k|th element of its list.
126@y
127|k|th element of its list.
128
129@d index == index_var
130@d class == class_var
131@z
132
133@x [118] No output unless verbose.
134@<Print |c| in octal notation@>;
135@y
136if verbose then @<Print |c| in octal notation@>;
137@z
138
139@x [144] Output of real numbers.
140@ @d round_message(#)==if delta>0 then print_ln('I had to round some ',
141@.I had to round...@>
142  #,'s by ',(((delta+1) div 2)/@'4000000):1:7,' units.')
143@y
144@ @d round_message(#)==if delta>0 then begin print('I had to round some ',
145@.I had to round...@>
146  #,'s by '); print_real((((delta+1) div 2)/@'4000000),1,7);
147  print_ln(' units.'); end
148@z
149
150@x [152] Fix up the mutually recursive procedures a la pltotf.
151@p function f(@!h,@!x,@!y:indx):indx; forward;@t\2@>
152  {compute $f$ for arguments known to be in |hash[h]|}
153@y
154@p
155ifdef('notdef')
156function f(@!h,@!x,@!y:indx):indx; begin end;@t\2@>
157  {compute $f$ for arguments known to be in |hash[h]|}
158endif('notdef')
159@z
160
161@x [153] Finish fixing up f.
162@p function f;
163@y
164@p function f(@!h,@!x,@!y:indx):indx;
165@z
166
167@x [156] Change TFM-byte output to fix ranges.
168@d out(#)==write(tfm_file,#)
169@y
170@d out(#)==putbyte(#,tfm_file)
171@z
172
173@x [165] Fix output of reals.
174@p procedure out_scaled(x:fix_word); {outputs a scaled |fix_word|}
175var @!n:byte; {the first byte after the sign}
176@!m:0..65535; {the two least significant bytes}
177begin if abs(x/design_units)>=16.0 then
178  begin print_ln('The relative dimension ',x/@'4000000:1:3,
179    ' is too large.');
180@.The relative dimension...@>
181  print('  (Must be less than 16*designsize');
182  if design_units<>unity then print(' =',design_units/@'200000:1:3,
183      ' designunits');
184@y
185@p procedure out_scaled(x:fix_word); {outputs a scaled |fix_word|}
186var @!n:byte; {the first byte after the sign}
187@!m:0..65535; {the two least significant bytes}
188begin if fabs(x/design_units)>=16.0 then
189  begin print('The relative dimension ');
190    print_real(x/@'4000000,1,3);
191    print_ln(' is too large.');
192@.The relative dimension...@>
193  print('  (Must be less than 16*designsize');
194  if design_units<>unity then begin print(' =');
195	print_real(design_units/@'200000,1,3);
196	print(' designunits');
197  end;
198@z
199
200@x [175] Change VF-byte output to fix ranges.
201@d vout(#)==write(vf_file,#)
202@y
203@d vout(#)==putbyte(#,vf_file)
204@z
205
206@x [181] Be quiet unless verbose.
207read_input; print_ln('.');@/
208@y
209read_input;
210if verbose then print_ln('.');
211@z
212
213@x [181] Non-zero return code in case of problems,
214end.
215@y
216if not perfect then uexit(1);
217end.
218@z
219
220@x [182] System-dependent changes.
221This section should be replaced, if necessary, by changes to the program
222that are necessary to make \.{VPtoVF} work at a particular installation.
223It is usually best to design your change file so that all changes to
224previous sections preserve the section numbering; then everybody's version
225will be consistent with the printed program. More extensive changes,
226which introduce new sections, can be inserted here; then only the index
227itself will get a new section number.
228@^system dependencies@>
229@y
230Parse a Unix-style command line.
231
232@d argument_is (#) == (strcmp (long_options[option_index].name, #) = 0)
233
234@<Define |parse_arguments|@> =
235procedure parse_arguments;
236const n_options = 3; {Pascal won't count array lengths for us.}
237var @!long_options: array[0..n_options] of getopt_struct;
238    @!getopt_return_val: integer;
239    @!option_index: c_int_type;
240    @!current_option: 0..n_options;
241begin
242  @<Initialize the option variables@>;
243  @<Define the option table@>;
244  repeat
245    getopt_return_val := getopt_long_only (argc, argv, '', long_options,
246                                           address_of (option_index));
247    if getopt_return_val = -1 then begin
248      {End of arguments; we exit the loop below.} ;
249
250    end else if getopt_return_val = "?" then begin
251      usage (my_name); {|getopt| has already given an error message.}
252
253    end else if argument_is ('help') then begin
254      usage_help (VPTOVF_HELP, nil);
255
256    end else if argument_is ('version') then begin
257      print_version_and_exit (banner, nil, 'D.E. Knuth', nil);
258
259    end; {Else it was a flag; |getopt| has already done the assignment.}
260  until getopt_return_val = -1;
261
262  {Now |optind| is the index of first non-option on the command line.
263   We must have one to three remaining arguments.}
264  if (optind + 1 <> argc) and (optind + 2 <> argc)
265     and (optind + 3 <> argc) then begin
266    write_ln (stderr, my_name ,': Need one to three file arguments.');
267    usage (my_name);
268  end;
269
270  vpl_name := extend_filename (cmdline (optind), 'vpl');
271
272  if optind + 2 <= argc then begin
273    {Specified one or both of the output files.}
274    vf_name := extend_filename (cmdline (optind + 1), 'vf');
275    if optind + 3 <= argc then begin {Both.}
276      tfm_name := extend_filename (cmdline (optind + 2), 'tfm');
277    end else begin {Just one.}
278      tfm_name := make_suffix (cmdline (optind + 1), 'tfm');
279    end;
280  end else begin {Neither.}
281    vf_name := basename_change_suffix (vpl_name, '.vpl', '.vf');
282    tfm_name := basename_change_suffix (vpl_name, '.vpl', '.tfm');
283  end;
284end;
285
286@ Here are the options we allow.  The first is one of the standard GNU options.
287@.-help@>
288
289@<Define the option...@> =
290current_option := 0;
291long_options[current_option].name := 'help';
292long_options[current_option].has_arg := 0;
293long_options[current_option].flag := 0;
294long_options[current_option].val := 0;
295incr (current_option);
296
297@ Another of the standard options.
298@.-version@>
299
300@<Define the option...@> =
301long_options[current_option].name := 'version';
302long_options[current_option].has_arg := 0;
303long_options[current_option].flag := 0;
304long_options[current_option].val := 0;
305incr (current_option);
306
307@ Print progress information?
308@.-verbose@>
309
310@<Define the option...@> =
311long_options[current_option].name := 'verbose';
312long_options[current_option].has_arg := 0;
313long_options[current_option].flag := address_of (verbose);
314long_options[current_option].val := 1;
315incr (current_option);
316
317@ The global variable |verbose| determines whether or not we print
318progress information.
319
320@<Glob...@> =
321@!verbose: c_int_type;
322
323@ It starts off |false|.
324
325@<Initialize the option...@> =
326verbose := false;
327
328@ An element with all zeros always ends the list.
329
330@<Define the option...@> =
331long_options[current_option].name := 0;
332long_options[current_option].has_arg := 0;
333long_options[current_option].flag := 0;
334long_options[current_option].val := 0;
335
336@ Global filenames.
337
338@<Global...@> =
339@!vpl_name, @!tfm_name, @!vf_name:const_c_string;
340@z
341