1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
|
% patgen.ch for C compilation with web2c.
%
% 07/01/83 (HWT) Original version, made to work with patgen released with
% version 0.99 of TeX in July 1983. It may not work
% properly---it is hard to test without more information.
% 03/23/88 (ETM) Brought up to date, converted for use with WEB to C.
@x WEAVE: print changes only
\pageno=\contentspagenumber \advance\pageno by 1
@y
\pageno=\contentspagenumber \advance\pageno by 1
\let\maybe=\iffalse
\def\title{PATGEN changes for C}
@z
@x [1] Define my_name
@d banner=='This is PATGEN, Version 2.4' {printed when the program starts}
@y
@d my_name=='patgen'
@d banner=='This is PATGEN, Version 2.4' {printed when the program starts}
@z
@x Terminal I/O, Need standard input.
@d get_input(#)==read(input,#)
@d get_input_ln(#)==
begin if eoln(input) then read_ln(input);
read(input,#);
end
@#
@y
@d get_input(#)==#:=input_int(std_input)
@d get_input_ln(#)==begin #:=getc(std_input); read_ln(std_input); end
@#
@d std_input==stdin
@z
@x Eliminate the |end_of_PATGEN| label.
@d end_of_PATGEN=9999
@y
@z
@x
label end_of_PATGEN;
@y
@z
@x Add file opening to initialization
procedure initialize; {this procedure gets things started properly}
var @<Local variables for initialization@>@/
begin print_ln(banner);@/
@y
@<Define |parse_arguments|@>
procedure initialize; {this procedure gets things started properly}
var @<Local variables for initialization@>@/
begin
kpse_set_program_name (argv[0], my_name);
parse_arguments;
print (banner);
print_ln (version_string);
@z
@x Error handling
@d error(#)==begin print_ln(#); jump_out; end
@y
@d error(#)==begin write_ln(stderr, #); uexit(1); end;
@z
@x Fix signed char problem
@!text_char=char; {the data type of characters in text files}
@!ASCII_code=0..last_ASCII_code; {internal representation of input characters}
@y
@!ASCII_code=0..last_ASCII_code; {internal representation of input characters}
@!text_char=ASCII_code; {the data type of characters in text files}
@z
% Much larger values requested from Keno Wehr, 17 May 2019 16:03:00,
% but reduced (76000000/38000000) due to lack of memory on other
% machines, from Johannes Hielscher, 10 Jul 2019 00:00:03 (tex-live list),
% and later from Mojca Miklavec, 23 Sep 2019 21:21:42.
% It seems hopeless, so went back to the original values (10000000/500000).
%
% The real solution is to provide a way to allocate the arrays
% dynamically, so that the large arrays can be used by those who need
% them but other are not affected.
%
% If the values here are still too big, you can probably get it to work
% by adding swap or zram; or write a patch to allocate the arrays dynamically.
@x
@!trie_size=55000; {space for pattern trie}
@!triec_size=26000; {space for pattern count trie, must be less than
|trie_size| and greater than the number of occurrences of any pattern in
the dictionary}
@y
@!trie_size=10000000; {space for pattern trie}
@!triec_size=5000000; {space for pattern count trie, must be less than
|trie_size| and greater than the number of occurrences of any pattern in
the dictionary}
@z
@x
@!max_buf_len=80; {maximum length of input lines, must be at least |max_len|}
@y
@!max_buf_len=3000; {maximum length of input lines, must be at least |max_len|}
@z
@x Close both input and output files.
@d close_out(#)==close(#) {close an output file}
@d close_in(#)==do_nothing {close an input file}
@y
@d close_out(#)==xfclose(#, 'outputfile') {close an output file}
@d close_in(#)==xfclose(#, 'inputfile') {close an input file}
@z
@x Add f_name declaration, and temporaries for efficiency printing.
@!dictionary, @!patterns, @!translate, @!patout, @!pattmp: text_file;
@y
@!dictionary, @!patterns, @!translate, @!patout, @!pattmp: text_file;
@!f_name: ^char;
@!bad_frac, @!denom, @!eff: real;
@z
@x Get translate filename from command line.
reset(translate);
@y
f_name := cmdline (4);
reset (translate, f_name);
@z
@x Input kludge.
repeat print('left_hyphen_min, right_hyphen_min: '); get_input(n1,n2);@/
@y
repeat print('left_hyphen_min, right_hyphen_min: '); input_2ints(n1,n2);@/
@z
@x Floating point output kludge for Web2c.
print_ln(', efficiency = ',
good_count/(good_pat_count+bad_count/bad_eff):1:2)
@y
begin
print(', efficiency = ');
print_real(good_count/(good_pat_count+bad_count/bad_eff),1,2);
write_ln(output);
end
@z
@x Get dictionary filename from command line.
reset(dictionary);@/
@y
f_name := cmdline(1);
reset (dictionary, f_name);
@z
% Fix file name initialization, since can't assign a constant string
% that we're going to write into.
@x
begin filnam:='pattmp. ';
filnam[8]:=xdig[hyph_level];
@y
begin strcpy (filnam, 'pattmp. ');
filnam[7]:=xdig[hyph_level];
@z
@x Work around floating point I/O deficiency; reorder to avoid overflow.
if (good_count+miss_count)>0 then
print_ln((100*good_count/(good_count+miss_count)):1:2,' %, ',
(100*bad_count/(good_count+miss_count)):1:2,' %, ',
(100*miss_count/(good_count+miss_count)):1:2,' %');
@y
if (good_count+miss_count)>0 then
begin print_real((100*(good_count/(good_count+miss_count))),1,2);
print(' %, ');
print_real((100*(bad_count/(good_count+miss_count))),1,2);
print(' %, ');
print_real((100*(miss_count/(good_count+miss_count))),1,2);
print_ln(' %');
end;
@z
@x Get pattern filename from command line.
reset(patterns);
@y
f_name := cmdline (2);
reset (patterns, f_name);
@z
@x Fix reading of multiple variables in the same line
repeat print('hyph_start, hyph_finish: '); get_input(n1,n2);@/
@y
repeat print('hyph_start, hyph_finish: '); input_2ints(n1,n2);@/
@z
@x
repeat print('pat_start, pat_finish: '); get_input(n1,n2);@/
@y
repeat print('pat_start, pat_finish: '); input_2ints(n1,n2);@/
@z
@x
get_input(n1,n2,n3);@/
@y
input_3ints(n1,n2,n3);@/
@z
@x Get output file name from command line.
rewrite(patout);
@y
f_name := cmdline (3);
rewrite (patout, f_name);
@z
@x Eliminate the |end_of_PATGEN| label.
end_of_PATGEN:
@y
@z
@x System-dependent changes.
This section should be replaced, if necessary, by changes to the program
that are necessary to make \.{PATGEN} 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
Parse a Unix-style command line.
@d argument_is (#) == (strcmp (long_options[option_index].name, #) = 0)
@<Define |parse_arguments|@> =
procedure parse_arguments;
const n_options = 2; {Pascal won't count array lengths for us.}
var @!long_options: array[0..n_options] of getopt_struct;
@!getopt_return_val: integer;
@!option_index: c_int_type;
@!current_option: 0..n_options;
begin
@<Define the option table@>;
repeat
getopt_return_val := getopt_long_only (argc, argv, '', long_options,
address_of (option_index));
if getopt_return_val = -1 then begin
do_nothing;
end else if getopt_return_val = '?' then begin
usage (my_name);
end else if argument_is ('help') then begin
usage_help (PATGEN_HELP, nil);
end else if argument_is ('version') then begin
print_version_and_exit (banner, nil,
'Frank M. Liang and Peter Breitenlohner',
nil);
end; {Else it was just a flag; |getopt| has already done the assignment.}
until getopt_return_val = -1;
{Now |optind| is the index of first non-option on the command line.}
if (optind + 4 <> argc) then begin
write_ln (stderr, my_name, ': Need exactly four arguments.');
usage (my_name);
end;
end;
@ Here are the options we allow. The first is one of the standard GNU options.
@.-help@>
@<Define the option...@> =
current_option := 0;
long_options[current_option].name := 'help';
long_options[current_option].has_arg := 0;
long_options[current_option].flag := 0;
long_options[current_option].val := 0;
incr (current_option);
@ Another of the standard options.
@.-version@>
@<Define the option...@> =
long_options[current_option].name := 'version';
long_options[current_option].has_arg := 0;
long_options[current_option].flag := 0;
long_options[current_option].val := 0;
incr (current_option);
@ An element with all zeros always ends the list.
@<Define the option...@> =
long_options[current_option].name := 0;
long_options[current_option].has_arg := 0;
long_options[current_option].flag := 0;
long_options[current_option].val := 0;
@z
|