diff --git a/source/texk/web2c/bibtex.ch b/source/texk/web2c/bibtex.ch new file mode 100644 index 0000000000000000000000000000000000000000..4b637d99d98a109fee91997cf5484c3511c10570 --- /dev/null +++ b/source/texk/web2c/bibtex.ch @@ -0,0 +1,1750 @@ +% Change file for BibTeX in C, originally by Howard Trickey. +% +% 05/28/84 Initial implementation, version 0.41 of BibTeX +% 07/01/84 Version 0.41a of BibTeX. +% 12/17/84 Version 0.97c of BibTeX. +% 02/12/85 Version 0.98c of BibTeX. +% 02/25/85 Newer version 0.98c of BibTeX. +% 03/25/85 Version 0.98f of BibTeX +% 05/23/85 Version 0.98i of BibTeX +% 02/11/88 Version 0.99b of BibTeX +% 04/04/88 Version 0.99c; converted for use with web2c (ETM). +% 11/30/89 Use FILENAMESIZE instead of 1024 (KB). +% 03/09/90 `int' is a bad variable name for C. +% (more recent changes in the ChangeLog) + +% [0] Let bibtex.tex work with latest webmac (which defines \ET, hence +% making E active loses). +@x +\catcode`E=13 \uppercase{\def E{e}} +\def\\#1{\hbox{\let E=\drop\it#1\/\kern.05em}} % italic type for identifiers +@y +\let\maybe = \iffalse % process only changed sections +@z + +@x [1] Define my_name +@d banner=='This is BibTeX, Version 0.99d' {printed when the program starts} +@y +@d my_name=='bibtex' +@d banner=='This is BibTeX, Version 0.99d' {printed when the program starts} +@z + +% [2] `term_in' and `term_out' are standard input and output. But +% there is a complication: BibTeX passes `term_out' to some routines as +% a var parameter. web2c turns a var parameter f into &f at the calling +% side -- and stdout is sometimes implemented as `&_iob[1]' or some +% such. An address of an address is invalid. Therefore, we define +% variables `standardinput' and `standardoutput' in openinout.c. +@x +@d term_out == tty +@d term_in == tty +@y +@d term_out == standard_output +@d term_in == standard_input + +@<Globals in the outer block@>= +standard_input, standard_output: text; +@z + +@x [3] Add log_pr macros. +@d trace_pr_newline == begin write_ln(log_file); end +@y +@d trace_pr_newline == begin write_ln(log_file); end +@# +@d log_pr(#) == trace_pr(#) +@d log_pr_ln(#) == trace_pr_ln(#) +@d log_pr_newline == trace_pr_newline +@z + +@x [4] Turn debug..gubed et al. into #ifdef's. +@d debug == @{ { remove the `|@{|' when debugging } +@d gubed == @t@>@} { remove the `|@}|' when debugging } +@f debug == begin +@f gubed == end +@# +@d stat == @{ { remove the `|@{|' when keeping statistics } +@d tats == @t@>@} { remove the `|@}|' when keeping statistics } +@f stat == begin +@f tats == end +@# +@d trace == @{ { remove the `|@{|' when in |trace| mode } +@d ecart == @t@>@} { remove the `|@}|' when in |trace| mode } +@f trace == begin +@f ecart == end +@y +@d debug == ifdef('TEXMF_DEBUG') +@d gubed == endif('TEXMF_DEBUG') +@f debug == begin +@f gubed == end +@# +@d stat == ifndef('NO_BIBTEX_STAT') +@d tats == endifn('NO_BIBTEX_STAT') +@f stat==begin +@f tats==end +@# +@d trace == ifdef@&('TRACE') +@d ecart == endif@&('TRACE') +@f trace == begin +@f ecart == end +@z + +@x [10] Eliminate the |exit_program| label. +label close_up_shop,@!exit_program @<Labels in the outer block@>; +@y +label close_up_shop @<Labels in the outer block@>; +@z + +@x [10] Don't print the banner unless verbose, and initialize dynamic arrays. +begin +initialize; +print_ln(banner);@/ +@y +@<Define |parse_arguments|@> +begin +standard_input := stdin; +standard_output := stdout; +@# +pool_size := POOL_SIZE; +buf_size := BUF_SIZE; +max_bib_files := MAX_BIB_FILES; +max_glob_strs := MAX_GLOB_STRS; +max_fields := MAX_FIELDS; +max_cites := MAX_CITES; +wiz_fn_space := WIZ_FN_SPACE; +lit_stk_size := LIT_STK_SIZE; +@# +setup_params; +@# +{Add one to the sizes because that's what bibtex uses.} +bib_file := XTALLOC (max_bib_files + 1, alpha_file); +bib_list := XTALLOC (max_bib_files + 1, str_number); +entry_ints := nil; +entry_strs := nil; +wiz_functions := XTALLOC (wiz_fn_space + 1, hash_ptr2); +field_info := XTALLOC (max_fields + 1, str_number); +s_preamble := XTALLOC (max_bib_files + 1, str_number); +str_pool := XTALLOC (pool_size + 1, ASCII_code); +buffer := XTALLOC (buf_size + 1, ASCII_code); +sv_buffer := XTALLOC (buf_size + 1, ASCII_code); +ex_buf := XTALLOC (buf_size + 1, ASCII_code); +out_buf := XTALLOC (buf_size + 1, ASCII_code); +name_tok := XTALLOC (buf_size + 1, buf_pointer); +name_sep_char := XTALLOC (buf_size + 1, ASCII_code); +@# +glb_str_ptr := XTALLOC (max_glob_strs, str_number); +global_strs := XTALLOC (max_glob_strs * (glob_str_size + 1), ASCII_code); +glb_str_end := XTALLOC (max_glob_strs, integer); +@# +cite_list := XTALLOC (max_cites + 1, str_number); +type_list := XTALLOC (max_cites + 1, hash_ptr2); +entry_exists := XTALLOC (max_cites + 1, boolean); +cite_info := XTALLOC (max_cites + 1, str_number); +@# +str_start := XTALLOC (max_strings + 1, pool_pointer); +@# +hash_next := XTALLOC (hash_max + 1, hash_pointer); +hash_text := XTALLOC (hash_max + 1, str_number); +hash_ilk := XTALLOC (hash_max + 1, str_ilk); +ilk_info := XTALLOC (hash_max + 1, integer); +fn_type := XTALLOC (hash_max + 1, fn_class); +@# +lit_stack := XTALLOC (lit_stk_size + 1, integer); +lit_stk_type := XTALLOC (lit_stk_size + 1, stk_type); +@# +compute_hash_prime; +@# +initialize; +{This initializes the jmp9998 buffer, which can be used early} +hack0; +if verbose then begin + print (banner); + print_ln (version_string); +end +else begin + log_pr (banner); + log_pr_ln (version_string); +end; +log_pr_ln ('Capacity: max_strings=', max_strings:1, + ', hash_size=', hash_size:1, ', hash_prime=', hash_prime:1); +@z + +% [10] Possibly exit with bad status. It doesn't seem worth it to move +% the definitions of the |history| values to above this module; hence the 1. +@x +exit_program: +end. +@y +if (history > 1) then uexit (history); +end. +@z + +@x [13] Remove nonlocal goto. + goto exit_program; +@y + uexit (1); +@z + +@x [14] Increase some constants, and uppercase others for dynamic arrays. +@<Constants in the outer block@>= +@y +@<Constants in the outer block@>= +@!hash_base = empty + 1; {lowest numbered hash-table location} +@!quote_next_fn = hash_base - 1; {special marker used in defining functions} +@z + +@x [still 14] +@!buf_size=1000; {maximum number of characters in an input line (or string)} +@y +@!BUF_SIZE=20000; {initial maximum number of characters in an input line + (or string)} +@z + +@x [still 14] +@!max_bib_files=20; {maximum number of \.{.bib} files allowed} +@!pool_size=65000; {maximum number of characters in strings} +@!max_strings=4000; {maximum number of strings, including pre-defined; + must be |<=hash_size|} +@!max_cites=750; {maximum number of distinct cite keys; must be + |<=max_strings|} +@!min_crossrefs=2; {minimum number of cross-refs required for automatic + |cite_list| inclusion} +@!wiz_fn_space=3000; {maximum amount of |wiz_defined|-function space} +@y [still 14] +@!MAX_BIB_FILES=20; {initial number of \.{.bib} files allowed} +@!POOL_SIZE=65000; {initial number of characters in strings} +@!MAX_STRINGS=4000; {minimum value for |max_strings|} +@!MAX_CITES=750; {initial number of distinct cite keys; must be + |<=max_strings|} +@!WIZ_FN_SPACE=3000; {initial amount of |wiz_defined|-function space} +{|min_crossrefs| can be set at runtime now.} +@z + +@x [still 14] +@!single_fn_space=100; {maximum amount for a single |wiz_defined|-function} +@y +@!SINGLE_FN_SPACE=50; {initial amount for a single |wiz_defined|-function} +@z + +@x [still 14] handle long citation strings +@!max_ent_ints=3000; {maximum number of |int_entry_var|s + (entries $\times$ |int_entry_var|s)} +@!max_ent_strs=3000; {maximum number of |str_entry_var|s + (entries $\times$ |str_entry_var|s)} +@!ent_str_size=100; {maximum size of a |str_entry_var|; must be |<=buf_size|} +@!glob_str_size=1000; {maximum size of a |str_global_var|; + must be |<=buf_size|} +@!max_fields=17250; {maximum number of fields (entries $\times$ fields, +@y +@!ENT_STR_SIZE=100; {maximum size of a |str_entry_var|; must be |<=buf_size|} +@!GLOB_STR_SIZE=1000; {maximum size of a |str_global_var|; + must be |<=buf_size|} +@!MAX_GLOB_STRS=10; {initial number of |str_global_var| names} +@!MAX_FIELDS=5000; {initial number of fields (entries $\times$ fields, +@z + +@x [still 14] +@!lit_stk_size=100; {maximum number of literal functions on the stack} +@y +@!LIT_STK_SIZE=50; {initial space for literal functions on the stack} +@z + +@x [15] Increase more constants in the web defines. +@d hash_size=5000 {must be |>= max_strings| and |>= hash_prime|} +@d hash_prime=4253 {a prime number about 85\% of |hash_size| and |>= 128| + and |< @t$2^{14}-2^6$@>|} +@d file_name_size=40 {file names shouldn't be longer than this} +@d max_glob_strs=10 {maximum number of |str_global_var| names} +@d max_glb_str_minus_1 = max_glob_strs-1 {to avoid wasting a |str_global_var|} +@y +{|hash_size| and |hash_prime| are now computed.} +@d HASH_SIZE=5000 {minimum value for |hash_size|} +@# +@d file_name_size==maxint {file names have no arbitrary maximum length} +@# +{For dynamic allocation.} +@d x_entry_strs_tail(#) == (#)] +@d x_entry_strs(#) == entry_strs[(#) * (ent_str_size+1) + x_entry_strs_tail +@d x_global_strs_tail(#) == (#)] +@d x_global_strs(#) == global_strs[(#) * (glob_str_size+1) + x_global_strs_tail +@z + +@x [16] Add new variables-that-used-to-be-constants for dynamic arrays. +@<Globals in the outer block@>= +@y +@<Globals in the outer block@>= +@!pool_size: integer; +@!max_bib_files: integer; +@!max_cites: integer; +@!wiz_fn_space: integer; +@!ent_str_size: integer; +@!glob_str_size: integer; +@!max_glob_strs: integer; +@!max_fields: integer; +@!lit_stk_size: integer; +@# +@!max_strings: integer; +@!hash_size: integer; +@!hash_prime: integer; +@# +@!hash_max: integer; {highest numbered hash-table location} +@!end_of_def: integer; {another special marker used in defining functions} +@!undefined: integer; {a special marker used for |type_list|} +@z + +@x [17] max_strings=hash_size settable at runtime. +if (hash_prime >= (16384-64)) then bad:=10*bad+6; +@y +if (hash_base <> 1) then bad:=10*bad+6; +@z + +@x [17] remove the following, since buf_size changes dynamically. +if (ent_str_size > buf_size) then bad:=10*bad+9; +if (glob_str_size > buf_size) then bad:=100*bad+11; +@y +@z + +@x [22, 23, 27, 28] Allow any character as input. [22] +@!ASCII_code=0..127; {seven-bit numbers} +@y +@!ASCII_code=0..255; {eight-bit numbers} +@z + +@x [23] +@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=127 {ordinal number of the largest element of |text_char|} + +@<Local variables for initialization@>= +i:0..last_text_char; {this is the first one declared} +@y +@d text_char == ASCII_code {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|} + +@<Local variables for initialization@>= +i:integer; +@z + +@x [27] +for i:=1 to @'37 do xchr[i]:=' '; +xchr[tab]:=chr(tab); +@y +for i:=0 to @'37 do xchr[i]:=chr(i); +for i:=@'177 to @'377 do xchr[i]:=chr(i); +@z + +@x [28] +for i:=first_text_char to last_text_char do xord[chr(i)]:=invalid_code; +for i:=1 to @'176 do xord[xchr[i]]:=i; +@y +for i:=first_text_char to last_text_char do xord[xchr[i]]:=i; +@z + +@x [32] Put the [128..255] range into lex_class alpha. +for i:=0 to @'177 do lex_class[i] := other_lex; +@y +for i:=0 to @'177 do lex_class[i] := other_lex; +for i:=@'200 to @'377 do lex_class[i] := alpha; +@z + +% [32] Make RET a `white_space' character, so we won't choke on DOS +% files, which use CR/LF for line endings. +@x +lex_class[tab] := white_space; +@y +lex_class[tab] := white_space; +lex_class[13] := white_space; +@z + +@x [33] Allow the [128..255] range in legal_id_char. +for i:=0 to @'177 do id_class[i] := legal_id_char; +@y +for i:=0 to @'377 do id_class[i] := legal_id_char; +@z + +% [37] file_name_size no longer exists. See comments in tex.ch for why +% we change the element type to text_char. +@x +@!name_of_file:packed array[1..file_name_size] of char; + {on some systems this is a \&{record} variable} +@!name_length:0..file_name_size; + {this many characters are relevant in |name_of_file| (the rest are blank)} +@!name_ptr:0..file_name_size+1; {index variable into |name_of_file|} +@y +@!name_of_file:^text_char; +@!name_length:integer; + {this many characters are relevant in |name_of_file| } +@!name_ptr:integer; {index variable into |name_of_file|} +@z + +@x [38] File opening. +The \ph\ compiler with which the present version of \TeX\ 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 +\TeX\ to undertake appropriate corrective action. + +\TeX'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 + +@<Procedures and functions for file-system interacting@>= +function erstat(var f:file):integer; extern; {in the runtime library} +@#@t\2@> +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; +@y +@ File opening will be done in C. But we want an auxiliary function to +change a \BibTeX\ string into a C string, to keep string pool stuff +out of the C code in @.{lib/openclose.c}. + +@d no_file_path = -1 + +@<Procedures and functions for all file...@>= +function bib_makecstring(s:str_number):cstring; +var cstr:cstring; + i:pool_pointer; +begin + cstr := xmalloc_array (ASCII_code, length (s) + 1); + for i := 0 to length(s) - 1 do begin + cstr[i] := str_pool[str_start[s] + i]; + end; + cstr[length(s)] := 0; + bib_makecstring := cstr; +exit: end; +@z + +@x [39] Do file closing in C. +@<Procedures and functions for file-system interacting@>= +procedure a_close(var f:alpha_file); {close a text file} +begin close(f); +end; +@y +File closing will be done in C, too. +@z + +@x [42] Dynamic buf_size. +@!buffer:buf_type; {usually, lines of characters being read} +@y +@!buf_size:integer; {size of buffer} +@!buffer:buf_type; {usually, lines of characters being read} +@z + +@x [43] Dyanmic buf_size. +@!buf_pointer = 0..buf_size; {an index into a |buf_type|} +@!buf_type = array[buf_pointer] of ASCII_code; {for various buffers} +@y +@!buf_pointer = integer; {an index into a |buf_type|} +@!buf_type = ^ASCII_code; {for various buffers} +@z + +@x [47] Dynamic buf_size. +overflow('buffer size ',buf_size); +@y +BIB_XRETALLOC_NOSET ('buffer', buffer, ASCII_code, + buf_size, buf_size + BUF_SIZE); +BIB_XRETALLOC_NOSET ('sv_buffer', sv_buffer, ASCII_code, + buf_size, buf_size + BUF_SIZE); +BIB_XRETALLOC_NOSET ('ex_buf', ex_buf, ASCII_code, + buf_size, buf_size + BUF_SIZE); +BIB_XRETALLOC_NOSET ('out_buf', out_buf, ASCII_code, + buf_size, buf_size + BUF_SIZE); +BIB_XRETALLOC_NOSET ('name_tok', name_tok, buf_pointer, + buf_size, buf_size + BUF_SIZE); +BIB_XRETALLOC ('name_sep_char', name_sep_char, ASCII_code, + buf_size, buf_size + BUF_SIZE); +@z + +@x [48] web2c doesn't understand f^. + buffer[last]:=xord[f^]; + get(f); incr(last); + end; + get(f); +@y + buffer[last] := xord[getc (f)]; + incr (last); + end; + vgetc (f); {skip the eol} +@z + +@x [49] Dynamically allocate str_pool. +@!str_pool : packed array[pool_pointer] of ASCII_code; {the characters} +@!str_start : packed array[str_number] of pool_pointer; {the starting pointers} +@y +@!str_pool : ^ASCII_code; {the characters} +@!str_start :^pool_pointer; {the starting pointers} +@z + +@x [50] pool_size is a variable now, so can't be used as a constant. +@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|} +@!str_number = 0..max_strings; {for variables that point into |str_start|} +@y +@!pool_pointer = integer; {for variables that point into |str_pool|} +@!str_number = integer; {for variables that point into |str_start|} +@z + +@x [51] Add log_pr_pool_str macro. +@d trace_pr_pool_str(#) == begin + out_pool_str(log_file,#); + end +@y +@d trace_pr_pool_str(#) == begin + out_pool_str(log_file,#); + end +@# +@d log_pr_pool_str(#) == trace_pr_pool_str(#) +@z + +@x [54] Reallocate str_pool. We may need more than POOL_SIZE. + if (pool_ptr+# > pool_size) then +@y + while (pool_ptr+# > pool_size) do +@z +@x [54] Reallocate str_pool. +overflow('pool size ',pool_size); +@y +BIB_XRETALLOC ('str_pool', str_pool, ASCII_code, pool_size, + pool_size + POOL_SIZE); +@z + +% [59] (start_name) reallocate name_of_file for the new name and +% terminate with null. +@x +if (length(file_name) > file_name_size) then + begin + print ('File='); + print_pool_str (file_name); + print_ln (','); + file_nm_size_overflow; + end; +@y +free (name_of_file); +name_of_file := xmalloc_array (ASCII_code, length (file_name) + 1); +@z + +@x +name_length := length(file_name); +@y +name_length := length(file_name); +name_of_file[name_length + 1] := 0; +@z + +@x [60] (file_nm_size_overflow) This procedure is not used. +procedure file_nm_size_overflow; +begin +overflow('file name size ',file_name_size); +end; +@y +@z + +% [61] (add_extension) Don't pad name_of_file with blanks, terminate +% with null. And junk the overflow check, since Web2c can't translate +% the print statement properly and it can never happen, anyway. +@x +if (name_length + length(ext) > file_name_size) then + begin + print ('File=',name_of_file,', extension='); + print_pool_str (ext); print_ln (','); + file_nm_size_overflow; + end; +@y +@z +@x +name_ptr := name_length+1; +while (name_ptr <= file_name_size) do {pad with blanks} + begin + name_of_file[name_ptr] := ' '; + incr(name_ptr); + end; +@y +name_of_file[name_length + 1] := 0; +@z + +@x [62] (add_area) This procedure is not used. +procedure add_area(@!area:str_number); +var p_ptr: pool_pointer; {running index} +begin +if (name_length + length(area) > file_name_size) then + begin + print ('File='); + print_pool_str (area); print (name_of_file,','); + file_nm_size_overflow; + end; +name_ptr := name_length; +while (name_ptr > 0) do {shift up name} + begin + name_of_file[name_ptr+length(area)] := name_of_file[name_ptr]; + decr(name_ptr); + end; +name_ptr := 1; +p_ptr := str_start[area]; +while (p_ptr < str_start[area+1]) do + begin + name_of_file[name_ptr] := chr (str_pool[p_ptr]); + incr(name_ptr); incr(p_ptr); + end; +name_length := name_length + length(area); +end; +@y +@z + +@x [65] now Pascal consts or vars, instead of web macros. +@d hash_base = empty + 1 {lowest numbered hash-table location} +@d hash_max = hash_base + hash_size - 1 {highest numbered hash-table location} +@y +@z + +@x [65] max_strings=hash_size settable at runtime. +@!hash_loc=hash_base..hash_max; {a location within the hash table} +@!hash_pointer=empty..hash_max; {either |empty| or a |hash_loc|} +@y +@!hash_loc=integer; {a location within the hash table} +@!hash_pointer=integer; {either |empty| or a |hash_loc|} +@z + +@x [66] max_strings=hash_size settable at runtime. +@!hash_next : packed array[hash_loc] of hash_pointer; {coalesced-list link} +@!hash_text : packed array[hash_loc] of str_number; {pointer to a string} +@!hash_ilk : packed array[hash_loc] of str_ilk; {the type of string} +@!ilk_info : packed array[hash_loc] of integer; {|ilk|-specific info} +@!hash_used : hash_base..hash_max+1; {allocation pointer for hash table} +@y +@!hash_next : ^hash_pointer; {coalesced-list link} +@!hash_text : ^str_number; {pointer to a string} +@!hash_ilk : ^str_ilk; {the type of string} +@!ilk_info : ^integer; {|ilk|-specific info} +@!hash_used : integer; {allocation pointer for hash table} +@z + +@x [69] Not used anymore. +@d max_hash_value = hash_prime+hash_prime-2+127 {|h|'s maximum value} +@y +@z + +@x [69] max_strings=hash_size settable at runtime. +var h:0..max_hash_value; {hash code} +@y +var h:integer; {hash code} +@z + +@x [69] str_lookup - Avoid 'uninitialized' warning. +@!old_string:boolean; {set to |true| if it's an already encountered string} +@y +@z + +@x [69] str_lookup - Avoid 'uninitialized' warning. +old_string := false; +@y +str_num := 0; {set to |>0| if it's an already encountered string} +@z + +@x [71] str_lookup - Avoid 'uninitialized' warning. + old_string := true; +@y +@z + +@x [72] str_lookup - Avoid 'uninitialized' warning. +if (old_string) then {it's an already encountered string} +@y +if (str_num>0) then {it's an already encountered string} +@z + +@x [74] Pascal Web's char +@!pds_type = packed array [pds_loc] of char; +@y +@!pds_type = const_cstring; +@z + +@x [78] C strings start at zero instead of one. +for i:=1 to len do + buffer[i] := xord[pds[i]]; +@y +for i:=1 to len do + buffer[i] := xord[ucharcast(pds[i-1])]; +@z + +@x [98] Can't do this tangle-time arithmetic with file_name_size. +@!aux_name_length : 0..file_name_size+1; {\.{.aux} name sans extension} +@y +@!aux_name_length : integer; +@z + +@x [101] Reading the aux file name and command-line processing. +This procedure consists of a loop that reads and processes a (nonnull) +\.{.aux} file name. It's this module and the next two that must be +changed on those systems using command-line arguments. Note: The +|term_out| and |term_in| files are system dependent. + +@<Procedures and functions for the reading and processing of input files@>= +procedure get_the_top_level_aux_file_name; +label aux_found,@!aux_not_found; +var @<Variables for possible command-line processing@>@/ +begin +check_cmnd_line := false; {many systems will change this} +loop + begin + if (check_cmnd_line) then + @<Process a possible command line@> + else + begin + write (term_out,'Please type input file name (no extension)--'); + if (eoln(term_in)) then {so the first |read| works} + read_ln (term_in); + aux_name_length := 0; + while (not eoln(term_in)) do + begin + if (aux_name_length = file_name_size) then + begin + while (not eoln(term_in)) do {discard the rest of the line} + get(term_in); + sam_you_made_the_file_name_too_long; + end; + incr(aux_name_length); + name_of_file[aux_name_length] := term_in^; + get(term_in); + end; + end; + @<Handle this \.{.aux} name@>; +aux_not_found: + check_cmnd_line := false; + end; +aux_found: {now we're ready to read the \.{.aux} file} +end; +@y +@<Procedures and functions for the reading and processing of input files@>= +procedure get_the_top_level_aux_file_name; +label aux_found,@!aux_not_found; +begin + @<Process a possible command line@> + {Leave room for the \.., the extension, the junk byte at the + beginning, and the null byte at the end.} + name_of_file := xmalloc_array (ASCII_code, strlen (cmdline (optind)) + 5); + strcpy (stringcast(name_of_file + 1), cmdline (optind)); + aux_name_length := strlen (stringcast(name_of_file + 1)); + @<Handle this \.{.aux} name@>; +aux_not_found: uexit (1); +aux_found: {now we're ready to read the \.{.aux} file} +end; +@z + +% [101] Don't need this variable; we use argc to check if we have a +% command line. +@x +@<Variables for possible command-line processing@>= +@!check_cmnd_line : boolean; {|true| if we're to check the command line} +@y +@z + +@x [103] Get the aux file name from the command line. +@<Process a possible command line@>= +begin +do_nothing; {the ``default system'' doesn't use the command line} +end +@y +@<Process a possible command line@>= +parse_arguments; +@z + +% [107] Don't use a path to find the aux file, and don't add the +% extension if it's already there. +@x +add_extension (s_aux_extension); {this also sets |name_length|} +aux_ptr := 0; {initialize the \.{.aux} file stack} +if (not a_open_in(cur_aux_file)) then +@y +if (name_length < 4) or + (strcmp (stringcast(name_of_file + 1 + name_length - 4), '.aux') <> 0) +then + add_extension (s_aux_extension) {this also sets |name_length|} +else + aux_name_length := aux_name_length - 4; {set to length without \.{.aux}} +aux_ptr := 0; {initialize the \.{.aux} file stack} +if (not kpse_in_name_ok(stringcast(name_of_file+1)) or + not a_open_in(cur_aux_file,no_file_path)) then +@z + +@x [107] - Check log_file name. +if (not a_open_out(log_file)) then +@y +if (not kpse_out_name_ok(stringcast(name_of_file+1)) or + not a_open_out(log_file)) then +@z + +@x [107] - Check bbl_file name +if (not a_open_out(bbl_file)) then +@y +if (not kpse_out_name_ok(stringcast(name_of_file+1)) or + not a_open_out(bbl_file)) then +@z + +@x [109] Add log_pr_aux_name. +procedure print_aux_name; +begin +print_pool_str (cur_aux_str); +print_newline; +end; +@y +procedure print_aux_name; +begin +print_pool_str (cur_aux_str); +print_newline; +end; +@# +procedure log_pr_aux_name; +begin +log_pr_pool_str (cur_aux_str); +log_pr_newline; +end; +@z + +@x [111] Be silent unless verbose. +print ('The top-level auxiliary file: '); +print_aux_name; +@y +if verbose then begin + print ('The top-level auxiliary file: '); + print_aux_name; +end +else begin + log_pr ('The top-level auxiliary file: '); + log_pr_aux_name; +end; +@z + +@x [118] bib_list is dynamically allocated. +@!bib_list : array[bib_number] of str_number; {the \.{.bib} file list} +@y +@!bib_list : ^str_number; {the \.{.bib} file list} +@z +@x [still 118] bib_file also. +@!bib_file : array[bib_number] of alpha_file; {corresponding |file| variables} +@y +@!bib_file : ^alpha_file; {corresponding |file| variables} +@z + +@x [119] max_bib_files is a variable now, so can't be used as a const. +@!bib_number = 0..max_bib_files; {gives the |bib_list| range} +@y +@!bib_number = integer; {gives the |bib_list| range} +@z + +@x [122] Don't print extension twice; add log_pr_bib_name function. +procedure print_bib_name; +begin +print_pool_str (cur_bib_str); +print_pool_str (s_bib_extension); +print_newline; +end; +@y +{Return true if the |ext| string is at the end of the |s| string. There + are surely far more clever ways to do this, but it doesn't matter.} +function str_ends_with (@!s:str_number; @!ext:str_number) : boolean; +var i : integer; + str_idx,ext_idx : integer; + str_char,ext_char : ASCII_code; +begin + str_ends_with := false; + if (length (ext) > length (s)) then + return; {if extension is longer, they don't match} + str_idx := length (s) - 1; + ext_idx := length (ext) - 1; + while (ext_idx >= 0) do begin {|>=| so we check the |'.'| char.} + str_char := str_pool[str_start[s]+str_idx]; + ext_char := str_pool[str_start[ext]+ext_idx]; + if (str_char <> ext_char) then + return; + decr (str_idx); + decr (ext_idx); + end; + str_ends_with := true; +exit: end; + +{The above is needed because the file name specified in the + \.{\\bibdata} command may or may not have the \.{.bib} extension. If it + does, we don't want to print \.{.bib} twice.} +procedure print_bib_name; +begin +print_pool_str (cur_bib_str); +if not str_ends_with (cur_bib_str, s_bib_extension) then + print_pool_str (s_bib_extension); +print_newline; +end; +@# +procedure log_pr_bib_name; +begin +log_pr_pool_str (cur_bib_str); +if not str_ends_with (cur_bib_str, s_bib_extension) then + log_pr_pool_str (s_bib_extension); +log_pr_newline; +end; +@z + +@x [124] Reallocate when we run out of bib files. + overflow('number of database files ',max_bib_files); +@y +begin + {Keep old value of |max_bib_files| for the last array.} + BIB_XRETALLOC_NOSET ('bib_list', bib_list, str_number, max_bib_files, + max_bib_files + MAX_BIB_FILES); + BIB_XRETALLOC_NOSET ('bib_file', bib_file, alpha_file, max_bib_files, + max_bib_files + MAX_BIB_FILES); + BIB_XRETALLOC ('s_preamble', s_preamble, str_number, max_bib_files, + max_bib_files + MAX_BIB_FILES); +end; +@z + +@x [still 124] Use BIBINPUTS to search for the .bib file. +add_extension (s_bib_extension); +if (not a_open_in(cur_bib_file)) then + begin + add_area (s_bib_area); + if (not a_open_in(cur_bib_file)) then + open_bibdata_aux_err ('I couldn''t open database file '); + end; +@y +if (not kpse_in_name_ok(stringcast(name_of_file+1)) or + not a_open_in(cur_bib_file, kpse_bib_format)) then + open_bibdata_aux_err ('I couldn''t open database file '); +@z + +@x [128] Use BSTINPUTS/TEXINPUTS to search for .bst files. +add_extension (s_bst_extension); +if (not a_open_in(bst_file)) then + begin + add_area (s_bst_area); + if (not a_open_in(bst_file)) then + begin + print ('I couldn''t open style file '); + print_bst_name;@/ + bst_str := 0; {mark as unused again} + aux_err_return; + end; + end; +@y +if (not kpse_in_name_ok(stringcast(name_of_file+1)) or + not a_open_in(bst_file, kpse_bst_format)) then + begin + print ('I couldn''t open style file '); + print_bst_name;@/ + bst_str := 0; {mark as unused again} + aux_err_return; + end; +@z + +@x [128] Be silent unless verbose. +print ('The style file: '); +print_bst_name; +@y +if verbose then begin + print ('The style file: '); + print_bst_name; +end +else begin + log_pr ('The style file: '); + log_pr_bst_name; +end; +@z + +@x [129] Add log_pr_bst_name. +procedure print_bst_name; +begin +print_pool_str (bst_str); +print_pool_str (s_bst_extension); +print_newline; +end; +@y +procedure print_bst_name; +begin +print_pool_str (bst_str); +print_pool_str (s_bst_extension); +print_newline; +end; +@# +procedure log_pr_bst_name; +begin +log_pr_pool_str (bst_str); +log_pr_pool_str (s_bst_extension); +log_pr_newline; +end; +@z + +@x [130] cite_list is dynamically allocated. +@!cite_list : packed array[cite_number] of str_number; {the cite-key list} +@y +@!cite_list : ^str_number; {the cite-key list} +@z + +@x [131] max_cites is no longer const. +@!cite_number = 0..max_cites; {gives the |cite_list| range} +@y +@!cite_number = integer; {gives the |cite_list| range} +@z + +@x [139] Dynamic max_cites. +if (last_cite = max_cites) then + begin + print_pool_str (hash_text[cite_loc]); + print_ln (' is the key:'); + overflow('number of cite keys ',max_cites); +@y +if (last_cite = max_cites) then + begin + BIB_XRETALLOC_NOSET ('cite_list', cite_list, str_number, + max_cites, max_cites + MAX_CITES); + BIB_XRETALLOC_NOSET ('type_list', type_list, hash_ptr2, + max_cites, max_cites + MAX_CITES); + BIB_XRETALLOC_NOSET ('entry_exists', entry_exists, boolean, + max_cites, max_cites + MAX_CITES); + BIB_XRETALLOC ('cite_info', cite_info, str_number, + max_cites, max_cites + MAX_CITES); + while (last_cite < max_cites) do + begin + type_list[last_cite] := empty;@/ + cite_info[last_cite] := any_value; {to appeas \PASCAL's boolean evaluation} + incr(last_cite); + end; +@z + +% [142] Don't pad with blanks, terminate with null. +% Don't use a path to search for subsidiary aux files, +% but do check the directory of the main .aux file. +% +% This last is useful, for example, when --output-dir is used and the +% .aux file has an \@input directive resulting from a LaTeX \include; +% see bibtex-auxinclude.test. It's necessary because BibTeX itself does +% not have --output-directory. Maybe it would be (have been?) better to +% add it, but seems too intrusive now? Different bbl location. +@x +while (name_ptr <= file_name_size) do {pad with blanks} + begin + name_of_file[name_ptr] := ' '; + incr(name_ptr); + end; +if (not a_open_in(cur_aux_file)) then +@y +name_of_file[name_ptr] := 0; +if (not kpse_in_name_ok(stringcast(name_of_file+1)) + or (not a_open_in(cur_aux_file, no_file_path) + and not a_open_in_with_dirname(cur_aux_file, no_file_path, + bib_makecstring(top_lev_str))) + ) then +@z + +% [152] This goto gets turned into a setjmp/longjmp by ./convert -- +% unfortunately, it is a nonlocal goto. ekrell@ulysses.att.com +% implemented the conversion. +@x +buf_ptr2 := last; {to get the first input line} +loop + begin + if (not eat_bst_white_space) then {the end of the \.{.bst} file} + goto bst_done; + get_bst_command_and_process; + end; +bst_done: a_close (bst_file); +@y +buf_ptr2 := last; {to get the first input line} +hack1; + begin + if (not eat_bst_white_space) then {the end of the \.{.bst} file} + hack2; + get_bst_command_and_process; + end; +bst_done: a_close (bst_file); +@z + +% max_ent_ints and max_ent_strs are gone, max_fields is no longer const. +@x [161] quote_next_fn and end_of_def are Pascal consts, instead of web macros. +@d quote_next_fn = hash_base - 1 {special marker used in defining functions} +@d end_of_def = hash_max + 1 {another such special marker} + +@<Types in the outer block@>= +@!fn_class = 0..last_fn_class; {the \.{.bst} function classes} +@!wiz_fn_loc = 0..wiz_fn_space; {|wiz_defined|-function storage locations} +@!int_ent_loc = 0..max_ent_ints; {|int_entry_var| storage locations} +@!str_ent_loc = 0..max_ent_strs; {|str_entry_var| storage locations} +@!str_glob_loc = 0..max_glb_str_minus_1; {|str_global_var| storage locations} +@!field_loc = 0..max_fields; {individual field storage locations} +@y +@<Types in the outer block@>= +@!fn_class = 0..last_fn_class; {the \.{.bst} function classes} +@!wiz_fn_loc = integer; {|wiz_defined|-function storage locations} +@!int_ent_loc = integer; {|int_entry_var| storage locations} +@!str_ent_loc = integer; {|str_entry_var| storage locations} +@!str_glob_loc = integer; {|str_global_var| storage locations} +@!field_loc = integer; {individual field storage locations} +@z + +@x [162] max_strings=hash_size settable at runtime. +@!fn_type : packed array[hash_loc] of fn_class; +@y +@!fn_type : ^fn_class; +@z + +@x [162] Dynamically allocate wiz_functions. +@!wiz_functions : packed array[wiz_fn_loc] of hash_ptr2; +@y +@!wiz_functions : ^hash_ptr2; +@z + +% [still 162] Convert entry_ints and entry_strs to dynamically-allocated +% one-dimensional arrays; too bad C and Pascal lag Fortran in supporting +% run-time dimensioning of multidimensional arrays. Other changes that +% follow this one will convert every reference to entry_strs[p][q] to +% x_entry_strs(p)(q), the equivalent of entry_strs[p*(ent_str_size+1) + +% q], but hidden inside a macro to mask the addressing computation. +% Although WEB does not have multi-argument macros, webman.tex shows how +% to get the equivalent effect. +@x +@!entry_ints : array[int_ent_loc] of integer; +@!num_ent_ints : int_ent_loc; {the number of distinct |int_entry_var| names} +@!str_ent_ptr : str_ent_loc; {general |str_entry_var| location} +@!entry_strs : array[str_ent_loc] of + packed array[0..ent_str_size] of ASCII_code; +@y +@!entry_ints : ^integer; {dynamically-allocated array} +@!num_ent_ints : int_ent_loc; {the number of distinct |int_entry_var| names} +@!str_ent_ptr : str_ent_loc; {general |str_entry_var| location} +@!entry_strs : ^ASCII_code; {dynamically-allocated array} +@z + +@x [still 162] Dynamically allocate global strings +@!str_glb_ptr : 0..max_glob_strs; {general |str_global_var| location} +@!glb_str_ptr : array[str_glob_loc] of str_number; +@!global_strs : array[str_glob_loc] of array[0..glob_str_size] of ASCII_code; +@!glb_str_end : array[str_glob_loc] of 0..glob_str_size; {end markers} +@!num_glb_strs : 0..max_glob_strs; {number of distinct |str_global_var| names} +@y +@!str_glb_ptr : integer; {general |str_global_var| location} +@!glb_str_ptr : ^str_number; +@!global_strs : ^ASCII_code; +@!glb_str_end : ^integer; {end markers} +@!num_glb_strs : integer; {number of distinct |str_global_var| names} +@z + +@x [still 162] Dynamically allocate field_info. +@!field_info : packed array[field_loc] of str_number; +@y +@!field_info : ^str_number; +@z + +@x [188] Dynamically allocate singl_function. +type @!fn_def_loc = 0..single_fn_space; {for a single |wiz_defined|-function} +var singl_function : packed array[fn_def_loc] of hash_ptr2; +@y +type @!fn_def_loc = integer; {for a single |wiz_defined|-function} +var singl_function : ^hash_ptr2; +@!single_fn_space : integer; {space allocated for this |singl_function| instance} +@z + +@x [still 188] Dynamically allocate singl_function. +begin +eat_bst_white_and_eof_check ('function'); +@y +begin +single_fn_space := SINGLE_FN_SPACE; +singl_function := XTALLOC (single_fn_space + 1, hash_ptr2); +eat_bst_white_and_eof_check ('function'); +@z + +@x [still 188] Dynamically allocate singl_function. +exit: +end; +@y +exit: +libc_free (singl_function); +end; +@z + +@x [189] Reallocate if out of single function space. + singl_fn_overflow; +@y + begin + BIB_XRETALLOC ('singl_function', singl_function, hash_ptr2, + single_fn_space, single_fn_space + SINGLE_FN_SPACE); + end; +@z + +@x [still 189] Procedure |singl_fn_overflow| replaced by inline code. +procedure singl_fn_overflow; +begin +overflow('single function space ',single_fn_space); +end; +@y +@z + +@x [199] A variable named `int' is no good in C. +@<Procedures and functions for handling numbers, characters, and strings@>= +@y +@d int == the_int +@<Procedures and functions for handling numbers, characters, and strings@>= +@z + +@x [201] Reallocate if out of wizard space. +if (single_ptr + wiz_def_ptr > wiz_fn_space) then + begin + print (single_ptr + wiz_def_ptr : 0,': '); + overflow('wizard-defined function space ',wiz_fn_space); + end; +@y +while (single_ptr + wiz_def_ptr > wiz_fn_space) do + begin + BIB_XRETALLOC ('wiz_functions', wiz_functions, hash_ptr2, + wiz_fn_space, wiz_fn_space + WIZ_FN_SPACE); + end; +@z + +@x [217] Reallocate if out of global strings. + overflow('number of string global-variables ',max_glob_strs); +@y + begin + BIB_XRETALLOC_NOSET ('glb_str_ptr', glb_str_ptr, str_number, + max_glob_strs, max_glob_strs + MAX_GLOB_STRS); + BIB_XRETALLOC_STRING ('global_strs', global_strs, glob_str_size, + max_glob_strs, max_glob_strs + MAX_GLOB_STRS); + BIB_XRETALLOC ('glb_str_end', glb_str_end, integer, + max_glob_strs, max_glob_strs + MAX_GLOB_STRS); + str_glb_ptr := num_glb_strs; + while (str_glb_ptr < max_glob_strs) do {make new |str_global_var|s empty} + begin + glb_str_ptr[str_glb_ptr] := 0; + glb_str_end[str_glb_ptr] := 0; + incr(str_glb_ptr); + end; + end; +@z + +@x [220] undefined is now a Pascal const, instead of a web macro +@d undefined = hash_max + 1 {a special marker used for |type_list|} +@y +@z + +@x [220] type_list is dynamically allocated. +@!type_list : packed array[cite_number] of hash_ptr2; +@y +@!type_list : ^hash_ptr2; +@z +@x [220] entry_exists also. +@!entry_exists : packed array[cite_number] of boolean; +@y +@!entry_exists : ^boolean; +@z +@x [220] cite_info also. +@!cite_info : packed array[cite_number] of str_number; {extra |cite_list| info} +@y +@!cite_info : ^str_number; {extra |cite_list| info} +@z + +@x [225] Be silent unless verbose. + print ('Database file #',bib_ptr+1:0,': '); + print_bib_name;@/ +@y + if verbose then begin + print ('Database file #',bib_ptr+1:0,': '); + print_bib_name; + end + else begin + log_pr ('Database file #',bib_ptr+1:0,': '); + log_pr_bib_name; + end; +@z + +@x [227] Reallocate if out of fields. +procedure check_field_overflow (@!total_fields : integer); +begin +if (total_fields > max_fields) then + begin + print_ln (total_fields:0,' fields:'); + overflow('total number of fields ',max_fields); +@y +procedure check_field_overflow (@!total_fields : integer); +var @!f_ptr: field_loc; + @!start_fields: field_loc; +begin +if (total_fields > max_fields) then + begin + start_fields := max_fields; + BIB_XRETALLOC ('field_info', field_info, str_number, max_fields, + total_fields + MAX_FIELDS); + {Initialize to |missing|.} + for f_ptr := start_fields to max_fields - 1 do begin + field_info[f_ptr] := missing; + end; +@z + +@x [243] Reallocate when we run out of s_preamble's. + bib_err ('You''ve exceeded ',max_bib_files:0,' preamble commands'); +@y +begin + {Keep old value of |max_bib_files| for the last array.} + BIB_XRETALLOC_NOSET ('bib_list', bib_list, str_number, max_bib_files, + max_bib_files + MAX_BIB_FILES); + BIB_XRETALLOC_NOSET ('bib_file', bib_file, alpha_file, max_bib_files, + max_bib_files + MAX_BIB_FILES); + BIB_XRETALLOC ('s_preamble', s_preamble, str_number, max_bib_files, + max_bib_files + MAX_BIB_FILES); +end; +@z + +@x [264] Add check for fieldinfo[] overflow. +field_ptr := entry_cite_ptr * num_fields + fn_info[field_name_loc]; +@y +field_ptr := entry_cite_ptr * num_fields + fn_info[field_name_loc]; +if (field_ptr >= max_fields) then + confusion ('field_info index is out of range'); +@z + +@x [266] Fix bug in the add_database_cite procedure. +check_field_overflow (num_fields*new_cite); +@y +check_field_overflow (num_fields*(new_cite+1)); +@z + +@x [278] Add check for fieldinfo[] overflow. +@<Add cross-reference information@>= +begin +@y +@<Add cross-reference information@>= +begin +if ((num_cites - 1) * num_fields + crossref_num >= max_fields) then + confusion ('field_info index is out of range'); +@z + +@x [280] Add check for fieldinfo[] overflow. +@<Subtract cross-reference information@>= +begin +@y +@<Subtract cross-reference information@>= +begin +if ((num_cites - 1) * num_fields + crossref_num >= max_fields) then + confusion ('field_info index is out of range'); +@z + +@x [286] Add check for fieldinfo[] overflow. +@<Slide this cite key down to its permanent spot@>= +begin +@y +@<Slide this cite key down to its permanent spot@>= +begin +if ((cite_xptr + 1) * num_fields > max_fields) then + confusion ('field_info index is out of range'); +@z + +@x [288] Allocate entry_ints as needed. +if (num_ent_ints*num_cites > max_ent_ints) then + begin + print (num_ent_ints*num_cites,': '); + overflow('total number of integer entry-variables ',max_ent_ints); + end; +@y +entry_ints := XTALLOC ((num_ent_ints + 1) * (num_cites + 1), integer); +@z + +@x [289] Allocate entry_strs as needed. +if (num_ent_strs*num_cites > max_ent_strs) then + begin + print (num_ent_strs*num_cites,': '); + overflow('total number of string entry-variables ',max_ent_strs); + end; +@y +entry_strs := XTALLOC ((num_ent_strs + 1) * (num_cites + 1) * (ent_str_size + 1), ASCII_code); +@z + +@x [289] Macroize entry_strs[][]. + entry_strs[str_ent_ptr][0] := end_of_string; +@y + x_entry_strs(str_ent_ptr)(0) := end_of_string; +@z + +@x [291] Dynamic lit_stk_size. +@!lit_stack : array[lit_stk_loc] of integer; {the literal function stack} +@!lit_stk_type : array[lit_stk_loc] of stk_type; {their corresponding types} +@y +@!lit_stack : ^integer; {the literal function stack} +@!lit_stk_type : ^stk_type; {their corresponding types} +@z + +@x [292] Dynamic lit_stk_size. +@!lit_stk_loc = 0..lit_stk_size; {the stack range} +@y +@!lit_stk_loc = integer; {the stack range} +@z + +@x [302] Macroize entry_strs[][]. + char1 := entry_strs[ptr1][char_ptr]; + char2 := entry_strs[ptr2][char_ptr]; +@y + char1 := x_entry_strs(ptr1)(char_ptr); + char2 := x_entry_strs(ptr2)(char_ptr); +@z + +@x [308] Reallocate literal stack. + overflow('literal-stack size ',lit_stk_size); +@y + begin + BIB_XRETALLOC_NOSET ('lit_stack', lit_stack, integer, + lit_stk_size, lit_stk_size + LIT_STK_SIZE); + BIB_XRETALLOC ('lit_stk_type', lit_stk_type, stk_type, + lit_stk_size, lit_stk_size + LIT_STK_SIZE); + end; +@z + +@x [321] Dynamic buf_size. +if (out_buf_length+(p_ptr2-p_ptr1) > buf_size) then + overflow('output buffer size ',buf_size); +@y +while (out_buf_length+(p_ptr2-p_ptr1) > buf_size) do + buffer_overflow; +@z + +@x [328] Add check for fieldinfo[] overflow. + field_ptr := cite_ptr*num_fields + fn_info[ex_fn_loc]; +@y + field_ptr := cite_ptr*num_fields + fn_info[ex_fn_loc]; + if (field_ptr >= max_fields) then + confusion ('field_info index is out of range'); +@z + +@x [330] Macroize entry_strs[][] + while (entry_strs[str_ent_ptr][ex_buf_ptr] <> end_of_string) do + {copy characters into the buffer} + append_ex_buf_char (entry_strs[str_ent_ptr][ex_buf_ptr]); +@y + while (x_entry_strs(str_ent_ptr)(ex_buf_ptr) <> end_of_string) do + {copy characters into the buffer} + append_ex_buf_char (x_entry_strs(str_ent_ptr)(ex_buf_ptr)); +@z + +@x [331] Macroize global_strs[][] + append_char (global_strs[str_glb_ptr][glob_chr_ptr]); +@y + append_char (x_global_strs(str_glb_ptr)(glob_chr_ptr)); +@z + +@x [335] Bug fix: remove duplicate entry. +build_in('width$ ',6,b_width,n_width); +build_in('while$ ',6,b_while,n_while); +build_in('width$ ',6,b_width,n_width); +@y +build_in('while$ ',6,b_while,n_while); +build_in('width$ ',6,b_width,n_width); +@z + +@x [338] s_preamble is dynamically allocated. +@!s_preamble : array[bib_number] of str_number; +@y +@!s_preamble : ^str_number; +@z + +@x [345] Dynamic buf_size. +@!name_tok : packed array[buf_pointer] of buf_pointer; {name-token ptr list} +@!name_sep_char : packed array[buf_pointer] of ASCII_code; {token-ending chars} +@y +@!name_tok : ^buf_pointer; {name-token ptr list} +@!name_sep_char : ^ASCII_code; {token-ending chars} +@z + +@x [358] Macroize entry_strs[][]. + while (sp_ptr < sp_xptr1) do + begin {copy characters into |entry_strs|} + entry_strs[str_ent_ptr][ent_chr_ptr] := str_pool[sp_ptr]; + incr(ent_chr_ptr); + incr(sp_ptr); + end; + entry_strs[str_ent_ptr][ent_chr_ptr] := end_of_string; +@y + while (sp_ptr < sp_xptr1) do + begin {copy characters into |entry_strs|} + x_entry_strs(str_ent_ptr)(ent_chr_ptr) := str_pool[sp_ptr]; + incr(ent_chr_ptr); + incr(sp_ptr); + end; + x_entry_strs(str_ent_ptr)(ent_chr_ptr) := end_of_string; +@z + +@x [360] Macroize global_strs[][] + global_strs[str_glb_ptr][glob_chr_ptr] := str_pool[sp_ptr]; +@y + x_global_strs(str_glb_ptr)(glob_chr_ptr) := str_pool[sp_ptr]; +@z + +% [389] bibtex.web has mutually exclusive tests here; Oren said he +% doesn't want to fix it until 1.0, since it's obviously of no practical +% import (or someone would have found it before GCC 2 did). Changing +% the second `and' to an `or' makes all but the last of multiple authors +% be omitted in the bbl file, so I simply removed the statement. +@x +while ((ex_buf_xptr < ex_buf_ptr) and + (lex_class[ex_buf[ex_buf_ptr]] = white_space) and + (lex_class[ex_buf[ex_buf_ptr]] = sep_char)) do + incr(ex_buf_xptr); {this removes leading stuff} +@y +@z + +% Forgot to check for pool overflow here. Triggered by test case linked +% from http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=520920. +@x [439] +while (sp_ptr < sp_end) do {shift the substring} +@y +str_room(sp_end - sp_ptr); +while (sp_ptr < sp_end) do {shift the substring} +@z + +% Forgot to check for pool overflow here. Triggered by bibtex-mem.test (3). +@x [445] +if (pop_lit2 >= cmd_str_ptr) then {no shifting---merely change pointers} +@y +str_room(sp_brace_level + sp_end - sp_ptr); +if (pop_lit2 >= cmd_str_ptr) then {no shifting---merely change pointers} +@z + +% [460] Eliminate unreferenced statement label, because `undefined' is +% now a constant expression that is not evaluated at the Web level. If +% this label were ever required, it could be replaced by the constant +% 9997, which is not used as a statement label in BibTeX. +@x + undefined : trace_pr ('unknown') +@y + trace_pr ('unknown') +@z + +@x [461] Macroize entry_strs[][]. + while (entry_strs[str_ent_ptr][ent_chr_ptr] <> end_of_string) do + begin + trace_pr (xchr[entry_strs[str_ent_ptr][ent_chr_ptr]]); + incr(ent_chr_ptr); + end; +@y + while (x_entry_strs(str_ent_ptr)(ent_chr_ptr) <> end_of_string) do + begin + trace_pr (xchr[x_entry_strs(str_ent_ptr)(ent_chr_ptr)]); + incr(ent_chr_ptr); + end; +@z + +@x [463] Add check for fieldinfo[] overflow. + field_ptr := cite_ptr * num_fields; + field_end_ptr := field_ptr + num_fields; +@y + field_ptr := cite_ptr * num_fields; + field_end_ptr := field_ptr + num_fields; + if (field_end_ptr > max_fields) then + confusion ('field_info index is out of range'); +@z + +@x [468] System-dependent changes. +This section should be replaced, if necessary, by changes to the program +that are necessary to make \BibTeX\ 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. +@y +@d argument_is (#) == (strcmp (long_options[option_index].name, #) = 0) + +@<Define |parse_arguments|@> = +procedure parse_arguments; +const n_options = 4; {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 + @<Initialize the option variables@>; + @<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 + {End of arguments; we exit the loop below.} ; + + end else if getopt_return_val = "?" then begin + usage (my_name); + + end else if argument_is ('min-crossrefs') then begin + min_crossrefs := atoi (optarg); + + end else if argument_is ('help') then begin + usage_help (BIBTEX_HELP, nil); + + end else if argument_is ('version') then begin + print_version_and_exit (banner, 'Oren Patashnik', nil, nil); + + end; {Else it was 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. + We must have one remaining argument.} + if (optind + 1 <> argc) then begin + write_ln (stderr, my_name, ': Need exactly one file argument.'); + usage (my_name); + end; +end; + +@ Here is the first of the options we allow. +@.-terse@> + +@<Define the option...@> = +current_option := 0; +long_options[0].name := 'terse'; +long_options[0].has_arg := 0; +long_options[0].flag := address_of (verbose); +long_options[0].val := 0; +incr (current_option); + +@ The global variable |verbose| determines whether or not we print +progress information. + +@<Glob...@> = +@!verbose: c_int_type; + +@ Start off |true|, to match the default behavior. + +@<Initialize the option...@> = +verbose := true; + +@ Here is an option to change the minimum number of cross-refs required +for automatic |cite_list| inclusion. +@.-min-crossrefs@> + +@<Define the option...@> = +long_options[current_option].name := 'min-crossrefs'; +long_options[current_option].has_arg := 1; +long_options[current_option].flag := 0; +long_options[current_option].val := 0; +incr (current_option); + +@ +@<Glob...@> = +@!min_crossrefs: integer; + +@ Set |min_crossrefs| to two by default, so we match the +documentation (\.{btxdoc.tex}). + +@<Initialize the option...@> = +min_crossrefs := 2; + +@ One of the standard options. +@.-help@> + +@<Define the option...@> = +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; + +@ Determine |ent_str_size|, |glob_str_size|, and |max_strings| from the +environment, configuration file, or default value. Set +|hash_size:=max_strings|, but not less than |HASH_SIZE|. + +{|setup_bound_var| stuff adapted from \.{tex.ch}.} +@d setup_bound_var(#)==bound_default:=#; setup_bound_var_end +@d setup_bound_var_end(#)==bound_name:=#; setup_bound_var_end_end +@d setup_bound_var_end_end(#)== + setup_bound_variable(address_of(#), bound_name, bound_default); + if # < bound_default then # := bound_default + +@<Procedures and functions for about everything@>= +procedure setup_params; +var bound_default: integer; {for setup} +@!bound_name: const_cstring; {for setup} +begin kpse_set_program_name (argv[0], 'bibtex'); +setup_bound_var (ENT_STR_SIZE)('ent_str_size')(ent_str_size); +setup_bound_var (GLOB_STR_SIZE)('glob_str_size')(glob_str_size); +setup_bound_var (MAX_STRINGS)('max_strings')(max_strings); +@# +hash_size := max_strings; +if hash_size < HASH_SIZE then hash_size := HASH_SIZE; +hash_max := hash_size + hash_base - 1; +end_of_def := hash_max + 1; +undefined := hash_max + 1; +end; + +@ We use the algorithm from Knuth's \.{primes.web} to compute |hash_prime| +as the smallest prime number not less than 85\% of |hash_size| (and +|>=128|). + +@d primes == hash_next {array holding the first |k| primes} +@d mult == hash_text {array holding odd multiples of the first |o| primes} + +@<Procedures and functions for about everything@>= +procedure compute_hash_prime; +var hash_want: integer; {85\% of |hash_size|} +@!k: integer; {number of prime numbers $p_i$ in |primes|} +@!j: integer; {a prime number candidate} +@!o: integer; {number of odd multiples of primes in |mult|} +@!square: integer; {$p_o^2$} +@!n: integer; {loop index} +@!j_prime: boolean; {is |j| a prime?} +begin hash_want := (hash_size div 20) * 17; +j := 1; +k := 1; +hash_prime := 2; +primes[k] := hash_prime; +o := 2; +square := 9; +while hash_prime < hash_want do + begin + repeat + j := j + 2; + if j = square then + begin + mult[o] := j; + j := j + 2; + incr (o); + square := primes[o] * primes[o]; + end; + n := 2; + j_prime := true; + while (n < o) and j_prime do + begin + while mult[n] < j do mult[n] := mult[n] + 2 * primes[n]; + if mult[n] = j then j_prime := false; + incr (n); + end; + until j_prime; + incr (k); + hash_prime := j; + primes[k] := hash_prime; + end; +end; +@z