1% Change file for BibTeX in C, originally by Howard Trickey.
2%
3% 05/28/84      Initial implementation, version 0.41 of BibTeX
4% 07/01/84      Version 0.41a of BibTeX.
5% 12/17/84      Version 0.97c of BibTeX.
6% 02/12/85      Version 0.98c of BibTeX.
7% 02/25/85      Newer version 0.98c of BibTeX.
8% 03/25/85      Version 0.98f of BibTeX
9% 05/23/85      Version 0.98i of BibTeX
10% 02/11/88      Version 0.99b of BibTeX
11% 04/04/88      Version 0.99c; converted for use with web2c (ETM).
12% 11/30/89      Use FILENAMESIZE instead of 1024 (KB).
13% 03/09/90	`int' is a bad variable name for C.
14% (more recent changes in the ChangeLog)
15
16% [0] Let bibtex.tex work with latest webmac (which defines \ET, hence
17% making E active loses).
18@x
19\catcode`E=13 \uppercase{\def E{e}}
20\def\\#1{\hbox{\let E=\drop\it#1\/\kern.05em}} % italic type for identifiers
21@y
22\let\maybe = \iffalse % process only changed sections
23@z
24
25@x [1] Define my_name
26@d banner=='This is BibTeX, Version 0.99d' {printed when the program starts}
27@y
28@d my_name=='bibtex'
29@d banner=='This is BibTeX, Version 0.99d' {printed when the program starts}
30@z
31
32% [2] `term_in' and `term_out' are standard input and output.  But
33% there is a complication: BibTeX passes `term_out' to some routines as
34% a var parameter.  web2c turns a var parameter f into &f at the calling
35% side -- and stdout is sometimes implemented as `&_iob[1]' or some
36% such.  An address of an address is invalid. Therefore, we define
37% variables `standardinput' and `standardoutput' in openinout.c.
38@x
39@d term_out == tty
40@d term_in == tty
41@y
42@d term_out == standard_output
43@d term_in == standard_input
44
45@<Globals in the outer block@>=
46standard_input, standard_output: text;
47@z
48
49@x [3] Add log_pr macros.
50@d trace_pr_newline == begin write_ln(log_file); end
51@y
52@d trace_pr_newline == begin write_ln(log_file); end
53@#
54@d log_pr(#) == trace_pr(#)
55@d log_pr_ln(#) == trace_pr_ln(#)
56@d log_pr_newline == trace_pr_newline
57@z
58
59@x [4] Turn debug..gubed et al. into #ifdef's.
60@d debug == @{          { remove the `|@{|' when debugging }
61@d gubed == @t@>@}      { remove the `|@}|' when debugging }
62@f debug == begin
63@f gubed == end
64@#
65@d stat == @{           { remove the `|@{|' when keeping statistics }
66@d tats == @t@>@}       { remove the `|@}|' when keeping statistics }
67@f stat == begin
68@f tats == end
69@#
70@d trace == @{          { remove the `|@{|' when in |trace| mode }
71@d ecart == @t@>@}      { remove the `|@}|' when in |trace| mode }
72@f trace == begin
73@f ecart == end
74@y
75@d debug == ifdef('TEXMF_DEBUG')
76@d gubed == endif('TEXMF_DEBUG')
77@f debug == begin
78@f gubed == end
79@#
80@d stat == ifndef('NO_BIBTEX_STAT')
81@d tats == endifn('NO_BIBTEX_STAT')
82@f stat==begin
83@f tats==end
84@#
85@d trace == ifdef@&('TRACE')
86@d ecart == endif@&('TRACE')
87@f trace == begin
88@f ecart == end
89@z
90
91@x [10] Eliminate the |exit_program| label.
92label   close_up_shop,@!exit_program @<Labels in the outer block@>;
93@y
94label   close_up_shop @<Labels in the outer block@>;
95@z
96
97@x [10] Don't print the banner unless verbose, and initialize dynamic arrays.
98begin
99initialize;
100print_ln(banner);@/
101@y
102@<Define |parse_arguments|@>
103begin
104standard_input := stdin;
105standard_output := stdout;
106@#
107pool_size := POOL_SIZE;
108buf_size := BUF_SIZE;
109max_bib_files := MAX_BIB_FILES;
110max_glob_strs := MAX_GLOB_STRS;
111max_fields := MAX_FIELDS;
112max_cites := MAX_CITES;
113wiz_fn_space := WIZ_FN_SPACE;
114lit_stk_size := LIT_STK_SIZE;
115@#
116setup_params;
117@#
118{Add one to the sizes because that's what bibtex uses.}
119bib_file   := XTALLOC (max_bib_files + 1, alpha_file);
120bib_list   := XTALLOC (max_bib_files + 1, str_number);
121entry_ints := nil;
122entry_strs := nil;
123wiz_functions := XTALLOC (wiz_fn_space + 1, hash_ptr2);
124field_info := XTALLOC (max_fields + 1, str_number);
125s_preamble := XTALLOC (max_bib_files + 1, str_number);
126str_pool   := XTALLOC (pool_size + 1, ASCII_code);
127buffer     := XTALLOC (buf_size + 1, ASCII_code);
128sv_buffer  := XTALLOC (buf_size + 1, ASCII_code);
129ex_buf     := XTALLOC (buf_size + 1, ASCII_code);
130out_buf    := XTALLOC (buf_size + 1, ASCII_code);
131name_tok   := XTALLOC (buf_size + 1, buf_pointer);
132name_sep_char := XTALLOC (buf_size + 1, ASCII_code);
133@#
134glb_str_ptr := XTALLOC (max_glob_strs, str_number);
135global_strs := XTALLOC (max_glob_strs * (glob_str_size + 1), ASCII_code);
136glb_str_end := XTALLOC (max_glob_strs, integer);
137@#
138cite_list  := XTALLOC (max_cites + 1, str_number);
139type_list  := XTALLOC (max_cites + 1, hash_ptr2);
140entry_exists := XTALLOC (max_cites + 1, boolean);
141cite_info  := XTALLOC (max_cites + 1, str_number);
142@#
143str_start  := XTALLOC (max_strings + 1, pool_pointer);
144@#
145hash_next  := XTALLOC (hash_max + 1, hash_pointer);
146hash_text  := XTALLOC (hash_max + 1, str_number);
147hash_ilk   := XTALLOC (hash_max + 1, str_ilk);
148ilk_info   := XTALLOC (hash_max + 1, integer);
149fn_type    := XTALLOC (hash_max + 1, fn_class);
150@#
151lit_stack  := XTALLOC (lit_stk_size + 1, integer);
152lit_stk_type := XTALLOC (lit_stk_size + 1, stk_type);
153@#
154compute_hash_prime;
155@#
156initialize;
157{This initializes the jmp9998 buffer, which can be used early}
158hack0;
159if verbose then begin
160  print (banner);
161  print_ln (version_string);
162end
163else begin
164  log_pr (banner);
165  log_pr_ln (version_string);
166end;
167log_pr_ln ('Capacity: max_strings=', max_strings:1,
168           ', hash_size=', hash_size:1, ', hash_prime=', hash_prime:1);
169@z
170
171% [10] Possibly exit with bad status.  It doesn't seem worth it to move
172% the definitions of the |history| values to above this module; hence the 1.
173@x
174exit_program:
175end.
176@y
177if (history > 1) then uexit (history);
178end.
179@z
180
181@x [13] Remove nonlocal goto.
182    goto exit_program;
183@y
184    uexit (1);
185@z
186
187@x [14] Increase some constants, and uppercase others for dynamic arrays.
188@<Constants in the outer block@>=
189@y
190@<Constants in the outer block@>=
191@!hash_base = empty + 1;                {lowest numbered hash-table location}
192@!quote_next_fn = hash_base - 1;  {special marker used in defining functions}
193@z
194
195@x [still 14]
196@!buf_size=1000; {maximum number of characters in an input line (or string)}
197@y
198@!BUF_SIZE=20000; {initial maximum number of characters in an input line
199                                                                (or string)}
200@z
201
202@x [still 14]
203@!max_bib_files=20; {maximum number of \.{.bib} files allowed}
204@!pool_size=65000; {maximum number of characters in strings}
205@!max_strings=4000; {maximum number of strings, including pre-defined;
206                                                        must be |<=hash_size|}
207@!max_cites=750; {maximum number of distinct cite keys; must be
208                                                        |<=max_strings|}
209@!min_crossrefs=2; {minimum number of cross-refs required for automatic
210                                                        |cite_list| inclusion}
211@!wiz_fn_space=3000; {maximum amount of |wiz_defined|-function space}
212@y [still 14]
213@!MAX_BIB_FILES=20; {initial number of \.{.bib} files allowed}
214@!POOL_SIZE=65000; {initial number of characters in strings}
215@!MAX_STRINGS=4000; {minimum value for |max_strings|}
216@!MAX_CITES=750; {initial number of distinct cite keys; must be
217                                                        |<=max_strings|}
218@!WIZ_FN_SPACE=3000; {initial amount of |wiz_defined|-function space}
219{|min_crossrefs| can be set at runtime now.}
220@z
221
222@x [still 14]
223@!single_fn_space=100; {maximum amount for a single |wiz_defined|-function}
224@y
225@!SINGLE_FN_SPACE=50; {initial amount for a single |wiz_defined|-function}
226@z
227
228@x [still 14] handle long citation strings
229@!max_ent_ints=3000; {maximum number of |int_entry_var|s
230                                        (entries $\times$ |int_entry_var|s)}
231@!max_ent_strs=3000; {maximum number of |str_entry_var|s
232                                        (entries $\times$ |str_entry_var|s)}
233@!ent_str_size=100; {maximum size of a |str_entry_var|; must be |<=buf_size|}
234@!glob_str_size=1000; {maximum size of a |str_global_var|;
235                                                        must be |<=buf_size|}
236@!max_fields=17250; {maximum number of fields (entries $\times$ fields,
237@y
238@!ENT_STR_SIZE=100; {maximum size of a |str_entry_var|; must be |<=buf_size|}
239@!GLOB_STR_SIZE=1000; {maximum  size of a |str_global_var|;
240                                                        must be |<=buf_size|}
241@!MAX_GLOB_STRS=10;    {initial number of |str_global_var| names}
242@!MAX_FIELDS=5000; {initial number of fields (entries $\times$ fields,
243@z
244
245@x [still 14]
246@!lit_stk_size=100; {maximum number of literal functions on the stack}
247@y
248@!LIT_STK_SIZE=50; {initial space for literal functions on the stack}
249@z
250
251@x [15] Increase more constants in the web defines.
252@d hash_size=5000       {must be |>= max_strings| and |>= hash_prime|}
253@d hash_prime=4253      {a prime number about 85\% of |hash_size| and |>= 128|
254                                                and |< @t$2^{14}-2^6$@>|}
255@d file_name_size=40    {file names shouldn't be longer than this}
256@d max_glob_strs=10     {maximum number of |str_global_var| names}
257@d max_glb_str_minus_1 = max_glob_strs-1  {to avoid wasting a |str_global_var|}
258@y
259{|hash_size| and |hash_prime| are now computed.}
260@d HASH_SIZE=5000       {minimum value for |hash_size|}
261@#
262@d file_name_size==maxint {file names have no arbitrary maximum length}
263@#
264{For dynamic allocation.}
265@d x_entry_strs_tail(#) == (#)]
266@d x_entry_strs(#) == entry_strs[(#) * (ent_str_size+1) + x_entry_strs_tail
267@d x_global_strs_tail(#) == (#)]
268@d x_global_strs(#) == global_strs[(#) * (glob_str_size+1) + x_global_strs_tail
269@z
270
271@x [16] Add new variables-that-used-to-be-constants for dynamic arrays.
272@<Globals in the outer block@>=
273@y
274@<Globals in the outer block@>=
275@!pool_size: integer;
276@!max_bib_files: integer;
277@!max_cites: integer;
278@!wiz_fn_space: integer;
279@!ent_str_size: integer;
280@!glob_str_size: integer;
281@!max_glob_strs: integer;
282@!max_fields: integer;
283@!lit_stk_size: integer;
284@#
285@!max_strings: integer;
286@!hash_size: integer;
287@!hash_prime: integer;
288@#
289@!hash_max: integer;     {highest numbered hash-table location}
290@!end_of_def: integer;   {another special marker used in defining functions}
291@!undefined: integer;    {a special marker used for |type_list|}
292@z
293
294@x [17] max_strings=hash_size settable at runtime.
295if (hash_prime >= (16384-64)) then              bad:=10*bad+6;
296@y
297if (hash_base <> 1) then                        bad:=10*bad+6;
298@z
299
300@x [17] remove the following, since buf_size changes dynamically.
301if (ent_str_size > buf_size) then               bad:=10*bad+9;
302if (glob_str_size > buf_size) then              bad:=100*bad+11;
303@y
304@z
305
306@x [22, 23, 27, 28] Allow any character as input. [22]
307@!ASCII_code=0..127;    {seven-bit numbers}
308@y
309@!ASCII_code=0..255;    {eight-bit numbers}
310@z
311
312@x [23]
313@d text_char == char    {the data type of characters in text files}
314@d first_text_char=0    {ordinal number of the smallest element of |text_char|}
315@d last_text_char=127   {ordinal number of the largest element of |text_char|}
316
317@<Local variables for initialization@>=
318i:0..last_text_char;    {this is the first one declared}
319@y
320@d text_char == ASCII_code    {the data type of characters in text files}
321@d first_text_char=0    {ordinal number of the smallest element of |text_char|}
322@d last_text_char=255   {ordinal number of the largest element of |text_char|}
323
324@<Local variables for initialization@>=
325i:integer;
326@z
327
328@x [27]
329for i:=1 to @'37 do xchr[i]:=' ';
330xchr[tab]:=chr(tab);
331@y
332for i:=0 to @'37 do xchr[i]:=chr(i);
333for i:=@'177 to @'377 do xchr[i]:=chr(i);
334@z
335
336@x [28]
337for i:=first_text_char to last_text_char do xord[chr(i)]:=invalid_code;
338for i:=1 to @'176 do xord[xchr[i]]:=i;
339@y
340for i:=first_text_char to last_text_char do xord[xchr[i]]:=i;
341@z
342
343@x [32] Put the [128..255] range into lex_class alpha.
344for i:=0 to @'177 do lex_class[i] := other_lex;
345@y
346for i:=0 to @'177 do lex_class[i] := other_lex;
347for i:=@'200 to @'377 do lex_class[i] := alpha;
348@z
349
350% [32] Make RET a `white_space' character, so we won't choke on DOS
351% files, which use CR/LF for line endings.
352@x
353lex_class[tab] := white_space;
354@y
355lex_class[tab] := white_space;
356lex_class[13] := white_space;
357@z
358
359@x [33] Allow the [128..255] range in legal_id_char.
360for i:=0 to @'177 do id_class[i] := legal_id_char;
361@y
362for i:=0 to @'377 do id_class[i] := legal_id_char;
363@z
364
365% [37] file_name_size no longer exists.  See comments in tex.ch for why
366% we change the element type to text_char.
367@x
368@!name_of_file:packed array[1..file_name_size] of char;
369                         {on some systems this is a \&{record} variable}
370@!name_length:0..file_name_size;
371  {this many characters are relevant in |name_of_file| (the rest are blank)}
372@!name_ptr:0..file_name_size+1;         {index variable into |name_of_file|}
373@y
374@!name_of_file:^text_char;
375@!name_length:integer;
376  {this many characters are relevant in |name_of_file| }
377@!name_ptr:integer;         {index variable into |name_of_file|}
378@z
379
380@x [38] File opening.
381The \ph\ compiler with which the present version of \TeX\ was prepared has
382extended the rules of \PASCAL\ in a very convenient way. To open file~|f|,
383we can write
384$$\vbox{\halign{#\hfil\qquad&#\hfil\cr
385|reset(f,@t\\{name}@>,'/O')|&for input;\cr
386|rewrite(f,@t\\{name}@>,'/O')|&for output.\cr}}$$
387The `\\{name}' parameter, which is of type `\ignorespaces|packed
388array[@t\<\\{any}>@>] of text_char|', stands for the name of
389the external file that is being opened for input or output.
390Blank spaces that might appear in \\{name} are ignored.
391
392The `\.{/O}' parameter tells the operating system not to issue its own
393error messages if something goes wrong. If a file of the specified name
394cannot be found, or if such a file cannot be opened for some other reason
395(e.g., someone may already be trying to write the same file), we will have
396|@!erstat(f)<>0| after an unsuccessful |reset| or |rewrite|.  This allows
397\TeX\ to undertake appropriate corrective action.
398
399\TeX's file-opening procedures return |false| if no file identified by
400|name_of_file| could be opened.
401
402@d reset_OK(#)==erstat(#)=0
403@d rewrite_OK(#)==erstat(#)=0
404
405@<Procedures and functions for file-system interacting@>=
406function erstat(var f:file):integer; extern;    {in the runtime library}
407@#@t\2@>
408function a_open_in(var f:alpha_file):boolean;   {open a text file for input}
409begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f);
410end;
411@#
412function a_open_out(var f:alpha_file):boolean;  {open a text file for output}
413begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f);
414end;
415@y
416@ File opening will be done in C.
417@d no_file_path = -1
418@z
419
420@x [39] Do file closing in C.
421@<Procedures and functions for file-system interacting@>=
422procedure a_close(var f:alpha_file);            {close a text file}
423begin close(f);
424end;
425@y
426File closing will be done in C, too.
427@z
428
429@x [42] Dynamic buf_size.
430@!buffer:buf_type;      {usually, lines of characters being read}
431@y
432@!buf_size:integer;     {size of buffer}
433@!buffer:buf_type;      {usually, lines of characters being read}
434@z
435
436@x [43] Dyanmic buf_size.
437@!buf_pointer = 0..buf_size;                    {an index into a |buf_type|}
438@!buf_type = array[buf_pointer] of ASCII_code;  {for various buffers}
439@y
440@!buf_pointer = integer;                        {an index into a |buf_type|}
441@!buf_type = ^ASCII_code;                       {for various buffers}
442@z
443
444@x [47] Dynamic buf_size.
445overflow('buffer size ',buf_size);
446@y
447BIB_XRETALLOC_NOSET ('buffer', buffer, ASCII_code,
448                     buf_size, buf_size + BUF_SIZE);
449BIB_XRETALLOC_NOSET ('sv_buffer', sv_buffer, ASCII_code,
450                     buf_size, buf_size + BUF_SIZE);
451BIB_XRETALLOC_NOSET ('ex_buf', ex_buf, ASCII_code,
452                     buf_size, buf_size + BUF_SIZE);
453BIB_XRETALLOC_NOSET ('out_buf', out_buf, ASCII_code,
454                     buf_size, buf_size + BUF_SIZE);
455BIB_XRETALLOC_NOSET ('name_tok', name_tok, buf_pointer,
456                     buf_size, buf_size + BUF_SIZE);
457BIB_XRETALLOC ('name_sep_char', name_sep_char, ASCII_code,
458               buf_size, buf_size + BUF_SIZE);
459@z
460
461@x [48] web2c doesn't understand f^.
462    buffer[last]:=xord[f^];
463    get(f); incr(last);
464    end;
465  get(f);
466@y
467    buffer[last] := xord[getc (f)];
468    incr (last);
469    end;
470  vgetc (f); {skip the eol}
471@z
472
473@x [49] Dynamically allocate str_pool.
474@!str_pool : packed array[pool_pointer] of ASCII_code;  {the characters}
475@!str_start : packed array[str_number] of pool_pointer; {the starting pointers}
476@y
477@!str_pool : ^ASCII_code;   {the characters}
478@!str_start :^pool_pointer; {the starting pointers}
479@z
480
481@x [50] pool_size is a variable now, so can't be used as a constant.
482@!pool_pointer = 0..pool_size;  {for variables that point into |str_pool|}
483@!str_number = 0..max_strings;  {for variables that point into |str_start|}
484@y
485@!pool_pointer = integer; {for variables that point into |str_pool|}
486@!str_number = integer;   {for variables that point into |str_start|}
487@z
488
489@x [51] Add log_pr_pool_str macro.
490@d trace_pr_pool_str(#) == begin
491                           out_pool_str(log_file,#);
492                           end
493@y
494@d trace_pr_pool_str(#) == begin
495                           out_pool_str(log_file,#);
496                           end
497@#
498@d log_pr_pool_str(#) == trace_pr_pool_str(#)
499@z
500
501@x [54] Reallocate str_pool.  We may need more than POOL_SIZE.
502  if (pool_ptr+# > pool_size) then
503@y
504  while (pool_ptr+# > pool_size) do
505@z
506@x [54] Reallocate str_pool.
507overflow('pool size ',pool_size);
508@y
509BIB_XRETALLOC ('str_pool', str_pool, ASCII_code, pool_size,
510               pool_size + POOL_SIZE);
511@z
512
513% [59] (start_name) reallocate name_of_file for the new name and
514% terminate with null.
515@x
516if (length(file_name) > file_name_size) then
517    begin
518    print ('File=');
519    print_pool_str (file_name);
520    print_ln (',');
521    file_nm_size_overflow;
522    end;
523@y
524free (name_of_file);
525name_of_file := xmalloc_array (ASCII_code, length (file_name) + 1);
526@z
527
528@x
529name_length := length(file_name);
530@y
531name_length := length(file_name);
532name_of_file[name_length + 1] := 0;
533@z
534
535@x [60] (file_nm_size_overflow) This procedure is not used.
536procedure file_nm_size_overflow;
537begin
538overflow('file name size ',file_name_size);
539end;
540@y
541@z
542
543% [61] (add_extension) Don't pad name_of_file with blanks, terminate
544% with null. And junk the overflow check, since Web2c can't translate
545% the print statement properly and it can never happen, anyway.
546@x
547if (name_length + length(ext) > file_name_size) then
548    begin
549    print ('File=',name_of_file,', extension=');
550    print_pool_str (ext); print_ln (',');
551    file_nm_size_overflow;
552    end;
553@y
554@z
555@x
556name_ptr := name_length+1;
557while (name_ptr <= file_name_size) do   {pad with blanks}
558    begin
559    name_of_file[name_ptr] := ' ';
560    incr(name_ptr);
561    end;
562@y
563name_of_file[name_length + 1] := 0;
564@z
565
566@x [62] (add_area) This procedure is not used.
567procedure add_area(@!area:str_number);
568var p_ptr: pool_pointer;        {running index}
569begin
570if (name_length + length(area) > file_name_size) then
571    begin
572    print ('File=');
573    print_pool_str (area); print (name_of_file,',');
574    file_nm_size_overflow;
575    end;
576name_ptr := name_length;
577while (name_ptr > 0) do         {shift up name}
578    begin
579    name_of_file[name_ptr+length(area)] := name_of_file[name_ptr];
580    decr(name_ptr);
581    end;
582name_ptr := 1;
583p_ptr := str_start[area];
584while (p_ptr < str_start[area+1]) do
585    begin
586    name_of_file[name_ptr] := chr (str_pool[p_ptr]);
587    incr(name_ptr); incr(p_ptr);
588    end;
589name_length := name_length + length(area);
590end;
591@y
592@z
593
594@x [65] now Pascal consts or vars, instead of web macros.
595@d hash_base = empty + 1                {lowest numbered hash-table location}
596@d hash_max = hash_base + hash_size - 1 {highest numbered hash-table location}
597@y
598@z
599
600@x [65] max_strings=hash_size settable at runtime.
601@!hash_loc=hash_base..hash_max;         {a location within the hash table}
602@!hash_pointer=empty..hash_max;         {either |empty| or a |hash_loc|}
603@y
604@!hash_loc=integer;             {a location within the hash table}
605@!hash_pointer=integer;         {either |empty| or a |hash_loc|}
606@z
607
608@x [66] max_strings=hash_size settable at runtime.
609@!hash_next : packed array[hash_loc] of hash_pointer;   {coalesced-list link}
610@!hash_text : packed array[hash_loc] of str_number;     {pointer to a string}
611@!hash_ilk : packed array[hash_loc] of str_ilk;         {the type of string}
612@!ilk_info : packed array[hash_loc] of integer;         {|ilk|-specific info}
613@!hash_used : hash_base..hash_max+1;    {allocation pointer for hash table}
614@y
615@!hash_next : ^hash_pointer;   {coalesced-list link}
616@!hash_text : ^str_number;     {pointer to a string}
617@!hash_ilk : ^str_ilk;         {the type of string}
618@!ilk_info : ^integer;         {|ilk|-specific info}
619@!hash_used : integer;    {allocation pointer for hash table}
620@z
621
622@x [69] Not used anymore.
623@d max_hash_value = hash_prime+hash_prime-2+127         {|h|'s maximum value}
624@y
625@z
626
627@x [69] max_strings=hash_size settable at runtime.
628var h:0..max_hash_value;        {hash code}
629@y
630var h:integer;        {hash code}
631@z
632
633@x [69] str_lookup - Avoid 'uninitialized' warning.
634@!old_string:boolean;   {set to |true| if it's an already encountered string}
635@y
636@z
637
638@x [69] str_lookup - Avoid 'uninitialized' warning.
639old_string := false;
640@y
641str_num := 0;           {set to |>0| if it's an already encountered string}
642@z
643
644@x [71] str_lookup - Avoid 'uninitialized' warning.
645            old_string := true;
646@y
647@z
648
649@x [72] str_lookup - Avoid 'uninitialized' warning.
650if (old_string) then            {it's an already encountered string}
651@y
652if (str_num>0) then             {it's an already encountered string}
653@z
654
655@x [74] Pascal Web's char
656@!pds_type = packed array [pds_loc] of char;
657@y
658@!pds_type = const_cstring;
659@z
660
661@x [78] C strings start at zero instead of one.
662for i:=1 to len do
663    buffer[i] := xord[pds[i]];
664@y
665for i:=1 to len do
666    buffer[i] := xord[ucharcast(pds[i-1])];
667@z
668
669@x [98] Can't do this tangle-time arithmetic with file_name_size.
670@!aux_name_length : 0..file_name_size+1;        {\.{.aux} name sans extension}
671@y
672@!aux_name_length : integer;
673@z
674
675@x [101] Reading the aux file name and command-line processing.
676This procedure consists of a loop that reads and processes a (nonnull)
677\.{.aux} file name.  It's this module and the next two that must be
678changed on those systems using command-line arguments.  Note: The
679|term_out| and |term_in| files are system dependent.
680
681@<Procedures and functions for the reading and processing of input files@>=
682procedure get_the_top_level_aux_file_name;
683label aux_found,@!aux_not_found;
684var @<Variables for possible command-line processing@>@/
685begin
686check_cmnd_line := false;                       {many systems will change this}
687loop
688    begin
689    if (check_cmnd_line) then
690        @<Process a possible command line@>
691      else
692        begin
693        write (term_out,'Please type input file name (no extension)--');
694        if (eoln(term_in)) then                 {so the first |read| works}
695            read_ln (term_in);
696        aux_name_length := 0;
697        while (not eoln(term_in)) do
698            begin
699            if (aux_name_length = file_name_size) then
700                begin
701                while (not eoln(term_in)) do    {discard the rest of the line}
702                    get(term_in);
703                sam_you_made_the_file_name_too_long;
704                end;
705            incr(aux_name_length);
706            name_of_file[aux_name_length] := term_in^;
707            get(term_in);
708            end;
709        end;
710    @<Handle this \.{.aux} name@>;
711aux_not_found:
712    check_cmnd_line := false;
713    end;
714aux_found:                      {now we're ready to read the \.{.aux} file}
715end;
716@y
717@<Procedures and functions for the reading and processing of input files@>=
718procedure get_the_top_level_aux_file_name;
719label aux_found,@!aux_not_found;
720begin
721  @<Process a possible command line@>
722  {Leave room for the \.., the extension, the junk byte at the
723   beginning, and the null byte at the end.}
724  name_of_file := xmalloc_array (ASCII_code, strlen (cmdline (optind)) + 5);
725  strcpy (stringcast(name_of_file + 1), cmdline (optind));
726  aux_name_length := strlen (stringcast(name_of_file + 1));
727  @<Handle this \.{.aux} name@>;
728aux_not_found:  uexit (1);
729aux_found:                      {now we're ready to read the \.{.aux} file}
730end;
731@z
732
733% [101] Don't need this variable; we use argc to check if we have a
734% command line.
735@x
736@<Variables for possible command-line processing@>=
737@!check_cmnd_line : boolean;    {|true| if we're to check the command line}
738@y
739@z
740
741@x [103] Get the aux file name from the command line.
742@<Process a possible command line@>=
743begin
744do_nothing;             {the ``default system'' doesn't use the command line}
745end
746@y
747@<Process a possible command line@>=
748parse_arguments;
749@z
750
751% [107] Don't use a path to find the aux file, and don't add the
752% extension if it's already there.
753@x
754add_extension (s_aux_extension);        {this also sets |name_length|}
755aux_ptr := 0;                           {initialize the \.{.aux} file stack}
756if (not a_open_in(cur_aux_file)) then
757@y
758if (name_length < 4) or
759   (strcmp (stringcast(name_of_file + 1 + name_length - 4), '.aux') <> 0)
760then
761  add_extension (s_aux_extension)        {this also sets |name_length|}
762else
763  aux_name_length := aux_name_length - 4; {set to length without \.{.aux}}
764aux_ptr := 0;                           {initialize the \.{.aux} file stack}
765if (not kpse_in_name_ok(stringcast(name_of_file+1)) or
766    not a_open_in(cur_aux_file,no_file_path)) then
767@z
768
769@x [107] - Check log_file name.
770if (not a_open_out(log_file)) then
771@y
772if (not kpse_out_name_ok(stringcast(name_of_file+1)) or
773    not a_open_out(log_file)) then
774@z
775
776@x [107] - Check bbl_file name
777if (not a_open_out(bbl_file)) then
778@y
779if (not kpse_out_name_ok(stringcast(name_of_file+1)) or
780    not a_open_out(bbl_file)) then
781@z
782
783@x [109] Add log_pr_aux_name.
784procedure print_aux_name;
785begin
786print_pool_str (cur_aux_str);
787print_newline;
788end;
789@y
790procedure print_aux_name;
791begin
792print_pool_str (cur_aux_str);
793print_newline;
794end;
795@#
796procedure log_pr_aux_name;
797begin
798log_pr_pool_str (cur_aux_str);
799log_pr_newline;
800end;
801@z
802
803@x [111] Be silent unless verbose.
804print ('The top-level auxiliary file: ');
805print_aux_name;
806@y
807if verbose then begin
808  print ('The top-level auxiliary file: ');
809  print_aux_name;
810end
811else begin
812  log_pr ('The top-level auxiliary file: ');
813  log_pr_aux_name;
814end;
815@z
816
817@x [118] bib_list is dynamically allocated.
818@!bib_list : array[bib_number] of str_number;   {the \.{.bib} file list}
819@y
820@!bib_list : ^str_number;   {the \.{.bib} file list}
821@z
822@x [still 118] bib_file also.
823@!bib_file : array[bib_number] of alpha_file; {corresponding |file| variables}
824@y
825@!bib_file : ^alpha_file; {corresponding |file| variables}
826@z
827
828@x [119] max_bib_files is a variable now, so can't be used as a const.
829@!bib_number = 0..max_bib_files;        {gives the |bib_list| range}
830@y
831@!bib_number = integer;        {gives the |bib_list| range}
832@z
833
834@x [122] Add log_pr_bib_name.
835procedure print_bib_name;
836begin
837print_pool_str (cur_bib_str);
838print_pool_str (s_bib_extension);
839print_newline;
840end;
841@y
842procedure print_bib_name;
843begin
844print_pool_str (cur_bib_str);
845print_pool_str (s_bib_extension);
846print_newline;
847end;
848@#
849procedure log_pr_bib_name;
850begin
851log_pr_pool_str (cur_bib_str);
852log_pr_pool_str (s_bib_extension);
853log_pr_newline;
854end;
855@z
856
857@x [124] Reallocate when we run out of bib files.
858    overflow('number of database files ',max_bib_files);
859@y
860begin
861  {Keep old value of |max_bib_files| for the last array.}
862  BIB_XRETALLOC_NOSET ('bib_list', bib_list, str_number, max_bib_files,
863                 max_bib_files + MAX_BIB_FILES);
864  BIB_XRETALLOC_NOSET ('bib_file', bib_file, alpha_file, max_bib_files,
865                 max_bib_files + MAX_BIB_FILES);
866  BIB_XRETALLOC ('s_preamble', s_preamble, str_number, max_bib_files,
867                 max_bib_files + MAX_BIB_FILES);
868end;
869@z
870
871@x [still 124] Use BIBINPUTS to search for the .bib file.
872add_extension (s_bib_extension);
873if (not a_open_in(cur_bib_file)) then
874    begin
875    add_area (s_bib_area);
876    if (not a_open_in(cur_bib_file)) then
877        open_bibdata_aux_err ('I couldn''t open database file ');
878    end;
879@y
880if (not kpse_in_name_ok(stringcast(name_of_file+1)) or
881    not a_open_in(cur_bib_file, kpse_bib_format)) then
882        open_bibdata_aux_err ('I couldn''t open database file ');
883@z
884
885@x [128] Use BSTINPUTS/TEXINPUTS to search for .bst files.
886add_extension (s_bst_extension);
887if (not a_open_in(bst_file)) then
888    begin
889    add_area (s_bst_area);
890    if (not a_open_in(bst_file)) then
891        begin
892        print ('I couldn''t open style file ');
893        print_bst_name;@/
894        bst_str := 0;                           {mark as unused again}
895        aux_err_return;
896        end;
897    end;
898@y
899if (not kpse_in_name_ok(stringcast(name_of_file+1)) or
900    not a_open_in(bst_file, kpse_bst_format)) then
901    begin
902        print ('I couldn''t open style file ');
903        print_bst_name;@/
904        bst_str := 0;                           {mark as unused again}
905        aux_err_return;
906    end;
907@z
908
909@x [128] Be silent unless verbose.
910print ('The style file: ');
911print_bst_name;
912@y
913if verbose then begin
914  print ('The style file: ');
915  print_bst_name;
916end
917else begin
918  log_pr ('The style file: ');
919  log_pr_bst_name;
920end;
921@z
922
923@x [129] Add log_pr_bst_name.
924procedure print_bst_name;
925begin
926print_pool_str (bst_str);
927print_pool_str (s_bst_extension);
928print_newline;
929end;
930@y
931procedure print_bst_name;
932begin
933print_pool_str (bst_str);
934print_pool_str (s_bst_extension);
935print_newline;
936end;
937@#
938procedure log_pr_bst_name;
939begin
940log_pr_pool_str (bst_str);
941log_pr_pool_str (s_bst_extension);
942log_pr_newline;
943end;
944@z
945
946@x [130] cite_list is dynamically allocated.
947@!cite_list : packed array[cite_number] of str_number;  {the cite-key list}
948@y
949@!cite_list : ^str_number;  {the cite-key list}
950@z
951
952@x [131] max_cites is no longer const.
953@!cite_number = 0..max_cites;   {gives the |cite_list| range}
954@y
955@!cite_number = integer;   {gives the |cite_list| range}
956@z
957
958@x [139] Dynamic max_cites.
959if (last_cite = max_cites) then
960    begin
961    print_pool_str (hash_text[cite_loc]);
962    print_ln (' is the key:');
963    overflow('number of cite keys ',max_cites);
964@y
965if (last_cite = max_cites) then
966    begin
967    BIB_XRETALLOC_NOSET ('cite_list', cite_list, str_number,
968                         max_cites, max_cites + MAX_CITES);
969    BIB_XRETALLOC_NOSET ('type_list', type_list, hash_ptr2,
970                         max_cites, max_cites + MAX_CITES);
971    BIB_XRETALLOC_NOSET ('entry_exists', entry_exists, boolean,
972                         max_cites, max_cites + MAX_CITES);
973    BIB_XRETALLOC ('cite_info', cite_info, str_number,
974                   max_cites, max_cites + MAX_CITES);
975    while (last_cite < max_cites) do
976        begin
977        type_list[last_cite] := empty;@/
978        cite_info[last_cite] := any_value;  {to appeas \PASCAL's boolean evaluation}
979        incr(last_cite);
980        end;
981@z
982
983% [142] Don't pad with blanks.
984% Don't use a path to search for subsidiary aux files, either.
985@x
986while (name_ptr <= file_name_size) do   {pad with blanks}
987    begin
988    name_of_file[name_ptr] := ' ';
989    incr(name_ptr);
990    end;
991if (not a_open_in(cur_aux_file)) then
992@y
993name_of_file[name_ptr] := 0;
994if (not kpse_in_name_ok(stringcast(name_of_file+1)) or
995    not a_open_in(cur_aux_file, no_file_path)) then
996@z
997
998% [152] This goto gets turned into a setjmp/longjmp by ./convert --
999% unfortunately, it is a nonlocal goto.  ekrell@ulysses.att.com
1000% implemented the conversion.
1001@x
1002buf_ptr2 := last;       {to get the first input line}
1003loop
1004    begin
1005    if (not eat_bst_white_space) then   {the end of the \.{.bst} file}
1006        goto bst_done;
1007    get_bst_command_and_process;
1008    end;
1009bst_done: a_close (bst_file);
1010@y
1011buf_ptr2 := last;       {to get the first input line}
1012hack1;
1013    begin
1014    if (not eat_bst_white_space) then   {the end of the \.{.bst} file}
1015        hack2;
1016    get_bst_command_and_process;
1017    end;
1018bst_done: a_close (bst_file);
1019@z
1020
1021% max_ent_ints and max_ent_strs are gone, max_fields is no longer const.
1022@x [161] quote_next_fn and end_of_def are Pascal consts, instead of web macros.
1023@d quote_next_fn = hash_base - 1  {special marker used in defining functions}
1024@d end_of_def = hash_max + 1      {another such special marker}
1025
1026@<Types in the outer block@>=
1027@!fn_class = 0..last_fn_class;          {the \.{.bst} function classes}
1028@!wiz_fn_loc = 0..wiz_fn_space;  {|wiz_defined|-function storage locations}
1029@!int_ent_loc = 0..max_ent_ints;        {|int_entry_var| storage locations}
1030@!str_ent_loc = 0..max_ent_strs;        {|str_entry_var| storage locations}
1031@!str_glob_loc = 0..max_glb_str_minus_1; {|str_global_var| storage locations}
1032@!field_loc = 0..max_fields;            {individual field storage locations}
1033@y
1034@<Types in the outer block@>=
1035@!fn_class = 0..last_fn_class;          {the \.{.bst} function classes}
1036@!wiz_fn_loc = integer;         {|wiz_defined|-function storage locations}
1037@!int_ent_loc = integer;        {|int_entry_var| storage locations}
1038@!str_ent_loc = integer;        {|str_entry_var| storage locations}
1039@!str_glob_loc = integer; {|str_global_var| storage locations}
1040@!field_loc = integer;            {individual field storage locations}
1041@z
1042
1043@x [162] max_strings=hash_size settable at runtime.
1044@!fn_type : packed array[hash_loc] of fn_class;
1045@y
1046@!fn_type : ^fn_class;
1047@z
1048
1049@x [162] Dynamically allocate wiz_functions.
1050@!wiz_functions : packed array[wiz_fn_loc] of hash_ptr2;
1051@y
1052@!wiz_functions : ^hash_ptr2;
1053@z
1054
1055% [still 162] Convert entry_ints and entry_strs to dynamically-allocated
1056% one-dimensional arrays; too bad C and Pascal lag Fortran in supporting
1057% run-time dimensioning of multidimensional arrays.  Other changes that
1058% follow this one will convert every reference to entry_strs[p][q] to
1059% x_entry_strs(p)(q), the equivalent of entry_strs[p*(ent_str_size+1) +
1060% q], but hidden inside a macro to mask the addressing computation.
1061% Although WEB does not have multi-argument macros, webman.tex shows how
1062% to get the equivalent effect.
1063@x
1064@!entry_ints : array[int_ent_loc] of integer;
1065@!num_ent_ints : int_ent_loc;   {the number of distinct |int_entry_var| names}
1066@!str_ent_ptr : str_ent_loc;    {general |str_entry_var| location}
1067@!entry_strs : array[str_ent_loc] of
1068                                packed array[0..ent_str_size] of ASCII_code;
1069@y
1070@!entry_ints : ^integer; {dynamically-allocated array}
1071@!num_ent_ints : int_ent_loc;   {the number of distinct |int_entry_var| names}
1072@!str_ent_ptr : str_ent_loc;    {general |str_entry_var| location}
1073@!entry_strs : ^ASCII_code; {dynamically-allocated array}
1074@z
1075
1076@x [still 162] Dynamically allocate global strings
1077@!str_glb_ptr : 0..max_glob_strs;       {general |str_global_var| location}
1078@!glb_str_ptr : array[str_glob_loc] of str_number;
1079@!global_strs : array[str_glob_loc] of array[0..glob_str_size] of ASCII_code;
1080@!glb_str_end : array[str_glob_loc] of 0..glob_str_size;        {end markers}
1081@!num_glb_strs : 0..max_glob_strs; {number of distinct |str_global_var| names}
1082@y
1083@!str_glb_ptr : integer;         {general |str_global_var| location}
1084@!glb_str_ptr : ^str_number;
1085@!global_strs : ^ASCII_code;
1086@!glb_str_end : ^integer;        {end markers}
1087@!num_glb_strs : integer;        {number of distinct |str_global_var| names}
1088@z
1089
1090@x [still 162] Dynamically allocate field_info.
1091@!field_info : packed array[field_loc] of str_number;
1092@y
1093@!field_info : ^str_number;
1094@z
1095
1096@x [188] Dynamically allocate singl_function.
1097type @!fn_def_loc = 0..single_fn_space; {for a single |wiz_defined|-function}
1098var singl_function : packed array[fn_def_loc] of hash_ptr2;
1099@y
1100type @!fn_def_loc = integer; {for a single |wiz_defined|-function}
1101var singl_function : ^hash_ptr2;
1102@!single_fn_space : integer; {space allocated for this |singl_function| instance}
1103@z
1104
1105@x [still 188] Dynamically allocate singl_function.
1106begin
1107eat_bst_white_and_eof_check ('function');
1108@y
1109begin
1110single_fn_space := SINGLE_FN_SPACE;
1111singl_function := XTALLOC (single_fn_space + 1, hash_ptr2);
1112eat_bst_white_and_eof_check ('function');
1113@z
1114
1115@x [still 188] Dynamically allocate singl_function.
1116exit:
1117end;
1118@y
1119exit:
1120libc_free (singl_function);
1121end;
1122@z
1123
1124@x [189] Reallocate if out of single function space.
1125                            singl_fn_overflow;
1126@y
1127                            begin
1128                            BIB_XRETALLOC ('singl_function', singl_function, hash_ptr2,
1129                                           single_fn_space, single_fn_space + SINGLE_FN_SPACE);
1130                            end;
1131@z
1132
1133@x [still 189] Procedure |singl_fn_overflow| replaced by inline code.
1134procedure singl_fn_overflow;
1135begin
1136overflow('single function space ',single_fn_space);
1137end;
1138@y
1139@z
1140
1141@x [199] A variable named `int' is no good in C.
1142@<Procedures and functions for handling numbers, characters, and strings@>=
1143@y
1144@d int == the_int
1145@<Procedures and functions for handling numbers, characters, and strings@>=
1146@z
1147
1148@x [201] Reallocate if out of wizard space.
1149if (single_ptr + wiz_def_ptr > wiz_fn_space) then
1150    begin
1151    print (single_ptr + wiz_def_ptr : 0,': ');
1152    overflow('wizard-defined function space ',wiz_fn_space);
1153    end;
1154@y
1155while (single_ptr + wiz_def_ptr > wiz_fn_space) do
1156    begin
1157    BIB_XRETALLOC ('wiz_functions', wiz_functions, hash_ptr2,
1158                    wiz_fn_space, wiz_fn_space + WIZ_FN_SPACE);
1159    end;
1160@z
1161
1162@x [217] Reallocate if out of global strings.
1163    overflow('number of string global-variables ',max_glob_strs);
1164@y
1165    begin
1166    BIB_XRETALLOC_NOSET ('glb_str_ptr', glb_str_ptr, str_number,
1167                         max_glob_strs, max_glob_strs + MAX_GLOB_STRS);
1168    BIB_XRETALLOC_STRING ('global_strs', global_strs, glob_str_size,
1169                          max_glob_strs, max_glob_strs + MAX_GLOB_STRS);
1170    BIB_XRETALLOC ('glb_str_end', glb_str_end, integer,
1171                   max_glob_strs, max_glob_strs + MAX_GLOB_STRS);
1172    str_glb_ptr := num_glb_strs;
1173    while (str_glb_ptr < max_glob_strs) do      {make new |str_global_var|s empty}
1174        begin
1175        glb_str_ptr[str_glb_ptr] := 0;
1176        glb_str_end[str_glb_ptr] := 0;
1177        incr(str_glb_ptr);
1178        end;
1179    end;
1180@z
1181
1182@x [220] undefined is now a Pascal const, instead of a web macro
1183@d undefined = hash_max + 1     {a special marker used for |type_list|}
1184@y
1185@z
1186
1187@x [220] type_list is dynamically allocated.
1188@!type_list : packed array[cite_number] of hash_ptr2;
1189@y
1190@!type_list : ^hash_ptr2;
1191@z
1192@x [220] entry_exists also.
1193@!entry_exists : packed array[cite_number] of boolean;
1194@y
1195@!entry_exists : ^boolean;
1196@z
1197@x [220] cite_info also.
1198@!cite_info : packed array[cite_number] of str_number; {extra |cite_list| info}
1199@y
1200@!cite_info : ^str_number; {extra |cite_list| info}
1201@z
1202
1203@x [225] Be silent unless verbose.
1204    print ('Database file #',bib_ptr+1:0,': ');
1205    print_bib_name;@/
1206@y
1207    if verbose then begin
1208      print ('Database file #',bib_ptr+1:0,': ');
1209      print_bib_name;
1210    end
1211    else begin
1212      log_pr ('Database file #',bib_ptr+1:0,': ');
1213      log_pr_bib_name;
1214    end;
1215@z
1216
1217@x [227] Reallocate if out of fields.
1218procedure check_field_overflow (@!total_fields : integer);
1219begin
1220if (total_fields > max_fields) then
1221    begin
1222    print_ln (total_fields:0,' fields:');
1223    overflow('total number of fields ',max_fields);
1224@y
1225procedure check_field_overflow (@!total_fields : integer);
1226var @!f_ptr: field_loc;
1227    @!start_fields: field_loc;
1228begin
1229if (total_fields > max_fields) then
1230    begin
1231    start_fields := max_fields;
1232    BIB_XRETALLOC ('field_info', field_info, str_number, max_fields,
1233                   total_fields + MAX_FIELDS);
1234    {Initialize to |missing|.}
1235    for f_ptr := start_fields to max_fields - 1 do begin
1236      field_info[f_ptr] := missing;
1237    end;
1238@z
1239
1240@x [243] Reallocate when we run out of s_preamble's.
1241    bib_err ('You''ve exceeded ',max_bib_files:0,' preamble commands');
1242@y
1243begin
1244  {Keep old value of |max_bib_files| for the last array.}
1245  BIB_XRETALLOC_NOSET ('bib_list', bib_list, str_number, max_bib_files,
1246                 max_bib_files + MAX_BIB_FILES);
1247  BIB_XRETALLOC_NOSET ('bib_file', bib_file, alpha_file, max_bib_files,
1248                 max_bib_files + MAX_BIB_FILES);
1249  BIB_XRETALLOC ('s_preamble', s_preamble, str_number, max_bib_files,
1250                 max_bib_files + MAX_BIB_FILES);
1251end;
1252@z
1253
1254@x [264] Add check for fieldinfo[] overflow.
1255field_ptr := entry_cite_ptr * num_fields + fn_info[field_name_loc];
1256@y
1257field_ptr := entry_cite_ptr * num_fields + fn_info[field_name_loc];
1258if (field_ptr >= max_fields) then
1259    confusion ('field_info index is out of range');
1260@z
1261
1262@x [266] Fix bug in the add_database_cite procedure.
1263check_field_overflow (num_fields*new_cite);
1264@y
1265check_field_overflow (num_fields*(new_cite+1));
1266@z
1267
1268@x [278] Add check for fieldinfo[] overflow.
1269@<Add cross-reference information@>=
1270begin
1271@y
1272@<Add cross-reference information@>=
1273begin
1274if ((num_cites - 1) * num_fields + crossref_num >= max_fields) then
1275    confusion ('field_info index is out of range');
1276@z
1277
1278@x [280] Add check for fieldinfo[] overflow.
1279@<Subtract cross-reference information@>=
1280begin
1281@y
1282@<Subtract cross-reference information@>=
1283begin
1284if ((num_cites - 1) * num_fields + crossref_num >= max_fields) then
1285    confusion ('field_info index is out of range');
1286@z
1287
1288@x [286] Add check for fieldinfo[] overflow.
1289@<Slide this cite key down to its permanent spot@>=
1290begin
1291@y
1292@<Slide this cite key down to its permanent spot@>=
1293begin
1294if ((cite_xptr + 1) * num_fields > max_fields) then
1295  confusion ('field_info index is out of range');
1296@z
1297
1298@x [288] Allocate entry_ints as needed.
1299if (num_ent_ints*num_cites > max_ent_ints) then
1300    begin
1301    print (num_ent_ints*num_cites,': ');
1302    overflow('total number of integer entry-variables ',max_ent_ints);
1303    end;
1304@y
1305entry_ints := XTALLOC ((num_ent_ints + 1) * (num_cites + 1), integer);
1306@z
1307
1308@x [289] Allocate entry_strs as needed.
1309if (num_ent_strs*num_cites > max_ent_strs) then
1310    begin
1311    print (num_ent_strs*num_cites,': ');
1312    overflow('total number of string entry-variables ',max_ent_strs);
1313    end;
1314@y
1315entry_strs := XTALLOC ((num_ent_strs + 1) * (num_cites + 1) * (ent_str_size + 1), ASCII_code);
1316@z
1317
1318@x [289] Macroize entry_strs[][].
1319    entry_strs[str_ent_ptr][0] := end_of_string;
1320@y
1321    x_entry_strs(str_ent_ptr)(0) := end_of_string;
1322@z
1323
1324@x [291] Dynamic lit_stk_size.
1325@!lit_stack : array[lit_stk_loc] of integer;    {the literal function stack}
1326@!lit_stk_type : array[lit_stk_loc] of stk_type; {their corresponding types}
1327@y
1328@!lit_stack : ^integer;    {the literal function stack}
1329@!lit_stk_type : ^stk_type; {their corresponding types}
1330@z
1331
1332@x [292] Dynamic lit_stk_size.
1333@!lit_stk_loc = 0..lit_stk_size;        {the stack range}
1334@y
1335@!lit_stk_loc = integer;        {the stack range}
1336@z
1337
1338@x [302] Macroize entry_strs[][].
1339    char1 := entry_strs[ptr1][char_ptr];
1340    char2 := entry_strs[ptr2][char_ptr];
1341@y
1342    char1 := x_entry_strs(ptr1)(char_ptr);
1343    char2 := x_entry_strs(ptr2)(char_ptr);
1344@z
1345
1346@x [308] Reallocate literal stack.
1347    overflow('literal-stack size ',lit_stk_size);
1348@y
1349    begin
1350    BIB_XRETALLOC_NOSET ('lit_stack', lit_stack, integer,
1351                         lit_stk_size, lit_stk_size + LIT_STK_SIZE);
1352    BIB_XRETALLOC ('lit_stk_type', lit_stk_type, stk_type,
1353                   lit_stk_size, lit_stk_size + LIT_STK_SIZE);
1354    end;
1355@z
1356
1357@x [321] Dynamic buf_size.
1358if (out_buf_length+(p_ptr2-p_ptr1) > buf_size) then
1359    overflow('output buffer size ',buf_size);
1360@y
1361while (out_buf_length+(p_ptr2-p_ptr1) > buf_size) do
1362    buffer_overflow;
1363@z
1364
1365@x [328] Add check for fieldinfo[] overflow.
1366    field_ptr := cite_ptr*num_fields + fn_info[ex_fn_loc];
1367@y
1368    field_ptr := cite_ptr*num_fields + fn_info[ex_fn_loc];
1369    if (field_ptr >= max_fields) then
1370        confusion ('field_info index is out of range');
1371@z
1372
1373@x [330] Macroize entry_strs[][]
1374    while (entry_strs[str_ent_ptr][ex_buf_ptr] <> end_of_string) do
1375                                        {copy characters into the buffer}
1376        append_ex_buf_char (entry_strs[str_ent_ptr][ex_buf_ptr]);
1377@y
1378    while (x_entry_strs(str_ent_ptr)(ex_buf_ptr) <> end_of_string) do
1379                                        {copy characters into the buffer}
1380        append_ex_buf_char (x_entry_strs(str_ent_ptr)(ex_buf_ptr));
1381@z
1382
1383@x [331] Macroize global_strs[][]
1384        append_char (global_strs[str_glb_ptr][glob_chr_ptr]);
1385@y
1386        append_char (x_global_strs(str_glb_ptr)(glob_chr_ptr));
1387@z
1388
1389@x [335] Bug fix: remove duplicate entry.
1390build_in('width$      ',6,b_width,n_width);
1391build_in('while$      ',6,b_while,n_while);
1392build_in('width$      ',6,b_width,n_width);
1393@y
1394build_in('while$      ',6,b_while,n_while);
1395build_in('width$      ',6,b_width,n_width);
1396@z
1397
1398@x [338] s_preamble is dynamically allocated.
1399@!s_preamble : array[bib_number] of str_number;
1400@y
1401@!s_preamble : ^str_number;
1402@z
1403
1404@x [345] Dynamic buf_size.
1405@!name_tok : packed array[buf_pointer] of buf_pointer; {name-token ptr list}
1406@!name_sep_char : packed array[buf_pointer] of ASCII_code; {token-ending chars}
1407@y
1408@!name_tok : ^buf_pointer; {name-token ptr list}
1409@!name_sep_char : ^ASCII_code; {token-ending chars}
1410@z
1411
1412@x [358] Macroize entry_strs[][].
1413    while (sp_ptr < sp_xptr1) do
1414        begin                   {copy characters into |entry_strs|}
1415        entry_strs[str_ent_ptr][ent_chr_ptr] := str_pool[sp_ptr];
1416        incr(ent_chr_ptr);
1417        incr(sp_ptr);
1418        end;
1419    entry_strs[str_ent_ptr][ent_chr_ptr] := end_of_string;
1420@y
1421    while (sp_ptr < sp_xptr1) do
1422        begin                   {copy characters into |entry_strs|}
1423        x_entry_strs(str_ent_ptr)(ent_chr_ptr) := str_pool[sp_ptr];
1424        incr(ent_chr_ptr);
1425        incr(sp_ptr);
1426        end;
1427    x_entry_strs(str_ent_ptr)(ent_chr_ptr) := end_of_string;
1428@z
1429
1430@x [360] Macroize global_strs[][]
1431            global_strs[str_glb_ptr][glob_chr_ptr] := str_pool[sp_ptr];
1432@y
1433            x_global_strs(str_glb_ptr)(glob_chr_ptr) := str_pool[sp_ptr];
1434@z
1435
1436% [389] bibtex.web has mutually exclusive tests here; Oren said he
1437% doesn't want to fix it until 1.0, since it's obviously of no practical
1438% import (or someone would have found it before GCC 2 did).  Changing
1439% the second `and' to an `or' makes all but the last of multiple authors
1440% be omitted in the bbl file, so I simply removed the statement.
1441@x
1442while ((ex_buf_xptr < ex_buf_ptr) and
1443                        (lex_class[ex_buf[ex_buf_ptr]] = white_space) and
1444                        (lex_class[ex_buf[ex_buf_ptr]] = sep_char)) do
1445        incr(ex_buf_xptr);                      {this removes leading stuff}
1446@y
1447@z
1448
1449% Forgot to check for pool overflow here.  Triggered by test case linked
1450% from http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=520920.
1451@x [439]
1452while (sp_ptr < sp_end) do                      {shift the substring}
1453@y
1454str_room(sp_end - sp_ptr);
1455while (sp_ptr < sp_end) do                      {shift the substring}
1456@z
1457
1458% Forgot to check for pool overflow here.  Triggered by bibtex-mem.test (3).
1459@x [445]
1460if (pop_lit2 >= cmd_str_ptr) then       {no shifting---merely change pointers}
1461@y
1462str_room(sp_brace_level + sp_end - sp_ptr);
1463if (pop_lit2 >= cmd_str_ptr) then       {no shifting---merely change pointers}
1464@z
1465
1466% [460] Eliminate unreferenced statement label, because `undefined' is
1467% now a constant expression that is not evaluated at the Web level. If
1468% this label were ever required, it could be replaced by the constant
1469% 9997, which is not used as a statement label in BibTeX.
1470@x
1471    undefined : trace_pr ('unknown')
1472@y
1473    trace_pr ('unknown')
1474@z
1475
1476@x [461] Macroize entry_strs[][].
1477        while (entry_strs[str_ent_ptr][ent_chr_ptr] <> end_of_string) do
1478            begin
1479            trace_pr (xchr[entry_strs[str_ent_ptr][ent_chr_ptr]]);
1480            incr(ent_chr_ptr);
1481            end;
1482@y
1483        while (x_entry_strs(str_ent_ptr)(ent_chr_ptr) <> end_of_string) do
1484            begin
1485            trace_pr (xchr[x_entry_strs(str_ent_ptr)(ent_chr_ptr)]);
1486            incr(ent_chr_ptr);
1487            end;
1488@z
1489
1490@x [463] Add check for fieldinfo[] overflow.
1491    field_ptr := cite_ptr * num_fields;
1492    field_end_ptr := field_ptr + num_fields;
1493@y
1494    field_ptr := cite_ptr * num_fields;
1495    field_end_ptr := field_ptr + num_fields;
1496    if (field_end_ptr > max_fields) then
1497        confusion ('field_info index is out of range');
1498@z
1499
1500@x [468] System-dependent changes.
1501This section should be replaced, if necessary, by changes to the program
1502that are necessary to make \BibTeX\ work at a particular installation.
1503It is usually best to design your change file so that all changes to
1504previous sections preserve the section numbering; then everybody's version
1505will be consistent with the printed program. More extensive changes,
1506which introduce new sections, can be inserted here; then only the index
1507itself will get a new section number.
1508@y
1509@d argument_is (#) == (strcmp (long_options[option_index].name, #) = 0)
1510
1511@<Define |parse_arguments|@> =
1512procedure parse_arguments;
1513const n_options = 4; {Pascal won't count array lengths for us.}
1514var @!long_options: array[0..n_options] of getopt_struct;
1515    @!getopt_return_val: integer;
1516    @!option_index: c_int_type;
1517    @!current_option: 0..n_options;
1518begin
1519  @<Initialize the option variables@>;
1520  @<Define the option table@>;
1521  repeat
1522    getopt_return_val := getopt_long_only (argc, argv, '', long_options,
1523                                           address_of (option_index));
1524    if getopt_return_val = -1 then begin
1525      {End of arguments; we exit the loop below.} ;
1526
1527    end else if getopt_return_val = "?" then begin
1528      usage (my_name);
1529
1530    end else if argument_is ('min-crossrefs') then begin
1531      min_crossrefs := atoi (optarg);
1532
1533    end else if argument_is ('help') then begin
1534      usage_help (BIBTEX_HELP, nil);
1535
1536    end else if argument_is ('version') then begin
1537      print_version_and_exit (banner, 'Oren Patashnik', nil, nil);
1538
1539    end; {Else it was a flag; |getopt| has already done the assignment.}
1540  until getopt_return_val = -1;
1541
1542  {Now |optind| is the index of first non-option on the command line.
1543   We must have one remaining argument.}
1544  if (optind + 1 <> argc) then begin
1545    write_ln (stderr, my_name, ': Need exactly one file argument.');
1546    usage (my_name);
1547  end;
1548end;
1549
1550@ Here is the first of the options we allow.
1551@.-terse@>
1552
1553@<Define the option...@> =
1554current_option := 0;
1555long_options[0].name := 'terse';
1556long_options[0].has_arg := 0;
1557long_options[0].flag := address_of (verbose);
1558long_options[0].val := 0;
1559incr (current_option);
1560
1561@ The global variable |verbose| determines whether or not we print
1562progress information.
1563
1564@<Glob...@> =
1565@!verbose: c_int_type;
1566
1567@ Start off |true|, to match the default behavior.
1568
1569@<Initialize the option...@> =
1570verbose := true;
1571
1572@ Here is an option to change the minimum number of cross-refs required
1573for automatic |cite_list| inclusion.
1574@.-min-crossrefs@>
1575
1576@<Define the option...@> =
1577long_options[current_option].name := 'min-crossrefs';
1578long_options[current_option].has_arg := 1;
1579long_options[current_option].flag := 0;
1580long_options[current_option].val := 0;
1581incr (current_option);
1582
1583@
1584@<Glob...@> =
1585@!min_crossrefs: integer;
1586
1587@ Set |min_crossrefs| to two by default, so we match the
1588documentation (\.{btxdoc.tex}).
1589
1590@<Initialize the option...@> =
1591min_crossrefs := 2;
1592
1593@ One of the standard options.
1594@.-help@>
1595
1596@<Define the option...@> =
1597long_options[current_option].name := 'help';
1598long_options[current_option].has_arg := 0;
1599long_options[current_option].flag := 0;
1600long_options[current_option].val := 0;
1601incr (current_option);
1602
1603@ Another of the standard options.
1604@.-version@>
1605
1606@<Define the option...@> =
1607long_options[current_option].name := 'version';
1608long_options[current_option].has_arg := 0;
1609long_options[current_option].flag := 0;
1610long_options[current_option].val := 0;
1611incr (current_option);
1612
1613@ An element with all zeros always ends the list.
1614
1615@<Define the option...@> =
1616long_options[current_option].name := 0;
1617long_options[current_option].has_arg := 0;
1618long_options[current_option].flag := 0;
1619long_options[current_option].val := 0;
1620
1621@ Determine |ent_str_size|, |glob_str_size|, and |max_strings| from the
1622environment, configuration file, or default value.  Set
1623|hash_size:=max_strings|, but not less than |HASH_SIZE|.
1624
1625{|setup_bound_var| stuff adapted from \.{tex.ch}.}
1626@d setup_bound_var(#)==bound_default:=#; setup_bound_var_end
1627@d setup_bound_var_end(#)==bound_name:=#; setup_bound_var_end_end
1628@d setup_bound_var_end_end(#)==
1629  setup_bound_variable(address_of(#), bound_name, bound_default);
1630  if # < bound_default then # := bound_default
1631
1632@<Procedures and functions for about everything@>=
1633procedure setup_params;
1634var bound_default: integer; {for setup}
1635@!bound_name: const_cstring; {for setup}
1636begin kpse_set_program_name (argv[0], 'bibtex');
1637setup_bound_var (ENT_STR_SIZE)('ent_str_size')(ent_str_size);
1638setup_bound_var (GLOB_STR_SIZE)('glob_str_size')(glob_str_size);
1639setup_bound_var (MAX_STRINGS)('max_strings')(max_strings);
1640@#
1641hash_size := max_strings;
1642if hash_size < HASH_SIZE then hash_size := HASH_SIZE;
1643hash_max := hash_size + hash_base - 1;
1644end_of_def := hash_max + 1;
1645undefined := hash_max + 1;
1646end;
1647
1648@ We use the algorithm from Knuth's \.{primes.web} to compute |hash_prime|
1649as the smallest prime number not less than 85\% of |hash_size| (and
1650|>=128|).
1651
1652@d primes == hash_next {array holding the first |k| primes}
1653@d mult == hash_text {array holding odd multiples of the first |o| primes}
1654
1655@<Procedures and functions for about everything@>=
1656procedure compute_hash_prime;
1657var hash_want: integer; {85\% of |hash_size|}
1658@!k: integer; {number of prime numbers $p_i$ in |primes|}
1659@!j: integer; {a prime number candidate}
1660@!o: integer; {number of odd multiples of primes in |mult|}
1661@!square: integer; {$p_o^2$}
1662@!n: integer; {loop index}
1663@!j_prime: boolean; {is |j| a prime?}
1664begin hash_want := (hash_size div 20) * 17;
1665j := 1;
1666k := 1;
1667hash_prime := 2;
1668primes[k] := hash_prime;
1669o := 2;
1670square := 9;
1671while hash_prime < hash_want do
1672  begin
1673  repeat
1674    j := j + 2;
1675    if j = square then
1676      begin
1677      mult[o] := j;
1678      j := j + 2;
1679      incr (o);
1680      square := primes[o] * primes[o];
1681      end;
1682    n := 2;
1683    j_prime := true;
1684    while (n < o) and j_prime do
1685      begin
1686      while mult[n] < j do mult[n] := mult[n] + 2 * primes[n];
1687      if mult[n] = j then j_prime := false;
1688      incr (n);
1689      end;
1690  until j_prime;
1691  incr (k);
1692  hash_prime := j;
1693  primes[k] := hash_prime;
1694  end;
1695end;
1696@z
1697