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