diff options
Diffstat (limited to 'Build')
27 files changed, 26944 insertions, 0 deletions
diff --git a/Build/source/extra/bibtex/README.file-listing b/Build/source/extra/bibtex/README.file-listing new file mode 100644 index 00000000000..469b4f2f164 --- /dev/null +++ b/Build/source/extra/bibtex/README.file-listing @@ -0,0 +1,28 @@ +Listing of ftp.cs.stanford.edu:pub/tex/bibtex, with dates: + +-rw-r--r-- 1 karl root 20285 Dec 5 1989 abbrv.bst +-rw-r--r-- 1 karl root 19367 Dec 12 1990 acm.bst +-rw-r--r-- 1 karl root 23863 Dec 5 1989 alpha.bst +-rw-r--r-- 1 karl root 21794 Dec 12 1990 apalike.bst +-rw-r--r-- 1 karl root 2303 Dec 12 1990 apalike.doc +-rw-r--r-- 1 karl root 1084 Dec 12 1990 apalike.sty +-rw-r--r-- 1 karl root 5370 Feb 29 1992 apalike.tex +-rw-r--r-- 1 karl root 1840 Jan 30 1992 bibtex.1 +-rw-r--r-- 1 karl root 6799 Jun 11 1988 bibtex.cms-changes +-rw-r--r-- 1 karl root 2435 Dec 5 1989 bibtex.ins +-rw-r--r-- 1 karl root 4037 Dec 5 1989 bibtex.tops20-changes +-rw-r--r-- 1 karl root 8616 Dec 5 1989 bibtex.vms-changes +-rw-r--r-- 1 karl root 383409 Dec 5 1989 bibtex.web +-rw-r--r-- 1 karl root 73045 Dec 5 1989 btxbst.doc +-rw-r--r-- 1 karl root 1508 Jan 31 1988 btxdoc.aux +-rw-r--r-- 1 karl root 596 Feb 8 1988 btxdoc.bbl +-rw-r--r-- 1 karl root 2594 Dec 5 1989 btxdoc.bib +-rw-r--r-- 1 karl root 41569 Feb 8 1988 btxdoc.tex +-rw-r--r-- 1 karl root 1398 Jan 31 1988 btxdoc.xua +-rw-r--r-- 1 karl root 25616 Dec 5 1989 btxhak.tex +-rw-r--r-- 1 karl root 33524 Nov 13 1995 btxmac.tex +-rw-r--r-- 1 karl root 16932 Dec 12 1990 ieeetr.bst +-rw-r--r-- 1 karl root 20569 Dec 5 1989 plain.bst +-rw-r--r-- 1 karl root 17956 Dec 12 1990 siam.bst +-rw-r--r-- 1 karl root 17986 Dec 5 1989 unsrt.bst +-rw-r--r-- 1 karl root 9894 Dec 5 1989 xampl.bib diff --git a/Build/source/extra/bibtex/abbrv.bst b/Build/source/extra/bibtex/abbrv.bst new file mode 100644 index 00000000000..740f569f860 --- /dev/null +++ b/Build/source/extra/bibtex/abbrv.bst @@ -0,0 +1,1097 @@ +% BibTeX standard bibliography style `abbrv' + % version 0.99a for BibTeX versions 0.99a or later, LaTeX version 2.09. + % Copyright (C) 1985, all rights reserved. + % Copying of this file is authorized only if either + % (1) you make absolutely no changes to your copy, including name, or + % (2) if you do make changes, you name it something other than + % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst. + % This restriction helps ensure that all standard styles are identical. + % The file btxbst.doc has the documentation for this style. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{f.~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { title "t" change.case$ } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ title emphasize +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "In {\em " journal * "\/}" * } + if$ + } + { "In " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "In {\em " booktitle * "\/}" * } + if$ + } + { "In " key * } + if$ + } + { "In " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ + { organization publisher new.sentence.checkb + organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + { publisher new.sentence.checka } + { organization publisher new.sentence.checkb + organization output + } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sept."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Softw. Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput.-Aided Design Integrated Circuits"} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Programming"} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Gr."} + +MACRO {toms} {"ACM Trans. Math. Softw."} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Prog. Lang. Syst."} + +MACRO {tcs} {"Theoretical Comput. Sci."} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ + s nameptr "{vv{ } }{ll{ }}{ f{ }}{ jj{ }}" format.name$ 't := + nameptr numnames = t "others" = and + { "et al" * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} + +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/Build/source/extra/bibtex/acm.bst b/Build/source/extra/bibtex/acm.bst new file mode 100644 index 00000000000..1750daa7a17 --- /dev/null +++ b/Build/source/extra/bibtex/acm.bst @@ -0,0 +1,1134 @@ +% ACM Transactions bibliography style (24-Jan-88 version) +% A lot like abbrv.bst, but names come out "Last, initials", and in \sc. +% Some dates are parenthesized. +% +% History +% 2/ 6/86 (HWT) Original version, by Howard Trickey. +% 3/ 5/86 (HWT) Put in pp. everywhere but articles, as per ACM style. +% 1/24/88 (OP&HWT) Updated for BibTeX version 0.99a, Oren Patashnik; +% corrected the abbreviations to "Mar." and "Sept."; +% THIS `acm' VERSION DOES NOT WORK WITH BIBTEX 0.98i. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +FUNCTION {emphasizeic} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "\/}" * } + if$ +} + +FUNCTION {scapify} +{ duplicate$ empty$ + { pop$ "" } + { "{\sc " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{vv~}{ll}{, jj}{, f.}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { t "others" = + { ", et~al." * } + { ", and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +% For names inside entries (e.g., editors of an "In ..."); +% this is exactly ABBRV.BST's `format.names' function. +FUNCTION {format.innames} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{f.~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names scapify } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names scapify + editor num.names$ #1 > + { ", Eds." * } + { ", Ed." * } + if$ + } + if$ +} + +FUNCTION {format.ineditors} +{ editor empty$ + { "" } + { editor format.innames + editor num.names$ #1 > + { ", Eds." * } + { ", Ed." * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { title "t" change.case$ } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ title emphasize +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "vol.~" volume * + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "no.~" } + { "No.~" } + if$ + number * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ "~ed." * } + { edition "t" change.case$ "~ed." * } + if$ + } + if$ +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages n.dashify } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pp.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pp.~" pages n.dashify * } + { "p.~" pages * } + if$ + } + if$ +} + +FUNCTION {format.journal.vol.num.date} +{ journal empty$ + { "empty journal in " cite$ * warning$ + "" + } + { journal + volume empty$ + 'skip$ + { " " * volume * } + if$ + number empty$ + 'emphasizeic + { emphasize ", " * number * } + if$ + year empty$ + { "empty year in " cite$ * warning$ } + { " (" * format.date * ")" * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pp.pages + { type empty$ + { "ch.~" chapter * } + { type "l" change.case$ chapter tie.or.space.connect } + if$ + pages empty$ + 'skip$ + { ", " * format.pp.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { "In " booktitle emphasize * + editor empty$ + 'skip$ + { ", " * format.ineditors * } + if$ + } + if$ +} + +% The proceedings title (it's on the stack) gets an (address, date) appended +FUNCTION {format.proc.date} +{ duplicate$ empty$ + { pop$ "" } + { year empty$ + { "empty year in " cite$ * warning$ + address empty$ + 'emphasize + { emphasizeic + " (" * address * ")" * + } + if$ + } + { emphasizeic + " (" * + address empty$ + 'skip$ + { address * ", " * } + if$ + format.date * + ")" * + } + if$ + } + if$ +} + +FUNCTION {format.in.proc.date} +{ booktitle empty$ + { "" } + { "In " booktitle format.proc.date * } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Tech. Rep." } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "In {\em " journal * "\/}" * } + if$ + } + { "In " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Vol.~" volume * + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "In {\em " booktitle * "\/}" * } + if$ + } + { "In " key * } + if$ + } + { "In " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.journal.vol.num.date output + format.pages output + } + { format.article.crossref output.nonnull + format.pp.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + format.edition output + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + format.edition output + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.date "year" output.check + format.chapter.pages "chapter and pages" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.edition output + format.bvolume output + format.number.series output + new.sentence + publisher "publisher" output.check + address output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull } + if$ + format.chapter.pages output + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.proc.date "booktitle" output.check + format.ineditors output + format.bvolume output + format.number.series output + organization output + publisher output + } + { format.incoll.inproc.crossref output.nonnull } + if$ + format.pp.pages output + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization scapify output } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.edition output + author empty$ + { address new.block.checka } + { organization address new.block.checkb + organization output + } + if$ + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization scapify output } + { format.editors output.nonnull } + if$ + new.block + title format.proc.date "title" output.check + format.bvolume output + format.number.series output + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sept."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Softw. Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput.-Aided Design Integrated Circuits"} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Programming"} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Gr."} + +MACRO {toms} {"ACM Trans. Math. Softw."} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Program. Lang. Syst."} + +MACRO {tcs} {"Theoretical Comput. Sci."} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ + s nameptr "{vv{ } }{ll{ }}{ f{ }}{ jj{ }}" format.name$ 't := + nameptr numnames = t "others" = and + { "et al" * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} + +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/Build/source/extra/bibtex/alpha.bst b/Build/source/extra/bibtex/alpha.bst new file mode 100644 index 00000000000..f8d5c5d3411 --- /dev/null +++ b/Build/source/extra/bibtex/alpha.bst @@ -0,0 +1,1257 @@ +% BibTeX standard bibliography style `alpha' + % version 0.99a for BibTeX versions 0.99a or later, LaTeX version 2.09. + % Copyright (C) 1985, all rights reserved. + % Copying of this file is authorized only if either + % (1) you make absolutely no changes to your copy, including name, or + % (2) if you do make changes, you name it something other than + % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst. + % This restriction helps ensure that all standard styles are identical. + % The file btxbst.doc has the documentation for this style. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label extra.label sort.label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem[" write$ + label write$ + "]{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { title "t" change.case$ } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ title emphasize +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "In {\em " journal * "\/}" * } + if$ + } + { "In " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "In {\em " booktitle * "\/}" * } + if$ + } + { "In " key * } + if$ + } + { "In " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ + { organization publisher new.sentence.checkb + organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + { publisher new.sentence.checka } + { organization publisher new.sentence.checkb + organization output + } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +INTEGERS { et.al.char.used } + +FUNCTION {initialize.et.al.char.used} +{ #0 'et.al.char.used := +} + +EXECUTE {initialize.et.al.char.used} + +FUNCTION {format.lab.names} +{ 's := + s num.names$ 'numnames := + numnames #1 > + { numnames #4 > + { #3 'namesleft := } + { numnames 'namesleft := } + if$ + #1 'nameptr := + "" + { namesleft #0 > } + { nameptr numnames = + { s nameptr "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { "{\etalchar{+}}" * + #1 'et.al.char.used := + } + { s nameptr "{v{}}{l{}}" format.name$ * } + if$ + } + { s nameptr "{v{}}{l{}}" format.name$ * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + numnames #4 > + { "{\etalchar{+}}" * + #1 'et.al.char.used := + } + 'skip$ + if$ + } + { s #1 "{v{}}{l{}}" format.name$ + duplicate$ text.length$ #2 < + { pop$ s #1 "{ll}" format.name$ #3 text.prefix$ } + 'skip$ + if$ + } + if$ +} + +FUNCTION {author.key.label} +{ author empty$ + { key empty$ + { cite$ #1 #3 substring$ } + { key #3 text.prefix$ } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {author.editor.key.label} +{ author empty$ + { editor empty$ + { key empty$ + { cite$ #1 #3 substring$ } + { key #3 text.prefix$ } + if$ + } + { editor format.lab.names } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {author.key.organization.label} +{ author empty$ + { key empty$ + { organization empty$ + { cite$ #1 #3 substring$ } + { "The " #4 organization chop.word #3 text.prefix$ } + if$ + } + { key #3 text.prefix$ } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {editor.key.organization.label} +{ editor empty$ + { key empty$ + { organization empty$ + { cite$ #1 #3 substring$ } + { "The " #4 organization chop.word #3 text.prefix$ } + if$ + } + { key #3 text.prefix$ } + if$ + } + { editor format.lab.names } + if$ +} + +FUNCTION {calc.label} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.key.label + { type$ "proceedings" = + 'editor.key.organization.label + { type$ "manual" = + 'author.key.organization.label + 'author.key.label + if$ + } + if$ + } + if$ + duplicate$ + year field.or.null purify$ #-1 #2 substring$ + * + 'label := + year field.or.null purify$ #-1 #4 substring$ + * + sortify 'sort.label := +} + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ + s nameptr "{vv{ } }{ll{ }}{ ff{ }}{ jj{ }}" format.name$ 't := + nameptr numnames = t "others" = and + { "et al" * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} + +FUNCTION {presort} +{ calc.label + sort.label + " " + * + type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + * + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT + +STRINGS { longest.label last.sort.label next.extra } + +INTEGERS { longest.label.width last.extra.num } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #0 int.to.chr$ 'last.sort.label := + "" 'next.extra := + #0 'longest.label.width := + #0 'last.extra.num := +} + +FUNCTION {forward.pass} +{ last.sort.label sort.label = + { last.extra.num #1 + 'last.extra.num := + last.extra.num int.to.chr$ 'extra.label := + } + { "a" chr.to.int$ 'last.extra.num := + "" 'extra.label := + sort.label 'last.sort.label := + } + if$ +} + +FUNCTION {reverse.pass} +{ next.extra "b" = + { "a" 'extra.label := } + 'skip$ + if$ + label extra.label * 'label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ + extra.label 'next.extra := +} + +EXECUTE {initialize.longest.label} + +ITERATE {forward.pass} + +REVERSE {reverse.pass} + +FUNCTION {begin.bib} +{ et.al.char.used + { "\newcommand{\etalchar}[1]{$^{#1}$}" write$ newline$ } + 'skip$ + if$ + preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/Build/source/extra/bibtex/apalike.bst b/Build/source/extra/bibtex/apalike.bst new file mode 100644 index 00000000000..dbd41afafc1 --- /dev/null +++ b/Build/source/extra/bibtex/apalike.bst @@ -0,0 +1,1101 @@ +% BibTeX `apalike' bibliography style (24-Jan-88 version) +% Adapted from the `alpha' style, version 0.99a; for BibTeX version 0.99a. +% Copyright (C) 1988, all rights reserved. +% Copying of this file is allowed, provided that if you make any changes at all +% you name it something other than `apalike.bst'. +% This restriction helps ensure that all copies are identical. +% Differences between this style and `alpha' are generally heralded by a `%'. +% The file btxbst.doc has the documentation for alpha.bst. +% +% This style should be used with the `apalike' LaTeX style (apalike.sty). +% \cite's come out like "(Jones, 1986)" in the text but there are no labels +% in the bibliography, and something like "(1986)" comes out immediately +% after the author. Author (and editor) names appear as last name, comma, +% initials. A `year' field is required for every entry, and so is either +% an author (or in some cases, an editor) field or a key field. +% +% Editorial note: +% Many journals require a style like `apalike', but I strongly, strongly, +% strongly recommend that you not use it if you have a choice---use something +% like `plain' instead. Mary-Claire van Leunen (A Handbook for Scholars, +% Knopf, 1979) argues convincingly that a style like `plain' encourages better +% writing than one like `apalike'. Furthermore the strongest arguments for +% using an author-date style like `apalike'---that it's "the most practical" +% (The Chicago Manual of Style, University of Chicago Press, thirteenth +% edition, 1982, pages 400--401)---fall flat on their face with the new +% computer-typesetting technology. For instance page 401 anachronistically +% states "The chief disadvantage of [a style like `plain'] is that additions +% or deletions cannot be made after the manuscript is typed without changing +% numbers in both text references and list." LaTeX sidesteps the disadvantage. +% +% History: +% 15-sep-86 (SK,OP) Original version, by Susan King and Oren Patashnik. +% 10-nov-86 (OP) Truncated the sort.key$ string to the correct length +% in bib.sort.order to eliminate error message. +% 24-jan-88 (OP) Updated for BibTeX version 0.99a, from alpha.bst 0.99a; +% apalike now sorts by author, then year, then title; +% THIS `apalike' VERSION DOES NOT WORK WITH BIBTEX 0.98i. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key +% month not used in apalike + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label extra.label sort.label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +% apalike needs this function because +% the year has special punctuation; +% apalike ignores the month +FUNCTION {output.year.check} +{ year empty$ + { "empty year in " cite$ * warning$ } + { write$ + " (" year * extra.label * ")" * + mid.sentence 'output.state := + } + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem[" write$ + label write$ + "]{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{vv~}{ll}{, jj}{, f.}" format.name$ 't := % last name first + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.key} % this function is just for apalike +{ empty$ + { key field.or.null } + { "" } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { title "t" change.case$ } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.btitle} +{ title emphasize +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ "In" % this is for apalike + " \cite{" * crossref * "}" * +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + "\cite{" * crossref * "}" * % this is for apalike +} + +FUNCTION {format.incoll.inproc.crossref} +{ "In" % this is for apalike + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + author format.key output % special for + output.year.check % apalike + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + editor format.key output + } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + output.year.check % special for apalike + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + author format.key output % special for + output.year.check % apalike + new.block + format.title "title" output.check + new.block + howpublished output + address output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check + editor format.key output + } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + output.year.check % special for apalike + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + author format.key output % special for + output.year.check % apalike + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + author format.key output % special for + output.year.check % apalike + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address output % for apalike + new.sentence % there's no year + organization output % here so things + publisher output % are simpler + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + format.authors output + author format.key output % special for + output.year.check % apalike + new.block + format.btitle "title" output.check + organization address new.block.checkb + organization output + address output + format.edition output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + author format.key output % special for + output.year.check % apalike + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + author format.key output % special for + output.year.check % apalike + new.block + format.title output + new.block + howpublished output + new.block + note output + fin.entry +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + author format.key output % special for + output.year.check % apalike + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + format.editors output + editor format.key output % special for + output.year.check % apalike + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address output % for apalike + new.sentence % we always output + organization output % a nonempty organization + publisher output % here + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + author format.key output % special for + output.year.check % apalike + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + author format.key output % special for + output.year.check % apalike + new.block + format.title "title" output.check + new.block + note "note" output.check + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +% There are three apalike cases: one person (Jones), +% two (Jones and de~Bruijn), and more (Jones et~al.). +% This function is much like format.crossref.editors. +% +FUNCTION {format.lab.names} +{ 's := + s #1 "{vv~}{ll}" format.name$ + s num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { s #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * s #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {author.key.label} +{ author empty$ + { key empty$ + { cite$ #1 #3 substring$ } + 'key % apalike uses the whole key + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {author.editor.key.label} +{ author empty$ + { editor empty$ + { key empty$ + { cite$ #1 #3 substring$ } + 'key % apalike uses the whole key + if$ + } + { editor format.lab.names } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {editor.key.label} +{ editor empty$ + { key empty$ + { cite$ #1 #3 substring$ } + 'key % apalike uses the whole key, no organization + if$ + } + { editor format.lab.names } + if$ +} + +FUNCTION {calc.label} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.key.label + { type$ "proceedings" = + 'editor.key.label % apalike ignores organization + 'author.key.label % for labeling and sorting + if$ + } + if$ + ", " % these three lines are + * % for apalike, which + year field.or.null purify$ #-1 #4 substring$ % uses all four digits + * + 'label := +} + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ % apalike uses initials + s nameptr "{vv{ } }{ll{ }}{ f{ }}{ jj{ }}" format.name$ 't := % <= here + nameptr numnames = t "others" = and + { "et al" * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.sort} +{ editor empty$ + { key empty$ + { "to sort, need editor or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ +} + +% apalike uses two sorting passes; the first one sets the +% labels so that the `a's, `b's, etc. can be computed; +% the second pass puts the references in "correct" order. +% The presort function is for the first pass. It computes +% label, sort.label, and title, and then concatenates. +FUNCTION {presort} +{ calc.label + label sortify + " " + * + type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.sort + 'author.sort + if$ + } + if$ + #1 entry.max$ substring$ % for + 'sort.label := % apalike + sort.label % style + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT % by label, sort.label, title---for final label calculation + +STRINGS { last.label next.extra } % apalike labels are only for the text; + +INTEGERS { last.extra.num } % there are none in the bibliography + +FUNCTION {initialize.extra.label.stuff} % and hence there is no `longest.label' +{ #0 int.to.chr$ 'last.label := + "" 'next.extra := + #0 'last.extra.num := +} + +FUNCTION {forward.pass} +{ last.label label = + { last.extra.num #1 + 'last.extra.num := + last.extra.num int.to.chr$ 'extra.label := + } + { "a" chr.to.int$ 'last.extra.num := + "" 'extra.label := + label 'last.label := + } + if$ +} + +FUNCTION {reverse.pass} +{ next.extra "b" = + { "a" 'extra.label := } + 'skip$ + if$ + label extra.label * 'label := + extra.label 'next.extra := +} + +EXECUTE {initialize.extra.label.stuff} + +ITERATE {forward.pass} + +REVERSE {reverse.pass} + +% Now that the label is right we sort for real, +% on sort.label then year then title. This is +% for the second sorting pass. +FUNCTION {bib.sort.order} +{ sort.label + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {bib.sort.order} + +SORT % by sort.label, year, title---giving final bibliography order + +FUNCTION {begin.bib} +{ preamble$ empty$ % no \etalchar in apalike + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{}" write$ newline$ % no labels in apalike +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/Build/source/extra/bibtex/apalike.doc b/Build/source/extra/bibtex/apalike.doc new file mode 100644 index 00000000000..8861e11e21c --- /dev/null +++ b/Build/source/extra/bibtex/apalike.doc @@ -0,0 +1,60 @@ +% apalike.sty style, used in conjunction with apalike.bst, +% will produce an apa-like bibliography style: +% +% 1) Bibliography entries formatted alphabetically, last name +% first, each entry having a hanging indentation and no label. +% 2) References in the following formats: +% (Author, 1986) +% (Author and Author, 1986) +% (Author et al., 1986). +% 3) Multiple references in the form (Author1, 1986; Author2, 1987) +% +% To be used as an optional argument to the \documentstyle command; for example +% \documentstyle[11pt,apalike]{book} +% +% 16-Sep-86, original version by Susan King and Oren Patashnik. +% 13-Oct-87 changes: +% Fixed bug in last line by adding the {} that disappeard when +% the \hbox{} was removed from the pre-APALIKE definition; +% added club and widow penalties; +% patched the \newblock LaTeX bug from `-.07em' to simply `.07em'; +% and made this work for document styles that don't define `chapter'. +% +% +% Use parens instead of brackets for \cite, and no label in the bibliography +% +\def\@cite#1#2{(#1\if@tempswa , #2\fi)} +\def\@biblabel#1{} + +% Set length of hanging indentation for bibliography entries +% +\newlength{\bibhang} +\setlength{\bibhang}{2em} + +% \thebibliography environment depends on whether or not `chapter's can exist +% +\@ifundefined{chapter}{\def\thebibliography#1{\section*{References\@mkboth + {REFERENCES}{REFERENCES}}\list + {\relax}{\setlength{\labelsep}{0em} + \setlength{\itemindent}{-\bibhang} + \setlength{\leftmargin}{\bibhang}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax}}% +{\def\thebibliography#1{\chapter*{Bibliography\@mkboth + {BIBLIOGRAPHY}{BIBLIOGRAPHY}}\list + {\relax}{\setlength{\labelsep}{0em} + \setlength{\itemindent}{-\bibhang} + \setlength{\leftmargin}{\bibhang}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax}} + +% `; ' goes between cites, and there's no \hbox around individual cites +% +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi + \def\@citea{}\@cite{\@for\@citeb:=#2\do + {\@citea\def\@citea{; }\@ifundefined + {b@\@citeb}{{\bf ?}\@warning + {Citation `\@citeb' on page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} diff --git a/Build/source/extra/bibtex/apalike.sty b/Build/source/extra/bibtex/apalike.sty new file mode 100644 index 00000000000..9c83ceb0d84 --- /dev/null +++ b/Build/source/extra/bibtex/apalike.sty @@ -0,0 +1,29 @@ +\def\@cite#1#2{(#1\if@tempswa , #2\fi)} +\def\@biblabel#1{} + +\newlength{\bibhang} +\setlength{\bibhang}{2em} + +\@ifundefined{chapter}{\def\thebibliography#1{\section*{References\@mkboth + {REFERENCES}{REFERENCES}}\list + {\relax}{\setlength{\labelsep}{0em} + \setlength{\itemindent}{-\bibhang} + \setlength{\leftmargin}{\bibhang}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax}}% +{\def\thebibliography#1{\chapter*{Bibliography\@mkboth + {BIBLIOGRAPHY}{BIBLIOGRAPHY}}\list + {\relax}{\setlength{\labelsep}{0em} + \setlength{\itemindent}{-\bibhang} + \setlength{\leftmargin}{\bibhang}} + \def\newblock{\hskip .11em plus .33em minus .07em} + \sloppy\clubpenalty4000\widowpenalty4000 + \sfcode`\.=1000\relax}} + +\def\@citex[#1]#2{\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi + \def\@citea{}\@cite{\@for\@citeb:=#2\do + {\@citea\def\@citea{; }\@ifundefined + {b@\@citeb}{{\bf ?}\@warning + {Citation `\@citeb' on page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}} diff --git a/Build/source/extra/bibtex/apalike.tex b/Build/source/extra/bibtex/apalike.tex new file mode 100644 index 00000000000..d8bfb87b6d6 --- /dev/null +++ b/Build/source/extra/bibtex/apalike.tex @@ -0,0 +1,103 @@ +%% @texfile{ +%% author = "Oren Patashnik", +%% version = "0.99b", +%% date = "29 Feb 1992", +%% filename = "apalike.tex", +%% address = "Please use electronic mail", +%% checksum = "103 854 5370", +%% email = "opbibtex@cs.stanford.edu", +%% codetable = "ISO/ASCII", +%% supported = "yes", +%% docstring = "Defines macros that make apalike work with plain TeX", +%% } +% apalike.tex, version 0.99b, for btxmac 0.99i, BibTeX 0.99c, TeX 3.0 or later. +% Copyright (C) 1990--92; all rights reserved. +% You may copy this file provided: that it's accompanied by btxmac.tex; +% and that either you make absolutely no changes to your copy, or if you +% do make changes, (1) you name the file something other than +% `apalike.tex' and you remove all occurrences of `apalike.tex' from the +% file, (2) you put, somewhere in the first twenty lines of the file, +% your name, along with an electronic address at which others who might +% use the file may reach you, and (3) you remove each occurrence of +% Oren's name and electronic address from this file. These restrictions +% help ensure that all standard versions of these macros are identical, +% and that Oren doesn't get deluged with inappropriate e-mail. +% +% This file, apalike.tex, contains TeX macros that let you use the +% apalike bibliography style with plain TeX. In essence, this file +% provides the TeX counterpart to apalike.sty, the LaTeX style file +% required for using the apalike bibliography style. Please report any +% bugs (outright goofs, misfeatures, or unclear documentation) to Oren +% Patashnik (opbibtex@cs.stanford.edu). These macros will become frozen +% shortly after BibTeX version 1.00 is released. +% +% AMS-TEX WARNING: This style (apalike) doesn't work with AmS-TeX's +% `amsppt' style, because AmS-TeX redefines the tie character `~' of +% plain TeX, and the `amsppt' style redefines plain TeX's `\nobreak' +% macro, so that a multiple-author reference for which `apalike' +% automatically produces an in-text citation like `(Jones et~al., 1992)' +% will throw AmS-TeX's `amsppt' style into an infinite loop, exceeding +% its input stack size. (I've checked no other AmS-TeX styles for this +% problem.) The AmS-TeX warning of btxmac.tex gives more information. +% END OF AMS-TEX WARNING. +% +% Editorial note (i.e., flame): +% Many journals require a style like `apalike', but I recommend that you +% not use it if you have a choice---use something like `plain' instead. +% Mary-Claire van Leunen (A Handbook for Scholars, Knopf, 1979) argues +% convincingly that a style like `plain' encourages better writing than +% one like `apalike'. Furthermore the best argument for using an +% author-date style like `apalike'---that it's "the most practical" +% (The Chicago Manual of Style, University of Chicago Press, thirteenth +% edition, 1982, pages 400--401)---falls flat on its face with the new +% computer-typesetting technology. For instance page 401 of the Chicago +% Manual anachronistically states "The chief disadvantage of [a style +% like `plain'] is that additions or deletions cannot be made after the +% manuscript is typed without changing numbers in both text references +% and list." With (La)TeX the disadvantage obviously evaporates. +% Moreover, apalike indulges in what I think is a shortsighted practice: +% automatically abbreviating first names. Abbreviating may occasionally +% make the work a page shorter, but at the cost of a less useful +% reference list; that's too high a cost for such a marginal benefit. +% The offense isn't egregious for a name like `Donald E. Knuth'---at +% least among those familiar with his field---since there aren't many +% other `D. E. Knuth's floating around. But referring to `D. E. Smith' +% in a field having more than one can be quite confusing. Moreover, +% with the proliferation of computers and citation indexes nowadays, +% it's important to indicate in the reference list an author's name +% exactly as it appears in the work cited. Automatically abbreviating +% first names is simply bad scholarship. (End of flame.) +% +% To use these macros you need the btxmac.tex macros, which let you use +% BibTeX with plain TeX (rather than with LaTeX); the file btxmac.tex +% explains those macros in detail, and gives examples. You simply +% \input apalike right after you \input btxmac to invoke these macros. +% +% +% HISTORY +% +% Oren Patashnik wrote the original version of these macros in December +% 1990, for use with btxmac.tex. +% +% 12-Dec-90 Version 0.99a, first general release. +% 29-Feb-92 0.99b, changed `\biblabelextrahang' to `\biblabelextraspace', +% to keep up with btxmac.tex version 0.99i. +% +% +% Here, finally (I swear, I thought he was never gonna stop), are the +% macros. The first bunch makes the label empty and sets 2em of +% hanging indentation (via \biblabelextraspace) for each entry. +% +\def\biblabelprint#1{\noindent}% +\def\biblabelcontents#1{}% +\def\bblhook{\biblabelextraspace = 2em }% +% +% +% And the last bunch formats an in-text citation: parens around the +% entire citation; semicolons separating individual references; and a +% comma between a reference and its note (like `page 41') if it exists. +% +\def\printcitestart{(}% left paren +\def\printcitefinish{)}% right parent +\def\printbetweencitations{; }% semicolon, space +\def\printcitenote#1{, #1}% comma, space, note (if it exists) diff --git a/Build/source/extra/bibtex/bibtex.1 b/Build/source/extra/bibtex/bibtex.1 new file mode 100644 index 00000000000..23b0676ddb1 --- /dev/null +++ b/Build/source/extra/bibtex/bibtex.1 @@ -0,0 +1,74 @@ +.TH BIBTEX 1 +.SH NAME +bibtex \- make a (La)TeX bibliography +.SH SYNOPSIS +.B bibtex auxname +.SH DESCRIPTION +BibTeX reads the top-level auxiliary +.I (.aux) +file that was output during the running of +.BR (la)tex (1) +and creates a bibliography +.I (.bbl) +file that will be incorporated into the document on subsequent runs of (La)TeX. +The auxname on the command line must be given without the +.I .aux +extension. +.PP +BibTeX looks up, in the bibliographic database +.I (.bib) +files, +the entries specified by the \\cite and \\nocite commands +in the (La)TeX source file. +It formats the information from those entries +according to instructions in the style +.I (.bst) +file, +and it outputs the results to the +.I .bbl +file. +.PP +The LaTeX manual (aka +.I LaTeX - A Document Preparation System, +by Leslie Lamport) +explains what a LaTeX source file must contain to work with BibTeX. +Appendix B of the LaTeX manual describes the format of the +.I .bib +files. +The "BibTeXing" document describes extensions and details of that format, +and it gives other useful hints for using BibTeX. + +BibTeX on Unix incorporates the path-searching mechanism +described in the man page for +.BR tex (1). +As of the August 1988 web2c version, +BibTeX searches the TEXINPUTS path for +.I .bst +files, and the BIBINPUTS path for +.I .bib +files. +.PP +.SH FILES +.TP 20 +btxdoc.tex +"BibTeXing" \- LaTeXable documentation for general BibTeX users +.TP +btxhak.tex +"Designing BibTeX Styles" \- LaTeXable documentation for style designers +.TP +btxmac.tex +macros for using BibTeX with plain TeX +.TP +btxdoc.bib +database file for those two documents +.TP +xampl.bib +database file giving examples of all standard entry types +.TP +btxbst.doc +template file and documentation for the standard styles +.PP +All those files should be available somewhere on the system. +.SH "SEE ALSO" +.BR latex (1), +.BR tex (1). diff --git a/Build/source/extra/bibtex/bibtex.cms-changes b/Build/source/extra/bibtex/bibtex.cms-changes new file mode 100644 index 00000000000..5e7cdd7549e --- /dev/null +++ b/Build/source/extra/bibtex/bibtex.cms-changes @@ -0,0 +1,253 @@ +This is BIBTEX.CMS-CHANGES in text format, as of June 9, 1988. + +BIBTEX change file for VM/CMS and MVS. +Created by Nhut Nguyen, IBM Japan. Ltd., Tokyo, Japan. (1986). + + +Mar 14, 1986 made it working +Mar 14, 1986 changed filetype of the log file to BIBLOG +Mar 14, 1986 eliminate the prompt for input file +Jul 14, 1986 made the initialize routine shorter, to avoid + overflow during compilation +Jul 30, 1986 Alan Spragens broke up |x_format_name| procedure; changed + extensions on aux and bbl files; cleaned up + VM/CMS declarations and procedures at end +Oct 29, 1986 Agnes Hsu leave extensions on aux, bib, and bst as in + Web; add '.*' extension before opening those + files +June 9, 1988 Dean Guenther Removed a few unecessary changes and did + some others for version .99 + Note that all tabs (x'05') in BIBTEX.WEB + were replaced by two blanks (x'4040'). + +@x banner line +@d banner=='This is BibTeX, Version 0.99c' {printed when the program starts} +@y +@d banner=='This is BibTeX, VM/CMS Version 0.99c' +@z + +@x term +@d term_out == tty +@d term_in == tty +@y +@d term_in==tty_in +@d term_out==tty_out +@z + +@x otherwise +@d othercases == others: {default for cases not listed explicitly} +@y +@d othercases == otherwise {default for cases not listed explicitly} +@z + +@x +begin +initialize; +print_ln(banner);@/ +@y +begin + termin(term_in); termout(term_out); + initialize; + print_ln(banner);@/ +@z + +@x compiler directives +@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead} +@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging} +@y +{It seems impossible to turn CHECK and DEBUG on and off easily given + how Tangle and VS/PASCAL work} +@z + +@x +@!ASCII_code=0..127; {seven-bit numbers} +@y +@!ASCII_code=packed 0..127; {seven-bit numbers} +@z + +@x +@d last_text_char=127 {ordinal number of the largest element of |text_char|} +@y +@d last_text_char=255 {ordinal number of the largest element of |text_char|} +@d ccat==@=||@> +@z + +@x +@!alpha_file=packed file of text_char; {files that contain textual data} +@y +@!alpha_file=text; {files that contain textual data} +@z + +@x +function erstat(var f:file):integer; extern; {in the runtime library} +@#@t\2@> +@y +@z + +@x +begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f); +@y +begin okstatus; pack_file_name; + reset(f,'NAME='ccat trim(str(name_of_file))); + a_open_in:=status; +@z + +@x +begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f); +@y +begin okstatus; pack_file_name; + rewrite(f,'NAME='ccat trim(str(name_of_file))); + a_open_out:=status; +@z + + +@x +function input_ln(var f:alpha_file) : boolean; +@y +@<VM/CMS stuff@> +@# +function input_ln(var f:alpha_file) : boolean; +@z + +@x +while (p_ptr < str_start[file_name+1]) do + begin + name_of_file[name_ptr] := chr (str_pool[p_ptr]); +@y +while (p_ptr < str_start[file_name+1]) do + begin + name_of_file[name_ptr] := xchr[str_pool[p_ptr]]; +@z + +@x +while (p_ptr < str_start[ext+1]) do + begin + name_of_file[name_ptr] := chr (str_pool[p_ptr]); + incr(name_ptr); incr(p_ptr); +@y +while (p_ptr < str_start[ext+1]) do + begin + name_of_file[name_ptr] := xchr[str_pool[p_ptr]]; + incr(name_ptr); incr(p_ptr); +@z + +@x +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); +@y +p_ptr := str_start[area]; +while (p_ptr < str_start[area+1]) do + begin + name_of_file[name_ptr] := xchr[str_pool[p_ptr]]; + incr(name_ptr); incr(p_ptr); +@z + +@x +@!s_bst_area : str_number; {\.{texinputs:}} +@y +@!s_aux_area : str_number; {\.{.*}} +@!s_bst_area : str_number; {\.{texinputs:}} +@z + +@x +pre_define('.blg ',4,file_ext_ilk); +s_log_extension := hash_text[pre_def_loc]; +pre_define('.bst ',4,file_ext_ilk); +s_bst_extension := hash_text[pre_def_loc]; +pre_define('.bib ',4,file_ext_ilk); +s_bib_extension := hash_text[pre_def_loc]; +pre_define('texinputs: ',10,file_area_ilk); +s_bst_area := hash_text[pre_def_loc]; +pre_define('texbib: ',7,file_area_ilk); +s_bib_area := hash_text[pre_def_loc]; +@y +pre_define('.biblog ',7,file_ext_ilk); +s_log_extension := hash_text[pre_def_loc]; +pre_define('.bst ',4,file_ext_ilk); +s_bst_extension := hash_text[pre_def_loc]; +pre_define('.bib ',4,file_ext_ilk); +s_bib_extension := hash_text[pre_def_loc]; +pre_define('.* ',2,file_area_ilk); +s_aux_area := hash_text[pre_def_loc]; +pre_define('.* ',2,file_area_ilk); +s_bst_area := hash_text[pre_def_loc]; +pre_define('.* ',2,file_area_ilk); +s_bib_area := hash_text[pre_def_loc]; +@z + +@x + write (term_out,'Please type input file name (no extension)--'); + if (eoln(term_in)) then {so the first |read| works} + read_ln (term_in); +@y + get (term_in) ; {so the first |get| works to clear EOL} +@z + + + +@x At line 2563 +@<Add extensions and open files@>= +begin +name_length := aux_name_length; {set to last used position} +add_extension (s_aux_extension); {this also sets |name_length|} +@y +@<Add extensions and open files@>= +begin +name_length := aux_name_length; {set to last used position} +add_extension (s_aux_extension); {this also sets |name_length|} +add_extension (s_aux_area); {this also sets |name_length|} +@z + +@x +add_extension (s_bib_extension); +@y +add_extension (s_bib_extension); +add_extension (s_bib_area); +@z + +@x +add_extension (s_bst_extension); +@y +add_extension (s_bst_extension); +add_extension (s_bst_area); +@z + +@x +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 +This section contains procedures particular to VM/CMS. + +@ Here are extra global variables for VM/CMS routines +@<Glob...@>= + +@!status: boolean; {did the last |reset| or |rewrite| succede?} + +@!tty_in, tty_out: text; +@ @<VM/CMS...@>= +procedure okstatus; begin status:=true; end; +procedure pack_file_name; +var buff : packed array[1..file_name_size] of char; + i, j : 1..file_name_size; +begin j := 1; + for i := 1 to file_name_size do buff[i] := ' '; + for i := 1 to file_name_size do + begin + if name_of_file[i] <> ' ' then + begin + buff[j] := name_of_file[i]; + incr(j); + end; + end; + for i := 1 to file_name_size do name_of_file[i] := buff[i]; +end; +@z diff --git a/Build/source/extra/bibtex/bibtex.ins b/Build/source/extra/bibtex/bibtex.ins new file mode 100644 index 00000000000..9a9b4ecedd6 --- /dev/null +++ b/Build/source/extra/bibtex/bibtex.ins @@ -0,0 +1,52 @@ +To get BibTeX running you should: make sure you have all files listed +below, read the overview section (the first page) of BTXDOC.TEX, and +(if needed) create or procure a BibTeX change file for your system so +you can Tangle and compile BibTeX. To test your implementation, +follow these simple steps (note: in what follows, the word `match' is +used loosely, because lines longer than 80 characters have been +broken manually in BTXDOC.AUX; thus, your system's file-compare +program may say the files are different even though they match): + +(A) Run BTXDOC.TEX through LaTeX. You'll get a bunch of LaTeX warning +messages, and LaTeX will produce a BTXDOC.AUX file that will NOT match +the supplied file of that name. NOTE: Don't let LaTeX "see" a copy of +the supplied BTXDOC.AUX or BTXDOC.BBL during this run. + +(B) Run BibTeX on the BTXDOC.AUX file created in step (A). BibTeX +will read in the supplied file BTXDOC.BIB. This run should produce +a BTXDOC.BBL file that matches the suppled file of the same name; +BibTeX will give one warning message (about chicago). + +(C) Run BTXDOC.TEX through LaTeX. Again, you'll get some LaTeX +warning messages, but this time LaTeX will produce a new BTXDOC.AUX +file that DOES match the supplied file of that name. This run will +read in the BTXDOC.AUX file produced in (A) and the BTXDOC.BBL file +produced in step (B). + +(D) Run BTXDOC.TEX through LaTeX. By reading the new BTXDOC.AUX file, +LaTeX will produce no warning messages, and you should get another +matching copy of the BTXDOC.AUX file. + +IMPORTANT NOTE: After you get BibTeX running you should make sure that +all the documentation files listed below are available on your system, +and you should state in the _Local Guide_ exactly how to access them. + +Here are BibTeX-related files in this directory: + + +BIBTEX.INS this file +BIBTEX.WEB the WEB source file for BibTeX +BTXDOC.TEX documentation, and also sample input for BibTeX implementors +BTXHAK.TEX documentation for style designers +BTXDOC.BIB the bibliography database file for BTXDOC.TEX +BTXDOC.BBL a file for comparing your implementation's output +BTXDOC.AUX another +XAMPL.BIB a database file with an example of every standard entry type + + +BTXBST.DOC the documentation and template for the four standard + bibliography styles: +ABBRV.BST abbreviated +ALPHA.BST alphabetic +PLAIN.BST plain +UNSRT.BST unsorted diff --git a/Build/source/extra/bibtex/bibtex.tops20-changes b/Build/source/extra/bibtex/bibtex.tops20-changes new file mode 100644 index 00000000000..ef77bcc61bc --- /dev/null +++ b/Build/source/extra/bibtex/bibtex.tops20-changes @@ -0,0 +1,113 @@ +BibTeX change file for TOPS-20, culled from Dave Fuchs's +TeX change file, with his permission. +Copyright (C) 1988 by Oren Patashnik. All rights reserved. + +History: +January 1988---The original version of the TOPS-20 change file, for + BibTeX version 0.99a. The only substantive feature allowed + specifying the top-level .AUX file in a command line argument. +February 1988---Changed for BibTeX's new version numbers, 0.99b,c. + + +@x Tell WEAVE to print only the changes: +\pageno=\contentspagenumber \advance\pageno by 1 +@y +\pageno=\contentspagenumber \advance\pageno by 1 +\let\maybe=\iffalse +\def\ttw{{\mc TOPS-20}} +\def\title{\BibTeX\ changes for \ttw} +@z + + +@x TOPS-20's banner: +@d banner=='This is BibTeX, Version 0.99c' {printed when the program starts} +@y +@d banner=='This is BibTeX, TOPS-20 Version 0.99c' +@z + + +@x Compiler directives: +@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead} +@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging} +@y The space after the B is due to a compiler bug. +@{@&$C-,A+,D-,P:520000@&B@= @>@} + {no range check, catch arithmetic overflow, no debug overhead, + move the code up to make room for the global data in production} +@!debug @{@&$C+,D+,P:520000@&B@= @>@}@+ gubed + {we turn everything on when debugging} +@z + + +@x Define the compile-time constant |max_rescan| for command-line processing +@!lit_stk_size=100; {maximum number of literal functions on the stack} +@y +@!lit_stk_size=100; {maximum number of literal functions on the stack} +@!max_rescan=500; {maximum length of the rescan buffer} +@z + + +@x Set the command-line switch +check_cmnd_line := false; {many systems will change this} +@y +check_cmnd_line := true; +@z + + +@x +@<Variables for possible command-line processing@>= +@!check_cmnd_line : boolean; {|true| if we're to check the command line} +@y + +@d RSCAN=@'500 {ReSCAN buffer JSYS} + +@<Variables for possible command-line processing@>= +@!check_cmnd_line : boolean; {|true| if we're to check the command line} +@!ac1: integer; {AC1 from Rescan} +@!rescan: packed array[1..max_rescan] of char; {rescan buffer} +@!rescan_len: integer; {amount of |rescan| used} +@!i: integer; {temporary} +@z + + +@x And finally, here's the code that handles the command line argument. +@<Process a possible command line@>= +begin +do_nothing; {the ``default system'' doesn't use the command line} +end +@y +\ttw\ puts the user command line into the so-called rescan buffer +(actually, we have to use a real hack to see if it's a bogus Execute, +Start, Continue, Debug, etc.\ command, in which case we should pretend +there was no command line, since the command line that was there was +not intended for \BibTeX). We copy the command line into the input +buffer, and once we've isolated the (\.{.aux} file-name) argument we +copy that into the |name_of_file| array. + +@<Process a possible command line@>= +begin +jsys(RSCAN,1,i;0;ac1); {put the command line into the |TTY| input buffer} +if (i<>2) or (ac1<=0) then goto aux_not_found; {RSCAN failed, somehow} +if eoln(term_in) then read_ln(term_in); {for some TOPS-20's} +read(term_in,rescan:rescan_len); {read in rescan buffer} +if rescan_len>max_rescan then begin + write_ln(term_out,'Command line longer than ',max_rescan:0, + ' characters, so I''m ignoring it'); + read_ln(term_in); goto aux_not_found; end; +@/{The following line is based upon experimentation with \ttw!} +if rescan_len=ac1-2 then goto aux_not_found; {EX, ST, DEB commands} +@# +i:=1; while rescan[i]>' ' do incr(i); {skip command name, presumably BibTeX}@/ +while (i<=rescan_len) and (rescan[i]=' ') do incr(i); {skip spaces}@/ +if i>rescan_len then goto aux_not_found; {there was no argument} +@# +aux_name_length := 0; +while (rescan[i]>' ') do {copy the argument into |name_of_file|} + begin + if (aux_name_length = file_name_size) then + sam_you_made_the_file_name_too_long; + incr(aux_name_length); + name_of_file[aux_name_length] := rescan[i]; + incr(i); + end; +end +@z diff --git a/Build/source/extra/bibtex/bibtex.vms-changes b/Build/source/extra/bibtex/bibtex.vms-changes new file mode 100644 index 00000000000..6fb4a808d27 --- /dev/null +++ b/Build/source/extra/bibtex/bibtex.vms-changes @@ -0,0 +1,277 @@ +BIBTeX change file for Vax/VMS +Modified, 12-Feb-88 by Jerry Leichter for Version .99b +Modified, 15-Apr-88 by Jerry Leichter for Version .99c +Modified, 27-May-88 by Nelson Beebe. Fixed some spelling errors and typos + that showed up when the code was woven. Added support for specifying + the file name on the command line. +@x +\def\title{\BibTeX\ } +@y +\pageno=\contentspagenumber \advance\pageno by 1 +\let\maybe=\iffalse +\def\title{\BibTeX changes for Vax/VMS} +@z + +@x +@d banner=='This is BibTeX, Version 0.99c' {printed when the program starts} +@y +@d banner=='This is BibTeX, Vax/VMS Version 0.99c' +@z + +@x +@d term_out == tty +@d term_in == tty +@y +@d term_out == output +@d term_in == input +@z + +@x +@d print(#) == begin write(log_file,#); write(term_out,#); end +@d print_ln(#) == begin write_ln(log_file,#); write_ln(term_out,#); end +@d print_newline == print_a_newline + {making this a procedure saves a little space} +@# +@d trace_pr(#) == begin write(log_file,#); end +@d trace_pr_ln(#) == begin write_ln(log_file,#); end +@d trace_pr_newline == begin write_ln(log_file); end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_a_newline; +begin +write_ln(log_file); +write_ln(term_out); +end; +@y +@d print(#) == begin write(log_file,#); write(term_out,#); end +@d print_ln(#) == begin write_ln(log_file,#,chr(13),chr(10)); + write_ln(term_out,#,chr(13),chr(10)); end +@d print_newline == print_a_newline + {making this a procedure saves a little space} +@# +@d trace_pr(#) == begin write(log_file,#); end +@d trace_pr_ln(#) == begin write_ln(log_file,#,chr(13),chr(10)); end +@d trace_pr_newline == begin write_ln(log_file,chr(13),chr(10)); end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_a_newline; +begin +write_ln(log_file,chr(13),chr(10)); +write_ln(term_out,chr(13),chr(10)); +end; +@z + +@x +@d othercases == others: {default for cases not listed explicitly} +@y +@d othercases == otherwise {Vax/VMS default for cases not listed + explicitly} +@z + +@x +program BibTEX; {all files are opened dynamically} +@y +program BibTEX(input,output); + {all files are opened dynamically} +@z + +@x +@<Compiler directives@>= +@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead} +@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging} +@y +On Vax/VMS, there are no compiler directives that can be introduced in this +way, but we take this opportunity to include a few system-dependent goodies. + +@d VAX_text==@= text @> +@d VAX_new==@= new @> +@d VAX_none==@= none @> +@d VAX_word==@= word @> +@d VAX_error==@= error @> +@d VAX_length==@= length @> +@d VAX_syi_sid==@= syi$_sid @> +@d VAX_continue==@= continue @> +@d VAX_external==@= external @> +@d VAX_readonly==@= readonly @> +@d VAX_volatile==@= volatile @> +@d VAX_aligned==@= aligned @> +@d VAX_unsigned==@= unsigned @> +@d VAX_carriage_control==@= carriage_control @> +@d VAX_io_setmode==@= io$_setmode @> +@d VAX_iom_ctrlcast==@= io$m_ctrlcast @> +@d VAX_immed==@= %immed @> +@d VAX_stdescr==@= %stdescr @> +@d VAX_ref==@= %ref @> +@d VAX_qiow==@= $qiow @> +@d VAX_assign==@= $assign @> +@d VAX_numtim==@= $numtim @> +@d VAX_getsyi==@= $getsyi @> +@d VAX_lib_get_foreign==@= lib$get_foreign @> +@d VAX_disposition==@= disposition @> +@d VAX_delete==@= delete @> +@d VAX_save==@= save @> +@d VAX_varying==@= varying @> +@d VAX_substr==@= substr @> +@d VAX_trnlog==@= $trnlog @> +@d VAX_ss_normal==@= ss$_normal @> + +@<Compiler directives@>= +@=[check(none)]@> {no debug overhead, but...} +debug @=[check(all)]@> gubed {turn everything on when debugging} +@z + +@x Define the compile-time constant |max_rescan| for command-line processing +@!lit_stk_size=100; {maximum number of literal functions on the stack} +@y +@!lit_stk_size=100; {maximum number of literal functions on the stack} +@!max_cmdline=500; {maximum length of the rescan buffer} +@z + +@x +@<Types in the outer block@>= +@y +@<Types in the outer block@>= +@!word_type = [word]-32768..32767; {16-bit integers} +@z + +@x +@!alpha_file=packed file of text_char; {files that contain textual data} +@y +@!alpha_file=text; {files that contain textual data} +@z + +@x +@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 +@<Procedures and functions for file-system interacting@>= +function a_open_in(var f:alpha_file):boolean; {open a text file for input} +begin +open(f,name_of_file,VAX_readonly,VAX_error:=VAX_continue); +if status(f)>0 then a_open_in:=false +else begin + reset(f,VAX_error:=VAX_continue); + a_open_in:=status(f)<=0; + end; +end; +@# +function a_open_out(var f:alpha_file):boolean; {open a text file for output} +begin +open(f,name_of_file,VAX_new,16383,{VAX\_disposition:=VAX\_delete,} + VAX_error:=VAX_continue); +if status(f)>0 then a_open_out:=false +else begin + rewrite(f,VAX_error:=VAX_continue); + a_open_out:=status(f)<=0; + end; +end; +@z + +@x +pre_define('texinputs: ',10,file_area_ilk); +s_bst_area := hash_text[pre_def_loc]; +pre_define('texbib: ',7,file_area_ilk); +s_bib_area := hash_text[pre_def_loc]; +@y +pre_define('tex$inputs: ',11,file_area_ilk); +s_bst_area := hash_text[pre_def_loc]; +pre_define('tex$bib: ',8,file_area_ilk); +s_bib_area := hash_text[pre_def_loc]; +@z + +@x +check_cmnd_line := false; {many systems will change this} +@y +check_cmnd_line := true; {many systems will change this} +@z + +@x And finally, here's the code that handles the command line argument. +@<Process a possible command line@>= +begin +do_nothing; {the ``default system'' doesn't use the command line} +end +@y +On VAX/VMS, we can make a program runnable by name by defining a foreign +command symbol for it; the command line is then accessible via a call to +\.{lib\$get\_foreign()}. Since all we need is a single word off the +command line, and since prompting for the input of that word is both a +nuisance, and precludes use of nice utilities like \.{Make}, it seems +simplest to pick up the name from the command line. + +The Kellerman and Smith VMS \TeX{} implementation takes this notion a +step further, and adds code to support running the program in native +mode, complete with command line switches and fancy parsing; they have +more ambition than I do just now. + +@<Process a possible command line@>= +begin + get_cmdline; + if (aux_name_length = file_name_size) then + sam_you_made_the_file_name_too_long + else if (aux_name_length = 0) then + goto aux_not_found +end +@ +@<Procedures and functions for all file I/O, error messages, and such@>= +function VAX_lib_get_foreign(VAX_stdescr s : + packed array [a..b : integer] of char; + %immed p2 : integer; + var p3 : word_type) : integer; + fortran; +@# +procedure get_cmdline; +label exit; +var + cmdline : packed array [1..max_cmdline] of char; + cmdlength : word_type; + i : integer; +@# +begin + aux_name_length := 0; + if not odd (VAX_lib_get_foreign(cmdline,0,cmdlength)) then + begin + print_ln('Cannot get command line; use "bibtex file"'); + return + end; +@# + i:=1; + while (i<=cmdlength) and (cmdline[i]=' ') do incr(i); {skip spaces}@/ + if i>cmdlength then return; {there was no argument} +@# + while (cmdline[i]>' ') do {copy the argument into |name_of_file|} + begin + if (aux_name_length = file_name_size) then + return; + incr(aux_name_length); + name_of_file[aux_name_length] := cmdline[i]; + incr(i) + end; +exit: +end; +@ +@z + +@x +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 +Here are the remaining changes to the program +that are necessary to make \.{TeX} work on Vax/VMS. + +@z diff --git a/Build/source/extra/bibtex/bibtex.web b/Build/source/extra/bibtex/bibtex.web new file mode 100644 index 00000000000..e465a33c48d --- /dev/null +++ b/Build/source/extra/bibtex/bibtex.web @@ -0,0 +1,11652 @@ +% This program is copyright (C) 1985 by Oren Patashnik; all rights reserved. +% Copying of this file is authorized only if (1) you are Oren Patashnik, or if +% (2) you make absolutely no changes to your copy. (The WEB system provides +% for alterations via an auxiliary file; the master file should stay intact.) +% See Appendix H of the WEB manual for hints on how to install this program. + +% Version 0.98f was released in March 1985. +% Version 0.98g was released in April; it removed some system dependencies +% (introducing term_in and term_out in place of just tty, and removing +% some nonlocal goto's) and it gave context for certain parsing errors. +% Version 0.98h was released in April; it patched a bug in the output +% line-breaking routine that can arise with some nonstandard style files. +% Version 0.98i was released in May; its main change split up the main program +% and some procedures to help certain compilers cope with size +% limitations, among other things changing error and warning macros so +% they'd produce (much) less inline code; it also redefined the class of +% legal style-file identifiers---although this affects only the bizarre +% ones, it makes BibTeX's error messages more coherent; and it had many +% minor changes, including about a 15% speed-up on TOPS-20. +% Version 0.99a was released in January 1988. Its main changes: allowed the +% inclusion of entire .bib files (rather than just those entries +% \cited or \nocited); made the sorting algorithm stable; eliminated +% any case conversion for file names; allowed concatenation in database +% fields and string definitions; handled hyphenated names properly; +% handled accented characters properly; implemented new empty$, +% preamble$, text.length$, text.prefix$, and warning$ built-in functions; +% allowed a new cross-referencing feature; and made many minor fixes, +% including about a 40% speed-up on TOPS-20. +% Version 0.99b was released in February 1988. It changed text.length$ and +% text.prefix$ to not count braces as text characters, and it changed +% text.prefix$ to add any necessary matching right braces. +% Version 0.99c was released in February 1988. It removed two begin-end pairs +% that, for convention only, surrounded entire modules, but that elicited +% label-related complaints from some compilers. + +% Please report any bugs to Oren Patashnik (PATASHNIK@@SCORE.STANFORD.EDU) + +% Although considerable effort has been expended to make the BibTeX program +% correct and reliable, no warranty is implied; the author disclaims any +% obligation or liability for damages, including but not limited to +% special, indirect, or consequential damages arising out of or in +% connection with the use or performance of this software. + +% This program was written by Oren Patashnik, in consultation with Leslie +% Lamport, to be used with Lamport's LaTeX document preparation system. +% Some modules were taken from Knuth's TeX and TeXware with his permission. + +% Here is TeX material that gets inserted after \input webmac +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\ninerm=cmr9 +\let\mc=\ninerm % medium caps for names like PASCAL +\def\PASCAL{{\mc PASCAL}} +\def\ph{{\mc PASCAL-H}} +\def\<#1>{$\langle#1\rangle$} +\def\section{\mathhexbox278} + +\def\(#1){} % this is used to make section names sort themselves better +\def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@> + +% Note: WEAVE will typeset an upper-case `E' in a PASCAL identifier a +% bit strangely so that the `TeX' in the name of this program is typeset +% correctly; if this becomes a problem remove these three lines to get +% normal upper-case `E's in PASCAL identifiers +\def\drop{\kern-.1667em\lower.5ex\hbox{E}\kern-.125em} % middle of TeX +\catcode`E=13 \uppercase{\def E{e}} +\def\\#1{\hbox{\let E=\drop\it#1\/\kern.05em}} % italic type for identifiers + +\font\sc=cmcsc10 + +\def\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} + +\def\LaTeX{{\rm L\kern-.36em\raise.3ex\hbox{\sc a}\kern-.15em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} + +\def\title{\BibTeX\ } +\def\today{\ifcase\month\or + January\or February\or March\or April\or May\or June\or + July\or August\or September\or October\or November\or December\fi + \space\number\day, \number\year} +\def\topofcontents{\null\vfill + \def\titlepage{F} + \centerline{\:\titlefont The {\:\ttitlefont \BibTeX} preprocessor} + \vskip 15pt \centerline{(Version 0.99c---\today)} \vfill} +\pageno=\contentspagenumber \advance\pageno by 1 + + + +@* Introduction. +@^documentation@> +@^space savings@> +@^system dependencies@> +@^wizard@> +@!@:BibTeX}{\BibTeX@> +@!@:BibTeX documentation}{\BibTeX\ documentation@> +@:LaTeX}{\LaTeX@> +\BibTeX\ is a preprocessor (with elements of postprocessing as +explained below) for the \LaTeX\ document-preparation system. It +handles most of the formatting decisions required to produce a +reference list, outputting a \.{.bbl} file that a user can edit to add +any finishing touches \BibTeX\ isn't designed to handle (in practice, +such editing almost never is needed); with this file \LaTeX\ actually +produces the reference list. + +Here's how \BibTeX\ works. It takes as input (a)~an \.{.aux} file +produced by \LaTeX\ on an earlier run; (b)~a \.{.bst} file (the style +file), which specifies the general reference-list style and specifies +how to format individual entries, and which is written by a style +designer (called a wizard throughout this program) in a +special-purpose language described in the \BibTeX\ documentation---see +the file {\.{btxdoc.tex}}; and (c)~\.{.bib} file(s) constituting a +database of all reference-list entries the user might ever hope to +use. \BibTeX\ chooses from the \.{.bib} file(s) only those entries +specified by the \.{.aux} file (that is, those given by \LaTeX's +\.{\\cite} or \.{\\nocite} commands), and creates as output a \.{.bbl} +file containing these entries together with the formatting commands +specified by the \.{.bst} file (\BibTeX\ also creates a \.{.blg} log +file, which includes any error or warning messages, but this file +isn't used by any program). \LaTeX\ will use the \.{.bbl} file, +perhaps edited by the user, to produce the reference list. + +Many modules of \BibTeX\ were taken from Knuth's \TeX\ and \TeX ware, +with his permission. All known system-dependent modules are marked in +the index entry ``system dependencies''; Dave Fuchs helped exorcise +unwanted ones. In addition, a few modules that can be changed to make +\BibTeX\ smaller are marked in the index entry ``space savings''. + +Megathanks to Howard Trickey, for whose suggestions future users and +style writers would be eternally grateful, if only they knew. + +The |banner| string defined here should be changed whenever \BibTeX\ +gets modified. + +@d banner=='This is BibTeX, Version 0.99c' {printed when the program starts} + + +@ +@^system dependencies@> +Terminal output goes to the file |term_out|, while terminal input +comes from |term_in|. On our system, these (system-dependent) files +are already opened at the beginning of the program, and have the same +real name. + +@d term_out == tty +@d term_in == tty + + +@ +@^system dependencies@> +This program uses the term |print| instead of |write| when writing on +both the |log_file| and (system-dependent) |term_out| file, and it +uses |trace_pr| when in |trace| mode, for which it writes on just the +|log_file|. If you want to change where either set of macros writes +to, you should also change the other macros in this program for that +set; each such macro begins with |print_| or |trace_pr_|. + +@d print(#) == begin write(log_file,#); write(term_out,#); end +@d print_ln(#) == begin write_ln(log_file,#); write_ln(term_out,#); end +@d print_newline == print_a_newline + {making this a procedure saves a little space} +@# +@d trace_pr(#) == begin write(log_file,#); end +@d trace_pr_ln(#) == begin write_ln(log_file,#); end +@d trace_pr_newline == begin write_ln(log_file); end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_a_newline; +begin +write_ln(log_file); +write_ln(term_out); +end; + + +@ +@^debugging@> +@^statistics@> +Some of the code below is intended to be used only when diagnosing the +strange behavior that sometimes occurs when \BibTeX\ is being +installed or when system wizards are fooling around with \BibTeX\ +without quite knowing what they are doing. Such code will not normally +be compiled; it is delimited by the codewords +`$|debug|\ldots|gubed|$', with apologies to people who wish to +preserve the purity of English. Similarly, there is some conditional +code delimited by `$|stat|\ldots|tats|$' that is intended only for use +when statistics are to be kept about \BibTeX's memory/cpu usage, +and there is conditional code delimited by `$|trace|\ldots|ecart|$' +that is intended to be a trace facility for use mainly when debugging +\.{.bst} files. + +@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 + + +@ +@^system dependencies@> +We assume that |case| statements may include a +default case that applies if no matching label is found, +since most \PASCAL\ compilers have plugged this hole in the language by +incorporating some sort of default mechanism. For example, the \ph\ +compiler allows `|others|:' as a default label, and other \PASCAL s allow +syntaxes like `\ignorespaces|else|\unskip' or `\\{otherwise}' or +`\\{otherwise}:', etc. The definitions of |othercases| and |endcases| +should be changed to agree with local conventions. Note that no semicolon +appears before |endcases| in this program, so the definition of |endcases| +should include a semicolon if the compiler wants one. (Of course, if no +default mechanism is available, the |case| statements of \BibTeX\ will have +to be laboriously extended by listing all remaining cases. People who are +stuck with such \PASCAL s have in fact done this, successfully but not +happily!) + +@d othercases == others: {default for cases not listed explicitly} +@d endcases == @+end {follows the default case in an extended |case| statement} +@f othercases == else +@f endcases == end + + +@ +Labels are given symbolic names by the following definitions, so that +occasional |goto| statements will be meaningful. We insert the label +`|exit|:' just before the `\ignorespaces|end|\unskip' of a procedure +in which we have used the `|return|' statement defined below (and this +is the only place `|exit|:' appears). This label is sometimes used +for exiting loops that are set up with the |loop| construction defined +below. Another generic label is `|loop_exit|:'; it appears +immediately after a loop. + +Incidentally, this program never declares a label that isn't actually used, +because some fussy \PASCAL\ compilers will complain about redundant labels. + +@d exit=10 {go here to leave a procedure} +@d loop_exit=15 {go here to leave a loop within a procedure} +@d loop1_exit=16 {the first generic label for a procedure with two} +@d loop2_exit=17 {the second} + + +@ +@^for loops@> +And |while| we're discussing loops: This program makes into |while| +loops many that would otherwise be |for| loops because of Standard +\PASCAL\ limitations (it's a bit complicated---standard \PASCAL\ +doesn't allow a global variable as the index of a |for| loop inside a +procedure; furthermore, many compilers have fairly severe limitations +on the size of a block, including the main block of the program; so +most of the code in this program occurs inside procedures, and since +for other reasons this program must use primarily global variables, it +doesn't use many |for| loops). + + +@ +@^program conventions@> +This program uses this convention: If there are several quantities in +a boolean expression, they are ordered by expected frequency (except +perhaps when an error message results) so that execution will be +fastest; this is more an attempt to understand the program than to +make it faster. + + +@ +Here are some macros for common programming idioms. + +@d incr(#) == #:=#+1 {increase a variable by unity} +@d decr(#) == #:=#-1 {decrease a variable by unity} +@d loop == @+ while true do@+ {repeat over and over until a |goto| happens} +@f loop == xclause + {\.{WEB}'s |xclause| acts like `\ignorespaces|while true do|\unskip'} +@d do_nothing == {empty statement} +@d return == goto exit {terminate a procedure call} +@f return == nil +@d empty=0 {symbolic name for a null constant} +@d any_value=0 {this appeases \PASCAL's boolean-evaluation scheme} + + + +@* The main program. +@^system dependencies@> +@:LaTeX}{\LaTeX@> +This program first reads the \.{.aux} file that \LaTeX\ produces, +(\romannumeral1) determining which \.{.bib} file(s) and \.{.bst} file +to read and (\romannumeral2) constructing a list of cite keys in order +of occurrence. The \.{.aux} file may have other \.{.aux} files nested +within. Second, it reads and executes the \.{.bst} file, +(\romannumeral1) determining how and in which order to process the +database entries in the \.{.bib} file(s) corresponding to those cite +keys in the list (or in some cases, to all the entries in the \.{.bib} +file(s)), (\romannumeral2) determining what text to be output for each +entry and determining any additional text to be output, and +(\romannumeral3) actually outputting this text to the \.{.bbl} file. +In addition, the program sends error messages and other remarks to the +|log_file| and terminal. + +@d close_up_shop=9998 {jump here after fatal errors} +@d exit_program=9999 {jump here if we couldn't even get started} + +@p +@t\4@>@<Compiler directives@>@/ +program BibTEX; {all files are opened dynamically} +label close_up_shop,@!exit_program @<Labels in the outer block@>; +const @<Constants in the outer block@> +type @<Types in the outer block@> +var @<Globals in the outer block@>@; +@<Procedures and functions for about everything@>@; +@<The procedure |initialize|@> +@# +begin +initialize; +print_ln(banner);@/ +@<Read the \.{.aux} file@>; +@<Read and execute the \.{.bst} file@>; +close_up_shop: +@<Clean up and leave@>; +exit_program: +end. + + +@ +@^overflow in arithmetic@> +@^system dependencies@> +If the first character of a \PASCAL\ comment is a dollar sign, +\ph\ treats the comment as a list of ``compiler directives'' that will +affect the translation of this program into machine language. The +directives shown below specify full checking and inclusion of the \PASCAL\ +debugger when \BibTeX\ is being debugged, +but they cause range checking and other +redundant code to be eliminated when the production system is being generated. +Arithmetic overflow will be detected in all cases. + +@<Compiler directives@>= +@{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead} +@!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging} + + +@ +@^bottom up@> +@^gymnastics@> +@^mooning@> +All procedures in this program (except for |initialize|) are grouped +into one of the seven classes below, and these classes are dispersed +throughout the program. However: Much of this program is written top +down, yet \PASCAL\ wants its procedures bottom up. Since mooning is +neither a technically nor a socially acceptable solution to the +bottom-up problem, this section instead performs the topological +gymnastics that \.{WEB} allows, ordering these classes to satisfy +\PASCAL\ compilers. There are a few procedures still out of place +after this ordering, though, and the other modules that complete the +task have ``gymnastics'' as an index entry. + +@<Procedures and functions for about everything@>= +@<Procedures and functions for all file I/O, error messages, and such@>@; +@<Procedures and functions for file-system interacting@>@; +@<Procedures and functions for handling numbers, characters, and strings@>@; +@<Procedures and functions for input scanning@>@; +@<Procedures and functions for name-string processing@>@; +@<Procedures and functions for style-file function execution@>@; +@<Procedures and functions for the reading and processing of input files@> + + +@ +This procedure gets things started properly. + +@<The procedure |initialize|@>= +procedure initialize; +var @<Local variables for initialization@> +begin +@<Check the ``constant'' values for consistency@>; +if (bad > 0) then + begin + write_ln (term_out,bad:0,' is a bad bad'); + goto exit_program; + end; +@<Set initial values of key variables@>; +pre_def_certain_strings;@/ +get_the_top_level_aux_file_name; +end; + + +@ +@^space savings@> +@^system dependencies@> +These parameters can be changed at compile time to extend or reduce +\BibTeX's capacity. They are set to accommodate about 750 cites when +used with the standard styles, although |pool_size| is usually the +first limitation to be a problem, often when there are 500 cites. + +@<Constants in the outer block@>= +@!buf_size=1000; {maximum number of characters in an input line (or string)} +@!min_print_line=3; {minimum \.{.bbl} line length: must be |>=3|} +@!max_print_line=79; {the maximum: must be |>min_print_line| and |<buf_size|} +@!aux_stack_size=20; {maximum number of simultaneous open \.{.aux} files} +@!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} +@!single_fn_space=100; {maximum amount for a single |wiz_defined|-function} +@!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, + about |23*max_cites| for consistency)} +@!lit_stk_size=100; {maximum number of literal functions on the stack} + + +@ +@^space savings@> +@^system dependencies@> +These parameters can also be changed at compile time, but they're +needed to define some \.{WEB} numeric macros so they must be so +defined themselves. + +@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|} + + +@ +In case somebody has inadvertently made bad settings of the ``constants,'' +\BibTeX\ checks them using a global variable called |bad|. + +This is the first of many sections of \BibTeX\ where global variables are +defined. + +@<Globals in the outer block@>= +@!bad:integer; {is some ``constant'' wrong?} + + +@ +Each digit-value of |bad| has a specific meaning. + +@<Check the ``constant'' values for consistency@>= +bad := 0; +if (min_print_line < 3) then bad:=1; +if (max_print_line <= min_print_line) then bad:=10*bad+2; +if (max_print_line >= buf_size) then bad:=10*bad+3; +if (hash_prime < 128) then bad:=10*bad+4; +if (hash_prime > hash_size) then bad:=10*bad+5; +if (hash_prime >= (16384-64)) then bad:=10*bad+6; +if (max_strings > hash_size) then bad:=10*bad+7; +if (max_cites > max_strings) then bad:=10*bad+8; +if (ent_str_size > buf_size) then bad:=10*bad+9; +if (glob_str_size > buf_size) then bad:=100*bad+11; + {well, almost each} + + +@ +A global variable called |history| will contain one of four values at +the end of every run: |spotless| means that no unusual messages were +printed; |warning_message| means that a message of possible interest +was printed but no serious errors were detected; |error_message| means +that at least one error was found; |fatal_message| means that the +program terminated abnormally. The value of |history| does not +influence the behavior of the program; it is simply computed for the +convenience of systems that might want to use such information. + +@d spotless=0 {|history| value for normal jobs} +@d warning_message=1 {|history| value when non-serious info was printed} +@d error_message=2 {|history| value when an error was noted} +@d fatal_message=3 {|history| value when we had to stop prematurely} + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure mark_warning; +begin +if (history = warning_message) then + incr(err_count) + else if (history = spotless) then + begin + history := warning_message; + err_count := 1; + end; +end; +@# +procedure mark_error; +begin +if (history < error_message) then + begin + history := error_message; + err_count := 1; + end + else {|history = error_message|} + incr(err_count); +end; +@# +procedure mark_fatal; +begin +history := fatal_message; +end; + + +@ +For the two states |warning_message| and |error_message| we keep track +of the number of messages given; but since |warning_message|s aren't +so serious, we ignore them once we've seen an |error_message|. Hence +we need just the single variable |err_count| to keep track. + + +@<Globals in the outer block@>= +@!history:spotless..fatal_message; {how bad was this run?} +@!err_count:integer; + + +@ +The |err_count| gets set or reset when |history| first changes to +|warning_message| or |error_message|, so we don't need to initialize +it. + +@<Set initial values of key variables@>= +history := spotless; + + + +@* The character set. +@^ASCII code@> +(The following material is copied (almost) verbatim from \TeX. +Thus, the same system-dependent changes should be made to both programs.) + +In order to make \TeX\ readily portable between a wide variety of +computers, all of its input text is converted to an internal seven-bit +code that is essentially standard ASCII, the ``American Standard Code for +Information Interchange.'' This conversion is done immediately when each +character is read in. Conversely, characters are converted from ASCII to +the user's external representation just before they are output to a +text file. + +Such an internal code is relevant to users of \TeX\ primarily because it +governs the positions of characters in the fonts. For example, the +character `\.A' has ASCII code $65=@'101$, and when \TeX\ typesets +this letter it specifies character number 65 in the current font. +If that font actually has `\.A' in a different position, \TeX\ doesn't +know what the real position is; the program that does the actual printing from +\TeX's device-independent files is responsible for converting from ASCII to +a particular font encoding. + +\TeX's internal code is relevant also with respect to constants +that begin with a reverse apostrophe. + + +@ +Characters of text that have been converted to \TeX's internal form +are said to be of type |ASCII_code|, which is a subrange of the integers. + +@<Types in the outer block@>= +@!ASCII_code=0..127; {seven-bit numbers} + + +@ +@^character set dependencies@> +@^system dependencies@> +The original \PASCAL\ compiler was designed in the late 60s, when six-bit +character sets were common, so it did not make provision for lower-case +letters. Nowadays, of course, we need to deal with both capital and small +letters in a convenient way, especially in a program for typesetting; +so the present specification of \TeX\ has been written under the assumption +that the \PASCAL\ compiler and run-time system permit the use of text files +with more than 64 distinguishable characters. More precisely, we assume that +the character set contains at least the letters and symbols associated +with ASCII codes @'40 through @'176; all of these characters are now +available on most computer terminals. + +Since we are dealing with more characters than were present in the first +\PASCAL\ compilers, we have to decide what to call the associated data +type. Some \PASCAL s use the original name |char| for the +characters in text files, even though there now are more than 64 such +characters, while other \PASCAL s consider |char| to be a 64-element +subrange of a larger data type that has some other name. + +In order to accommodate this difference, we shall use the name |text_char| +to stand for the data type of the characters that are converted to and +from |ASCII_code| when they are input and output. We shall also assume +that |text_char| consists of the elements |chr(first_text_char)| through +|chr(last_text_char)|, inclusive. The following definitions should be +adjusted if necessary. + +@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} + + +@ +The \TeX\ processor converts between ASCII code and +the user's external character set by means of arrays |xord| and |xchr| +that are analogous to \PASCAL's |ord| and |chr| functions. + +@<Globals in the outer block@>= +@!xord: array [text_char] of ASCII_code; + {specifies conversion of input characters} +@!xchr: array [ASCII_code] of text_char; + {specifies conversion of output characters} + + +@ +@^character set dependencies@> +@^system dependencies@> +Since we are assuming that our \PASCAL\ system is able to read and write the +visible characters of standard ASCII (although not necessarily using the +ASCII codes to represent them), the following assignment statements initialize +most of the |xchr| array properly, without needing any system-dependent +changes. On the other hand, it is possible to implement \TeX\ with +less complete character sets, and in such cases it will be necessary to +change something here. + +@<Set initial values of key variables@>= +xchr[@'40]:=' '; +xchr[@'41]:='!'; +xchr[@'42]:='"'; +xchr[@'43]:='#'; +xchr[@'44]:='$'; +xchr[@'45]:='%'; +xchr[@'46]:='&'; +xchr[@'47]:='''';@/ +xchr[@'50]:='('; +xchr[@'51]:=')'; +xchr[@'52]:='*'; +xchr[@'53]:='+'; +xchr[@'54]:=','; +xchr[@'55]:='-'; +xchr[@'56]:='.'; +xchr[@'57]:='/';@/ +xchr[@'60]:='0'; +xchr[@'61]:='1'; +xchr[@'62]:='2'; +xchr[@'63]:='3'; +xchr[@'64]:='4'; +xchr[@'65]:='5'; +xchr[@'66]:='6'; +xchr[@'67]:='7';@/ +xchr[@'70]:='8'; +xchr[@'71]:='9'; +xchr[@'72]:=':'; +xchr[@'73]:=';'; +xchr[@'74]:='<'; +xchr[@'75]:='='; +xchr[@'76]:='>'; +xchr[@'77]:='?';@/ +xchr[@'100]:='@@'; +xchr[@'101]:='A'; +xchr[@'102]:='B'; +xchr[@'103]:='C'; +xchr[@'104]:='D'; +xchr[@'105]:='E'; +xchr[@'106]:='F'; +xchr[@'107]:='G';@/ +xchr[@'110]:='H'; +xchr[@'111]:='I'; +xchr[@'112]:='J'; +xchr[@'113]:='K'; +xchr[@'114]:='L'; +xchr[@'115]:='M'; +xchr[@'116]:='N'; +xchr[@'117]:='O';@/ +xchr[@'120]:='P'; +xchr[@'121]:='Q'; +xchr[@'122]:='R'; +xchr[@'123]:='S'; +xchr[@'124]:='T'; +xchr[@'125]:='U'; +xchr[@'126]:='V'; +xchr[@'127]:='W';@/ +xchr[@'130]:='X'; +xchr[@'131]:='Y'; +xchr[@'132]:='Z'; +xchr[@'133]:='['; +xchr[@'134]:='\'; +xchr[@'135]:=']'; +xchr[@'136]:='^'; +xchr[@'137]:='_';@/ +xchr[@'140]:='`'; +xchr[@'141]:='a'; +xchr[@'142]:='b'; +xchr[@'143]:='c'; +xchr[@'144]:='d'; +xchr[@'145]:='e'; +xchr[@'146]:='f'; +xchr[@'147]:='g';@/ +xchr[@'150]:='h'; +xchr[@'151]:='i'; +xchr[@'152]:='j'; +xchr[@'153]:='k'; +xchr[@'154]:='l'; +xchr[@'155]:='m'; +xchr[@'156]:='n'; +xchr[@'157]:='o';@/ +xchr[@'160]:='p'; +xchr[@'161]:='q'; +xchr[@'162]:='r'; +xchr[@'163]:='s'; +xchr[@'164]:='t'; +xchr[@'165]:='u'; +xchr[@'166]:='v'; +xchr[@'167]:='w';@/ +xchr[@'170]:='x'; +xchr[@'171]:='y'; +xchr[@'172]:='z'; +xchr[@'173]:='{'; +xchr[@'174]:='|'; +xchr[@'175]:='}'; +xchr[@'176]:='~';@/ +xchr[0]:=' '; xchr[@'177]:=' '; + {ASCII codes 0 and |@'177| do not appear in text} + + +@ +@^character set dependencies@> +@^system dependencies@> +Some of the ASCII codes without visible characters have been given symbolic +names in this program because they are used with a special meaning. The +|tab| character may be system dependent. + +@d null_code=@'0 {ASCII code that might disappear} +@d tab=@'11 {ASCII code treated as |white_space|} +@d space=@'40 {ASCII code treated as |white_space|} +@d invalid_code=@'177 {ASCII code that should not appear} + + +@ +@^character set dependencies@> +@^system dependencies@> +@:TeXbook}{\sl The \TeX book@> +The ASCII code is ``standard'' only to a certain extent, since many +computer installations have found it advantageous to have ready access +to more than 94 printing characters. Appendix~C of {\sl The \TeX book\/} +gives a complete specification of the intended correspondence between +characters and \TeX's internal representation. + +If \TeX\ is being used +on a garden-variety \PASCAL\ for which only standard ASCII +codes will appear in the input and output files, it doesn't really matter +what codes are specified in |xchr[1..@'37]|, but the safest policy is to +blank everything out by using the code shown below. + +However, other settings of |xchr| will make \TeX\ more friendly on +computers that have an extended character set, so that users can type things +like `\.^^Z' instead of `\.{\\ne}'. At MIT, for example, it would be more +appropriate to substitute the code +$$\hbox{|for i:=1 to @'37 do xchr[i]:=chr(i);|}$$ +\TeX's character set is essentially the same as MIT's, even with respect to +characters less than~@'40. People with extended character sets can +assign codes arbitrarily, giving an |xchr| equivalent to whatever +characters the users of \TeX\ are allowed to have in their input files. +It is best to make the codes correspond to the intended interpretations as +shown in Appendix~C whenever possible; but this is not necessary. For +example, in countries with an alphabet of more than 26 letters, it is +usually best to map the additional letters into codes less than~@'40. + +@<Set initial values of key variables@>= +for i:=1 to @'37 do xchr[i]:=' '; +xchr[tab]:=chr(tab); + + +@ +This system-independent code makes the |xord| array contain a suitable +inverse to the information in |xchr|. Note that if |xchr[i]=xchr[j]| +where |i<j<@'177|, the value of |xord[xchr[i]]| will turn out to be +|j| or more; hence, standard ASCII code numbers will be used instead +of codes below @'40 in case there is a coincidence. + +@<Set initial values of key variables@>= +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; + + +@ +Also, various characters are given symbolic names; all the ones this +program uses are collected here. We use the sharp sign as the +|concat_char|, rather than something more natural (like an ampersand), +for uniformity of database syntax (ampersand is a valid character in +identifiers). + +@d double_quote = """" {delimits strings} +@d number_sign = "#" {marks an |int_literal|} +@d comment = "%" {ignore the rest of a \.{.bst} or \TeX\ line} +@d single_quote = "'" {marks a quoted function} +@d left_paren = "(" {optional database entry left delimiter} +@d right_paren = ")" {corresponding right delimiter} +@d comma = "," {separates various things} +@d minus_sign = "-" {for a negative number} +@d equals_sign = "=" {separates a field name from a field value} +@d at_sign = "@@" {the beginning of a database entry} +@d left_brace = "{" {left delimiter of many things} +@d right_brace = "}" {corresponding right delimiter} +@d period = "." {these are three} +@d question_mark = "?" {string-ending characters} +@d exclamation_mark = "!" {of interest in \.{add.period\$}} +@d tie = "~" {the default space char, in \.{format.name\$}} +@d hyphen = "-" {like |white_space|, in \.{format.name\$}} +@d star = "*" {for including entire database} +@d concat_char = "#" {for concatenating field tokens} +@d colon = ":" {for lower-casing (usually title) strings} +@d backslash = "\" {used to recognize accented characters} + + +@ +These arrays give a lexical classification for the |ASCII_code|s; +|lex_class| is used for general scanning and |id_class| is used for +scanning identifiers. + +@<Globals in the outer block@>= +@!lex_class: array [ASCII_code] of lex_type; +@!id_class: array [ASCII_code] of id_type; + + +@ +Every character has two types of the lexical classifications. The +first type is general, and the second type tells whether the character +is legal in identifiers. + +@d illegal = 0 {the unrecognized |ASCII_code|s} +@d white_space = 1 {things like |space|s that you can't see} +@d alpha = 2 {the upper- and lower-case letters} +@d numeric = 3 {the ten digits} +@d sep_char = 4 {things sometimes treated like |white_space|} +@d other_lex = 5 {when none of the above applies} +@d last_lex = 5 {the same number as on the line above} +@# +@d illegal_id_char = 0 {a few forbidden ones} +@d legal_id_char = 1 {most printing characters} + +@<Types in the outer block@>= +@!lex_type = 0..last_lex;@/ +@!id_type = 0..1; + + +@ +@^character set dependencies@> +@^system dependencies@> +Now we initialize the system-dependent |lex_class| array. The |tab| +character may be system dependent. Note that the order of these +assignments is important here. + +@<Set initial values of key variables@>= +for i:=0 to @'177 do lex_class[i] := other_lex; +for i:=0 to @'37 do lex_class[i] := illegal; +lex_class[invalid_code] := illegal; +lex_class[tab] := white_space; +lex_class[space] := white_space; +lex_class[tie] := sep_char; +lex_class[hyphen] := sep_char; +for i:=@'60 to @'71 do lex_class[i] := numeric; +for i:=@'101 to @'132 do lex_class[i] := alpha; +for i:=@'141 to @'172 do lex_class[i] := alpha; + + +@ +@^character set dependencies@> +@^system dependencies@> +And now the |id_class| array. + +@<Set initial values of key variables@>= +for i:=0 to @'177 do id_class[i] := legal_id_char; +for i:=0 to @'37 do id_class[i] := illegal_id_char; +id_class[space] := illegal_id_char; +id_class[tab] := illegal_id_char; +id_class[double_quote] := illegal_id_char; +id_class[number_sign] := illegal_id_char; +id_class[comment] := illegal_id_char; +id_class[single_quote] := illegal_id_char; +id_class[left_paren] := illegal_id_char; +id_class[right_paren] := illegal_id_char; +id_class[comma] := illegal_id_char; +id_class[equals_sign] := illegal_id_char; +id_class[left_brace] := illegal_id_char; +id_class[right_brace] := illegal_id_char; + + +@ +The array |char_width| gives relative printing widths of each +|ASCII_code|, and |string_width| will be used later to sum up +|char_width|s in a string. + +@<Globals in the outer block@>= +@!char_width : array [ASCII_code] of integer; +@!string_width : integer; + + +@ +@^character set dependencies@> +@^system dependencies@> +Now we initialize the system-dependent |char_width| array, for which +|space| is the only |white_space| character given a nonzero printing +width. The widths here are taken from Stanford's June~'87 +$cmr10$~font and represent hundredths of a point (rounded), but since +they're used only for relative comparisons, the units have no meaning. + +@d ss_width = 500 {character |@'31|'s width in the $cmr10$ font} +@d ae_width = 722 {character |@'32|'s width in the $cmr10$ font} +@d oe_width = 778 {character |@'33|'s width in the $cmr10$ font} +@d upper_ae_width = 903 {character |@'35|'s width in the $cmr10$ font} +@d upper_oe_width = 1014 {character |@'36|'s width in the $cmr10$ font} + +@<Set initial values of key variables@>= +for i:=0 to @'177 do char_width[i] := 0; +@# +char_width[@'40] := 278; +char_width[@'41] := 278; +char_width[@'42] := 500; +char_width[@'43] := 833; +char_width[@'44] := 500; +char_width[@'45] := 833; +char_width[@'46] := 778; +char_width[@'47] := 278; +char_width[@'50] := 389; +char_width[@'51] := 389; +char_width[@'52] := 500; +char_width[@'53] := 778; +char_width[@'54] := 278; +char_width[@'55] := 333; +char_width[@'56] := 278; +char_width[@'57] := 500; +char_width[@'60] := 500; +char_width[@'61] := 500; +char_width[@'62] := 500; +char_width[@'63] := 500; +char_width[@'64] := 500; +char_width[@'65] := 500; +char_width[@'66] := 500; +char_width[@'67] := 500; +char_width[@'70] := 500; +char_width[@'71] := 500; +char_width[@'72] := 278; +char_width[@'73] := 278; +char_width[@'74] := 278; +char_width[@'75] := 778; +char_width[@'76] := 472; +char_width[@'77] := 472; +char_width[@'100] := 778; +char_width[@'101] := 750; +char_width[@'102] := 708; +char_width[@'103] := 722; +char_width[@'104] := 764; +char_width[@'105] := 681; +char_width[@'106] := 653; +char_width[@'107] := 785; +char_width[@'110] := 750; +char_width[@'111] := 361; +char_width[@'112] := 514; +char_width[@'113] := 778; +char_width[@'114] := 625; +char_width[@'115] := 917; +char_width[@'116] := 750; +char_width[@'117] := 778; +char_width[@'120] := 681; +char_width[@'121] := 778; +char_width[@'122] := 736; +char_width[@'123] := 556; +char_width[@'124] := 722; +char_width[@'125] := 750; +char_width[@'126] := 750; +char_width[@'127] :=1028; +char_width[@'130] := 750; +char_width[@'131] := 750; +char_width[@'132] := 611; +char_width[@'133] := 278; +char_width[@'134] := 500; +char_width[@'135] := 278; +char_width[@'136] := 500; +char_width[@'137] := 278; +char_width[@'140] := 278; +char_width[@'141] := 500; +char_width[@'142] := 556; +char_width[@'143] := 444; +char_width[@'144] := 556; +char_width[@'145] := 444; +char_width[@'146] := 306; +char_width[@'147] := 500; +char_width[@'150] := 556; +char_width[@'151] := 278; +char_width[@'152] := 306; +char_width[@'153] := 528; +char_width[@'154] := 278; +char_width[@'155] := 833; +char_width[@'156] := 556; +char_width[@'157] := 500; +char_width[@'160] := 556; +char_width[@'161] := 528; +char_width[@'162] := 392; +char_width[@'163] := 394; +char_width[@'164] := 389; +char_width[@'165] := 556; +char_width[@'166] := 528; +char_width[@'167] := 722; +char_width[@'170] := 528; +char_width[@'171] := 528; +char_width[@'172] := 444; +char_width[@'173] := 500; +char_width[@'174] :=1000; +char_width[@'175] := 500; +char_width[@'176] := 500; + + + +@* Input and output. +The basic operations we need to do are +(1)~inputting and outputting of text characters to or from a file; +(2)~instructing the operating system to initiate (``open'') +or to terminate (``close'') input or output to or from a specified file; and +(3)~testing whether the end of an input file has been reached. + +@<Types in the outer block@>= +@!alpha_file=packed file of text_char; {files that contain textual data} + + +@ +@^system dependencies@> +Most of what we need to do with respect to input and output can be handled +by the I/O facilities that are standard in \PASCAL, i.e., the routines +called |get|, |put|, |eof|, and so on. But +standard \PASCAL\ does not allow file variables to be associated with file +names that are determined at run time, so it cannot be used to implement +\BibTeX; some sort of extension to \PASCAL's ordinary |reset| and |rewrite| +is crucial for our purposes. We shall assume that |name_of_file| is a variable +of an appropriate type such that the \PASCAL\ run-time system being used to +implement \BibTeX\ can open a file whose external name is specified by +|name_of_file|. \BibTeX\ does no case conversion for file names. + +@<Globals in the outer block@>= +@!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|} + + +@ +@^system dependencies@> +@:PASCAL H}{\ph@> +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; + + +@ +@^system dependencies@> +Files can be closed with the \ph\ routine `|close(f)|', which should +be used when all input or output with respect to |f| has been +completed. This makes |f| available to be opened again, if desired; +and if |f| was used for output, the |close| operation makes the +corresponding external file appear on the user's area, ready to be +read. + +@<Procedures and functions for file-system interacting@>= +procedure a_close(var f:alpha_file); {close a text file} +begin close(f); +end; + + +@ +Text output is easy to do with the ordinary \PASCAL\ |put| procedure, +so we don't have to make any other special arrangements. +The treatment of text input is more difficult, however, because +of the necessary translation to |ASCII_code| values, and because +\TeX's conventions should be efficient and they should +blend nicely with the user's operating environment. + + +@ +Input from text files is read one line at a time, using a routine +called |input_ln|. This function is defined in terms of global +variables called |buffer| and |last|. The |buffer| array contains +|ASCII_code| values, and |last| is an index into this array marking +the end of a line of text. (Occasionally, |buffer| is used for +something else, in which case it is copied to a temporary array.) + +@<Globals in the outer block@>= +@!buffer:buf_type; {usually, lines of characters being read} +@!last:buf_pointer; {end of the line just input to |buffer|} + + +@ +@^save space@> +@^space savings@> +@^system dependencies@> +The type |buf_type| is used for |buffer|, for saved copies of it, or +for scratch work. It's not |packed| because otherwise the program +would run much slower on some systems (more than 25 percent slower, +for example, on a TOPS-20 operating system). But on systems that are +byte-addressable and that have a good compiler, packing |buf_type| +would save lots of space without much loss of speed. Other modules +that have packable arrays are also marked with a ``space savings'' +index entry. + +@<Types in the outer block@>= +@!buf_pointer = 0..buf_size; {an index into a |buf_type|} +@!buf_type = array[buf_pointer] of ASCII_code; {for various buffers} + + +@ +@^kludge@> +And while we're at it, we declare another buffer for general use. +Because buffers are not packed and can get large, we use |sv_buffer| +several purposes; this is a bit kludgy, but it helps make the stack +space not overflow on some machines. It's used when reading the +entire database file (in the \.{read} command) and when doing +name-handling (through the alias |name_buf|) in the |built_in| +functions \.{format.names\$} and \.{num.names\$}. + +@<Globals in the outer block@>= +@!sv_buffer : buf_type; +@!sv_ptr1 : buf_pointer; +@!sv_ptr2 : buf_pointer; +@!tmp_ptr,@!tmp_end_ptr : integer; {copy pointers only, usually for buffers} + + +@ +@.BibTeX capacity exceeded@> +When something in the program wants to be bigger or something out +there wants to be smaller, it's time to call it a run. Here's the +first of several macros that have associated procedures so that they +produce less inline code. + +@d overflow(#)==begin {fatal error---close up shop} + print_overflow; + print_ln(#:0); + goto close_up_shop; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_overflow; +begin +print ('Sorry---you''ve exceeded BibTeX''s '); +mark_fatal; +end; + + +@ +@.this can't happen@> +When something happens that the program thinks is impossible, +call the maintainer. + +@d confusion(#)==begin {fatal error---close up shop} + print (#); + print_confusion; + goto close_up_shop; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_confusion; +begin +print_ln ('---this can''t happen'); +print_ln ('*Please notify the BibTeX maintainer*'); +mark_fatal; +end; + + +@ +@:BibTeX capacity exceeded}{\quad buffer size@> +When a buffer overflows, it's time to complain (and then quit). + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure buffer_overflow; +begin +overflow('buffer size ',buf_size); +end; + + +@ +@:BibTeX capacity exceeded}{\quad buffer size@> +The |input_ln| function brings the next line of input from the +specified file into available positions of the buffer array and +returns the value |true|, unless the file has already been entirely +read, in which case it returns |false| and sets |last:=0|. In +general, the |ASCII_code| numbers that represent the next line of the +file are input into |buffer[0]|, |buffer[1]|, \dots, |buffer[last-1]|; +and the global variable |last| is set equal to the length of the line. +Trailing |white_space| characters are removed from the line +(|white_space| characters are explained in the character-set section% +---most likely they're blanks); thus, either |last=0| (in which case +the line was entirely blank) or |lex_class[buffer[last-1]]<>white_space|. +An overflow error is given if the normal actions of |input_ln| would +make |last>buf_size|. + +Standard \PASCAL\ says that a file should have |eoln| immediately +before |eof|, but \BibTeX\ needs only a weaker restriction: If |eof| +occurs in the middle of a line, the system function |eoln| should return +a |true| result (even though |f^| will be undefined). + +@<Procedures and functions for all file I/O, error messages, and such@>= +function input_ln(var f:alpha_file) : boolean; + {inputs the next line or returns |false|} +label loop_exit; +begin +last:=0; +if (eof(f)) then input_ln:=false +else + begin + while (not eoln(f)) do + begin + if (last >= buf_size) then + buffer_overflow; + buffer[last]:=xord[f^]; + get(f); incr(last); + end; + get(f); + while (last > 0) do {remove trailing |white_space|} + if (lex_class[buffer[last-1]] = white_space) then + decr(last) + else + goto loop_exit; +loop_exit: + input_ln:=true; + end; +end; + + + +@* String handling. +\BibTeX\ uses variable-length strings of seven-bit characters. +Since \PASCAL\ does not have a well-developed string mechanism, +\BibTeX\ does all its string processing by home-grown +(predominantly \TeX's) methods. +Unlike \TeX, however, \BibTeX\ does not use a |pool_file| for +string storage; it creates its few pre-defined strings at run-time. + +The necessary operations are handled with a simple data structure. +The array |str_pool| contains all the (seven-bit) ASCII codes in all +the strings \BibTeX\ must ever search for (generally identifiers +names), and the array |str_start| contains indices of the starting +points of each such string. Strings are referred to by integer +numbers, so that string number |s| comprises the characters +|str_pool[j]| for |str_start[s]<=j<str_start[s+1]|. Additional integer +variables |pool_ptr| and |str_ptr| indicate the number of entries used +so far in |str_pool| and |str_start|; locations |str_pool[pool_ptr]| +and |str_start[str_ptr]| are ready for the next string to be +allocated. Location |str_start[0]| is unused so that hashing will +work correctly. + +Elements of the |str_pool| array must be ASCII codes that can actually be +printed; i.e., they must have an |xchr| equivalent in the local +character set. + +@<Globals in the outer block@>= +@!str_pool : packed array[pool_pointer] of ASCII_code; {the characters} +@!str_start : packed array[str_number] of pool_pointer; {the starting pointers} +@!pool_ptr : pool_pointer; {first unused position in |str_pool|} +@!str_ptr : str_number; {start of the current string being created} +@!str_num : str_number; {general index variable into |str_start|} +@!p_ptr1,@!p_ptr2 : pool_pointer; {several procedures use these locally} + + +@ +Where |pool_pointer| and |str_number| are pointers into |str_pool| and +|str_start|. + +@<Types in the outer block@>= +@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|} +@!str_number = 0..max_strings; {for variables that point into |str_start|} + + +@ +These macros send a string in |str_pool| to an output file. + +@d max_pop = 3 {---see the |built_in| functions section} +@# +@d print_pool_str(#) == print_a_pool_str(#) + {making this a procedure saves a little space} +@# +@d trace_pr_pool_str(#) == begin + out_pool_str(log_file,#); + end + + +@ +@^kludge@> +@^system dependencies@> +@:this can't happen}{\quad Illegal string number@> +And here are the associated procedures. Note: The |term_out| file is +system dependent. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure out_pool_str (var f:alpha_file; @!s:str_number); +var i:pool_pointer; +begin {allowing |str_ptr <= s < str_ptr+max_pop| is a \.{.bst}-stack kludge} +if ((s<0) or (s>=str_ptr+max_pop) or (s>=max_strings)) then + confusion ('Illegal string number:',s:0); +for i := str_start[s] to str_start[s+1]-1 do + write(f,xchr[str_pool[i]]); +end; +@# +procedure print_a_pool_str (@!s:str_number); +begin +out_pool_str(term_out,s); +out_pool_str(log_file,s); +end; + + +@ +@.WEB@> +Several of the elementary string operations are performed using \.{WEB} +macros instead of using \PASCAL\ procedures, because many of the +operations are done quite frequently and we want to avoid the +overhead of procedure calls. For example, here is +a simple macro that computes the length of a string. + +@d length(#) == (str_start[#+1]-str_start[#]) + {the number of characters in string number \#} + + +@ +@:BibTeX capacity exceeded}{\quad pool size@> +Strings are created by appending character codes to |str_pool|. +The macro called |append_char|, defined here, does not check to see if the +value of |pool_ptr| has gotten too high; this test is supposed to be +made before |append_char| is used. + +To test if there is room to append |l| more characters to |str_pool|, +we shall write |str_room(l)|, which aborts \BibTeX\ and gives an +error message if there isn't enough room. + +@d append_char(#) == {put |ASCII_code| \# at the end of |str_pool|} +begin str_pool[pool_ptr]:=#; incr(pool_ptr); +end +@# +@d str_room(#) == {make sure that the pool hasn't overflowed} + begin + if (pool_ptr+# > pool_size) then + pool_overflow; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure pool_overflow; +begin +overflow('pool size ',pool_size); +end; + + +@ +@:BibTeX capacity exceeded}{\quad number of strings@> +Once a sequence of characters has been appended to |str_pool|, it +officially becomes a string when the function |make_string| is called. +It returns the string number of the string it just made. + +@<Procedures and functions for handling numbers, characters, and strings@>= +function make_string : str_number; {current string enters the pool} +begin +if (str_ptr=max_strings) then + overflow('number of strings ',max_strings); +incr(str_ptr); +str_start[str_ptr]:=pool_ptr; +make_string := str_ptr - 1; +end; + + +@ +These macros destroy and recreate the string at the end of the pool. + +@d flush_string == begin + decr(str_ptr); + pool_ptr := str_start[str_ptr]; + end +@# +@d unflush_string == begin + incr(str_ptr); + pool_ptr := str_start[str_ptr]; + end + + +@ +This subroutine compares string |s| with another string that appears +in the buffer |buf| between positions |bf_ptr| and |bf_ptr+len-1|; the +result is |true| if and only if the strings are equal. + +@<Procedures and functions for handling numbers, characters, and strings@>= +function str_eq_buf (@!s:str_number; var buf:buf_type; + @!bf_ptr,@!len:buf_pointer) : boolean; + {test equality of strings} +label exit; +var i : buf_pointer; {running} +@!j : pool_pointer; {indices} +begin +if (length(s) <> len) then {strings of unequal length} + begin + str_eq_buf := false; + return; + end; +i := bf_ptr; +j := str_start[s]; +while (j < str_start[s+1]) do + begin + if (str_pool[j] <> buf[i]) then + begin + str_eq_buf := false; + return; + end; + incr(i); + incr(j); + end; +str_eq_buf := true; +exit: +end; + + +@ +This subroutine compares two |str_pool| strings and returns true +|true| if and only if the strings are equal. + +@<Procedures and functions for handling numbers, characters, and strings@>= +function str_eq_str (@!s1,@!s2:str_number) : boolean; +label exit; +begin +if (length(s1) <> length(s2)) then + begin + str_eq_str := false; + return; + end; +p_ptr1 := str_start[s1]; +p_ptr2 := str_start[s2]; +while (p_ptr1 < str_start[s1+1]) do + begin + if (str_pool[p_ptr1] <> str_pool[p_ptr2]) then + begin + str_eq_str := false; + return; + end; + incr(p_ptr1); + incr(p_ptr2); + end; +str_eq_str:=true; +exit: +end; + + +@ +@:BibTeX capacity exceeded}{\quad file name size@> +This procedure copies file name |file_name| into the beginning of +|name_of_file|, if it will fit. It also sets the global variable +|name_length| to the appropriate value. + +@<Procedures and functions for file-system interacting@>= +procedure start_name (@!file_name:str_number); +var p_ptr: pool_pointer; {running index} +begin +if (length(file_name) > file_name_size) then + begin + print ('File='); + print_pool_str (file_name); + print_ln (','); + file_nm_size_overflow; + end; +name_ptr := 1; +p_ptr := str_start[file_name]; +while (p_ptr < str_start[file_name+1]) do + begin + name_of_file[name_ptr] := chr (str_pool[p_ptr]); + incr(name_ptr); incr(p_ptr); + end; +name_length := length(file_name); +end; + + +@ +@:BibTeX capacity exceeded}{\quad file name size@> +Yet another complaint-before-quiting. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure file_nm_size_overflow; +begin +overflow('file name size ',file_name_size); +end; + + +@ +@:BibTeX capacity exceeded}{\quad file name size@> +This procedure copies file extension |ext| into the array +|name_of_file| starting at position |name_length+1|. It also sets the +global variable |name_length| to the appropriate value. + +@<Procedures and functions for file-system interacting@>= +procedure add_extension(@!ext:str_number); +var p_ptr: pool_pointer; {running index} +begin +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; +name_ptr := name_length + 1; +p_ptr := str_start[ext]; +while (p_ptr < str_start[ext+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(ext); +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; +end; + + +@ +@:BibTeX capacity exceeded}{\quad file name size@> +This procedure copies the default logical area name |area| into the +array |name_of_file| starting at position 1, after shifting up the +rest of the filename. It also sets the global variable |name_length| +to the appropriate value. + +@<Procedures and functions for file-system interacting@>= +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; + + +@ +This system-independent procedure converts upper-case characters to +lower case for the specified part of |buf|. It is system independent +because it uses only the internal representation for characters. + +@d case_difference = "a" - "A" + +@<Procedures and functions for handling numbers, characters, and strings@>= +procedure lower_case (var buf:buf_type; @!bf_ptr,@!len:buf_pointer); +var i:buf_pointer; +begin +if (len > 0) then + for i := bf_ptr to bf_ptr+len-1 do + if ((buf[i]>="A") and (buf[i]<="Z")) then + buf[i] := buf[i] + case_difference; +end; + + +@ +This system-independent procedure is the same as the previous except +that it converts lower- to upper-case letters. + +@<Procedures and functions for handling numbers, characters, and strings@>= +procedure upper_case (var buf:buf_type; @!bf_ptr,@!len:buf_pointer); +var i:buf_pointer; +begin +if (len > 0) then + for i := bf_ptr to bf_ptr+len-1 do + if ((buf[i]>="a") and (buf[i]<="z")) then + buf[i] := buf[i] - case_difference; +end; + + + +@* The hash table. +All static strings that \BibTeX\ might have to search for, generally +identifiers, are stored and retrieved by means of a fairly standard +hash-table algorithm (but slightly altered here) called the method of +``coalescing lists'' +(cf.\ Algorithm 6.4C in {\sl The Art of Computer Programming}). +Once a string enters the table, it is never removed. The actual +sequence of characters forming a string is stored in the |str_pool| +array. + +The hash table consists of the four arrays |hash_next|, |hash_text|, +|hash_ilk|, and |ilk_info|. The first array, |hash_next[p]|, points +to the next identifier belonging to the same coalesced list as the +identifier corresponding to~|p|. The second, |hash_text[p]|, points +to the |str_start| entry for |p|'s string. If position~|p| of the hash +table is empty, we have |hash_text[p]=0|; if position |p| is either +empty or the end of a coalesced hash list, we have +|hash_next[p]=empty|; an auxiliary pointer variable called |hash_used| +is maintained in such a way that all locations |p>=hash_used| are +nonempty. The third, |hash_ilk[p]|, tells how this string is used (as +ordinary text, as a variable name, as an \.{.aux} file command, etc). +The fourth, |ilk_info[p]|, contains information specific to the +corresponding |hash_ilk|---for |integer_ilk|s: the integer's value; +for |cite_ilk|s: a pointer into |cite_list|; for |lc_cite_ilk|s: a +pointer to a |cite_ilk| string; for |command_ilk|s: a constant to be +used in a |case| statement; for |bst_fn_ilk|s: function-specific +information; for |macro_ilk|s: a pointer to its definition string; for +|control_seq_ilk|s: a constant for use in a |case| statement; for all +other |ilk|s it contains no information. This |ilk|-specific +information is set in other parts of the program rather than here in +the hashing routine. + +@d hash_base = empty + 1 {lowest numbered hash-table location} +@d hash_max = hash_base + hash_size - 1 {highest numbered hash-table location} +@d hash_is_full == (hash_used=hash_base) {test if all positions are occupied} +@# +@d text_ilk = 0 {a string of ordinary text} +@d integer_ilk = 1 {an integer (possibly with a |minus_sign|)} +@d aux_command_ilk = 2 {an \.{.aux}-file command} +@d aux_file_ilk = 3 {an \.{.aux} file name} +@d bst_command_ilk = 4 {a \.{.bst}-file command} +@d bst_file_ilk = 5 {a \.{.bst} file name} +@d bib_file_ilk = 6 {a \.{.bib} file name} +@d file_ext_ilk = 7 {one of \.{.aux}, \.{.bst}, \.{.bib}, \.{.bbl}, + or \.{.blg}} +@d file_area_ilk = 8 {one of \.{texinputs:} or \.{texbib:}} +@d cite_ilk = 9 {a \.{\\citation} argument} +@d lc_cite_ilk = 10 {a \.{\\citation} argument converted to lower case} +@d bst_fn_ilk = 11 {a \.{.bst} function name} +@d bib_command_ilk = 12 {a \.{.bib}-file command} +@d macro_ilk = 13 {a \.{.bst} macro or a \.{.bib} string} +@d control_seq_ilk = 14 {a control sequence specifying a foreign character} +@d last_ilk = 14 {the same number as on the line above} + +@<Types in the outer block@>= +@!hash_loc=hash_base..hash_max; {a location within the hash table} +@!hash_pointer=empty..hash_max; {either |empty| or a |hash_loc|} +@# +@!str_ilk=0..last_ilk; {the legal string types} + + +@ +@<Globals in the outer block@>= +@!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} +@!hash_found : boolean; {set to |true| if it's already in the hash table} +@!dummy_loc : hash_loc; {receives |str_lookup| value whenever it's useless} + + +@ +@<Local variables for initialization@>= +@!k:hash_loc; + + +@ +Now it's time to initialize the hash table; note that |str_start[0]| +must be unused if |hash_text[k] := 0| is to have the desired effect. + +@<Set initial values of key variables@>= +for k:=hash_base to hash_max do + begin + hash_next[k] := empty; + hash_text[k] := 0; {thus, no need to initialize |hash_ilk| or |ilk_info|} + end; +hash_used := hash_max + 1; {nothing in table initially} + + +@ +Here is the subroutine that searches the hash table for a +(string,~|str_ilk|) pair, where the string is of length |l>=0| and +appears in |buffer[j..(j+l-1)]|. If it finds the pair, it returns the +corresponding hash-table location and sets the global variable +|hash_found| to |true|. Otherwise it sets |hash_found| to |false|, +and if the parameter |insert_it| is |true|, it inserts the pair into +the hash table, inserts the string into |str_pool| if not previously +encountered, and returns its location. Note that two different pairs +can have the same string but different |str_ilk|s, in which case the +second pair encountered, if |insert_it| were |true|, would be inserted +into the hash table though its string wouldn't be inserted into +|str_pool| because it would already be there. + +@d max_hash_value = hash_prime+hash_prime-2+127 {|h|'s maximum value} +@d do_insert == true {insert string if not found in hash table} +@d dont_insert == false {don't insert string} +@# +@d str_found = 40 {go here when you've found the string} +@d str_not_found = 45 {go here when you haven't} + +@<Procedures and functions for handling numbers, characters, and strings@>= +function str_lookup(var buf:buf_type; @!j,@!l:buf_pointer; @!ilk:str_ilk; + @!insert_it:boolean) : hash_loc; {search the hash table} +label str_found,@!str_not_found; +var h:0..max_hash_value; {hash code} +@!p:hash_loc; {index into |hash_| arrays} +@!k:buf_pointer; {index into |buf| array} +@!old_string:boolean; {set to |true| if it's an already encountered string} +@!str_num:str_number; {pointer to an already encountered string} +begin +@<Compute the hash code |h|@>; +p:=h+hash_base; {start searching here; note that |0<=h<hash_prime|} +hash_found := false; +old_string := false; +loop + begin + @<Process the string if we've already encountered it@>; + if (hash_next[p]=empty) then {location |p| may or may not be empty} + begin + if (not insert_it) then goto str_not_found; + @<Insert pair into hash table and make |p| point to it@>; + goto str_found; + end; + p:=hash_next[p]; {old and new locations |p| are not empty} + end; +str_not_found: do_nothing; {don't insert pair; function value meaningless} +str_found: str_lookup:=p; +end; + + +@ +@^for loops@> +@.WEB@> +The value of |hash_prime| should be roughly 85\% of |hash_size|, and +it should be a prime number +(it should also be less than $2^{14} + 2^{6} = 16320$ because of +\.{WEB}'s simple-macro bound). The theory of hashing tells us to expect +fewer than two table probes, on the average, when the search is +successful. + +@<Compute the hash code |h|@>= +begin +h := 0; {note that this works for zero-length strings} +k := j; +while (k < j+l) do {not a |for| loop in case |j = l = 0|} + begin + h:=h+h+buf[k]; + while (h >= hash_prime) do h:=h-hash_prime; + incr(k); + end; +end + + +@ +Here we handle the case in which we've already encountered this +string; note that even if we have, we'll still have to insert the pair +into the hash table if |str_ilk| doesn't match. + +@<Process the string if we've already encountered it@>= +begin +if (hash_text[p]>0) then {there's something here} + if (str_eq_buf(hash_text[p],buf,j,l)) then {it's the right string} + if (hash_ilk[p] = ilk) then {it's the right |str_ilk|} + begin + hash_found := true; + goto str_found; + end + else + begin {it's the wrong |str_ilk|} + old_string := true; + str_num := hash_text[p]; + end; +end + + +@ +@^for loops@> +@:BibTeX capacity exceeded}{\quad hash size@> +This code inserts the pair in the appropriate unused location. + +@<Insert pair into hash table and make |p| point to it@>= +begin +if (hash_text[p]>0) then {location |p| isn't empty} + begin + repeat if (hash_is_full) then overflow('hash size ',hash_size); + decr(hash_used); + until (hash_text[hash_used]=0); {search for an empty location} + hash_next[p]:=hash_used; + p:=hash_used; + end; {now location |p| is empty} +if (old_string) then {it's an already encountered string} + hash_text[p] := str_num + else + begin {it's a new string} + str_room(l); {make sure it'll fit in |str_pool|} + k := j; + while (k < j+l) do {not a |for| loop in case |j = l = 0|} + begin + append_char(buf[k]); + incr(k); + end; + hash_text[p] := make_string; {and make it official} + end; +hash_ilk[p] := ilk; +end + + +@ +@^string pool@> +Now that we've defined the hash-table workings we can initialize the +string pool. Unlike \TeX, \BibTeX\ does not use a |pool_file| for +string storage; instead it inserts its pre-defined strings into +|str_pool|---this makes one file fewer for the \BibTeX\ implementor +to deal with. This section initializes |str_pool|; the pre-defined +strings will be inserted into it shortly; and other strings are +inserted while processing the input files. + +@<Set initial values of key variables@>= +pool_ptr:=0; str_ptr:=1; {hash table must have |str_start[0]| unused} +str_start[str_ptr]:=pool_ptr; + + +@ +The longest pre-defined string determines type definitions used to +insert the pre-defined strings into |str_pool|. + +@d longest_pds=12 {the length of `\.{change.case\$}'} + +@<Types in the outer block@>= +@!pds_loc = 1..longest_pds; +@!pds_len = 0..longest_pds; +@!pds_type = packed array [pds_loc] of char; + + +@ +The variables in this program beginning with |s_| specify the +locations in |str_pool| for certain often-used strings. Those here +have to do with the file system; the next section will actually insert +them into |str_pool|. + +@<Globals in the outer block@>= +@!s_aux_extension : str_number; {\.{.aux}} +@!s_log_extension : str_number; {\.{.blg}} +@!s_bbl_extension : str_number; {\.{.bbl}} +@!s_bst_extension : str_number; {\.{.bst}} +@!s_bib_extension : str_number; {\.{.bib}} +@!s_bst_area : str_number; {\.{texinputs:}} +@!s_bib_area : str_number; {\.{texbib:}} + + +@ +@^important note@> +@^system dependencies@> +It's time to insert some of the pre-defined strings into |str_pool| +(and thus the hash table). These system-dependent strings should +contain no upper-case letters, and they must all be exactly +|longest_pds| characters long (even if fewer characters are actually +stored). The |pre_define| routine appears shortly. + +Important notes: These pre-definitions must not have any glitches or +the program may bomb because the |log_file| hasn't been opened yet, +and |text_ilk|s should be pre-defined later, for +\.{.bst}-function-execution purposes. + +@<Pre-define certain strings@>= +pre_define('.aux ',4,file_ext_ilk); +s_aux_extension := hash_text[pre_def_loc]; +pre_define('.bbl ',4,file_ext_ilk); +s_bbl_extension := hash_text[pre_def_loc]; +pre_define('.blg ',4,file_ext_ilk); +s_log_extension := hash_text[pre_def_loc]; +pre_define('.bst ',4,file_ext_ilk); +s_bst_extension := hash_text[pre_def_loc]; +pre_define('.bib ',4,file_ext_ilk); +s_bib_extension := hash_text[pre_def_loc]; +pre_define('texinputs: ',10,file_area_ilk); +s_bst_area := hash_text[pre_def_loc]; +pre_define('texbib: ',7,file_area_ilk); +s_bib_area := hash_text[pre_def_loc]; + + +@ +This global variable gives the hash-table location of pre-defined +strings generated by calls to |str_lookup|. + +@<Globals in the outer block@>= +@!pre_def_loc : hash_loc; + + +@ +This procedure initializes a pre-defined string of length at most +|longest_pds|. + +@<Procedures and functions for handling numbers, characters, and strings@>= +procedure pre_define (@!pds:pds_type; @!len:pds_len; @!ilk:str_ilk); +var i : pds_len; +begin +for i:=1 to len do + buffer[i] := xord[pds[i]]; +pre_def_loc := str_lookup(buffer,1,len,ilk,do_insert); +end; + + +@ +These constants all begin with |n_| and are used for the |case| +statement that determines which command to execute. The variable +|command_num| is set to one of these and is used to do the branching, +but it must have the full |integer| range because at times it can +assume an arbitrary |ilk_info| value (though it will be one of the +values here when we actually use it). + +@d n_aux_bibdata = 0 {\.{\\bibdata}} +@d n_aux_bibstyle = 1 {\.{\\bibstyle}} +@d n_aux_citation = 2 {\.{\\citation}} +@d n_aux_input = 3 {\.{\\@@input}} +@# +@d n_bst_entry = 0 {\.{entry}} +@d n_bst_execute = 1 {\.{execute}} +@d n_bst_function = 2 {\.{function}} +@d n_bst_integers = 3 {\.{integers}} +@d n_bst_iterate = 4 {\.{iterate}} +@d n_bst_macro = 5 {\.{macro}} +@d n_bst_read = 6 {\.{read}} +@d n_bst_reverse = 7 {\.{reverse}} +@d n_bst_sort = 8 {\.{sort}} +@d n_bst_strings = 9 {\.{strings}} +@# +@d n_bib_comment = 0 {\.{comment}} +@d n_bib_preamble = 1 {\.{preamble}} +@d n_bib_string = 2 {\.{string}} + +@<Globals in the outer block@>= +@!command_num : integer; + + +@ +@^important note@> +Now we pre-define the command strings; they must all be exactly +|longest_pds| characters long. + +Important note: These pre-definitions must not have any glitches or +the program may bomb because the |log_file| hasn't been opened yet. + +@<Pre-define certain strings@>= +pre_define('\citation ',9,aux_command_ilk); +ilk_info[pre_def_loc] := n_aux_citation; +pre_define('\bibdata ',8,aux_command_ilk); +ilk_info[pre_def_loc] := n_aux_bibdata; +pre_define('\bibstyle ',9,aux_command_ilk); +ilk_info[pre_def_loc] := n_aux_bibstyle; +pre_define('\@@input ',7,aux_command_ilk); +ilk_info[pre_def_loc] := n_aux_input; +@# +pre_define('entry ',5,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_entry; +pre_define('execute ',7,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_execute; +pre_define('function ',8,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_function; +pre_define('integers ',8,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_integers; +pre_define('iterate ',7,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_iterate; +pre_define('macro ',5,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_macro; +pre_define('read ',4,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_read; +pre_define('reverse ',7,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_reverse; +pre_define('sort ',4,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_sort; +pre_define('strings ',7,bst_command_ilk); +ilk_info[pre_def_loc] := n_bst_strings; +@# +pre_define('comment ',7,bib_command_ilk); +ilk_info[pre_def_loc] := n_bib_comment; +pre_define('preamble ',8,bib_command_ilk); +ilk_info[pre_def_loc] := n_bib_preamble; +pre_define('string ',6,bib_command_ilk); +ilk_info[pre_def_loc] := n_bib_string; + + + +@* Scanning an input line. +This section describes the various |buffer| scanning routines. The +two global variables |buf_ptr1| and |buf_ptr2| are used in scanning an +input line. Between scans, |buf_ptr1| points to the first character +of the current token and |buf_ptr2| points to that of the next. The +global variable |last|, set by the function |input_ln|, marks the end +of the current line; it equals 0 at the end of the current file. All +the procedures and functions in this section will indicate an +end-of-line when it's the end of the file. + +@d token_len == (buf_ptr2 - buf_ptr1) {of the current token} +@d scan_char == buffer[buf_ptr2] {the current character} + +@<Globals in the outer block@>= +@!buf_ptr1:buf_pointer; {points to the first position of the current token} +@!buf_ptr2:buf_pointer; {used to find the end of the current token} + + +@ +These macros send the current token, in |buffer[buf_ptr1]| to +|buffer[buf_ptr2-1]|, to an output file. + +@d print_token == print_a_token {making this a procedure saves a little space} +@# +@d trace_pr_token == begin + out_token(log_file); + end + + +@ +@^system dependencies@> +And here are the associated procedures. Note: The |term_out| file is +system dependent. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure out_token (var f:alpha_file); +var i:buf_pointer; +begin +i := buf_ptr1; +while (i < buf_ptr2) do + begin + write(f,xchr[buffer[i]]); + incr(i); + end; +end; +@# +procedure print_a_token; +begin +out_token(term_out); +out_token(log_file); +end; + + +@ +This function scans the |buffer| for the next token, starting at the +global variable |buf_ptr2| and ending just before either the single +specified stop-character or the end of the current line, whichever +comes first, respectively returning |true| or |false|; afterward, +|scan_char| is the first character following this token. + +@<Procedures and functions for input scanning@>= +function scan1 (@!char1:ASCII_code) : boolean; +begin +buf_ptr1 := buf_ptr2; + {scan until end-of-line or the specified character} +while ((scan_char <> char1) and (buf_ptr2 < last)) do + incr(buf_ptr2); +if (buf_ptr2 < last) then + scan1 := true + else + scan1 := false; +end; + + +@ +This function is the same but stops at |white_space| characters as well. + +@<Procedures and functions for input scanning@>= +function scan1_white (@!char1:ASCII_code) : boolean; +begin +buf_ptr1 := buf_ptr2; + {scan until end-of-line, the specified character, or |white_space|} +while ((lex_class[scan_char] <> white_space) and (scan_char <> char1) and + (buf_ptr2 < last)) do + incr(buf_ptr2); +if (buf_ptr2 < last) then + scan1_white := true + else + scan1_white := false; +end; + + +@ +This function is similar to |scan1|, but stops at either of two +stop-characters as well as the end of the current line. + +@<Procedures and functions for input scanning@>= +function scan2 (@!char1,@!char2:ASCII_code) : boolean; +begin +buf_ptr1 := buf_ptr2; + {scan until end-of-line or the specified characters} +while ((scan_char <> char1) and (scan_char <> char2) and (buf_ptr2 < last)) do + incr(buf_ptr2); +if (buf_ptr2 < last) then + scan2 := true + else + scan2 := false; +end; + + +@ +This function is the same but stops at |white_space| characters as well. + +@<Procedures and functions for input scanning@>= +function scan2_white (@!char1,@!char2:ASCII_code) : boolean; +begin +buf_ptr1 := buf_ptr2; + {scan until end-of-line, the specified characters, or |white_space|} +while ((scan_char <> char1) and (scan_char <> char2) and + (lex_class[scan_char] <> white_space) and (buf_ptr2 < last)) do + incr(buf_ptr2); +if (buf_ptr2 < last) then + scan2_white := true + else + scan2_white := false; +end; + + +@ +This function is similar to |scan2|, but stops at either of three +stop-characters as well as the end of the current line. + +@<Procedures and functions for input scanning@>= +function scan3 (@!char1,@!char2,@!char3:ASCII_code) : boolean; +begin +buf_ptr1 := buf_ptr2; + {scan until end-of-line or the specified characters} +while ((scan_char <> char1) and (scan_char <> char2) and + (scan_char <> char3) and (buf_ptr2 < last)) do + incr(buf_ptr2); +if (buf_ptr2 < last) then + scan3 := true + else + scan3 := false; +end; + + +@ +This function scans for letters, stopping at the first nonletter; it +returns |true| if there is at least one letter. + +@<Procedures and functions for input scanning@>= +function scan_alpha : boolean; +begin +buf_ptr1 := buf_ptr2; + {scan until end-of-line or a nonletter} +while ((lex_class[scan_char] = alpha) and (buf_ptr2 < last)) do + incr(buf_ptr2); +if (token_len = 0) then + scan_alpha := false + else + scan_alpha := true; +end; + + +@ +These are the possible values for |scan_result|; they're set by the +|scan_identifier| procedure and are described in the next section. + +@d id_null = 0 +@d specified_char_adjacent = 1 +@d other_char_adjacent = 2 +@d white_adjacent = 3 + +@<Globals in the outer block@>= +@!scan_result : id_null..white_adjacent; + + +@ +This procedure scans for an identifier, stopping at the first +|illegal_id_char|, or stopping at the first character if it's +|numeric|. It sets the global variable |scan_result| to |id_null| if +the identifier is null, else to |white_adjacent| if it ended at a +|white_space| character or an end-of-line, else to +|specified_char_adjacent| if it ended at one of |char1| or |char2| or +|char3|, else to |other_char_adjacent| if it ended at a nonspecified, +non|white_space| |illegal_id_char|. By convention, when some calling +code really wants just one or two ``specified'' characters, it merely +repeats one of the characters. + +@<Procedures and functions for input scanning@>= +procedure scan_identifier (@!char1,@!char2,@!char3:ASCII_code); +begin +buf_ptr1 := buf_ptr2; +if (lex_class[scan_char] <> numeric) then + {scan until end-of-line or an |illegal_id_char|} + while ((id_class[scan_char] = legal_id_char) and (buf_ptr2 < last)) do + incr(buf_ptr2); +if (token_len = 0) then + scan_result := id_null +else if ((lex_class[scan_char] = white_space) or (buf_ptr2 = last)) then + scan_result := white_adjacent +else if ((scan_char = char1) or (scan_char = char2) or (scan_char = char3)) + then + scan_result := specified_char_adjacent +else + scan_result := other_char_adjacent; +end; + + +@ +The next two procedures scan for an integer, setting the global +variable |token_value| to the corresponding integer. + +@d char_value == (scan_char - "0") {the value of the digit being scanned} + +@<Globals in the outer block@>= +@!token_value : integer; {the numeric value of the current token} + + +@ +This function scans for a nonnegative integer, stopping at the first +nondigit; it sets the value of |token_value| accordingly. It returns +|true| if the token was a legal nonnegative integer (i.e., consisted +of one or more digits). + +@<Procedures and functions for input scanning@>= +function scan_nonneg_integer : boolean; +begin +buf_ptr1 := buf_ptr2; +token_value := 0; + {scan until end-of-line or a nondigit} +while ((lex_class[scan_char] = numeric) and (buf_ptr2 < last)) do + begin + token_value := token_value*10 + char_value; + incr(buf_ptr2); + end; +if (token_len = 0) then {there were no digits} + scan_nonneg_integer := false + else + scan_nonneg_integer := true; +end; + + +@ +This procedure scans for an integer, stopping at the first nondigit; +it sets the value of |token_value| accordingly. It returns |true| if +the token was a legal integer (i.e., consisted of an optional +|minus_sign| followed by one or more digits). + +@d negative == (sign_length = 1) {if this integer is negative} + +@<Procedures and functions for input scanning@>= +function scan_integer : boolean; +var sign_length : 0..1; {1 if there's a |minus_sign|, 0 if not} +begin +buf_ptr1 := buf_ptr2; +if (scan_char = minus_sign) then {it's a negative number} + begin + sign_length := 1; + incr(buf_ptr2); {skip over the |minus_sign|} + end + else + sign_length := 0; +token_value := 0; + {scan until end-of-line or a nondigit} +while ((lex_class[scan_char] = numeric) and (buf_ptr2 < last)) do + begin + token_value := token_value*10 + char_value; + incr(buf_ptr2); + end; +if (negative) then + token_value := -token_value; +if (token_len = sign_length) then {there were no digits} + scan_integer := false + else + scan_integer := true; +end; + + +@ +This function scans over |white_space| characters, stopping either at +the first nonwhite character or the end of the line, respectively +returning |true| or |false|. + +@<Procedures and functions for input scanning@>= +function scan_white_space : boolean; +begin + {scan until end-of-line or a nonwhite} +while ((lex_class[scan_char] = white_space) and (buf_ptr2 < last)) do + incr(buf_ptr2); +if (buf_ptr2 < last) then + scan_white_space := true + else + scan_white_space := false; +end; + + +@ +The |print_bad_input_line| procedure prints the current input line, +splitting it at the character being scanned: It prints |buffer[0]|, +|buffer[1]|, \dots, |buffer[buf_ptr2-1]| on one line and +|buffer[buf_ptr2]|, \dots, |buffer[last-1]| on the next (and both +lines start with a colon between two |space|s). Each |white_space| +character is printed as a |space|. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_bad_input_line; +var bf_ptr : buf_pointer; +begin +print (' : '); +bf_ptr := 0; +while (bf_ptr < buf_ptr2) do + begin + if (lex_class[buffer[bf_ptr]] = white_space) then + print (xchr[space]) + else + print (xchr[buffer[bf_ptr]]); + incr(bf_ptr); + end; +print_newline; +print (' : '); +bf_ptr := 0; +while (bf_ptr < buf_ptr2) do + begin + print (xchr[space]); + incr(bf_ptr); + end; +bf_ptr := buf_ptr2; +while (bf_ptr < last) do + begin + if (lex_class[buffer[bf_ptr]] = white_space) then + print (xchr[space]) + else + print (xchr[buffer[bf_ptr]]); + incr(bf_ptr); + end; +print_newline;@/ +bf_ptr := 0; +while ((bf_ptr < buf_ptr2) and (lex_class[buffer[bf_ptr]] = white_space)) do + incr(bf_ptr); +if (bf_ptr = buf_ptr2) then + print_ln ('(Error may have been on previous line)'); +mark_error; +end; + + +@ +This little procedure exists because it's used by at least two other +procedures and thus saves some space. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_skipping_whatever_remains; +begin +print ('I''m skipping whatever remains of this '); +end; + + + +@* Getting the top-level auxiliary file name. +@^system dependencies@> +These modules read the name of the top-level \.{.aux} file. Some +systems will try to find this on the command line; if it's not there +it will come from the user's terminal. In either case, the name goes +into the |char| array |name_of_file|, and the files relevant to this +name are opened. + +@d aux_found=41 {go here when the \.{.aux} name is legit} +@d aux_not_found=46 {go here when it's not} + +@<Globals in the outer block@>= +@!aux_name_length : 0..file_name_size+1; {\.{.aux} name sans extension} + + +@ +@^system dependencies@> +@^user abuse@> +I mean, this is truly disgraceful. A user has to type something in to +the terminal just once during the entire run. And it's not some +complicated string where you have to get every last punctuation mark +just right, and it's not some fancy list where you get nervous because +if you forget one item you have to type the whole thing again; it's +just a simple, ordinary, file name. Now you'd think a five-year-old +could do it; you'd think it's so simple a user should be able to do it +in his sleep. But noooooooooo. He had to sit there droning on and on +about who knows what until he exceeded the bounds of common sense, and +he probably didn't even realize it. Just pitiful. What's this world +coming to? We should probably just delete all his files and be done +with him. Note: The |term_out| file is system dependent. + +@d sam_you_made_the_file_name_too_long == begin + sam_too_long_file_name_print; + goto aux_not_found; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure sam_too_long_file_name_print; +begin +write (term_out,'File name `'); +name_ptr := 1; +while (name_ptr <= aux_name_length) do + begin + write (term_out,name_of_file[name_ptr]); + incr(name_ptr); + end; +write_ln (term_out,''' is too long'); +end; + + +@ +@^system dependencies@> +@^user abuse@> +We've abused the user enough for one section; suffice it to +say here that most of what we said last module still applies. +Note: The |term_out| file is system dependent. + +@d sam_you_made_the_file_name_wrong == begin + sam_wrong_file_name_print; + goto aux_not_found; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure sam_wrong_file_name_print; +begin +write (term_out,'I couldn''t open file name `'); +name_ptr := 1; +while (name_ptr <= name_length) do + begin + write (term_out,name_of_file[name_ptr]); + incr(name_ptr); + end; +write_ln (term_out,''''); +end; + + +@ +@^system dependencies@> +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; + + +@ +@^system dependencies@> +The switch |check_cmnd_line| tells us whether we're to check for a +possible command-line argument. + +@<Variables for possible command-line processing@>= +@!check_cmnd_line : boolean; {|true| if we're to check the command line} + + +@ +@^system dependencies@> +Here's where we do the real command-line work. Those systems needing +more than a single module to handle the task should add the extras to +the ``System-dependent changes'' section. + +@<Process a possible command line@>= +begin +do_nothing; {the ``default system'' doesn't use the command line} +end + + +@ +Here we orchestrate this \.{.aux} name's handling: we add the various +extensions, try to open the files with the resulting name, and +store the name strings we'll need later. + +@<Handle this \.{.aux} name@>= +begin +if ((aux_name_length + length(s_aux_extension) > file_name_size) or@| + (aux_name_length + length(s_log_extension) > file_name_size) or@| + (aux_name_length + length(s_bbl_extension) > file_name_size)) then + sam_you_made_the_file_name_too_long; +@<Add extensions and open files@>; +@<Put this name into the hash table@>; +goto aux_found; +end + + +@ +Here we set up definitions and declarations for files opened in this +section. Each element in |aux_list| (except for +|aux_list[aux_stack_size]|, which is always unused) is a pointer to +the appropriate |str_pool| string representing the \.{.aux} file name. +The array |aux_file| contains the corresponding \PASCAL\ |file| +variables. + +@d cur_aux_str == aux_list[aux_ptr] {shorthand for the current \.{.aux} file} +@d cur_aux_file == aux_file[aux_ptr] {shorthand for the current |aux_file|} +@d cur_aux_line == aux_ln_stack[aux_ptr] {line number of current \.{.aux} file} + +@<Globals in the outer block@>= +@!aux_file : array[aux_number] of alpha_file; {open \.{.aux} |file| variables} +@!aux_list : array[aux_number] of str_number; {the open \.{.aux} file list} +@!aux_ptr : aux_number; {points to the currently open \.{.aux} file} +@!aux_ln_stack : array[aux_number] of integer; {open \.{.aux} line numbers} +@# +@!top_lev_str : str_number; {the top-level \.{.aux} file's name} +@# +@!log_file : alpha_file; {the |file| variable for the \.{.blg} file} +@!bbl_file : alpha_file; {the |file| variable for the \.{.bbl} file} + + +@ +Where |aux_number| is the obvious. + +@<Types in the outer block@>= +@!aux_number = 0..aux_stack_size; {gives the |aux_list| range} + + +@ +@^system dependencies@> +We must make sure the (top-level) \.{.aux}, \.{.blg}, and \.{.bbl} +files can be opened. + +@<Add extensions and open files@>= +begin +name_length := aux_name_length; {set to last used position} +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 + sam_you_made_the_file_name_wrong; +@# +name_length := aux_name_length; +add_extension (s_log_extension); {this also sets |name_length|} +if (not a_open_out(log_file)) then + sam_you_made_the_file_name_wrong; +@# +name_length := aux_name_length; +add_extension (s_bbl_extension); {this also sets |name_length|} +if (not a_open_out(bbl_file)) then + sam_you_made_the_file_name_wrong; +end + + +@ +@:this can't happen}{\quad Already encountered auxiliary file@> +This code puts the \.{.aux} file name, both with and without the +extension, into the hash table, and it initializes |aux_list|. Note +that all previous top-level \.{.aux}-file stuff must have been +successful. + +@<Put this name into the hash table@>= +begin +name_length := aux_name_length; +add_extension (s_aux_extension); {this also sets |name_length|} +name_ptr := 1; +while (name_ptr <= name_length) do + begin + buffer[name_ptr] := xord[name_of_file[name_ptr]]; + incr(name_ptr); + end; +top_lev_str := hash_text[ + str_lookup(buffer,1,aux_name_length,text_ilk,do_insert)]; +cur_aux_str := hash_text[ + str_lookup(buffer,1,name_length,aux_file_ilk,do_insert)]; + {note that this has initialized |aux_list|} +if (hash_found) then + begin + trace + print_aux_name; + ecart@/ + confusion ('Already encountered auxiliary file'); + end; +cur_aux_line := 0; {this finishes initializing the top-level \.{.aux} file} +end + + +@ +Print the name of the current \.{.aux} file, followed by a |newline|. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_aux_name; +begin +print_pool_str (cur_aux_str); +print_newline; +end; + + + +@* Reading the auxiliary file(s). +@^auxiliary-file commands@> +Now it's time to read the \.{.aux} file. The only commands we handle +are \.{\\citation} (there can be arbitrarily many, each having +arbitrarily many arguments), \.{\\bibdata} (there can be just one, but +it can have arbitrarily many arguments), \.{\\bibstyle} (there can be +just one, and it can have just one argument), and \.{\\@@input} (there +can be arbitrarily many, each with one argument, and they can be +nested to a depth of |aux_stack_size|). Each of these commands is +assumed to be on just a single line. The rest of the \.{.aux} file is +ignored. + +@d aux_done=31 {go here when finished with the \.{.aux} files} + +@<Labels in the outer block@>= +,@!aux_done + + +@ +We keep reading and processing input lines until none left. This is +part of the main program; hence, because of the |aux_done| label, +there's no conventional |begin|-|end| pair surrounding the entire +module. + +@<Read the \.{.aux} file@>= +print ('The top-level auxiliary file: '); +print_aux_name; +loop + begin {|pop_the_aux_stack| will exit the loop} + incr(cur_aux_line); + if (not input_ln(cur_aux_file)) then {end of current \.{.aux} file} + pop_the_aux_stack + else + get_aux_command_and_process; + end; + trace + trace_pr_ln ('Finished reading the auxiliary file(s)'); + ecart@/ +aux_done: +last_check_for_aux_errors; + + +@ +When we find a bug, we print a message and flush the rest of the line. +This macro must be called from within a procedure that has an |exit| +label. + +@d aux_err_return == begin + aux_err_print; + return; {flush this input line} + end + +@d aux_err(#) == begin + print (#); + aux_err_return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure aux_err_print; +begin +print ('---line ',cur_aux_line:0,' of file '); +print_aux_name;@/ +print_bad_input_line; {this call does the |mark_error|} +print_skipping_whatever_remains; +print_ln ('command') +end; + + +@ +@:this can't happen}{\quad Illegal auxiliary-file command@> +Here are a bunch of macros whose print statements are used at least +twice. Thus we save space by making the statements procedures. This +macro complains when there's a repeated command that's to be used just +once. + +@d aux_err_illegal_another(#) == begin + aux_err_illegal_another_print (#); + aux_err_return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure aux_err_illegal_another_print (@!cmd_num : integer); +begin +print ('Illegal, another \bib'); +case (cmd_num) of + n_aux_bibdata : print ('data'); + n_aux_bibstyle : print ('style'); + othercases + confusion ('Illegal auxiliary-file command') +endcases; +print (' command'); +end; + + +@ +This one complains when a command is missing its |right_brace|. + +@d aux_err_no_right_brace == begin + aux_err_no_right_brace_print; + aux_err_return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure aux_err_no_right_brace_print; +begin +print ('No "',xchr[right_brace],'"'); +end; + + +@ +This one complains when a command has stuff after its |right_brace|. + +@d aux_err_stuff_after_right_brace == begin + aux_err_stuff_after_right_brace_print; + aux_err_return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure aux_err_stuff_after_right_brace_print; +begin +print ('Stuff after "',xchr[right_brace],'"'); +end; + + +@ +And this one complains when a command has |white_space| in its +argument. + +@d aux_err_white_space_in_argument == begin + aux_err_white_space_in_argument_print; + aux_err_return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure aux_err_white_space_in_argument_print; +begin +print ('White space in argument'); +end; + + +@ +@^auxiliary-file commands@> +@:this can't happen}{\quad Unknown auxiliary-file command@> +We're not at the end of an \.{.aux} file, so we see if the current +line might be a command of interest. A command of interest will be a +line without blanks, consisting of a command name, a |left_brace|, one +or more arguments separated by commas, and a |right_brace|. + +@<Scan for and process an \.{.aux} command@>= +procedure get_aux_command_and_process; +label exit; +begin +buf_ptr2 := 0; {mark the beginning of the next token} +if (not scan1(left_brace)) then {no |left_brace|---flush line} + return; +command_num := ilk_info[ + str_lookup(buffer,buf_ptr1,token_len,aux_command_ilk,dont_insert)]; +if (hash_found) then + case (command_num) of + n_aux_bibdata : aux_bib_data_command; + n_aux_bibstyle : aux_bib_style_command; + n_aux_citation : aux_citation_command; + n_aux_input : aux_input_command; + othercases + confusion ('Unknown auxiliary-file command') + endcases; +exit: +end; + + +@ +Here we introduce some variables for processing a \.{\\bibdata} +command. Each element in |bib_list| (except for +|bib_list[max_bib_files]|, which is always unused) is a pointer to the +appropriate |str_pool| string representing the \.{.bib} file name. +The array |bib_file| contains the corresponding \PASCAL\ |file| +variables. + +@d cur_bib_str == bib_list[bib_ptr] {shorthand for current \.{.bib} file} +@d cur_bib_file == bib_file[bib_ptr] {shorthand for current |bib_file|} + +@<Globals in the outer block@>= +@!bib_list : array[bib_number] of str_number; {the \.{.bib} file list} +@!bib_ptr : bib_number; {pointer for the current \.{.bib} file} +@!num_bib_files : bib_number; {the total number of \.{.bib} files} +@!bib_seen : boolean; {|true| if we've already seen a \.{\\bibdata} command} +@!bib_file : array[bib_number] of alpha_file; {corresponding |file| variables} + + +@ +Where |bib_number| is the obvious. + +@<Types in the outer block@>= +@!bib_number = 0..max_bib_files; {gives the |bib_list| range} + + +@ +@<Set initial values of key variables@>= +bib_ptr := 0; {this makes |bib_list| empty} +bib_seen := false; {we haven't seen a \.{\\bibdata} command yet} + + +@ +@:auxiliary-file commands}{\quad \.{\\bibdata}@> +A \.{\\bibdata} command will have its arguments between braces and +separated by commas. There must be exactly one such command in the +\.{.aux} file(s). All upper-case letters are converted to lower case. + +@<Procedures and functions for the reading and processing of input files@>= +procedure aux_bib_data_command; +label exit; +begin +if (bib_seen) then + aux_err_illegal_another (n_aux_bibdata); +bib_seen := true; {now we've seen a \.{\\bibdata} command} +while (scan_char <> right_brace) do + begin + incr(buf_ptr2); {skip over the previous stop-character} + if (not scan2_white(right_brace,comma)) then + aux_err_no_right_brace; + if (lex_class[scan_char] = white_space) then + aux_err_white_space_in_argument; + if ((last > buf_ptr2+1) and (scan_char = right_brace)) then + aux_err_stuff_after_right_brace; + @<Open a \.{.bib} file@>; + end; +exit: +end; + + +@ +Here's a procedure we'll need shortly. It prints the name of the +current \.{.bib} file, followed by a |newline|. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_bib_name; +begin +print_pool_str (cur_bib_str); +print_pool_str (s_bib_extension); +print_newline; +end; + + +@ +This macro is similar to |aux_err| but it complains specifically about +opening a file for a \.{\\bibdata} command. + +@d open_bibdata_aux_err(#) == begin + print (#); + print_bib_name; + aux_err_return; {this does the |mark_error|} + end + + +@ +@:BibTeX capacity exceeded}{\quad number of \.{.bib} files@> +Now we add the just-found argument to |bib_list| if it hasn't already +been encountered as a \.{\\bibdata} argument and if, after appending +the |s_bib_extension| string, the resulting file name can be opened. + +@<Open a \.{.bib} file@>= +begin +if (bib_ptr = max_bib_files) then + overflow('number of database files ',max_bib_files); +cur_bib_str := hash_text[ + str_lookup(buffer,buf_ptr1,token_len,bib_file_ilk,do_insert)]; +if (hash_found) then {already encountered this as a \.{\\bibdata} argument} + open_bibdata_aux_err ('This database file appears more than once: '); +start_name (cur_bib_str); +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; + trace + trace_pr_pool_str (cur_bib_str); + trace_pr_pool_str (s_bib_extension); + trace_pr_ln (' is a bibdata file'); + ecart@/ +incr(bib_ptr); +end + + +@ +Here we introduce some variables for processing a \.{\\bibstyle} +command. + +@<Globals in the outer block@>= +@!bst_seen : boolean; {|true| if we've already seen a \.{\\bibstyle} command} +@!bst_str : str_number; {the string number for the \.{.bst} file} +@!bst_file : alpha_file; {the corresponding |file| variable} + + +@ +And we initialize. + +@<Set initial values of key variables@>= +bst_str := 0; {mark |bst_str| as unused} +bst_seen := false; {we haven't seen a \.{\\bibstyle} command yet} + + +@ +@:auxiliary-file commands}{\quad \.{\\bibstyle}@> +A \.{\\bibstyle} command will have exactly one argument, and it will +be between braces. There must be exactly one such command in the +\.{.aux} file(s). All upper-case letters are converted to lower case. + +@<Procedures and functions for the reading and processing of input files@>= +procedure aux_bib_style_command; +label exit; +begin +if (bst_seen) then + aux_err_illegal_another (n_aux_bibstyle); +bst_seen := true; {now we've seen a \.{\\bibstyle} command} +incr(buf_ptr2); {skip over the |left_brace|} +if (not scan1_white(right_brace)) then + aux_err_no_right_brace; +if (lex_class[scan_char] = white_space) then + aux_err_white_space_in_argument; +if (last > buf_ptr2+1) then + aux_err_stuff_after_right_brace; +@<Open the \.{.bst} file@>; +exit: +end; + + +@ +@:this can't happen}{\quad Already encountered style file@> +Now we open the file whose name is the just-found argument appended +with the |s_bst_extension| string, if possible. + +@<Open the \.{.bst} file@>= +begin +bst_str := hash_text[ + str_lookup(buffer,buf_ptr1,token_len,bst_file_ilk,do_insert)]; +if (hash_found) then + begin + trace + print_bst_name; + ecart@/ + confusion ('Already encountered style file'); + end; +start_name (bst_str); +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; +print ('The style file: '); +print_bst_name; +end + + +@ +Print the name of the \.{.bst} file, followed by a |newline|. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_bst_name; +begin +print_pool_str (bst_str); +print_pool_str (s_bst_extension); +print_newline; +end; + + +@ +Here we introduce some variables for processing a \.{\\citation} +command. Each element in |cite_list| (except for +|cite_list[max_cites]|, which is always unused) is a pointer to the +appropriate |str_pool| string. The cite-key list is kept in order of +occurrence with duplicates removed. + +@d cur_cite_str == cite_list[cite_ptr] {shorthand for the current cite key} + +@<Globals in the outer block@>= +@!cite_list : packed array[cite_number] of str_number; {the cite-key list} +@!cite_ptr : cite_number; {pointer for the current cite key} +@!entry_cite_ptr : cite_number; {cite pointer for the current entry} +@!num_cites : cite_number; {the total number of distinct cite keys} +@!old_num_cites : cite_number; {set to a previous |num_cites| value} +@!citation_seen : boolean; {|true| if we've seen a \.{\\citation} command} +@!cite_loc : hash_loc; {the hash-table location of a cite key} +@!lc_cite_loc : hash_loc; {and of its lower-case equivalent} +@!lc_xcite_loc : hash_loc; {a second |lc_cite_loc| variable} +@!cite_found : boolean; {|true| if we've already seen this cite key} +@!all_entries : boolean; {|true| if we're to use the entire database} +@!all_marker : cite_number; {we put the other entries in |cite_list| here} + + +@ +Where |cite_number| is the obvious. + +@<Types in the outer block@>= +@!cite_number = 0..max_cites; {gives the |cite_list| range} + + +@ +@<Set initial values of key variables@>= +cite_ptr := 0; {this makes |cite_list| empty} +citation_seen := false; {we haven't seen a \.{\\citation} command yet} +all_entries := false; {by default, use just the entries explicitly named} + + +@ +@^case mismatch@> +@^entire database inclusion@> +@^whole database inclusion@> +@:LaTeX}{\LaTeX@> +@:auxiliary-file commands}{\quad \.{\\citation}@> +A \.{\\citation} command will have its arguments between braces and +separated by commas. Upper/lower cases are considered to be different +for \.{\\citation} arguments, which is the same as the rest of \LaTeX\ +but different from the rest of \BibTeX. A cite key needn't exactly +case-match its corresponding database key to work, although two cite +keys that are case-mismatched will produce an error message. +(A {\sl case mismatch\/} is a mismatch, but only because of a case +difference.) + +A \.{\\citation} command having \.{*} as an argument indicates that +the entire database will be included (almost as if a \.{\\nocite} +command that listed every cite key in the database, in order, had been +given at the corresponding spot in the \.{.tex} file). + +@d next_cite = 23 {read the next argument} + +@<Procedures and functions for the reading and processing of input files@>= +procedure aux_citation_command; +label next_cite,@!exit; +begin +citation_seen := true; {now we've seen a \.{\\citation} command} +while (scan_char <> right_brace) do + begin + incr(buf_ptr2); {skip over the previous stop-character} + if (not scan2_white(right_brace,comma)) then + aux_err_no_right_brace; + if (lex_class[scan_char] = white_space) then + aux_err_white_space_in_argument; + if ((last > buf_ptr2+1) and (scan_char = right_brace)) then + aux_err_stuff_after_right_brace; + @<Check the cite key@>; +next_cite: + end; +exit: +end; + + +@ +@^kludge@> +We must check if (the lower-case version of) this cite key has been +previously encountered, and proceed accordingly. The alias kludge +helps make the stack space not overflow on some machines. + +@d ex_buf1== ex_buf {an alias, used only in this module} + +@<Check the cite key@>= +begin + trace + trace_pr_token; + trace_pr (' cite key encountered'); + ecart@/ +@<Check for entire database inclusion (and thus skip this cite key)@>; +tmp_ptr := buf_ptr1; +while (tmp_ptr < buf_ptr2) do + begin + ex_buf1[tmp_ptr] := buffer[tmp_ptr]; + incr(tmp_ptr); + end; +lower_case (ex_buf1, buf_ptr1, token_len); {convert to `canonical' form} +lc_cite_loc := str_lookup(ex_buf1,buf_ptr1,token_len,lc_cite_ilk,do_insert); +if (hash_found) then {already encountered this as a \.{\\citation} argument} + @<Cite seen, don't add a cite key@> + else + @<Cite unseen, add a cite key@>; + {it's a new cite key---add it to |cite_list|} +end + + +@ +Here we check for a \.{\\citation} command having \.{*} as an +argument, indicating that the entire database will be included. + +@<Check for entire database inclusion (and thus skip this cite key)@>= +begin +if (token_len = 1) then + if (buffer[buf_ptr1] = star) then + begin + trace + trace_pr_ln ('---entire database to be included'); + ecart@/ + if (all_entries) then + begin + print_ln ('Multiple inclusions of entire database'); + aux_err_return; + end + else + begin + all_entries := true; + all_marker := cite_ptr; + goto next_cite; + end; + end; +end + + +@ +@^case mismatch errors@> +We've previously encountered the lower-case version, so we check that +the actual version exactly matches the actual version of the +previously-encountered cite key(s). + +@<Cite seen, don't add a cite key@>= +begin + trace + trace_pr_ln (' previously'); + ecart@/ +dummy_loc := str_lookup(buffer,buf_ptr1,token_len,cite_ilk,dont_insert); +if (not hash_found) then {case mismatch error} + begin + print ('Case mismatch error between cite keys '); + print_token; + print (' and '); + print_pool_str (cite_list[ilk_info[ilk_info[lc_cite_loc]]]); + print_newline; + aux_err_return; + end; +end + + +@ +@:this can't happen}{\quad Cite hash error@> +Now we add the just-found argument to |cite_list| if there isn't +anything funny happening. + +@<Cite unseen, add a cite key@>= +begin + trace + trace_pr_newline; + ecart@/ +cite_loc := str_lookup(buffer,buf_ptr1,token_len,cite_ilk,do_insert); +if (hash_found) then + hash_cite_confusion; +check_cite_overflow (cite_ptr); +cur_cite_str := hash_text[cite_loc]; +ilk_info[cite_loc] := cite_ptr; +ilk_info[lc_cite_loc] := cite_loc; +incr(cite_ptr); +end + + +@ +@:this can't happen}{\quad Cite hash error@> +Here's a serious complaint (that is, a bug) concerning hash problems. +This is the first of several similar bug-procedures that exist only +because they save space. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure hash_cite_confusion; +begin +confusion ('Cite hash error'); +end; + + +@ +@^fetish@> +@:BibTeX capacity exceeded}{\quad number of cite keys@> +Complain if somebody's got a cite fetish. This procedure is called +when were about to add another cite key to |cite_list|. It assumes +that |cite_loc| gives the potential cite key's hash table location. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure check_cite_overflow (@!last_cite : cite_number); +begin +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); + end; +end; + + +@ +@:auxiliary-file commands}{\quad \.{\\\AT!input}@> +An \.{\\@@input} command will have exactly one argument, it will +be between braces, and it must have the |s_aux_extension|. +All upper-case letters are converted to lower case. + +@<Procedures and functions for the reading and processing of input files@>= +procedure aux_input_command; +label exit; +var aux_extension_ok : boolean; {to check for a correct file extension} +begin +incr(buf_ptr2); {skip over the |left_brace|} +if (not scan1_white(right_brace)) then + aux_err_no_right_brace; +if (lex_class[scan_char] = white_space) then + aux_err_white_space_in_argument; +if (last > buf_ptr2+1) then + aux_err_stuff_after_right_brace; +@<Push the \.{.aux} stack@>; +exit: +end; + + +@ +@:BibTeX capacity exceeded}{\quad number of \.{.aux} files@> +We must check that this potential \.{.aux} file won't overflow the +stack, that it has the correct extension, that we haven't encountered +it before (to prevent, among other things, an infinite loop). + +@<Push the \.{.aux} stack@>= +begin +incr(aux_ptr); +if (aux_ptr = aux_stack_size) then + begin + print_token; print (': '); + overflow('auxiliary file depth ',aux_stack_size); + end; +aux_extension_ok := true; +if (token_len < length(s_aux_extension)) then@/ + aux_extension_ok := false {else |str_eq_buf| might bomb the program} +else if (not str_eq_buf(s_aux_extension, buffer, + buf_ptr2-length(s_aux_extension), length(s_aux_extension))) then + aux_extension_ok := false; +if (not aux_extension_ok) then + begin + print_token; + print (' has a wrong extension'); + decr(aux_ptr); + aux_err_return; + end; +cur_aux_str := hash_text[ + str_lookup(buffer,buf_ptr1,token_len,aux_file_ilk,do_insert)]; +if (hash_found) then + begin + print ('Already encountered file '); + print_aux_name; + decr(aux_ptr); + aux_err_return; + end; +@<Open this \.{.aux} file@>; +end + + +@ +We check that this \.{.aux} file can actually be opened, and then open it. + +@<Open this \.{.aux} file@>= +begin +start_name (cur_aux_str); {extension already there for \.{.aux} files} +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; +if (not a_open_in(cur_aux_file)) then + begin + print ('I couldn''t open auxiliary file '); + print_aux_name; + decr(aux_ptr); + aux_err_return; + end; +print ('A level-',aux_ptr:0,' auxiliary file: '); +print_aux_name; +cur_aux_line := 0; +end + + +@ +Here we close the current-level \.{.aux} file and go back up a level, +if possible, by decrementing |aux_ptr|. + +@<Procedures and functions for the reading and processing of input files@>= +procedure pop_the_aux_stack; +begin +a_close (cur_aux_file); +if (aux_ptr=0) then + goto aux_done + else + decr(aux_ptr); +end; + + +@ +@^gymnastics@> +That's it for processing \.{.aux} commands, except for finishing the +procedural gymnastics. + +@<Procedures and functions for the reading and processing of input files@>= +@<Scan for and process an \.{.aux} command@> + + +@ +We must complain if anything's amiss. + +@d aux_end_err(#) == begin + aux_end1_err_print; + print (#); + aux_end2_err_print; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure aux_end1_err_print; +begin +print ('I found no '); +end; +@# +procedure aux_end2_err_print; +begin +print ('---while reading file '); +print_aux_name; +mark_error; +end; + + +@ +Before proceeding, we see if we have any complaints. + +@<Procedures and functions for the reading and processing of input files@>= +procedure last_check_for_aux_errors; +begin +num_cites := cite_ptr; {record the number of distinct cite keys} +num_bib_files := bib_ptr; {and the number of \.{.bib} files} +if (not citation_seen) then + aux_end_err ('\citation commands') + else if ((num_cites = 0) and (not all_entries)) then + aux_end_err ('cite keys'); +if (not bib_seen) then + aux_end_err ('\bibdata command') + else if (num_bib_files = 0) then + aux_end_err ('database files'); +if (not bst_seen) then + aux_end_err ('\bibstyle command') + else if (bst_str = 0) then + aux_end_err ('style file'); +end; + + + +@* Reading the style file. +This part of the program reads the \.{.bst} file, which consists of a +sequence of commands. Each \.{.bst} command consists of a name (for +which case differences are ignored) followed by zero or more +arguments, each enclosed in braces. + +@d bst_done=32 {go here when finished with the \.{.bst} file} +@d no_bst_file=9932 {go here when skipping the \.{.bst} file} + +@<Labels in the outer block@>= +,@!bst_done,@!no_bst_file + + +@ +The |bbl_line_num| gets initialized along with the |bst_line_num|, so +it's declared here too. + +@<Globals in the outer block@>= +@!bbl_line_num : integer; {line number of the \.{.bbl} (output) file} +@!bst_line_num : integer; {line number of the \.{.bst} file} + + +@ +This little procedure exists because it's used by at least two other +procedures and thus saves some space. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_ln_num_print; +begin +print ('--line ',bst_line_num:0,' of file '); +print_bst_name; +end; + + +@ +When there's a serious error parsing the \.{.bst} file, we flush the +rest of the current command; a blank line is assumed to mark the end +of a command (but for the purposes of error recovery only). Thus, +error recovery will be better if style designers leave blank lines +between \.{.bst} commands. This macro must be called from within a +procedure that has an |exit| label. + +@d bst_err_print_and_look_for_blank_line_return == + begin + bst_err_print_and_look_for_blank_line; + return; + end + +@d bst_err(#) == begin {serious error during \.{.bst} parsing} + print (#); + bst_err_print_and_look_for_blank_line_return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_err_print_and_look_for_blank_line; +begin +print ('-'); +bst_ln_num_print; +print_bad_input_line; {this call does the |mark_error|} +while (last <> 0) do {look for a blank input line} + if (not input_ln(bst_file)) then {or the end of the file} + goto bst_done + else + incr(bst_line_num); +buf_ptr2 := last; {to input the next line} +end; + + +@ +When there's a harmless error parsing the \.{.bst} file (harmless +syntactically, at least) we give just a |warning_message|. + +@d bst_warn(#) == begin {non-serious error during \.{.bst} parsing} + print (#); + bst_warn_print; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_warn_print; +begin +bst_ln_num_print; +mark_warning; +end; + + +@ +Here's the outer loop for reading the \.{.bst} file---it keeps reading +and processing \.{.bst} commands until none left. This is part of the +main program; hence, because of the |bst_done| label, there's no +conventional |begin|-|end| pair surrounding the entire module. + +@<Read and execute the \.{.bst} file@>= +if (bst_str = 0) then {there's no \.{.bst} file to read} + goto no_bst_file; {this is a |goto| so that |bst_done| is not in a block} +bst_line_num := 0; {initialize things} +bbl_line_num := 1; {best spot to initialize the output line number} +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); +no_bst_file: a_close (bbl_file); + + +@ +This \.{.bst}-specific scanning function skips over |white_space| +characters (and comments) until hitting a nonwhite character or the +end of the file, respectively returning |true| or |false|. It also +updates |bst_line_num|, the line counter. + +@<Procedures and functions for input scanning@>= +function eat_bst_white_space : boolean; +label exit; +begin +loop + begin + if (scan_white_space) then {hit a nonwhite character on this line} + if (scan_char <> comment) then {it's not a comment character; return} + begin + eat_bst_white_space := true; + return; + end; + if (not input_ln(bst_file)) then {end-of-file; return |false|} + begin + eat_bst_white_space := false; + return; + end; + incr(bst_line_num); + buf_ptr2 := 0; + end; +exit: +end; + + +@ +It's often illegal to end a \.{.bst} command in certain places, and +this is where we come to check. + +@d eat_bst_white_and_eof_check(#) == + begin + if (not eat_bst_white_space) then + begin + eat_bst_print; + bst_err (#); + end; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure eat_bst_print; +begin +print ('Illegal end of style file in command: '); +end; + + +@ +We must attend to a few details before getting to work on this +\.{.bst} command. + +@<Scan for and process a \.{.bst} command@>= +procedure get_bst_command_and_process; +label exit; +begin +if (not scan_alpha) then + bst_err ('"',xchr[scan_char],'" can''t start a style-file command'); +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +command_num := ilk_info[ + str_lookup(buffer,buf_ptr1,token_len,bst_command_ilk,dont_insert)]; +if (not hash_found) then + begin + print_token; + bst_err (' is an illegal style-file command'); + end; +@<Process the appropriate \.{.bst} command@>; +exit: +end; + + +@ +@^style-file commands@> +@:this can't happen}{\quad Unknown style-file command@> +Here we determine which \.{.bst} command we're about to process, and +then go to it. + +@<Process the appropriate \.{.bst} command@>= +case (command_num) of + n_bst_entry : bst_entry_command; + n_bst_execute : bst_execute_command; + n_bst_function : bst_function_command; + n_bst_integers : bst_integers_command; + n_bst_iterate : bst_iterate_command; + n_bst_macro : bst_macro_command; + n_bst_read : bst_read_command; + n_bst_reverse : bst_reverse_command; + n_bst_sort : bst_sort_command; + n_bst_strings : bst_strings_command; + othercases confusion ('Unknown style-file command') +endcases + + +@ +We need data structures for the function definitions, the entry +variables, the global variables, and the actual entries corresponding +to the cite-key list. First we define the classes of `function's +used. Functions in all classes are of |bst_fn_ilk| except for +|int_literal|s, which are of |integer_ilk|; and |str_literal|s, which +are of |text_ilk|. + +@d built_in = 0 {the `primitive' functions} +@d wiz_defined = 1 {defined in the \.{.bst} file} +@d int_literal = 2 {integer `constants'} +@d str_literal = 3 {string `constants'} +@d field = 4 {things like `author' and `title'} +@d int_entry_var = 5 {integer entry variable} +@d str_entry_var = 6 {string entry variable} +@d int_global_var = 7 {integer global variable} +@d str_global_var = 8 {string global variable} +@d last_fn_class = 8 {the same number as on the line above} + + +@ +@:this can't happen}{\quad Unknown function class@> +Here's another bug report. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure unknwn_function_class_confusion; +begin +confusion ('Unknown function class'); +end; + + +@ +@:this can't happen}{\quad Unknown function class@> +Occasionally we'll want to |print| the name of one of these function +classes. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_fn_class (@!fn_loc : hash_loc); +begin +case (fn_type[fn_loc]) of + built_in : print ('built-in'); + wiz_defined : print ('wizard-defined'); + int_literal : print ('integer-literal'); + str_literal : print ('string-literal'); + field : print ('field'); + int_entry_var : print ('integer-entry-variable'); + str_entry_var : print ('string-entry-variable'); + int_global_var : print ('integer-global-variable'); + str_global_var : print ('string-global-variable'); + othercases unknwn_function_class_confusion +endcases; +end; + + +@ +@:this can't happen}{\quad Unknown function class@> +This version is for printing when in |trace| mode. + +@<Procedures and functions for all file I/O, error messages, and such@>= + trace + procedure trace_pr_fn_class (@!fn_loc : hash_loc); + begin + case (fn_type[fn_loc]) of + built_in : trace_pr ('built-in'); + wiz_defined : trace_pr ('wizard-defined'); + int_literal : trace_pr ('integer-literal'); + str_literal : trace_pr ('string-literal'); + field : trace_pr ('field'); + int_entry_var : trace_pr ('integer-entry-variable'); + str_entry_var : trace_pr ('string-entry-variable'); + int_global_var : trace_pr ('integer-global-variable'); + str_global_var : trace_pr ('string-global-variable'); + othercases unknwn_function_class_confusion + endcases; + end; + ecart + + +@ +Besides the function classes, we have types based on \BibTeX's +capacity limitations and one based on what can go into the array +|wiz_functions| explained below. + +@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} +@!hash_ptr2 = quote_next_fn..end_of_def; {a special marker or a |hash_loc|} + + +@ +@^save space@> +@^space savings@> +@^system dependencies@> +We store information about the \.{.bst} functions in arrays the same +size as the hash-table arrays and in locations corresponding to their +hash-table locations. The two arrays |fn_info| (an alias of +|ilk_info| described earlier) and |fn_type| accomplish this: |fn_type| +specifies one of the above classes, and |fn_info| gives information +dependent on the class. + +Six other arrays give the contents of functions: The array +|wiz_functions| holds definitions for |wiz_defined| functions---each +such function consists of a sequence of pointers to hash-table +locations of other functions (with the two special-marker exceptions +above); the array |entry_ints| contains the current values of +|int_entry_var|s; the array |entry_strs| contains the current values +of |str_entry_var|s; an element of the array |global_strs| contains +the current value of a |str_global_var| if the corresponding +|glb_str_ptr| entry is empty, otherwise the nonempty entry is a +pointer to the string; and the array |field_info|, for each field of +each entry, contains either a pointer to the string or the special +value |missing|. + +The array |global_strs| isn't packed (that is, it isn't |array| \dots\ +|of packed array| \dots$\,$) to increase speed on some systems; +however, on systems that are byte-addressable and that have a good +compiler, packing |global_strs| would save lots of space without much +loss of speed. + +@d fn_info == ilk_info {an alias used with functions} +@# +@d missing = empty {a special pointer for missing fields} + +@<Globals in the outer block@>= +@!fn_loc : hash_loc; {the hash-table location of a function} +@!wiz_loc : hash_loc; {the hash-table location of a wizard function} +@!literal_loc : hash_loc; {the hash-table location of a literal function} +@!macro_name_loc : hash_loc; {the hash-table location of a macro name} +@!macro_def_loc : hash_loc; {the hash-table location of a macro definition} +@!fn_type : packed array[hash_loc] of fn_class; +@!wiz_def_ptr : wiz_fn_loc; {storage location for the next wizard function} +@!wiz_fn_ptr : wiz_fn_loc; {general |wiz_functions| location} +@!wiz_functions : packed array[wiz_fn_loc] of hash_ptr2; +@!int_ent_ptr : int_ent_loc; {general |int_entry_var| location} +@!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; +@!num_ent_strs : str_ent_loc; {the number of distinct |str_entry_var| names} +@!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} +@!field_ptr : field_loc; {general |field_info| location} +@!field_parent_ptr,@!field_end_ptr : field_loc; {two more for doing cross-refs} +@!cite_parent_ptr,@!cite_xptr : cite_number; {two others for doing cross-refs} +@!field_info : packed array[field_loc] of str_number; +@!num_fields : field_loc; {the number of distinct field names} +@!num_pre_defined_fields : field_loc; {so far, just one: \.{crossref}} +@!crossref_num : field_loc; {the number given to \.{crossref}} +@!no_fields : boolean; {used for |tr_print|ing entry information} + + +@ +Now we initialize storage for the |wiz_defined| functions and we +initialize variables so that the first |str_entry_var|, +|int_entry_var|, |str_global_var|, and |field| name will be assigned +the number~0. Note: The variables |num_ent_strs| and |num_fields| +will also be set when pre-defining strings. + +@<Set initial values of key variables@>= +wiz_def_ptr := 0; +num_ent_ints := 0; +num_ent_strs := 0; +num_fields := 0; +str_glb_ptr := 0; +while (str_glb_ptr < max_glob_strs) do {make |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; +num_glb_strs := 0; + + + +@* Style-file commands. +@^style-file commands@> +There are ten \.{.bst} commands: Five (\.{entry}, \.{function}, +\.{integers}, \.{macro}, and \.{strings}) declare and define +functions, one (\.{read}) reads in the \.{.bib}-file entries, and four +(\.{execute}, \.{iterate}, \.{reverse}, and \.{sort}) +manipulate the entries and produce output. + +The boolean variables |entry_seen| and |read_seen| indicate whether +we've yet encountered an \.{entry} and a \.{read} command. There must +be exactly one of each of these, and the \.{entry} command, as well as +any \.{macro} command, must precede the \.{read} command. +Furthermore, the \.{read} command must precede the four that +manipulate the entries and produce output. + +@<Globals in the outer block@>= +@!entry_seen : boolean; {|true| if we've already seen an \.{entry} command} +@!read_seen : boolean; {|true| if we've already seen a \.{read} command} +@!read_performed : boolean; {|true| if we started reading the database file(s)} +@!reading_completed : boolean; {|true| if we made it all the way through} +@!read_completed : boolean; {|true| if the database info didn't bomb \BibTeX} + + +@ +And we initialize them. + +@<Set initial values of key variables@>= +entry_seen := false; +read_seen := false; +read_performed := false; +reading_completed := false; +read_completed := false; + + +@ +@:this can't happen}{\quad Identifier scanning error@> +Here's another bug. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure id_scanning_confusion; +begin +confusion ('Identifier scanning error'); +end; + + +@ +@:this can't happen}{\quad Identifier scanning error@> +This macro is used to scan all \.{.bst} identifiers. The argument +supplies the \.{.bst} command name. The associated procedure simply +prints an error message. + +@d bst_identifier_scan(#) == + begin + scan_identifier (right_brace,comment,comment); + if ((scan_result = white_adjacent) or + (scan_result = specified_char_adjacent)) then + do_nothing + else + begin + bst_id_print; + bst_err (#); + end; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_id_print; +begin +if (scan_result = id_null) then + print ('"',xchr[scan_char],'" begins identifier, command: ') +else if (scan_result = other_char_adjacent) then + print ('"',xchr[scan_char],'" immediately follows identifier, command: ') +else + id_scanning_confusion; +end; + + +@ +This macro just makes sure we're at a |left_brace|. + +@d bst_get_and_check_left_brace(#) == + begin + if (scan_char <> left_brace) then + begin + bst_left_brace_print; + bst_err (#); + end; + incr(buf_ptr2); {skip over the |left_brace|} + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_left_brace_print; +begin +print ('"',xchr[left_brace],'" is missing in command: '); +end; + + +@ +And this one, a |right_brace|. + +@d bst_get_and_check_right_brace(#) == + begin + if (scan_char <> right_brace) then + begin + bst_right_brace_print; + bst_err (#); + end; + incr(buf_ptr2); {skip over the |right_brace|} + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_right_brace_print; +begin +print ('"',xchr[right_brace],'" is missing in command: '); +end; + + +@ +This macro complains if we've already encountered a function to be +inserted into the hash table. + +@d check_for_already_seen_function(#) == + begin + if (hash_found) then {already encountered this as a \.{.bst} function} + begin + already_seen_function_print (#); + return; + end; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure already_seen_function_print (@!seen_fn_loc : hash_loc); +label exit; {so the call to |bst_err| works} +begin +print_pool_str (hash_text[seen_fn_loc]); +print (' is already a type "'); +print_fn_class (seen_fn_loc); +print_ln ('" function name'); +bst_err_print_and_look_for_blank_line_return; +exit: +end; + + +@ +@:style-file commands}{\quad \.{entry}@> +An \.{entry} command has three arguments, each a (possibly empty) list +of function names between braces (the names are separated by one or +more |white_space| characters). All function names in this and other +commands must be legal \.{.bst} identifiers. Upper/lower cases are +considered to be the same for function names in these lists---all +upper-case letters are converted to lower case. These arguments give +lists of |field|s, |int_entry_var|s, and |str_entry_var|s. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_entry_command; +label exit; +begin +if (entry_seen) then + bst_err ('Illegal, another entry command'); +entry_seen := true; {now we've seen an \.{entry} command} +eat_bst_white_and_eof_check ('entry'); +@<Scan the list of |field|s@>; +eat_bst_white_and_eof_check ('entry'); +if (num_fields = num_pre_defined_fields) then + bst_warn ('Warning--I didn''t find any fields'); +@<Scan the list of |int_entry_var|s@>; +eat_bst_white_and_eof_check ('entry'); +@<Scan the list of |str_entry_var|s@>; +exit: +end; + + +@ +This module reads a |left_brace|, the list of |field|s, and a +|right_brace|. The |field|s are those like `author' and `title.' + +@<Scan the list of |field|s@>= +begin +bst_get_and_check_left_brace ('entry'); +eat_bst_white_and_eof_check ('entry'); +while (scan_char <> right_brace) do + begin + bst_identifier_scan ('entry'); + @<Insert a |field| into the hash table@>; + eat_bst_white_and_eof_check ('entry'); + end; +incr(buf_ptr2); {skip over the |right_brace|} +end + + +@ +@^secret agent man@> +Here we insert the just found field name into the hash table, record +it as a |field|, and assign it a number to be used in indexing into +the |field_info| array. + +@<Insert a |field| into the hash table@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a field'); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +fn_loc := str_lookup(buffer,buf_ptr1,token_len,bst_fn_ilk,do_insert); +check_for_already_seen_function (fn_loc); +fn_type[fn_loc] := field;@/ +fn_info[fn_loc] := num_fields; {give this field a number (take away its name)} +incr(num_fields); +end + + +@ +This module reads a |left_brace|, the list of |int_entry_var|s, +and a |right_brace|. + +@<Scan the list of |int_entry_var|s@>= +begin +bst_get_and_check_left_brace ('entry'); +eat_bst_white_and_eof_check ('entry'); +while (scan_char <> right_brace) do + begin + bst_identifier_scan ('entry'); + @<Insert an |int_entry_var| into the hash table@>; + eat_bst_white_and_eof_check ('entry'); + end; +incr(buf_ptr2); {skip over the |right_brace|} +end + + +@ +Here we insert the just found |int_entry_var| name into the hash table +and record it as an |int_entry_var|. An |int_entry_var| is one that +the style designer wants a separate copy of for each entry. + +@<Insert an |int_entry_var| into the hash table@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is an integer entry-variable'); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +fn_loc := str_lookup(buffer,buf_ptr1,token_len,bst_fn_ilk,do_insert); +check_for_already_seen_function (fn_loc); +fn_type[fn_loc] := int_entry_var;@/ +fn_info[fn_loc] := num_ent_ints; {give this |int_entry_var| a number} +incr(num_ent_ints); +end + + +@ +This module reads a |left_brace|, the list of |str_entry_var|s, and a +|right_brace|. A |str_entry_var| is one that the style designer wants +a separate copy of for each entry. + +@<Scan the list of |str_entry_var|s@>= +begin +bst_get_and_check_left_brace ('entry'); +eat_bst_white_and_eof_check ('entry'); +while (scan_char <> right_brace) do + begin + bst_identifier_scan ('entry'); + @<Insert a |str_entry_var| into the hash table@>; + eat_bst_white_and_eof_check ('entry'); + end; +incr(buf_ptr2); {skip over the |right_brace|} +end + + +@ +Here we insert the just found |str_entry_var| name into the hash +table, record it as a |str_entry_var|, and set its pointer into +|entry_strs|. + +@<Insert a |str_entry_var| into the hash table@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a string entry-variable'); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +fn_loc := str_lookup(buffer,buf_ptr1,token_len,bst_fn_ilk,do_insert); +check_for_already_seen_function (fn_loc); +fn_type[fn_loc] := str_entry_var;@/ +fn_info[fn_loc] := num_ent_strs; {give this |str_entry_var| a number} +incr(num_ent_strs); +end + + +@ +A legal argument for an \.{execute}, \.{iterate}, or \.{reverse} +command must exist and be |built_in| or |wiz_defined|. +Here's where we check, returning |true| if the argument is illegal. + +@<Procedures and functions for the reading and processing of input files@>= +function bad_argument_token : boolean; +label exit; +begin +bad_argument_token := true; {now it's easy to exit if necessary} +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +fn_loc := str_lookup(buffer,buf_ptr1,token_len,bst_fn_ilk,dont_insert); +if (not hash_found) then {unknown \.{.bst} function} + begin + print_token; + bst_err (' is an unknown function'); + end +else if ((fn_type[fn_loc] <> built_in) and + (fn_type[fn_loc] <> wiz_defined)) then + begin + print_token; + print (' has bad function type '); + print_fn_class (fn_loc); + bst_err_print_and_look_for_blank_line_return; + end; +bad_argument_token := false; +exit: +end; + + +@ +@:style-file commands}{\quad \.{execute}@> +An \.{execute} command has one argument, a single |built_in| or +|wiz_defined| function name between braces. Upper/lower cases are +considered to be the same---all upper-case letters are converted to +lower case. Also, we must make sure we've already seen a \.{read} +command. + +This module reads a |left_brace|, a single function to be executed, +and a |right_brace|. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_execute_command; +label exit; +begin +if (not read_seen) then + bst_err ('Illegal, execute command before read command'); +eat_bst_white_and_eof_check ('execute'); +bst_get_and_check_left_brace ('execute'); +eat_bst_white_and_eof_check ('execute'); +bst_identifier_scan ('execute'); +@<Check the \.{execute}-command argument token@>; +eat_bst_white_and_eof_check ('execute'); +bst_get_and_check_right_brace ('execute'); +@<Perform an \.{execute} command@>; +exit: +end; + + +@ +Before executing the function, we must make sure it's a legal one. It +must exist and be |built_in| or |wiz_defined|. + +@<Check the \.{execute}-command argument token@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a to be executed function'); + ecart@/ +if (bad_argument_token) then + return; +end + + +@ +@:style-file commands}{\quad \.{function}@> +A \.{function} command has two arguments; the first is a +|wiz_defined| function name between braces. Upper/lower cases are +considered to be the same---all upper-case letters are converted to +lower case. The second argument defines this function. It consists +of a sequence of functions, between braces, separated by |white_space| +characters. Upper/lower cases are considered to be the same for +function names but not for |str_literal|s. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_function_command; +label exit; +begin +eat_bst_white_and_eof_check ('function'); +@<Scan the |wiz_defined| function name@>; +eat_bst_white_and_eof_check ('function'); +bst_get_and_check_left_brace ('function'); +scan_fn_def(wiz_loc); {this scans the function definition} +exit: +end; + + +@ +This module reads a |left_brace|, a |wiz_defined| function name, and +a |right_brace|. + +@<Scan the |wiz_defined| function name@>= +begin +bst_get_and_check_left_brace ('function'); +eat_bst_white_and_eof_check ('function'); +bst_identifier_scan ('function'); +@<Check the |wiz_defined| function name@>; +eat_bst_white_and_eof_check ('function'); +bst_get_and_check_right_brace ('function'); +end + + +@ +The function name must exist and be a new one; we mark it as +|wiz_defined|. Also, see if it's the default entry-type function. + +@<Check the |wiz_defined| function name@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a wizard-defined function'); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +wiz_loc := str_lookup(buffer,buf_ptr1,token_len,bst_fn_ilk,do_insert); +check_for_already_seen_function (wiz_loc); +fn_type[wiz_loc] := wiz_defined; +if (hash_text[wiz_loc] = s_default) then {we've found the default entry-type} + b_default := wiz_loc; {see the |built_in| functions for |b_default|} +end + + +@ +We're about to start scanning tokens in a function definition. When a +function token is illegal, we skip until it ends; a |white_space| +character, an end-of-line, a |right_brace|, or a |comment| marks the +end of the current token. + +@d next_token=25 {a bad function token; go read the next one} +@# +@d skip_token(#) == begin {not-so-serious error during \.{.bst} parsing} + print (#); + skip_token_print; {also, skip to the current token's end} + goto next_token; + end + +@<Procedures and functions for input scanning@>= +procedure skip_token_print; +begin +print ('-'); +bst_ln_num_print; +mark_error; +if (scan2_white(right_brace,comment)) then {ok if token ends line} + do_nothing; +end; + + +@ +@^commented-out code@> +@^for a good time, try comment-out code@> +This macro is similar to the last one but is specifically for +recursion in a |wiz_defined| function, which is illegal; it helps save +space. + +@d skip_recursive_token == begin + print_recursion_illegal; + goto next_token; + end + +@<Procedures and functions for input scanning@>= +procedure print_recursion_illegal; +begin + trace + trace_pr_newline; + ecart@/ +print_ln ('Curse you, wizard, before you recurse me:'); +print ('function '); +print_token; +print_ln (' is illegal in its own definition'); + @{ + print_recursion_illegal; + @}@/ +skip_token_print; {also, skip to the current token's end} +end; + + +@ +Here's another macro for saving some space when there's a problem with +a token. + +@d skip_token_unknown_function == begin + skp_token_unknown_function_print; + goto next_token; + end + +@<Procedures and functions for input scanning@>= +procedure skp_token_unknown_function_print; +begin +print_token; +print (' is an unknown function'); +skip_token_print; {also, skip to the current token's end} +end; + + +@ +And another. + +@d skip_token_illegal_stuff_after_literal == + begin + skip_illegal_stuff_after_token_print; + goto next_token; + end + +@<Procedures and functions for input scanning@>= +procedure skip_illegal_stuff_after_token_print; +begin +print ('"',xchr[scan_char],'" can''t follow a literal'); +skip_token_print; {also, skip to the current token's end} +end; + + +@ +This recursive function reads and stores the list of functions +(separated by |white_space| characters or ends-of-line) that define +this new function, and reads a |right_brace|. + +@<Procedures and functions for input scanning@>= +procedure scan_fn_def (@!fn_hash_loc : hash_loc); +label next_token,@!exit; +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; + @!single_ptr : fn_def_loc; {next storage location for this definition} + @!copy_ptr : fn_def_loc; {dummy variable} + @!end_of_num : buf_pointer; {the end of an implicit function's name} + @!impl_fn_loc : hash_loc; {an implicit function's hash-table location} +begin +eat_bst_white_and_eof_check ('function'); +single_ptr := 0; +while (scan_char <> right_brace) do + begin + @<Get the next function of the definition@>; +next_token: + eat_bst_white_and_eof_check ('function'); + end; +@<Complete this function's definition@>; +incr(buf_ptr2); {skip over the |right_brace|} +exit: +end; + + +@ +@:BibTeX capacity exceeded}{\quad single function space@> +This macro inserts a hash-table location (or one of the two +special markers |quote_next_fn| and |end_of_def|) into the +|singl_function| array, which will later be copied into the +|wiz_functions| array. + +@d insert_fn_loc(#) == begin + singl_function[single_ptr] := #; + if (single_ptr = single_fn_space) then + singl_fn_overflow; + incr(single_ptr); + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure singl_fn_overflow; +begin +overflow('single function space ',single_fn_space); +end; + + +@ +There are five possibilities for the first character of the token +representing the next function of the definition: If it's a +|number_sign|, the token is an |int_literal|; if it's a +|double_quote|, the token is a |str_literal|; if it's a +|single_quote|, the token is a quoted function; if it's a +|left_brace|, the token isn't really a token, but rather the start of +another function definition (which will result in a recursive call to +|scan_fn_def|); if it's anything else, the token is the name of an +already-defined function. Note: To prevent the wizard from using +recursion, we have to check that neither a quoted function nor an +already-defined-function is actually the currently-being-defined +function (which is stored at |wiz_loc|). + +@<Get the next function of the definition@>= +case (scan_char) of + number_sign : @<Scan an |int_literal|@>; + double_quote : @<Scan a |str_literal|@>; + single_quote : @<Scan a quoted function@>; + left_brace : @<Start a new function definition@>; + othercases @<Scan an already-defined function@> +endcases + + +@ +An |int_literal| is preceded by a |number_sign|, consists of an +integer (i.e., an optional |minus_sign| followed by one or more +|numeric| characters), and is followed either by a |white_space| +character, an end-of-line, or a |right_brace|. The array |fn_info| +contains the value of the integer for |int_literal|s. + +@<Scan an |int_literal|@>= +begin +incr(buf_ptr2); {skip over the |number_sign|} +if (not scan_integer) then + skip_token ('Illegal integer in integer literal'); + trace + trace_pr ('#'); + trace_pr_token; + trace_pr_ln (' is an integer literal with value ',token_value:0); + ecart@/ +literal_loc := str_lookup(buffer,buf_ptr1,token_len,integer_ilk,do_insert); +if (not hash_found) then + begin + fn_type[literal_loc] := int_literal; {set the |fn_class|} + fn_info[literal_loc] := token_value; {the value of this integer} + end; +if ((lex_class[scan_char]<>white_space) and (buf_ptr2<last) and + (scan_char<>right_brace) and@| (scan_char<>comment)) then + skip_token_illegal_stuff_after_literal; +insert_fn_loc (literal_loc); {add this function to |wiz_functions|} +end + + +@ +A |str_literal| is preceded by a |double_quote| and consists of all +characters on this line up to the next |double_quote|. Also, there +must be either a |white_space| character, an end-of-line, a +|right_brace|, or a |comment| following (since functions in the +definition must be separated by |white_space|). The array |fn_info| +contains nothing for |str_literal|s. + +@<Scan a |str_literal|@>= +begin +incr(buf_ptr2); {skip over the |double_quote|} +if (not scan1(double_quote)) then + skip_token ('No `',xchr[double_quote],''' to end string literal'); + trace + trace_pr ('"'); + trace_pr_token; + trace_pr ('"'); + trace_pr_ln (' is a string literal'); + ecart@/ +literal_loc := str_lookup(buffer,buf_ptr1,token_len,text_ilk,do_insert);@/ +fn_type[literal_loc] := str_literal; {set the |fn_class|} +incr(buf_ptr2); {skip over the |double_quote|} +if ((lex_class[scan_char]<>white_space) and (buf_ptr2<last) and + (scan_char<>right_brace) and@| (scan_char<>comment)) then + skip_token_illegal_stuff_after_literal; +insert_fn_loc (literal_loc); {add this function to |wiz_functions|} +end + + +@ +A quoted function is preceded by a |single_quote| and consists of all +characters up to the next |white_space| character, end-of-line, +|right_brace|, or |comment|. + +@<Scan a quoted function@>= +begin +incr(buf_ptr2); {skip over the |single_quote|} +if (scan2_white(right_brace,comment)) then {ok if token ends line} + do_nothing; + trace + trace_pr (''''); + trace_pr_token; + trace_pr (' is a quoted function '); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +fn_loc := str_lookup(buffer,buf_ptr1,token_len,bst_fn_ilk,dont_insert); +if (not hash_found) then {unknown \.{.bst} function} + skip_token_unknown_function +else + @<Check and insert the quoted function@>; +end + + +@ +Here we check that this quoted function is a legal one---the function +name must already exist, but it mustn't be the currently-being-defined +function (which is stored at |wiz_loc|). + +@<Check and insert the quoted function@>= +begin +if (fn_loc = wiz_loc) then + skip_recursive_token +else + begin + trace + trace_pr ('of type '); + trace_pr_fn_class (fn_loc); + trace_pr_newline; + ecart@/ + insert_fn_loc (quote_next_fn); {add special marker together with} + insert_fn_loc (fn_loc); {this function to |wiz_functions|} + end +end + + +@ +@^kludge@> +@:this can't happen}{\quad Already encountered implicit function@> +This module marks the implicit function as being quoted, generates a +name, and stores it in the hash table. This name is strictly internal +to this program, starts with a |single_quote| (since that will make +this function name unique), and ends with the variable |impl_fn_num| +converted to ASCII. The alias kludge helps make the stack space not +overflow on some machines. + +@d ex_buf2 == ex_buf {an alias, used only in this module} + +@<Start a new function definition@>= +begin +ex_buf2[0] := single_quote; +int_to_ASCII (impl_fn_num,ex_buf2,1,end_of_num); +impl_fn_loc := str_lookup(ex_buf2,0,end_of_num,bst_fn_ilk,do_insert); +if (hash_found) then + confusion ('Already encountered implicit function'); + trace + trace_pr_pool_str (hash_text[impl_fn_loc]); + trace_pr_ln (' is an implicit function'); + ecart@/ +incr(impl_fn_num); +fn_type[impl_fn_loc] := wiz_defined;@/ +insert_fn_loc (quote_next_fn); {all implicit functions are quoted} +insert_fn_loc (impl_fn_loc); {add it to |wiz_functions|} +incr(buf_ptr2); {skip over the |left_brace|} +scan_fn_def (impl_fn_loc); {this is the recursive call} +end + + +@ +The variable |impl_fn_num| counts the number of implicit functions +seen in the \.{.bst} file. + +@<Globals in the outer block@>= +@!impl_fn_num : integer; {the number of implicit functions seen so far} + + +@ +Now we initialize it. + +@<Set initial values of key variables@>= +impl_fn_num := 0; + + +@ +@:BibTeX capacity exceeded}{\quad buffer size@> +This module appends a character to |int_buf| after checking to make +sure it will fit; for use in |int_to_ASCII|. + +@d append_int_char(#) == begin + if (int_ptr = buf_size) then + buffer_overflow; + int_buf[int_ptr]:=#; + incr(int_ptr); + end + + +@ +This procedure takes the integer |int|, copies the appropriate +|ASCII_code| string into |int_buf| starting at |int_begin|, and sets +the |var| parameter |int_end| to the first unused |int_buf| location. +The ASCII string will consist of decimal digits, the first of which +will be not be a~0 if the integer is nonzero, with a prepended minus +sign if the integer is negative. + +@<Procedures and functions for handling numbers, characters, and strings@>= +procedure int_to_ASCII (@!int:integer; var int_buf:buf_type; + @!int_begin:buf_pointer; var int_end:buf_pointer); +var int_ptr,@!int_xptr : buf_pointer; {pointers into |int_buf|} + @!int_tmp_val : ASCII_code; {the temporary element in an exchange} +begin +int_ptr := int_begin; +if (int < 0) then {add the |minus_sign| and use the absolute value} + begin + append_int_char (minus_sign); + int := -int; + end; +int_xptr := int_ptr; +repeat {copy digits into |int_buf|} + append_int_char ("0" + (int mod 10)); + int := int div 10; + until (int = 0); +int_end := int_ptr; {set the string length} +decr(int_ptr); +while (int_xptr < int_ptr) do {and reorder (flip) the digits} + begin + int_tmp_val := int_buf[int_xptr]; + int_buf[int_xptr] := int_buf[int_ptr]; + int_buf[int_ptr] := int_tmp_val; + decr(int_ptr); + incr(int_xptr); + end +end; + + +@ +An already-defined function consists of all characters up to the next +|white_space| character, end-of-line, |right_brace|, or |comment|. +This function name must already exist, but it mustn't be the +currently-being-defined function (which is stored at |wiz_loc|). + +@<Scan an already-defined function@>= +begin +if (scan2_white(right_brace,comment)) then {ok if token ends line} + do_nothing; + trace + trace_pr_token; + trace_pr (' is a function '); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +fn_loc := str_lookup(buffer,buf_ptr1,token_len,bst_fn_ilk,dont_insert); +if (not hash_found) then {unknown \.{.bst} function} + skip_token_unknown_function +else if (fn_loc = wiz_loc) then + skip_recursive_token +else + begin + trace + trace_pr ('of type '); + trace_pr_fn_class (fn_loc); + trace_pr_newline; + ecart@/ + insert_fn_loc (fn_loc); {add this function to |wiz_functions|} + end; +end + + +@ +@:BibTeX capacity exceeded}{\quad wizard-defined function space@> +Now we add the |end_of_def| special marker, make sure this function will +fit into |wiz_functions|, and put it there. + +@<Complete this function's definition@>= +begin +insert_fn_loc (end_of_def); {add special marker ending the definition} +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; +fn_info[fn_hash_loc] := wiz_def_ptr; {pointer into |wiz_functions|} +copy_ptr := 0; +while (copy_ptr < single_ptr) do {make this function official} + begin + wiz_functions[wiz_def_ptr] := singl_function[copy_ptr]; + incr(copy_ptr); + incr(wiz_def_ptr); + end; +end + + +@ +@:style-file commands}{\quad \.{integers}@> +An \.{integers} command has one argument, a list of function names +between braces (the names are separated by one or more |white_space| +characters). Upper/lower cases are considered to be the same for +function names in these lists---all upper-case letters are converted to +lower case. Each name in this list specifies an |int_global_var|. +There may be several \.{integers} commands in the \.{.bst} file. + +This module reads a |left_brace|, a list of |int_global_var|s, and a +|right_brace|. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_integers_command; +label exit; +begin +eat_bst_white_and_eof_check ('integers'); +bst_get_and_check_left_brace ('integers'); +eat_bst_white_and_eof_check ('integers'); +while (scan_char <> right_brace) do + begin + bst_identifier_scan ('integers'); + @<Insert an |int_global_var| into the hash table@>; + eat_bst_white_and_eof_check ('integers'); + end; +incr(buf_ptr2); {skip over the |right_brace|} +exit: +end; + + +@ +Here we insert the just found |int_global_var| name into the hash +table and record it as an |int_global_var|. Also, we initialize it by +setting |fn_info[fn_loc]| to 0. + +@<Insert an |int_global_var| into the hash table@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is an integer global-variable'); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +fn_loc := str_lookup(buffer,buf_ptr1,token_len,bst_fn_ilk,do_insert); +check_for_already_seen_function (fn_loc); +fn_type[fn_loc] := int_global_var;@/ +fn_info[fn_loc] := 0; {initialize} +end + + +@ +@:style-file commands}{\quad \.{iterate}@> +An \.{iterate} command has one argument, a single |built_in| or +|wiz_defined| function name between braces. Upper/lower cases are +considered to be the same---all upper-case letters are converted to +lower case. Also, we must make sure we've already seen a \.{read} +command. + +This module reads a |left_brace|, a single function to be iterated, +and a |right_brace|. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_iterate_command; +label exit; +begin +if (not read_seen) then + bst_err ('Illegal, iterate command before read command'); +eat_bst_white_and_eof_check ('iterate'); +bst_get_and_check_left_brace ('iterate'); +eat_bst_white_and_eof_check ('iterate'); +bst_identifier_scan ('iterate'); +@<Check the \.{iterate}-command argument token@>; +eat_bst_white_and_eof_check ('iterate'); +bst_get_and_check_right_brace ('iterate'); +@<Perform an \.{iterate} command@>; +exit: +end; + + +@ +Before iterating the function, we must make sure it's a legal one. It +must exist and be |built_in| or |wiz_defined|. + +@<Check the \.{iterate}-command argument token@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a to be iterated function'); + ecart@/ +if (bad_argument_token) then + return; +end + + +@ +@:style-file commands}{\quad \.{macro}@> +A \.{macro} command, like a \.{function} command, has two arguments; +the first is a macro name between braces. The name must be a legal +\.{.bst} identifier. Upper/lower cases are considered to be the +same---all upper-case letters are converted to lower case. The second +argument defines this macro. It consists of a +|double_quote|-delimited string (which must be on a single line) +between braces, with optional |white_space| characters between the +braces and the |double_quote|s. This |double_quote|-delimited string +is parsed exactly as a |str_literal| is for the \.{function} command. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_macro_command; +label exit; +begin +if (read_seen) then + bst_err ('Illegal, macro command after read command'); +eat_bst_white_and_eof_check ('macro'); +@<Scan the macro name@>; +eat_bst_white_and_eof_check ('macro'); +@<Scan the macro's definition@>; +exit: +end; + + +@ +This module reads a |left_brace|, a macro name, and a |right_brace|. + +@<Scan the macro name@>= +begin +bst_get_and_check_left_brace ('macro'); +eat_bst_white_and_eof_check ('macro'); +bst_identifier_scan ('macro'); +@<Check the macro name@>; +eat_bst_white_and_eof_check ('macro'); +bst_get_and_check_right_brace ('macro'); +end + + +@ +The macro name must be a new one; we mark it as |macro_ilk|. + +@<Check the macro name@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a macro'); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +macro_name_loc := str_lookup(buffer,buf_ptr1,token_len,macro_ilk,do_insert); +if (hash_found) then + begin + print_token; + bst_err (' is already defined as a macro'); + end; +ilk_info[macro_name_loc]:=hash_text[macro_name_loc]; {default in case of error} +end + + +@ +This module reads a |left_brace|, the |double_quote|-delimited string +that defines this macro, and a |right_brace|. + +@<Scan the macro's definition@>= +begin +bst_get_and_check_left_brace ('macro'); +eat_bst_white_and_eof_check ('macro'); +if (scan_char <> double_quote) then + bst_err ('A macro definition must be ',xchr[double_quote],'-delimited'); +@<Scan the macro definition-string@>; +eat_bst_white_and_eof_check ('macro'); +bst_get_and_check_right_brace ('macro'); +end + + +@ +A macro definition-string is preceded by a |double_quote| and consists +of all characters on this line up to the next |double_quote|. The +array |ilk_info| contains a pointer to this string for the macro name. + +@<Scan the macro definition-string@>= +begin +incr(buf_ptr2); {skip over the |double_quote|} +if (not scan1(double_quote)) then + bst_err ('There''s no `',xchr[double_quote],''' to end macro definition'); + trace + trace_pr ('"'); + trace_pr_token; + trace_pr ('"'); + trace_pr_ln (' is a macro string'); + ecart@/ +macro_def_loc := str_lookup(buffer,buf_ptr1,token_len,text_ilk,do_insert);@/ +fn_type[macro_def_loc] := str_literal; {set the |fn_class|} +ilk_info[macro_name_loc] := hash_text[macro_def_loc]; +incr(buf_ptr2); {skip over the |double_quote|} +end + + +@ +@^gymnastics@> +We need to include stuff for \.{.bib} reading here because that's done +by the \.{read} command. + +@<Procedures and functions for the reading and processing of input files@>= +@<Scan for and process a \.{.bib} command or database entry@> + + +@ +@:style-file commands}{\quad \.{read}@> +The \.{read} command has no arguments so there's no more parsing to +do. We must make sure we haven't seen a \.{read} command before and +we've already seen an \.{entry} command. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_read_command; +label exit; +begin +if (read_seen) then + bst_err ('Illegal, another read command'); +read_seen := true; {now we've seen a \.{read} command} +if (not entry_seen) then + bst_err ('Illegal, read command before entry command'); +sv_ptr1 := buf_ptr2; {save the contents of the \.{.bst} input line} +sv_ptr2 := last; +tmp_ptr := sv_ptr1; +while (tmp_ptr < sv_ptr2) do + begin + sv_buffer[tmp_ptr] := buffer[tmp_ptr]; + incr(tmp_ptr); + end; +@<Read the \.{.bib} file(s)@>; +buf_ptr2 := sv_ptr1; {and restore} +last := sv_ptr2; +tmp_ptr := buf_ptr2; +while (tmp_ptr < last) do + begin + buffer[tmp_ptr] := sv_buffer[tmp_ptr]; + incr(tmp_ptr); + end; +exit: +end; + + +@ +@:style-file commands}{\quad \.{reverse}@> +A \.{reverse} command has one argument, a single |built_in| or +|wiz_defined| function name between braces. Upper/lower cases are +considered to be the same---all upper-case letters are converted to +lower case. Also, we must make sure we've already seen a \.{read} +command. + +This module reads a |left_brace|, a single function to be iterated in +reverse, and a |right_brace|. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_reverse_command; +label exit; +begin +if (not read_seen) then + bst_err ('Illegal, reverse command before read command'); +eat_bst_white_and_eof_check ('reverse'); +bst_get_and_check_left_brace ('reverse'); +eat_bst_white_and_eof_check ('reverse'); +bst_identifier_scan ('reverse'); +@<Check the \.{reverse}-command argument token@>; +eat_bst_white_and_eof_check ('reverse'); +bst_get_and_check_right_brace ('reverse'); +@<Perform a \.{reverse} command@>; +exit: +end; + + +@ +Before iterating the function in reverse, we must make sure it's a +legal one. It must exist and be |built_in| or |wiz_defined|. + +@<Check the \.{reverse}-command argument token@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a to be iterated in reverse function'); + ecart@/ +if (bad_argument_token) then + return; +end + + +@ +@:style-file commands}{\quad \.{sort}@> +The \.{sort} command has no arguments so there's no more parsing to +do, but we must make sure we've already seen a \.{read} command. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_sort_command; +label exit; +begin +if (not read_seen) then + bst_err ('Illegal, sort command before read command'); +@<Perform a \.{sort} command@>; +exit: +end; + + +@ +@:style-file commands}{\quad \.{strings}@> +A \.{strings} command has one argument, a list of function names +between braces (the names are separated by one or more |white_space| +characters). Upper/lower cases are considered to be the same for +function names in these lists---all upper-case letters are converted to +lower case. Each name in this list specifies a |str_global_var|. +There may be several \.{strings} commands in the \.{.bst} file. + +This module reads a |left_brace|, a list of |str_global_var|s, +and a |right_brace|. + +@<Procedures and functions for the reading and processing of input files@>= +procedure bst_strings_command; +label exit; +begin +eat_bst_white_and_eof_check ('strings'); +bst_get_and_check_left_brace ('strings'); +eat_bst_white_and_eof_check ('strings'); +while (scan_char <> right_brace) do + begin + bst_identifier_scan ('strings'); + @<Insert a |str_global_var| into the hash table@>; + eat_bst_white_and_eof_check ('strings'); + end; +incr(buf_ptr2); {skip over the |right_brace|} +exit: +end; + + +@ +@:BibTeX capacity exceeded}{\quad number of string global-variables@> +Here we insert the just found |str_global_var| name into the hash +table, record it as a |str_global_var|, set its pointer into +|global_strs|, and initialize its value there to the null string. + +@d end_of_string = invalid_code {this illegal |ASCII_code| ends a string} + +@<Insert a |str_global_var| into the hash table@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a string global-variable'); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +fn_loc := str_lookup(buffer,buf_ptr1,token_len,bst_fn_ilk,do_insert); +check_for_already_seen_function (fn_loc); +fn_type[fn_loc] := str_global_var;@/ +fn_info[fn_loc] := num_glb_strs; {pointer into |global_strs|} +if (num_glb_strs = max_glob_strs) then + overflow('number of string global-variables ',max_glob_strs); +incr(num_glb_strs); +end + + +@ +@^gymnastics@> +That's it for processing \.{.bst} commands, except for finishing the +procedural gymnastics. Note that this must topologically follow the +stuff for \.{.bib} reading, because that's done by the \.{.bst}'s +\.{read} command. + +@<Procedures and functions for the reading and processing of input files@>= +@<Scan for and process a \.{.bst} command@> + + + +@* Reading the database file(s). +This section reads the \.{.bib} file(s), each of which consists of a +sequence of entries (perhaps with a few \.{.bib} commands thrown in, +as explained later). Each entry consists of an |at_sign|, an entry +type, and, between braces or parentheses and separated by |comma|s, a +database key and a list of fields. Each field consists of a field +name, an |equals_sign|, and nonempty list of field tokens separated by +|concat_char|s. Each field token is either a nonnegative number, a +macro name (like `jan'), or a brace-balanced string delimited by +either |double_quote|s or braces. Finally, case differences are +ignored for all but delimited strings and database keys, and +|white_space| characters and ends-of-line may appear in all reasonable +places (i.e., anywhere except within entry types, database keys, field +names, and macro names); furthermore, comments may appear anywhere +between entries (or before the first or after the last) as long as +they contain no |at_sign|s. + + +@ +These global variables are used while reading the \.{.bib} file(s). +The elements of |type_list|, which indicate an entry's type (book, +article, etc.), point either to a |hash_loc| or are one of two special +markers: |empty|, from which |hash_base = empty + 1| was defined, +means we haven't yet encountered the \.{.bib} entry corresponding to +this cite key; and |undefined| means we've encountered it but it had +an unknown entry type. Thus the array |type_list| is of type +|hash_ptr2|, also defined earlier. An element of the boolean array +|entry_exists| whose corresponding entry in |cite_list| gets +overwritten (which happens only when |all_entries| is |true|) +indicates whether we've encountered that entry of |cite_list| while +reading the \.{.bib} file(s); this information is unused for entries +that aren't (or more precisely, that have no chance of being) +overwritten. When we're reading the database file, the array +|cite_info| contains auxiliary information for |cite_list|. Later, +|cite_info| will become |sorted_cites|, and this dual role imposes the +(not-very-imposing) restriction |max_strings >= max_cites|. + +@d undefined = hash_max + 1 {a special marker used for |type_list|} + +@<Globals in the outer block@>= +@!bib_line_num : integer; {line number of the \.{.bib} file} +@!entry_type_loc : hash_loc; {the hash-table location of an entry type} +@!type_list : packed array[cite_number] of hash_ptr2; +@!type_exists : boolean; {|true| if this entry type is \.{.bst}-defined} +@!entry_exists : packed array[cite_number] of boolean; +@!store_entry : boolean; {|true| if we're to store info for this entry} +@!field_name_loc : hash_loc; {the hash-table location of a field name} +@!field_val_loc : hash_loc; {the hash-table location of a field value} +@!store_field : boolean; {|true| if we're to store info for this field} +@!store_token : boolean; {|true| if we're to store this macro token} +@!right_outer_delim : ASCII_code; {either a |right_brace| or a |right_paren|} +@!right_str_delim : ASCII_code; {either a |right_brace| or a |double_quote|} +@!at_bib_command : boolean; {|true| for a command, false for an entry} +@!cur_macro_loc : hash_loc; {|macro_loc| for a \.{string} being defined} +@!cite_info : packed array[cite_number] of str_number; {extra |cite_list| info} +@!cite_hash_found : boolean; {set to a previous |hash_found| value} +@!preamble_ptr : bib_number; {pointer into the |s_preamble| array} +@!num_preamble_strings : bib_number; {counts the |s_preamble| strings} + + +@ +This little procedure exists because it's used by at least two other +procedures and thus saves some space. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bib_ln_num_print; +begin +print ('--line ',bib_line_num:0,' of file '); +print_bib_name; +end; + + +@ +When there's a serious error parsing a \.{.bib} file, we flush +everything up to the beginning of the next entry. + +@d bib_err(#) == begin {serious error during \.{.bib} parsing} + print (#); + bib_err_print; + return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bib_err_print; +begin +print ('-'); +bib_ln_num_print; +print_bad_input_line; {this call does the |mark_error|} +print_skipping_whatever_remains; +if (at_bib_command) then + print_ln ('command') + else + print_ln ('entry'); +end; + + +@ +When there's a harmless error parsing a \.{.bib} file, we just give a +warning message. This is always called after other stuff has been +printed out. + +@d bib_warn(#) == begin {non-serious error during \.{.bst} parsing} + print (#); + bib_warn_print; + end +@# +@d bib_warn_newline(#) == begin {same as above but with a newline} + print_ln (#); + bib_warn_print; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bib_warn_print; +begin +bib_ln_num_print; +mark_warning; +end; + + +@ +For all |num_bib_files| database files, we keep reading and processing +\.{.bib} entries until none left. + +@<Read the \.{.bib} file(s)@>= +begin +@<Final initialization for \.{.bib} processing@>; +read_performed := true; +bib_ptr := 0; +while (bib_ptr < num_bib_files) do + begin + print ('Database file #',bib_ptr+1:0,': '); + print_bib_name;@/ + bib_line_num := 0; {initialize to get the first input line} + buf_ptr2 := last; + while (not eof(cur_bib_file)) do + get_bib_command_or_entry_and_process; + a_close (cur_bib_file); + incr(bib_ptr); + end; +reading_completed := true; + trace + trace_pr_ln ('Finished reading the database file(s)'); + ecart@/ +@<Final initialization for processing the entries@>; +read_completed := true; +end + + +@ +We need to initialize the |field_info| array, and also various things +associated with the |cite_list| array (but not |cite_list| itself). + +@<Final initialization for \.{.bib} processing@>= +begin +@<Initialize the |field_info|@>; +@<Initialize things for the |cite_list|@>; +end + + +@ +This module initializes all fields of all entries to |missing|, the +value to which all fields are initialized. + +@<Initialize the |field_info|@>= +begin +check_field_overflow (num_fields*num_cites); +field_ptr := 0; +while (field_ptr < max_fields) do + begin + field_info[field_ptr] := missing; + incr(field_ptr); + end; +end + + +@ +@^fetish@> +@:BibTeX capacity exceeded}{\quad total number of fields@> +Complain if somebody's got a field fetish. + +@<Procedures and functions for all file I/O, error messages, and such@>= +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); + end; +end; + + +@ +We must initialize the |type_list| array so that we can detect +duplicate (or missing) entries for cite keys on |cite_list|. Also, +when we're to include the entire database, we use the array +|entry_exists| to detect those missing entries whose |cite_list| info +will (or to be more precise, might) be overwritten; and we use the +array |cite_info| to save the part of |cite_list| that will (might) be +overwritten. We also use |cite_info| for counting cross~references +when it's appropriate---when an entry isn't otherwise to be included +on |cite_list| (that is, the entry isn't \.{\\cite}d or +\.{\\nocite}d). Such an entry is included on the final |cite_list| if +it's cross~referenced at least |min_crossrefs| times. + +@<Initialize things for the |cite_list|@>= +begin +cite_ptr := 0; +while (cite_ptr < max_cites) do + begin + type_list[cite_ptr] := empty;@/ + cite_info[cite_ptr] := any_value; {to appeas \PASCAL's boolean evaluation} + incr(cite_ptr); + end; +old_num_cites := num_cites; +if (all_entries) then + begin + cite_ptr := all_marker; + while (cite_ptr < old_num_cites) do + begin + cite_info[cite_ptr] := cite_list[cite_ptr]; + entry_exists[cite_ptr] := false; + incr(cite_ptr); + end; + cite_ptr := all_marker; {we insert the ``other'' entries here} + end + else + begin + cite_ptr := num_cites; {we insert the cross-referenced entries here} + all_marker := any_value; {to appease \PASCAL's boolean evaluation} + end; +end + + +@ +Before we actually start the code for reading a database file, we must +define this \.{.bib}-specific scanning function. It skips over +|white_space| characters until hitting a nonwhite character or the end +of the file, respectively returning |true| or |false|. It also +updates |bib_line_num|, the line counter. + +@<Procedures and functions for input scanning@>= +function eat_bib_white_space : boolean; +label exit; +begin +while (not scan_white_space) do {no characters left; read another line} + begin + if (not input_ln(cur_bib_file)) then {end-of-file; return |false|} + begin + eat_bib_white_space := false; + return; + end; + incr(bib_line_num); + buf_ptr2 := 0; + end; +eat_bib_white_space := true; +exit: +end; + + +@ +It's often illegal to end a \.{.bib} command in certain places, and +this is where we come to check. + +@d eat_bib_white_and_eof_check == + begin + if (not eat_bib_white_space) then + begin + eat_bib_print; + return; + end; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure eat_bib_print; +label exit; {so the call to |bib_err| works} +begin +bib_err ('Illegal end of database file'); +exit: +end; + + +@ +And here are a bunch of error-message macros, each called more than +once, that thus save space as implemented. This one is for when one +of two possible characters is expected while scanning. + +@d bib_one_of_two_expected_err(#) == + begin + bib_one_of_two_print (#); + return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bib_one_of_two_print (@!char1,@!char2:ASCII_code); +label exit; {so the call to |bib_err| works} +begin +bib_err ('I was expecting a `',xchr[char1],''' or a `',xchr[char2],''''); +exit: +end; + + +@ +This one's for an expected |equals_sign|. + +@d bib_equals_sign_expected_err == + begin + bib_equals_sign_print; + return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bib_equals_sign_print; +label exit; {so the call to |bib_err| works} +begin +bib_err ('I was expecting an "',xchr[equals_sign],'"'); +exit: +end; + + +@ +This complains about unbalanced braces. + +@d bib_unbalanced_braces_err == + begin + bib_unbalanced_braces_print; + return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bib_unbalanced_braces_print; +label exit; {so the call to |bib_err| works} +begin +bib_err ('Unbalanced braces'); +exit: +end; + + +@ +And this one about an overly exuberant field. + +@d bib_field_too_long_err == + begin + bib_field_too_long_print; + return; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bib_field_too_long_print; +label exit; {so the call to |bib_err| works} +begin +bib_err ('Your field is more than ',buf_size:0,' characters'); +exit: +end; + + +@ +This one is just a warning, not an error. It's for when something +isn't (or might not be) quite right with a macro name. + +@d macro_name_warning(#) == + begin + macro_warn_print; + bib_warn_newline (#); + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure macro_warn_print; +begin +print ('Warning--string name "'); +print_token; +print ('" is '); +end; + + +@ +@:this can't happen}{\quad Identifier scanning error@> +This macro is used to scan all \.{.bib} identifiers. The argument +tells what was happening at the time. The associated procedure simply +prints an error message. + +@d bib_identifier_scan_check(#) == + begin + if ((scan_result = white_adjacent) or + (scan_result = specified_char_adjacent)) then + do_nothing + else + begin + bib_id_print; + bib_err (#); + end; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bib_id_print; +begin +if (scan_result = id_null) then + print ('You''re missing ') +else if (scan_result = other_char_adjacent) then + print ('"',xchr[scan_char],'" immediately follows ') +else + id_scanning_confusion; +end; + + +@ +This module either reads a database entry, whose three main components +are an entry type, a database key, and a list of fields, or it reads a +\.{.bib} command, whose structure is command dependent and explained +later. + +@d cite_already_set = 22 {this gets around \PASCAL\ limitations} +@d first_time_entry = 26 {for checking for repeated database entries} + +@<Scan for and process a \.{.bib} command or database entry@>= +procedure get_bib_command_or_entry_and_process; +label cite_already_set,@!first_time_entry,@!loop_exit,@!exit; +begin +at_bib_command := false;@/ +@<Skip to the next database entry or \.{.bib} command@>; +@<Scan the entry type or scan and process the \.{.bib} command@>; +eat_bib_white_and_eof_check; +@<Scan the entry's database key@>; +eat_bib_white_and_eof_check; +@<Scan the entry's list of fields@>; +exit: +end; + + +@ +This module skips over everything until hitting an |at_sign| or the +end of the file. It also updates |bib_line_num|, the line counter. + +@<Skip to the next database entry or \.{.bib} command@>= +while (not scan1(at_sign)) do {no |at_sign|; get next line} + begin + if (not input_ln(cur_bib_file)) then {end-of-file} + return; + incr(bib_line_num); + buf_ptr2 := 0; + end + + +@ +@:this can't happen}{\quad An at-sign disappeared@> +This module reads an |at_sign| and an entry type (like `book' or +`article') or a \.{.bib} command. If it's an entry type, it must be +defined in the \.{.bst} file if this entry is to be included in the +reference list. + +@<Scan the entry type or scan and process the \.{.bib} command@>= +begin +if (scan_char <> at_sign) then + confusion ('An "',xchr[at_sign],'" disappeared'); +incr(buf_ptr2); {skip over the |at_sign|} +eat_bib_white_and_eof_check; +scan_identifier (left_brace,left_paren,left_paren); +bib_identifier_scan_check ('an entry type'); + trace + trace_pr_token; + trace_pr_ln (' is an entry type or a database-file command'); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +command_num := ilk_info[ + str_lookup(buffer,buf_ptr1,token_len,bib_command_ilk,dont_insert)]; +if (hash_found) then + @<Process a \.{.bib} command@> +else + begin {process an entry type} + entry_type_loc := str_lookup( + buffer,buf_ptr1,token_len,bst_fn_ilk,dont_insert); + if ((not hash_found) or (fn_type[entry_type_loc]<>wiz_defined)) then@/ + type_exists := false {no such entry type defined in the \.{.bst} file} + else + type_exists := true; + end; +end + + +@ +@^database-file commands@> +@:this can't happen}{\quad Unknown database-file command@> +Here we determine which \.{.bib} command we're about to process, then +go to it. + +@<Process a \.{.bib} command@>= +begin +at_bib_command := true; +case (command_num) of + n_bib_comment : @<Process a \.{comment} command@>; + n_bib_preamble : @<Process a \.{preamble} command@>; + n_bib_string : @<Process a \.{string} command@>; + othercases bib_cmd_confusion +endcases; +end + + +@ +@:this can't happen}{\quad Unknown database-file command@> +Here's another bug. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bib_cmd_confusion; +begin +confusion ('Unknown database-file command'); +end; + + +@ +@:database-file commands}{\quad \.{comment}@> +The \.{comment} command is implemented for SCRIBE compatibility. It's +not really needed because \BibTeX\ treats (flushes) everything not +within an entry as a comment anyway. + +@<Process a \.{comment} command@>= +begin +return; {flush comments} +end + + +@ +@:database-file commands}{\quad \.{preamble}@> +The \.{preamble} command lets a user have \TeX\ stuff inserted (by the +standard styles, at least) directly into the \.{.bbl} file. It is +intended primarily for allowing \TeX\ macro definitions used within +the bibliography entries (for better sorting, for example). One +\.{preamble} command per \.{.bib} file should suffice. + +A \.{preamble} command has either braces or parentheses as outer +delimiters. Inside is the preamble string, which has the same syntax +as a field value: a nonempty list of field tokens separated by +|concat_char|s. There are three types of field tokens---nonnegative +numbers, macro names, and delimited strings. + +This module does all the scanning (that's not subcontracted), but the +\.{.bib}-specific scanning function +|scan_and_store_the_field_value_and_eat_white| actually stores the +value. + +@<Process a \.{preamble} command@>= +begin +if (preamble_ptr = max_bib_files) then + bib_err ('You''ve exceeded ',max_bib_files:0,' preamble commands'); +eat_bib_white_and_eof_check; +if (scan_char = left_brace) then + right_outer_delim := right_brace +else if (scan_char = left_paren) then + right_outer_delim := right_paren +else + bib_one_of_two_expected_err (left_brace,left_paren); +incr(buf_ptr2); {skip over the left-delimiter} +eat_bib_white_and_eof_check; +store_field := true; +if (not scan_and_store_the_field_value_and_eat_white) then + return; +if (scan_char <> right_outer_delim) then + bib_err ('Missing "',xchr[right_outer_delim],'" in preamble command'); +incr(buf_ptr2); {skip over the |right_outer_delim|} +return; +end + + +@ +@:database-file commands}{\quad \.{string}@> +The \.{string} command is implemented both for SCRIBE compatibility +and for allowing a user: to override a \.{.bst}-file \.{macro} +command, to define one that the \.{.bst} file doesn't, or to engage in +good, wholesome, typing laziness. + +The \.{string} command does mostly the same thing as the +\.{.bst}-file's \.{macro} command (but the syntax is different and the +\.{string} command compresses |white_space|). In fact, later in this +program, the term ``macro'' refers to either a \.{.bst} ``macro'' or a +\.{.bib} ``string'' (when it's clear from the context that it's not +a \.{WEB} macro). + +A \.{string} command has either braces or parentheses as outer +delimiters. Inside is the string's name (it must be a legal +identifier, and case differences are ignored---all upper-case letters +are converted to lower case), then an |equals_sign|, and the string's +definition, which has the same syntax as a field value: a nonempty +list of field tokens separated by |concat_char|s. There are three +types of field tokens---nonnegative numbers, macro names, and +delimited strings. + +@<Process a \.{string} command@>= +begin +eat_bib_white_and_eof_check; +@<Scan the string's name@>; +eat_bib_white_and_eof_check; +@<Scan the string's definition field@>; +return; +end + + +@ +This module reads a left outer-delimiter and a string name. + +@<Scan the string's name@>= +begin +if (scan_char = left_brace) then + right_outer_delim := right_brace +else if (scan_char = left_paren) then + right_outer_delim := right_paren +else + bib_one_of_two_expected_err (left_brace,left_paren); +incr(buf_ptr2); {skip over the left-delimiter} +eat_bib_white_and_eof_check; +scan_identifier (equals_sign,equals_sign,equals_sign); +bib_identifier_scan_check ('a string name'); +@<Store the string's name@>; +end + + +@ +@^commented-out code@> +This module marks this string as |macro_ilk|; the commented-out code +will give a warning message when overwriting a previously defined +macro. + +@<Store the string's name@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a database-defined macro'); + ecart@/ +lower_case (buffer, buf_ptr1, token_len); {ignore case differences} +cur_macro_loc := str_lookup(buffer,buf_ptr1,token_len,macro_ilk,do_insert); +ilk_info[cur_macro_loc] := hash_text[cur_macro_loc]; {default in case of error} + @{ + if (hash_found) then {already seen macro} + macro_name_warning ('having its definition overwritten'); + @}@/ +end + + +@ +This module skips over the |equals_sign|, reads and stores the list of +field tokens that defines this macro (compressing |white_space|), and +reads a |right_outer_delim|. + +@<Scan the string's definition field@>= +begin +if (scan_char <> equals_sign) then + bib_equals_sign_expected_err; +incr(buf_ptr2); {skip over the |equals_sign|} +eat_bib_white_and_eof_check; +store_field := true; +if (not scan_and_store_the_field_value_and_eat_white) then + return; +if (scan_char <> right_outer_delim) then + bib_err ('Missing "',xchr[right_outer_delim],'" in string command'); +incr(buf_ptr2); {skip over the |right_outer_delim|} +end + + +@ +@^kludge@> +The variables for the function +|scan_and_store_the_field_value_and_eat_white| must be global since +the functions it calls use them too. The alias kludge helps make the +stack space not overflow on some machines. + +@d field_vl_str == ex_buf {aliases, used ``only'' for this function} +@d field_end == ex_buf_ptr {the end marker for the field-value string} +@d field_start == ex_buf_xptr {and the start marker} + +@<Globals in the outer block@>= +@!bib_brace_level : integer; {brace nesting depth (excluding |str_delim|s)} + + +@ +@^gymnastics@> +Since the function |scan_and_store_the_field_value_and_eat_white| +calls several other yet-to-be-described functions (one directly and +two indirectly), we must perform some topological gymnastics. + +@<Procedures and functions for input scanning@>= +@<The scanning function |compress_bib_white|@>@; +@<The scanning function |scan_balanced_braces|@>@; +@<The scanning function |scan_a_field_token_and_eat_white|@> + + +@ +This function scans the list of field tokens that define the field +value string. If |store_field| is |true| it accumulates (indirectly) +in |field_vl_str| the concatenation of all the field tokens, +compressing nonnull |white_space| to a single |space| and, if the +field value is for a field (rather than a string definition), removing +any leading or trailing |white_space|; when it's finished it puts the +string into the hash table. It returns |false| if there was a serious +syntax error. + +@<Procedures and functions for input scanning@>= +function scan_and_store_the_field_value_and_eat_white : boolean; +label exit; +begin +scan_and_store_the_field_value_and_eat_white := false; + {now it's easy to exit if necessary} +field_end := 0; +if (not scan_a_field_token_and_eat_white) then + return; +while (scan_char = concat_char) do {scan remaining field tokens} + begin + incr(buf_ptr2); {skip over the |concat_char|} + eat_bib_white_and_eof_check; + if (not scan_a_field_token_and_eat_white) then + return; + end; +if (store_field) then + @<Store the field value string@>; +scan_and_store_the_field_value_and_eat_white := true; +exit: +end; + + +@ +Each field token is either a nonnegative number, a macro name (like +`jan'), or a brace-balanced string delimited by either |double_quote|s +or braces. Thus there are four possibilities for the first character +of the field token: If it's a |left_brace| or a |double_quote|, the +token (with balanced braces, up to the matching |right_str_delim|) is +a string; if it's |numeric|, the token is a number; if it's anything +else, the token is a macro name (and should thus have been defined by +either the \.{.bst}-file's \.{macro} command or the \.{.bib}-file's +\.{string} command). This function returns |false| if there was a +serious syntax error. + +@<The scanning function |scan_a_field_token_and_eat_white|@>= +function scan_a_field_token_and_eat_white : boolean; +label exit; +begin +scan_a_field_token_and_eat_white := false; {now it's easy to exit if necessary} +case (scan_char) of + left_brace : + begin + right_str_delim := right_brace; + if (not scan_balanced_braces) then + return; + end; + double_quote : + begin + right_str_delim := double_quote; + if (not scan_balanced_braces) then + return; + end; + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" : + @<Scan a number@>; + othercases + @<Scan a macro name@> +endcases; +eat_bib_white_and_eof_check; +scan_a_field_token_and_eat_white := true; +exit: +end; + + +@ +Now we come to the stuff that actually accumulates the field value to +be stored. This module copies a character into |field_vl_str| if it +will fit; since it's so low level, it's implemented as a macro. + +@d copy_char(#) == begin + if (field_end = buf_size) then + bib_field_too_long_err + else + begin + field_vl_str[field_end] := #; + incr(field_end); + end; + end + + +@ +The \.{.bib}-specific scanning function |compress_bib_white| skips +over |white_space| characters within a string until hitting a nonwhite +character; in fact, it does everything |eat_bib_white_space| does, but +it also adds a |space| to |field_vl_str|. This function is never +called if there are no |white_space| characters (or ends-of-line) to +be scanned (though the associated macro might be). The function +returns |false| if there is a serious syntax error. + +@d check_for_and_compress_bib_white_space == + begin + if ((lex_class[scan_char]=white_space) or (buf_ptr2=last)) then + if (not compress_bib_white) then + return; + end + +@<The scanning function |compress_bib_white|@>= +function compress_bib_white : boolean; +label exit; +begin +compress_bib_white := false; {now it's easy to exit if necessary} +copy_char (space); +while (not scan_white_space) do {no characters left; read another line} + begin + if (not input_ln(cur_bib_file)) then {end-of-file; complain} + begin + eat_bib_print; + return; + end; + incr(bib_line_num); + buf_ptr2 := 0; + end; +compress_bib_white := true; +exit: +end; + + +@ +This \.{.bib}-specific function scans a string with balanced braces, +stopping just past the matching |right_str_delim|. How much work it +does depends on whether |store_field = true|. It returns |false| if +there was a serious syntax error. + +@<The scanning function |scan_balanced_braces|@>= +function scan_balanced_braces : boolean; +label loop_exit,@!exit; +begin +scan_balanced_braces := false; {now it's easy to exit if necessary} +incr(buf_ptr2); {skip over the left-delimiter} +check_for_and_compress_bib_white_space; +if (field_end > 1) then + if (field_vl_str[field_end-1] = space) then + if (field_vl_str[field_end-2] = space) then {remove wrongly added |space|} + decr(field_end); +bib_brace_level := 0; {and we're at a non|white_space| character} +if (store_field) then + @<Do a full brace-balanced scan@> + else + @<Do a quick brace-balanced scan@>; +incr(buf_ptr2); {skip over the |right_str_delim|} +scan_balanced_braces := true; +exit: +end; + + +@ +This module scans over a brace-balanced string without keeping track +of anything but the brace level. It starts with |bib_brace_level = 0| +and at a non|white_space| character. + +@<Do a quick brace-balanced scan@>= +begin +while (scan_char <> right_str_delim) do {we're at |bib_brace_level = 0|} + if (scan_char = left_brace) then + begin + incr(bib_brace_level); + incr(buf_ptr2); {skip over the |left_brace|} + eat_bib_white_and_eof_check; + while (bib_brace_level > 0) do + @<Do a quick scan with |bib_brace_level > 0|@>; + end + else if (scan_char = right_brace) then + bib_unbalanced_braces_err + else + begin + incr(buf_ptr2); {skip over some other character} + if (not scan3 (right_str_delim, left_brace, right_brace)) then + eat_bib_white_and_eof_check; + end +end + + +@ +This module does the same as above but, because |bib_brace_level > 0|, it +doesn't have to look for a |right_str_delim|. + +@<Do a quick scan with |bib_brace_level > 0|@>= +begin {top part of the |while| loop---we're always at a nonwhite character} +if (scan_char = right_brace) then + begin + decr(bib_brace_level); + incr(buf_ptr2); {skip over the |right_brace|} + eat_bib_white_and_eof_check; + end +else if (scan_char = left_brace) then + begin + incr(bib_brace_level); + incr(buf_ptr2); {skip over the |left_brace|} + eat_bib_white_and_eof_check; + end +else + begin + incr(buf_ptr2); {skip over some other character} + if (not scan2 (right_brace, left_brace)) then + eat_bib_white_and_eof_check; + end +end + + +@ +This module scans over a brace-balanced string, compressing multiple +|white_space| characters into a single |space|. It starts with +|bib_brace_level = 0| and starts at a non|white_space| character. + +@<Do a full brace-balanced scan@>= +begin +while (scan_char <> right_str_delim) do + case (scan_char) of + left_brace : + begin + incr(bib_brace_level); + copy_char (left_brace);@/ + incr(buf_ptr2); {skip over the |left_brace|} + check_for_and_compress_bib_white_space;@/ + @<Do a full scan with |bib_brace_level > 0|@>; + end; + right_brace : + bib_unbalanced_braces_err; + othercases + begin + copy_char (scan_char); + incr(buf_ptr2); {skip over some other character} + check_for_and_compress_bib_white_space; + end + endcases; +end + + +@ +This module is similar to the last but starts with |bib_brace_level > 0| +(and, like the last, it starts at a non|white_space| character). + +@<Do a full scan with |bib_brace_level > 0|@>= +begin +loop + case (scan_char) of + right_brace : + begin + decr(bib_brace_level); + copy_char (right_brace);@/ + incr(buf_ptr2); {skip over the |right_brace|} + check_for_and_compress_bib_white_space; + if (bib_brace_level = 0) then + goto loop_exit; + end; + left_brace : + begin + incr(bib_brace_level); + copy_char (left_brace);@/ + incr(buf_ptr2); {skip over the |left_brace|} + check_for_and_compress_bib_white_space; + end; + othercases + begin + copy_char (scan_char); + incr(buf_ptr2); {skip over some other character} + check_for_and_compress_bib_white_space; + end + endcases; +loop_exit: +end + + +@ +@:this can't happen}{\quad A digit disappeared@> +This module scans a nonnegative number and copies it to |field_vl_str| +if it's to store the field. + +@<Scan a number@>= +begin +if (not scan_nonneg_integer) then + confusion ('A digit disappeared'); +if (store_field) then + begin + tmp_ptr := buf_ptr1; + while (tmp_ptr < buf_ptr2) do + begin + copy_char (buffer[tmp_ptr]); + incr(tmp_ptr); + end; + end; +end + + +@ +This module scans a macro name and copies its string to |field_vl_str| +if it's to store the field, complaining if the macro is recursive or +undefined. + +@<Scan a macro name@>= +begin +scan_identifier (comma,right_outer_delim,concat_char); +bib_identifier_scan_check ('a field part'); +if (store_field) then + begin + lower_case (buffer, buf_ptr1, token_len); {ignore case differences} + macro_name_loc := str_lookup( + buffer,buf_ptr1,token_len,macro_ilk,dont_insert); + store_token := true; + if (at_bib_command) then + if (command_num = n_bib_string) then + if (macro_name_loc = cur_macro_loc) then + begin + store_token := false; + macro_name_warning ('used in its own definition'); + end; + if (not hash_found) then + begin + store_token := false; + macro_name_warning ('undefined'); + end; + if (store_token) then + @<Copy the macro string to |field_vl_str|@>; + end; +end + + +@ +The macro definition may have |white_space| that needs compressing, +because it may have been defined in the \.{.bst} file. + +@<Copy the macro string to |field_vl_str|@>= +begin +tmp_ptr := str_start[ilk_info[macro_name_loc]]; +tmp_end_ptr := str_start[ilk_info[macro_name_loc]+1]; +if (field_end = 0) then + if ((lex_class[str_pool[tmp_ptr]] = white_space) and (tmp_ptr < tmp_end_ptr)) + then + begin {compress leading |white_space| of first nonnull token} + copy_char (space); + incr(tmp_ptr); + while ((lex_class[str_pool[tmp_ptr]] = white_space) and + (tmp_ptr < tmp_end_ptr)) do + incr(tmp_ptr); + end; {the next remaining character is non|white_space|} +while (tmp_ptr < tmp_end_ptr) do + begin + if (lex_class[str_pool[tmp_ptr]] <> white_space) then + copy_char (str_pool[tmp_ptr]) + else if (field_vl_str[field_end-1] <> space) then + copy_char (space); + incr(tmp_ptr); + end; +end + + +@ +@^ham and eggs@> +Now it's time to store the field value in the hash table, and store an +appropriate pointer to it (depending on whether it's for a database +entry or command). But first, if necessary, we remove a trailing +|space| and a leading |space| if these exist. (Hey, if we had some +ham we could make ham-and-eggs if we had some eggs.) + +@<Store the field value string@>= +begin +if (not at_bib_command) then {chop trailing |space| for a field} + if (field_end > 0) then + if (field_vl_str[field_end-1] = space) then + decr(field_end); +if ((not at_bib_command) and (field_vl_str[0] = space) and (field_end > 0)) + then {chop leading |space| for a field} + field_start := 1 + else + field_start := 0; +field_val_loc := str_lookup(field_vl_str,field_start,field_end-field_start, + text_ilk,do_insert); +fn_type[field_val_loc] := str_literal; {set the |fn_class|} + trace + trace_pr ('"'); + trace_pr_pool_str (hash_text[field_val_loc]); + trace_pr_ln ('" is a field value'); + ecart@/ +if (at_bib_command) then {for a \.{preamble} or \.{string} command} + @<Store the field value for a command@> + else {for a database entry} + @<Store the field value for a database entry@>; +end + + +@ +@:this can't happen}{\quad Unknown database-file command@> +Here's where we store the goods when we're dealing with a command +rather than an entry. + +@<Store the field value for a command@>= +begin +case (command_num) of + n_bib_preamble : + begin + s_preamble[preamble_ptr] := hash_text[field_val_loc]; + incr(preamble_ptr); + end; + n_bib_string : + ilk_info[cur_macro_loc] := hash_text[field_val_loc]; + othercases bib_cmd_confusion +endcases; +end + + +@ +And here, an entry. + +@<Store the field value for a database entry@>= +begin +field_ptr := entry_cite_ptr * num_fields + fn_info[field_name_loc]; +if (field_info[field_ptr] <> missing) then + begin + print ('Warning--I''m ignoring '); + print_pool_str (cite_list[entry_cite_ptr]); + print ('''s extra "'); + print_pool_str (hash_text[field_name_loc]); + bib_warn_newline ('" field'); + end + else + begin {the field was empty, store its new value} + field_info[field_ptr] := hash_text[field_val_loc]; + if ((fn_info[field_name_loc] = crossref_num) and (not all_entries)) then + @<Add or update a cross reference on |cite_list| if necessary@>; + end; +end + + +@ +@^kludge@> +@:this can't happen}{\quad Cite hash error@> +If the cross-referenced entry isn't already on |cite_list| we add it +(at least temporarily); if it is already on |cite_list| we update the +cross-reference count, if necessary. Note that |all_entries| is +|false| here. The alias kludge helps make the stack space not +overflow on some machines. + +@d extra_buf == out_buf {an alias, used only in this module} + +@<Add or update a cross reference on |cite_list| if necessary@>= +begin +tmp_ptr := field_start; +while (tmp_ptr < field_end) do + begin + extra_buf[tmp_ptr] := field_vl_str[tmp_ptr]; + incr(tmp_ptr); + end; +lower_case (extra_buf, field_start, field_end-field_start); + {convert to `canonical' form} +lc_cite_loc := str_lookup(extra_buf,field_start,field_end-field_start, + lc_cite_ilk,do_insert); +if (hash_found) then + begin + cite_loc := ilk_info[lc_cite_loc]; {even if there's a case mismatch} + if (ilk_info[cite_loc] >= old_num_cites) then {a previous \.{crossref}} + incr(cite_info[ilk_info[cite_loc]]); + end + else + begin {it's a new \.{crossref}} + cite_loc := str_lookup(field_vl_str,field_start,field_end-field_start, + cite_ilk,do_insert); + if (hash_found) then + hash_cite_confusion; + add_database_cite (cite_ptr); {this increments |cite_ptr|} + cite_info[ilk_info[cite_loc]] := 1; {the first cross-ref for this cite key} + end; +end + + +@ +This procedure adds (or restores) to |cite_list| a cite key; it is +called only when |all_entries| is |true| or when adding +cross~references, and it assumes that |cite_loc| and |lc_cite_loc| are +set. It also increments its argument. + +@<Procedures and functions for handling numbers, characters, and strings@>= +procedure add_database_cite (var new_cite : cite_number); +begin +check_cite_overflow (new_cite); {make sure this cite will fit} +check_field_overflow (num_fields*new_cite); +cite_list[new_cite] := hash_text[cite_loc]; +ilk_info[cite_loc] := new_cite; +ilk_info[lc_cite_loc] := cite_loc; +incr(new_cite); +end; + + +@ +And now, back to processing an entry (rather than a command). This +module reads a left outer-delimiter and a database key. + +@<Scan the entry's database key@>= +begin +if (scan_char = left_brace) then + right_outer_delim := right_brace +else if (scan_char = left_paren) then + right_outer_delim := right_paren +else + bib_one_of_two_expected_err (left_brace,left_paren); +incr(buf_ptr2); {skip over the left-delimiter} +eat_bib_white_and_eof_check; +if (right_outer_delim = right_paren) then {to allow it in a database key} + begin + if (scan1_white(comma)) then {ok if database key ends line} + do_nothing; + end + else + if (scan2_white(comma,right_brace)) then {|right_brace=right_outer_delim|} + do_nothing; +@<Check for a database key of interest@>; +end + + +@ +@^kludge@> +The lower-case version of this database key must correspond to one in +|cite_list|, or else |all_entries| must be |true|, if this entry is to +be included in the reference list. Accordingly, this module sets +|store_entry|, which determines whether the relevant information for +this entry is stored. The alias kludge helps make the stack space not +overflow on some machines. + +@d ex_buf3 == ex_buf {an alias, used only in this module} + +@<Check for a database key of interest@>= +begin + trace + trace_pr_token; + trace_pr_ln (' is a database key'); + ecart@/ +tmp_ptr := buf_ptr1; +while (tmp_ptr < buf_ptr2) do + begin + ex_buf3[tmp_ptr] := buffer[tmp_ptr]; + incr(tmp_ptr); + end; +lower_case (ex_buf3, buf_ptr1, token_len); {convert to `canonical' form} +if (all_entries) then + lc_cite_loc := str_lookup(ex_buf3,buf_ptr1,token_len,lc_cite_ilk,do_insert) + else + lc_cite_loc := str_lookup(ex_buf3,buf_ptr1,token_len,lc_cite_ilk, + dont_insert); +if (hash_found) then + begin + entry_cite_ptr := ilk_info[ilk_info[lc_cite_loc]]; + @<Check for a duplicate or \.{crossref}-matching database key@>; + end; +store_entry := true; {unless |(not hash_found) and (not all_entries)|} +if (all_entries) then + @<Put this cite key in its place@> + else if (not hash_found) then + store_entry := false; {no such cite key exists on |cite_list|} +if (store_entry) then + @<Make sure this entry is ok before proceeding@>; +end + + +@ +@:this can't happen}{\quad The cite list is messed up@> +It's illegal to have two (or more) entries with the same database key +(even if there are case differrences), and we skip the rest of the +entry for such a repeat occurrence. Also, we make this entry's +database key the official |cite_list| key if it's on |cite_list| only +because of cross references. + +@<Check for a duplicate or \.{crossref}-matching database key@>= +begin +if ((not all_entries) or (entry_cite_ptr < all_marker) + or (entry_cite_ptr >= old_num_cites)) then + begin + if (type_list[entry_cite_ptr] = empty) then + begin + @<Make sure this entry's database key is on |cite_list|@>; + goto first_time_entry; + end; + end +else if (not entry_exists[entry_cite_ptr]) then + begin + @<Find the lower-case equivalent of the |cite_info| key@>; + if (lc_xcite_loc = lc_cite_loc) then + goto first_time_entry; + end;@/ + {oops---repeated entry---issue a reprimand} +if (type_list[entry_cite_ptr] = empty) then + confusion ('The cite list is messed up'); +bib_err ('Repeated entry'); +first_time_entry: {note that when we leave normally, |hash_found| is |true|} +end + + +@ +An entry that's on |cite_list| only because of cross referencing must +have its database key (rather than one of the \.{crossref} keys) as +the official |cite_list| string. Here's where we assure that. The +variable |hash_found| is |true| upon entrance to and exit from this +module. + +@<Make sure this entry's database key is on |cite_list|@>= +begin +if ((not all_entries) and (entry_cite_ptr >= old_num_cites)) then + begin + cite_loc := str_lookup(buffer,buf_ptr1,token_len,cite_ilk,do_insert); + if (not hash_found) then + begin {it's not on |cite_list|---put it there} + ilk_info[lc_cite_loc] := cite_loc; + ilk_info[cite_loc] := entry_cite_ptr; + cite_list[entry_cite_ptr] := hash_text[cite_loc];@/ + hash_found := true; {restore this value for later use} + end; + end; +end + + +@ +@^kludge@> +@:this can't happen}{\quad A cite key disappeared@> +This module, a simpler version of the +|find_cite_locs_for_this_cite_key| function, exists primarily to +compute |lc_xcite_loc|. When this code is executed we have +|(all_entries) and (entry_cite_ptr >= all_marker) and (not +entry_exists[entry_cite_ptr])|. The alias kludge helps make the stack +space not overflow on some machines. + +@d ex_buf4 == ex_buf {aliases, used only} +@d ex_buf4_ptr == ex_buf_ptr {in this module} + +@<Find the lower-case equivalent of the |cite_info| key@>= +begin +ex_buf4_ptr := 0; +tmp_ptr := str_start[cite_info[entry_cite_ptr]]; +tmp_end_ptr := str_start[cite_info[entry_cite_ptr]+1]; +while (tmp_ptr < tmp_end_ptr) do + begin + ex_buf4[ex_buf4_ptr] := str_pool[tmp_ptr]; + incr(ex_buf4_ptr); + incr(tmp_ptr); + end; +lower_case (ex_buf4, 0, length(cite_info[entry_cite_ptr])); + {convert to `canonical' form} +lc_xcite_loc := str_lookup(ex_buf4,0,length(cite_info[entry_cite_ptr]), + lc_cite_ilk,dont_insert); +if (not hash_found) then + cite_key_disappeared_confusion; +end + + +@ +@:this can't happen}{\quad A cite key disappeared@> +Here's another bug complaint. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure cite_key_disappeared_confusion; +begin +confusion ('A cite key disappeared'); +end; + + +@ +@:this can't happen}{\quad Cite hash error@> +This module, which gets executed only when |all_entries| is |true|, +does one of three things, depending on whether or not, and where, the +cite key appears on |cite_list|: If it's on |cite_list| before +|all_marker|, there's nothing to be done; if it's after |all_marker|, +it must be reinserted (at the current place) and we must note that its +corresponding entry exists; and if it's not on |cite_list| at all, it +must be inserted for the first time. The |goto| construct must stay +as is, partly because some \PASCAL\ compilers might complain if +``|and|'' were to connect the two boolean expressions (since +|entry_cite_ptr| could be uninitialized when |hash_found| is |false|). + +@<Put this cite key in its place@>= +begin +if (hash_found) then + begin + if (entry_cite_ptr < all_marker) then + goto cite_already_set {that is, do nothing} + else + begin + entry_exists[entry_cite_ptr] := true; + cite_loc := ilk_info[lc_cite_loc]; + end; + end + else + begin {this is a new key} + cite_loc := str_lookup(buffer,buf_ptr1,token_len,cite_ilk,do_insert); + if (hash_found) then + hash_cite_confusion; + end;@/ +entry_cite_ptr := cite_ptr; +add_database_cite (cite_ptr); {this increments |cite_ptr|} +cite_already_set: +end + + +@ +@^case mismatch errors@> +@^commented-out code@> +We must give a warning if this entry~type doesn't exist. Also, we +point the appropriate entry of |type_list| to the entry type just read +above. + +For SCRIBE compatibility, the code to give a warning for a case +mismatch between a cite key and a database key has been commented out. +In fact, SCRIBE is the reason that it doesn't produce an error message +outright. (Note: Case mismatches between two cite keys produce +full-blown errors.) + +@<Make sure this entry is ok before proceeding@>= +begin + @{ + dummy_loc := str_lookup(buffer,buf_ptr1,token_len,cite_ilk,dont_insert); + if (not hash_found) then {give a warning if there is a case difference} + begin + print ('Warning--case mismatch, database key "'); + print_token; + print ('", cite key "'); + print_pool_str (cite_list[entry_cite_ptr]); + bib_warn_newline ('"'); + end; + @}@/ +if (type_exists) then + type_list[entry_cite_ptr] := entry_type_loc + else + begin + type_list[entry_cite_ptr] := undefined; + print ('Warning--entry type for "'); + print_token; + bib_warn_newline ('" isn''t style-file defined'); + end; +end + + +@ +This module reads a |comma| and a field as many times as it can, and +then reads a |right_outer_delim|, ending the current entry. + +@<Scan the entry's list of fields@>= +begin +while (scan_char <> right_outer_delim) do + begin + if (scan_char <> comma) then + bib_one_of_two_expected_err (comma,right_outer_delim); + incr(buf_ptr2); {skip over the |comma|} + eat_bib_white_and_eof_check; + if (scan_char = right_outer_delim) then + goto loop_exit; + @<Get the next field name@>; + eat_bib_white_and_eof_check; + if (not scan_and_store_the_field_value_and_eat_white) then + return; + end; +loop_exit: +incr(buf_ptr2); {skip over the |right_outer_delim|} +end + + +@ +This module reads a field name; its contents won't be stored unless it +was declared in the \.{.bst} file and |store_entry = true|. + +@<Get the next field name@>= +begin +scan_identifier (equals_sign,equals_sign,equals_sign); +bib_identifier_scan_check ('a field name'); + trace + trace_pr_token; + trace_pr_ln (' is a field name'); + ecart@/ +store_field := false; +if (store_entry) then + begin + lower_case (buffer, buf_ptr1, token_len); {ignore case differences} + field_name_loc := str_lookup( + buffer,buf_ptr1,token_len,bst_fn_ilk,dont_insert); + if (hash_found) then + if (fn_type[field_name_loc]=field) then@/ + store_field := true; {field name was pre-defined or \.{.bst}-declared} + end; +eat_bib_white_and_eof_check; +if (scan_char <> equals_sign) then + bib_equals_sign_expected_err; +incr(buf_ptr2); {skip over the |equals_sign|} +end + + +@ +This gets things ready for further \.{.bst} processing. + +@<Final initialization for processing the entries@>= +begin +num_cites := cite_ptr; {to include database and \.{crossref} cite keys, too} +num_preamble_strings := preamble_ptr; {number of \.{preamble} commands seen} +@<Add cross-reference information@>; +@<Subtract cross-reference information@>; +@<Remove missing entries or those cross referenced too few times@>; +@<Initialize the |int_entry_var|s@>; +@<Initialize the |str_entry_var|s@>; +@<Initialize the |sorted_cites|@>; +end + + +@ +@^child entry@> +@^cross references@> +@^nested cross references@> +@^parent entry@> +Now we update any entry (here called a {\it child\/} entry) that +cross~referenced another (here called a {\it parent\/} entry); this +cross~referencing occurs when the child's \.{crossref} field (value) +consists of the parent's database key. To do the update, we replace +the child's |missing| fields by the corresponding fields of the +parent. Also, we make sure the \.{crossref} field contains the +case-correct version. Finally, although it is technically illegal to +nest cross~references, and although we give a warning (a few modules +hence) when someone tries, we do what we can to accommodate the +attempt. + +@<Add cross-reference information@>= +begin +cite_ptr := 0; +while (cite_ptr < num_cites) do + begin + field_ptr := cite_ptr * num_fields + crossref_num; + if (field_info[field_ptr] <> missing) then + if (find_cite_locs_for_this_cite_key (field_info[field_ptr])) then + begin + cite_loc := ilk_info[lc_cite_loc]; + field_info[field_ptr] := hash_text[cite_loc]; + cite_parent_ptr := ilk_info[cite_loc]; + field_ptr := cite_ptr * num_fields + num_pre_defined_fields; + field_end_ptr := field_ptr - num_pre_defined_fields + num_fields; + field_parent_ptr := cite_parent_ptr * num_fields + + num_pre_defined_fields; + while (field_ptr < field_end_ptr) do + begin + if (field_info[field_ptr] = missing) then + field_info[field_ptr] := field_info[field_parent_ptr]; + incr(field_ptr); + incr(field_parent_ptr); + end; + end; + incr(cite_ptr); + end; +end + + +@ +@^kludge@> +@^raisin@> +Occasionally we need to figure out the hash-table location of a given +cite-key string and its lower-case equivalent. This function does +that. To perform the task it needs to borrow a buffer, a need that +gives rise to the alias kludge---it helps make the stack space not +overflow on some machines (and while it's at it, it'll borrow a +pointer, too). Finally, the function returns |true| if the cite key +exists on |cite_list|, and its sets |cite_hash_found| according to +whether or not it found the actual version (before |lower_case|ing) of +the cite key; however, its {\sl raison d'\^$\mkern-8mu$etre\/} +(literally, ``to eat a raisin'') is to compute |cite_loc| and +|lc_cite_loc|. + +@d ex_buf5 == ex_buf {aliases, used only} +@d ex_buf5_ptr == ex_buf_ptr {in this module} + +@<Procedures and functions for handling numbers, characters, and strings@>= +function find_cite_locs_for_this_cite_key (@!cite_str : str_number) : boolean; +begin +ex_buf5_ptr := 0; +tmp_ptr := str_start[cite_str]; +tmp_end_ptr := str_start[cite_str+1]; +while (tmp_ptr < tmp_end_ptr) do + begin + ex_buf5[ex_buf5_ptr] := str_pool[tmp_ptr]; + incr(ex_buf5_ptr); + incr(tmp_ptr); + end; +cite_loc := str_lookup(ex_buf5,0,length(cite_str),cite_ilk,dont_insert); +cite_hash_found := hash_found; +lower_case (ex_buf5, 0, length(cite_str)); {convert to `canonical' form} +lc_cite_loc := str_lookup(ex_buf5,0,length(cite_str),lc_cite_ilk,dont_insert); +if (hash_found) then + find_cite_locs_for_this_cite_key := true + else + find_cite_locs_for_this_cite_key := false; +end; + + +@ +@:this can't happen}{\quad Cite hash error@> +Here we remove the \.{crossref} field value for each child whose +parent was cross~referenced too few times. We also issue any +necessary warnings arising from a bad cross~reference. + +@<Subtract cross-reference information@>= +begin +cite_ptr := 0; +while (cite_ptr < num_cites) do + begin + field_ptr := cite_ptr * num_fields + crossref_num; + if (field_info[field_ptr] <> missing) then + if (not find_cite_locs_for_this_cite_key (field_info[field_ptr])) then + begin {the parent is not on |cite_list|} + if (cite_hash_found) then + hash_cite_confusion; + nonexistent_cross_reference_error; + field_info[field_ptr] := missing; {remove the \.{crossref} ptr} + end + else + begin {the parent exists on |cite_list|} + if (cite_loc <> ilk_info[lc_cite_loc]) then + hash_cite_confusion; + cite_parent_ptr := ilk_info[cite_loc]; + if (type_list[cite_parent_ptr] = empty) then + begin + nonexistent_cross_reference_error;@/ + field_info[field_ptr] := missing; {remove the \.{crossref} ptr} + end + else + begin {the parent exists in the database too} + field_parent_ptr := cite_parent_ptr * num_fields + crossref_num; + if (field_info[field_parent_ptr] <> missing) then + @<Complain about a nested cross reference@>; + if ((not all_entries) and (cite_parent_ptr >= old_num_cites) and + (cite_info[cite_parent_ptr] < min_crossrefs)) then@/ + field_info[field_ptr] := missing; {remove the \.{crossref} ptr} + end; + end; + incr(cite_ptr); + end; +end + + +@ +This procedure exists to save space, since it's used twice---once for +each of the two succeeding modules. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bad_cross_reference_print (@!s:str_number); +begin +print ('--entry "'); +print_pool_str (cur_cite_str); +print_ln ('"'); +print ('refers to entry "'); +print_pool_str (s); +end; + + +@ +When an entry being cross referenced doesn't exist on |cite_list|, we +complain. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure nonexistent_cross_reference_error; +begin +print ('A bad cross reference-'); +bad_cross_reference_print (field_info[field_ptr]); +print_ln ('", which doesn''t exist'); +mark_error; +end; + + +@ +We also complain when an entry being cross referenced has a +non|missing| \.{crossref} field itself, but this one is just a +warning, not a full-blown error. + +@<Complain about a nested cross reference@>= +begin +print ('Warning--you''ve nested cross references'); +bad_cross_reference_print (cite_list[cite_parent_ptr]); +print_ln ('", which also refers to something'); +mark_warning; +end + + +@ +We remove (and give a warning for) each cite key on the original +|cite_list| without a corresponding database entry. And we remove any +entry that was included on |cite_list| only because it was +cross~referenced, yet was cross~referenced fewer than |min_crossrefs| +times. Throughout this module, |cite_ptr| points to the next cite key +to be checked and |cite_xptr| points to the next permanent spot on +|cite_list|. + +@<Remove missing entries or those cross referenced too few times@>= +begin +cite_ptr := 0; +while (cite_ptr < num_cites) do + begin + if (type_list[cite_ptr] = empty) then + print_missing_entry (cur_cite_str) + else if ((all_entries) or (cite_ptr < old_num_cites) or + (cite_info[cite_ptr] >= min_crossrefs)) then + begin + if (cite_ptr > cite_xptr) then + @<Slide this cite key down to its permanent spot@>; + incr(cite_xptr); + end; + incr(cite_ptr); + end; +num_cites := cite_xptr; +if (all_entries) then + @<Complain about missing entries whose cite keys got overwritten@>; +end + + +@ +When a cite key on the original |cite_list| (or added to |cite_list| +because of cross~referencing) didn't appear in the database, complain. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_missing_entry (@!s:str_number); +begin +print ('Warning--I didn''t find a database entry for "'); +print_pool_str (s); +print_ln ('"'); +mark_warning; +end; + + +@ +@:this can't happen}{\quad A cite key disappeared@> +@:this can't happen}{\quad Cite hash error@> +We have to move to its final resting place all the entry information +associated with the exact location in |cite_list| of this cite key. + +@<Slide this cite key down to its permanent spot@>= +begin +cite_list[cite_xptr] := cite_list[cite_ptr]; +type_list[cite_xptr] := type_list[cite_ptr]; +if (not find_cite_locs_for_this_cite_key (cite_list[cite_ptr])) then + cite_key_disappeared_confusion; +if ((not cite_hash_found) or (cite_loc <> ilk_info[lc_cite_loc])) then + hash_cite_confusion; +ilk_info[cite_loc] := cite_xptr;@/ +field_ptr := cite_xptr * num_fields; +field_end_ptr := field_ptr + num_fields; +tmp_ptr := cite_ptr * num_fields; +while (field_ptr < field_end_ptr) do + begin + field_info[field_ptr] := field_info[tmp_ptr]; + incr(field_ptr); + incr(tmp_ptr); + end; +end + + +@ +We need this module only when we're including the whole database. +It's for missing entries whose cite key originally resided in +|cite_list| at a spot that another cite key (might have) claimed. + +@<Complain about missing entries whose cite keys got overwritten@>= +begin +cite_ptr := all_marker; +while (cite_ptr < old_num_cites) do + begin + if (not entry_exists[cite_ptr]) then + print_missing_entry (cite_info[cite_ptr]); + incr(cite_ptr); + end; +end + + +@ +@:BibTeX capacity exceeded}{\quad total number of integer entry-variables@> +This module initializes all |int_entry_var|s of all entries to 0, the +value to which all integers are initialized. + +@<Initialize the |int_entry_var|s@>= +begin +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; +int_ent_ptr := 0; +while (int_ent_ptr < num_ent_ints*num_cites) do + begin + entry_ints[int_ent_ptr] := 0; + incr(int_ent_ptr); + end; +end + + +@ +@:BibTeX capacity exceeded}{\quad total number of string entry-variables@> +This module initializes all |str_entry_var|s of all entries to the +null string, the value to which all strings are initialized. + +@<Initialize the |str_entry_var|s@>= +begin +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; +str_ent_ptr := 0; +while (str_ent_ptr < num_ent_strs*num_cites) do + begin + entry_strs[str_ent_ptr][0] := end_of_string; + incr(str_ent_ptr); + end; +end + + +@ +The array |sorted_cites| initially specifies that the entries are to +be processed in order of cite-key occurrence. The \.{sort} command +may change this to whatever it likes (which, we hope, is whatever the +style-designer instructs it to like). We make |sorted_cites| an alias +to save space; this works fine because we're done with |cite_info|. + +@d sorted_cites == cite_info {an alias used for the rest of the program} + +@<Initialize the |sorted_cites|@>= +begin +cite_ptr := 0; +while (cite_ptr < num_cites) do + begin + sorted_cites[cite_ptr] := cite_ptr; + incr(cite_ptr); + end; +end + + + +@* Executing the style file. +This part of the program produces the output by executing the +\.{.bst}-file commands \.{execute}, \.{iterate}, \.{reverse}, and +\.{sort}. To do this it uses a stack (consisting of the two arrays +|lit_stack| and |lit_stk_type|) for storing literals, a buffer +|ex_buf| for manipulating strings, and an array |sorted_cites| +for holding pointers to the sorted cite keys (|sorted_cites| is an +alias of |cite_info|). + +@<Globals in the outer block@>= +@!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} +@!lit_stk_ptr : lit_stk_loc; {points just above the top of the stack} +@!cmd_str_ptr : str_number; {stores value of |str_ptr| during execution} +@!ent_chr_ptr : 0..ent_str_size; {points at a |str_entry_var| character} +@!glob_chr_ptr : 0..glob_str_size; {points at a |str_global_var| character} +@!ex_buf : buf_type; {a buffer for manipulating strings} +@!ex_buf_ptr : buf_pointer; {general |ex_buf| location} +@!ex_buf_length : buf_pointer; {the length of the current string in |ex_buf|} +@!out_buf : buf_type; {the \.{.bbl} output buffer} +@!out_buf_ptr : buf_pointer; {general |out_buf| location} +@!out_buf_length : buf_pointer; {the length of the current string in |out_buf|} +@!mess_with_entries : boolean; {|true| if functions can use entry info} +@!sort_cite_ptr : cite_number; {a loop index for the sorted cite keys} +@!sort_key_num : str_ent_loc; {index for the |str_entry_var| \.{sort.key\$}} +@!brace_level : integer; {the brace nesting depth within a string} + + +@ +Where |lit_stk_loc| is a stack location, and where |stk_type| gives +one of the three types of literals (an integer, a string, or a +function) or a special marker. If a |lit_stk_type| element is a +|stk_int| then the corresponding |lit_stack| element is an integer; if +a |stk_str|, then a pointer to a |str_pool| string; and if a |stk_fn|, +then a pointer to the function's hash-table location. However, if the +literal should have been a |stk_str| that was the value of a field +that happened to be |missing|, then the special value +|stk_field_missing| goes on the stack instead; its corresponding +|lit_stack| element is a pointer to the field-name's string. Finally, +|stk_empty| is the type of a literal popped from an empty stack. + +@d stk_int = 0 {an integer literal} +@d stk_str = 1 {a string literal} +@d stk_fn = 2 {a function literal} +@d stk_field_missing = 3 {a special marker: a field value was missing} +@d stk_empty = 4 {another: the stack was empty when this was popped} +@d last_lit_type = 4 {the same number as on the line above} + +@<Types in the outer block@>= +@!lit_stk_loc = 0..lit_stk_size; {the stack range} +@!stk_type = 0..last_lit_type; {the literal types} + + +@ +And the first output line requires this initialization. + +@<Set initial values of key variables@>= +out_buf_length := 0; + + +@ +When there's an error while executing \.{.bst} functions, what we do +depends on whether the function is messing with the entries. +Furthermore this error is serious enough to classify as an +|error_message| instead of a |warning_message|. These messages (that +is, from |bst_ex_warn|) are meant both for the user and for the style +designer while debugging. + +@d bst_ex_warn(#) == begin {error while executing some function} + print (#); + bst_ex_warn_print; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_ex_warn_print; +begin +if (mess_with_entries) then + begin + print (' for entry '); + print_pool_str (cur_cite_str); + end; +print_newline; +print ('while executing-'); +bst_ln_num_print; +mark_error; +end; + + +@ +When an error is so harmless, we print a |warning_message| instead of +an |error_message|. + +@d bst_mild_ex_warn(#) == begin {error while executing some function} + print (#); + bst_mild_ex_warn_print; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_mild_ex_warn_print; +begin +if (mess_with_entries) then + begin + print (' for entry '); + print_pool_str (cur_cite_str); + end; +print_newline; +bst_warn ('while executing'); {This does the |mark_warning|} +end; + + +@ +It's illegal to mess with the entry information at certain times; +here's a complaint for these times. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_cant_mess_with_entries_print; +begin +bst_ex_warn ('You can''t mess with entries here'); +end; + + +@ +This module executes a single specified function once. It can't do +anything with the entries. + +@<Perform an \.{execute} command@>= +begin +init_command_execution; +mess_with_entries := false; +execute_fn (fn_loc); +check_command_execution; +end + + +@ +This module iterates a single specified function for all entries +specified by |cite_list|. + +@<Perform an \.{iterate} command@>= +begin +init_command_execution; +mess_with_entries := true; +sort_cite_ptr := 0; +while (sort_cite_ptr < num_cites) do + begin + cite_ptr := sorted_cites[sort_cite_ptr]; + trace + trace_pr_pool_str (hash_text[fn_loc]); + trace_pr (' to be iterated on '); + trace_pr_pool_str (cur_cite_str); + trace_pr_newline; + ecart@/ + execute_fn (fn_loc); + check_command_execution; + incr(sort_cite_ptr); + end; +end + + +@ +This module iterates a single specified function for all entries +specified by |cite_list|, but does it in reverse order. + +@<Perform a \.{reverse} command@>= +begin +init_command_execution; +mess_with_entries := true; +if (num_cites > 0) then + begin + sort_cite_ptr := num_cites; + repeat + decr(sort_cite_ptr); + cite_ptr := sorted_cites[sort_cite_ptr]; + trace + trace_pr_pool_str (hash_text[fn_loc]); + trace_pr (' to be iterated in reverse on '); + trace_pr_pool_str (cur_cite_str); + trace_pr_newline; + ecart@/ + execute_fn (fn_loc); + check_command_execution; + until (sort_cite_ptr = 0); + end; +end + + +@ +This module sorts the entries based on \.{sort.key\$}; it is a stable +sort. + +@<Perform a \.{sort} command@>= +begin + trace + trace_pr_ln ('Sorting the entries'); + ecart@/ +if (num_cites > 1) then + quick_sort (0, num_cites-1); + trace + trace_pr_ln ('Done sorting'); + ecart@/ +end + + +@ +These next two procedures (actually, one procedures and one function, +but who's counting) are subroutines for |quick_sort|, which follows. +The |swap| procedure exchanges the two elements its arguments point +to. + +@<Procedures and functions for handling numbers, characters, and strings@>= +procedure swap (@!swap1,@!swap2 : cite_number); +var innocent_bystander : cite_number; {the temporary element in an exchange} +begin +innocent_bystander := sorted_cites[swap2]; +sorted_cites[swap2] := sorted_cites[swap1]; +sorted_cites[swap1] := innocent_bystander; +end; + + +@ +@:this can't happen}{\quad Duplicate sort key@> +The function |less_than| compares the two \.{sort.key\$}s indirectly +pointed to by its arguments and returns |true| if the first argument's +\.{sort.key\$} is lexicographically less than the second's (that is, +alphabetically earlier). In case of ties the function compares the +indices |arg1| and |arg2|, which are assumed to be different, and +returns |true| if the first is smaller. This function uses +|ASCII_code|s to compare, so it might give ``interesting'' results +when handling nonletters. + +@d compare_return(#) == begin {the compare is finished} + less_than := #; + return; + end + +@<Procedures and functions for handling numbers, characters, and strings@>= +function less_than (@!arg1,@!arg2 : cite_number) : boolean; +label exit; +var char_ptr : 0..ent_str_size; {character index into compared strings} + @!ptr1,@!ptr2 : str_ent_loc; {the two \.{sort.key\$} pointers} + @!char1,@!char2 : ASCII_code; {the two characters being compared} +begin +ptr1 := arg1*num_ent_strs + sort_key_num; +ptr2 := arg2*num_ent_strs + sort_key_num; +char_ptr := 0; +loop + begin + char1 := entry_strs[ptr1][char_ptr]; + char2 := entry_strs[ptr2][char_ptr]; + if (char1 = end_of_string) then + if (char2 = end_of_string) then + if (arg1 < arg2) then + compare_return (true) + else if (arg1 > arg2) then + compare_return (false) + else {|arg1 = arg2|} + confusion ('Duplicate sort key') + else {|char2 <> end_of_string|} + compare_return (true) + else {|char1 <> end_of_string|} + if (char2 = end_of_string) then + compare_return (false) + else if (char1 < char2) then + compare_return (true) + else if (char1 > char2) then + compare_return (false); + incr(char_ptr); + end; +exit: +end; + + +@ +The recursive procedure |quick_sort| sorts the entries indirectly +pointed to by the |sorted_cites| elements between |left_end| and +|right_end|, inclusive, based on the value of the |str_entry_var| +\.{sort.key\$}. It's a fairly standard quicksort (for example, see +Algorithm 5.2.2Q in {\sl The Art of Computer Programming}), but uses +the median-of-three method to choose the partition element just in +case the entries are already sorted (or nearly sorted---humans and +ASCII might have different ideas on lexicographic ordering); it is a +stable sort. This code generally prefers clarity to assembler-type +execution-time efficiency since |cite_list|s will rarely be huge. + +The value |short_list|, which must be at least |2*end_offset + 2| for +this code to work, tells us the list-length at which the list is small +enough to warrant switching over to straight insertion sort from the +recursive quicksort. The values here come from modest empirical tests +aimed at minimizing, for large |cite_list|s (five hundred or so), the +number of comparisons (between keys) plus the number of calls to +|quick_sort|. The value |end_offset| must be positive; this helps +avoid $n^2$ behavior observed when the list starts out nearly, but not +completely, sorted (and fairly frequently large |cite_list|s come from +entire databases, which fairly frequently are nearly sorted). + +@d short_list = 10 {use straight insertion sort at or below this length} +@d end_offset = 4 {the index end-offsets for choosing a median-of-three} + +@<Check the ``constant'' values for consistency@>= +if (short_list < 2*end_offset + 2) then bad:=100*bad+22; + + +@ +Here's the actual procedure. + +@d next_insert = 24 {now insert the next element} + +@<Procedures and functions for handling numbers, characters, and strings@>= +procedure quick_sort (@!left_end,@!right_end : cite_number); +label next_insert; +var left,@!right : cite_number; {two general |sorted_cites| pointers} + @!insert_ptr : cite_number; {the to-be-(straight)-inserted element} + @!middle : cite_number; {the |(left_end+right_end) div 2| element} + @!partition : cite_number; {the median-of-three partition element} +begin + trace + trace_pr_ln ('Sorting ',left_end:0,' through ',right_end:0); + ecart@/ +if (right_end - left_end < short_list) then + @<Do a straight insertion sort@> + else + begin + @<Draw out the median-of-three partition element@>; + @<Do the partitioning and the recursive calls@>; + end; +end; + + +@ +This code sorts the entries between |left_end| and |right_end| when +the difference is less than |short_list|. Each iteration of the outer +loop inserts the element indicated by |insert_ptr| into its proper +place among the (sorted) elements from |left_end| through +|insert_ptr-1|. + +@<Do a straight insertion sort@>= +begin +for insert_ptr := left_end+1 to right_end do + begin + for right := insert_ptr downto left_end+1 do + begin + if (less_than (sorted_cites[right-1], sorted_cites[right])) then + goto next_insert; + swap (right-1, right); + end; +next_insert: + end; +end + + +@ +Now we find the median of the three \.{sort.key\$}s to which the three +elements |sorted_cites[left_end+end_offset]|, +|sorted_cites[right_end]-end_offset|, and +|sorted_cites[(left_end+right_end) div 2]| point (a nonzero +|end_offset| avoids using as the leftmost of the three elements the +one that was swapped there when the old partition element was swapped +into its final spot; this turns out to avoid $n^2$ behavior when the +list is nearly sorted to start with). This code determines which of +the six possible permutations we're dealing with and moves the median +element to |left_end|. The comments next to the |swap| actions give +the known orderings of the corresponding elements of |sorted_cites| +before the action. + +@<Draw out the median-of-three partition element@>= +begin +left := left_end + end_offset; +middle := (left_end+right_end) div 2; +right := right_end - end_offset; +if (less_than (sorted_cites[left], sorted_cites[middle])) then + if (less_than (sorted_cites[middle], sorted_cites[right])) then + {|left < middle < right|} + swap(left_end,middle) + else if (less_than (sorted_cites[left], sorted_cites[right])) then + {|left < right < middle|} + swap(left_end,right) + else {|right < left < middle|} + swap(left_end,left) + else if (less_than (sorted_cites[right], sorted_cites[middle])) then + {|right < middle < left|} + swap(left_end,middle) + else if (less_than (sorted_cites[right], sorted_cites[left])) then + {|middle < right < left|} + swap(left_end,right) + else {|middle < left < right|} + swap(left_end,left); +end + + +@ +This module uses the median-of-three computed above to partition the +elements into those less than and those greater than the median. +Equal \.{sort.key\$}s are sorted by order of occurrence (in +|cite_list|). + +@<Do the partitioning and the recursive calls@>= +begin +partition := sorted_cites[left_end]; +left := left_end + 1; +right := right_end; +repeat + while (less_than (sorted_cites[left], partition)) do + incr(left); + while (less_than (partition, sorted_cites[right])) do + decr(right); + {now |sorted_cites[right] < partition < sorted_cites[left]|} + if (left < right) then + begin + swap (left,right); + incr(left); + decr(right); + end; +until (left = right+1); {pointers have crossed} +swap (left_end,right);{restoring the partition element to its |right|ful place} +quick_sort (left_end,right-1); +quick_sort (left,right_end); +end + + +@ +@:BibTeX capacity exceeded}{\quad literal-stack size@> +@:this can't happen}{\quad Unknown literal type@> +Ok, that's it for sorting; now we'll play with the literal stack. +This procedure pushes a literal onto the stack, checking for stack +overflow. + +@<Procedures and functions for style-file function execution@>= +procedure push_lit_stk (@!push_lt:integer; @!push_type:stk_type); + trace + var dum_ptr : lit_stk_loc; {used just as an index variable} + ecart@/ +begin +lit_stack[lit_stk_ptr] := push_lt; +lit_stk_type[lit_stk_ptr] := push_type; + trace + for dum_ptr := 0 to lit_stk_ptr do + trace_pr (' '); + trace_pr ('Pushing '); + case (lit_stk_type[lit_stk_ptr]) of + stk_int : trace_pr_ln (lit_stack[lit_stk_ptr]:0); + stk_str : begin + trace_pr ('"'); + trace_pr_pool_str (lit_stack[lit_stk_ptr]); + trace_pr_ln ('"'); + end; + stk_fn : begin + trace_pr ('`'); + trace_pr_pool_str (hash_text[lit_stack[lit_stk_ptr]]); + trace_pr_ln (''''); + end; + stk_field_missing : begin + trace_pr ('missing field `'); + trace_pr_pool_str (lit_stack[lit_stk_ptr]); + trace_pr_ln (''''); + end; + stk_empty : trace_pr_ln ('a bad literal--popped from an empty stack'); + othercases unknwn_literal_confusion + endcases; + ecart@/ +if (lit_stk_ptr = lit_stk_size) then + overflow('literal-stack size ',lit_stk_size); +incr(lit_stk_ptr); +end; + + +@ +@^push the literal stack@> +This macro pushes the last thing, necessarily a string, that was +popped. And this module, along with others that push the literal +stack without explicitly calling |push_lit_stack|, have an index entry +under ``push the literal stack''; these implicit pushes collectively +speed up the program by about ten percent. + +@d repush_string == begin + if (lit_stack[lit_stk_ptr] >= cmd_str_ptr) then + unflush_string; + incr(lit_stk_ptr); + end + + +@ +@:this can't happen}{\quad Nontop top of string stack@> +This procedure pops the stack, checking for, and trying to recover +from, stack underflow. (Actually, this procedure is really a +function, since it returns the two values through its |var| +parameters.) Also, if the literal being popped is a |stk_str| that's +been created during the execution of the current \.{.bst} command, pop +it from |str_pool| as well (it will be the string corresponding to +|str_ptr-1|). Note that when this happens, the string is no longer +`officially' available so that it must be used before anything else is +added to |str_pool|. + +@<Procedures and functions for style-file function execution@>= +procedure pop_lit_stk (var pop_lit:integer; var pop_type:stk_type); +begin +if (lit_stk_ptr = 0) then + begin + bst_ex_warn ('You can''t pop an empty literal stack');@/ + pop_type := stk_empty; {this is an error recovery attempt} + end + else + begin + decr(lit_stk_ptr); + pop_lit := lit_stack[lit_stk_ptr]; + pop_type := lit_stk_type[lit_stk_ptr]; + if (pop_type = stk_str) then + if (pop_lit >= cmd_str_ptr) then + begin + if (pop_lit <> str_ptr-1) then + confusion ('Nontop top of string stack'); + flush_string; + end; + end; +end; + + +@ +@:this can't happen}{\quad Illegal literal type@> +@:this can't happen}{\quad Unknown literal type@> +More bug complaints, this time about bad literals. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure illegl_literal_confusion; +begin +confusion ('Illegal literal type'); +end; +@# +procedure unknwn_literal_confusion; +begin +confusion ('Unknown literal type'); +end; + + +@ +@:this can't happen}{\quad Illegal literal type@> +@:this can't happen}{\quad Unknown literal type@> +Occasionally we'll want to know what's on the literal stack. Here we +print out a stack literal, giving its type. This procedure should +never be called after popping an empty stack. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_stk_lit (@!stk_lt:integer; @!stk_tp:stk_type); +begin +case (stk_tp) of + stk_int : print (stk_lt:0,' is an integer literal'); + stk_str : begin + print ('"'); + print_pool_str (stk_lt); + print ('" is a string literal'); + end; + stk_fn : begin + print ('`'); + print_pool_str (hash_text[stk_lt]); + print (''' is a function literal'); + end; + stk_field_missing : begin + print ('`'); + print_pool_str (stk_lt); + print (''' is a missing field'); + end; + stk_empty : illegl_literal_confusion; + othercases unknwn_literal_confusion +endcases; +end; + + +@ +@:this can't happen}{\quad Illegal literal type@> +@:this can't happen}{\quad Unknown literal type@> +This procedure appropriately chastises the style designer; however, if +the wrong literal came from popping an empty stack, the procedure +|pop_lit_stack| will have already done the chastising (because this +procedure is called only after popping the stack) so there's no need +for more. + +@<Procedures and functions for style-file function execution@>= +procedure print_wrong_stk_lit (@!stk_lt:integer; @!stk_tp1,@!stk_tp2:stk_type); +begin +if (stk_tp1 <> stk_empty) then + begin + print_stk_lit (stk_lt, stk_tp1); + case (stk_tp2) of + stk_int : print (', not an integer,'); + stk_str : print (', not a string,'); + stk_fn : print (', not a function,'); + stk_field_missing, + stk_empty : illegl_literal_confusion; + othercases unknwn_literal_confusion + endcases; + bst_ex_warn_print; + end; +end; + + +@ +@:this can't happen}{\quad Illegal literal type@> +@:this can't happen}{\quad Unknown literal type@> +This is similar to |print_stk_lit|, but here we don't give the +literal's type, and here we end with a new line. This procedure +should never be called after popping an empty stack. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure print_lit (@!stk_lt:integer; @!stk_tp:stk_type); +begin +case (stk_tp) of + stk_int : print_ln (stk_lt:0); + stk_str : begin + print_pool_str (stk_lt); + print_newline; + end; + stk_fn : begin + print_pool_str (hash_text[stk_lt]); + print_newline; + end; + stk_field_missing : begin + print_pool_str (stk_lt); + print_newline; + end; + stk_empty : illegl_literal_confusion; + othercases unknwn_literal_confusion +endcases; +end; + + +@ +This procedure pops and prints the top of the stack; when the stack is +empty the procedure |pop_lit_stk| complains. + +@<Procedures and functions for style-file function execution@>= +procedure pop_top_and_print; +var stk_lt : integer; + @!stk_tp : stk_type; +begin +pop_lit_stk (stk_lt,stk_tp); +if (stk_tp = stk_empty) then + print_ln ('Empty literal') + else + print_lit (stk_lt,stk_tp); +end; + + +@ +This procedure pops and prints the whole stack. + +@<Procedures and functions for style-file function execution@>= +procedure pop_whole_stack; +begin +while (lit_stk_ptr > 0) do + pop_top_and_print; +end; + + +@ +At the beginning of a \.{.bst}-command execution we make the stack +empty and record how much of |str_pool| has been used. + +@<Procedures and functions for style-file function execution@>= +procedure init_command_execution; +begin +lit_stk_ptr := 0; {make the stack empty} +cmd_str_ptr := str_ptr; {we'll check this when we finish command execution} +end; + + +@ +@:this can't happen}{\quad Nonempty empty string stack@> +At the end of a \.{.bst} command-execution we check that the stack and +|str_pool| are still in good shape. + +@<Procedures and functions for style-file function execution@>= +procedure check_command_execution; +begin +if (lit_stk_ptr<>0) then + begin + print_ln ('ptr=',lit_stk_ptr:0,', stack='); + pop_whole_stack; + bst_ex_warn ('---the literal stack isn''t empty'); + end; +if (cmd_str_ptr<>str_ptr) then + begin + trace + print_ln ('Pointer is ',str_ptr:0,' but should be ',cmd_str_ptr:0); + ecart@/ + confusion ('Nonempty empty string stack'); + end; +end; + + +@ +This procedure adds to |str_pool| the string from |ex_buf[0]| through +|ex_buf[ex_buf_length-1]| if it will fit. It assumes the global +variable |ex_buf_length| gives the length of the current string in +|ex_buf|. It then pushes this string onto the literal stack. + +@<Procedures and functions for style-file function execution@>= +procedure add_pool_buf_and_push; +begin +str_room (ex_buf_length); {make sure this string will fit} +ex_buf_ptr := 0; +while (ex_buf_ptr < ex_buf_length) do + begin + append_char (ex_buf[ex_buf_ptr]); + incr(ex_buf_ptr); + end; +push_lit_stk (make_string, stk_str); {and push it onto the stack} +end; + + +@ +@:BibTeX capacity exceeded}{\quad buffer size@> +These macros append a character to |ex_buf|. Which is called depends +on whether the character is known to fit. + +@d append_ex_buf_char(#) == begin + ex_buf[ex_buf_ptr] := #; + incr(ex_buf_ptr); + end +@# +@d append_ex_buf_char_and_check(#) == + begin + if (ex_buf_ptr = buf_size) then + buffer_overflow; + append_ex_buf_char(#); + end + + +@ +@:BibTeX capacity exceeded}{\quad buffer size@> +This procedure adds to the execution buffer the given string in +|str_pool| if it will fit. It assumes the global variable +|ex_buf_length| gives the length of the current string in |ex_buf|, +and thus also gives the location of the next character. + +@<Procedures and functions for style-file function execution@>= +procedure add_buf_pool (@!p_str : str_number); +begin +p_ptr1 := str_start[p_str]; +p_ptr2 := str_start[p_str+1]; +if (ex_buf_length+(p_ptr2-p_ptr1) > buf_size) then + buffer_overflow; +ex_buf_ptr := ex_buf_length; +while (p_ptr1 < p_ptr2) do + begin {copy characters into the buffer} + append_ex_buf_char (str_pool[p_ptr1]); + incr(p_ptr1); + end; +ex_buf_length := ex_buf_ptr; +end; + + +@ +This procedure actually writes onto the \.{.bbl}~file a line of output +(the characters from |out_buf[0]| to |out_buf[out_buf_length-1]|, +after removing trailing |white_space| characters). It also updates +|bbl_line_num|, the line counter. It writes a blank line if and only +if |out_buf| is empty. The program uses this procedure in such a way +that |out_buf| will be nonempty if there have been characters put in +it since the most recent \.{newline\$}. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure output_bbl_line; +label loop_exit,@!exit; +begin +if (out_buf_length <> 0) then {the buffer's not empty} + begin + while (out_buf_length > 0) do {remove trailing |white_space|} + if (lex_class[out_buf[out_buf_length-1]] = white_space) then + decr(out_buf_length) + else + goto loop_exit; +loop_exit: + if (out_buf_length = 0) then {ignore a line of just |white_space|} + return; + out_buf_ptr := 0; + while (out_buf_ptr < out_buf_length) do + begin + write (bbl_file, xchr[out_buf[out_buf_ptr]]); + incr(out_buf_ptr); + end; + end; +write_ln (bbl_file); +incr(bbl_line_num); {update line number} +out_buf_length := 0; {make the next line empty} +exit: +end; + + +@ +@:BibTeX capacity exceeded}{\quad output buffer size@> +This procedure adds to the output buffer the given string in +|str_pool|. It assumes the global variable |out_buf_length| gives the +length of the current string in |out_buf|, and thus also gives the +location for the next character. If there are enough characters +present in the output buffer, it writes one or more lines out to the +\.{.bbl} file. It may break a line at any |white_space| character it +likes, but if it does, it will add two |space|s to the next output +line. + +@<Procedures and functions for style-file function execution@>= +procedure add_out_pool (@!p_str : str_number); +var break_ptr : buf_pointer; {the first character following the line break} +@!end_ptr : buf_pointer; {temporary end-of-buffer pointer} +begin +p_ptr1 := str_start[p_str]; +p_ptr2 := str_start[p_str+1]; +if (out_buf_length+(p_ptr2-p_ptr1) > buf_size) then + overflow('output buffer size ',buf_size); +out_buf_ptr := out_buf_length; +while (p_ptr1 < p_ptr2) do + begin {copy characters into the buffer} + out_buf[out_buf_ptr] := str_pool[p_ptr1]; + incr(p_ptr1); + incr(out_buf_ptr); + end; +out_buf_length := out_buf_ptr; +while (out_buf_length > max_print_line) do + @<Break that line@>; +end; + + +@ +Here we break the line by looking for a |white_space| character, +backwards from |out_buf[max_print_line]| until +|out_buf[min_print_line]|; we break at the |white_space| and indent +the next line two |space|s. The next module handles things when +there's no |white_space| character to break at. + +@<Break that line@>= +begin +end_ptr := out_buf_length; +out_buf_ptr := max_print_line; +while ((lex_class[out_buf[out_buf_ptr]] <> white_space) and + (out_buf_ptr >= min_print_line)) do + decr(out_buf_ptr); +if (out_buf_ptr = min_print_line-1) then {no |white_space| character} + @<Break that unbreakable line@> +else + begin {hit a |white_space| character} + out_buf_length := out_buf_ptr; + break_ptr := out_buf_length + 1; + output_bbl_line; {output what we can} + out_buf[0] := space; + out_buf[1] := space; {start the next line with two |space|s} + out_buf_ptr := 2; + tmp_ptr := break_ptr; + while (tmp_ptr < end_ptr) do {and slide the rest down} + begin + out_buf[out_buf_ptr] := out_buf[tmp_ptr]; + incr(out_buf_ptr); + incr(tmp_ptr); + end; + out_buf_length := end_ptr - break_ptr + 2; + end; +end + + +@ +If there's no |white_space| character to break the line at, we break +it at |out_buf[max_print_line-1]|, append a |comment| character, and +don't indent the next line. + +@<Break that unbreakable line@>= +begin +out_buf[end_ptr] := out_buf[max_print_line-1]; {save this character} +out_buf[max_print_line-1] := comment; {so \TeX\ does the thing right} +out_buf_length := max_print_line; +break_ptr := out_buf_length - 1; {the `|-1|' allows for the restoration} +output_bbl_line; {output what we can,} +out_buf[max_print_line-1] := out_buf[end_ptr]; {restore this character} +out_buf_ptr := 0; +tmp_ptr := break_ptr; +while (tmp_ptr < end_ptr) do {and slide the rest down} + begin + out_buf[out_buf_ptr] := out_buf[tmp_ptr]; + incr(out_buf_ptr); + incr(tmp_ptr); + end; +out_buf_length := end_ptr - break_ptr; +end + + +@ +@^Tuesdays@> +@^windows@> +@:this can't happen}{\quad Unknown function class@> +This procedure executes a single specified function; it is the single +execution-primitive that does everything (except windows, and it takes +Tuesdays off). + +@<|execute_fn| itself@>= +procedure execute_fn (@!ex_fn_loc : hash_loc); +@<Declarations for executing |built_in| functions@> +@!wiz_ptr : wiz_fn_loc; {general |wiz_functions| location} +begin + trace + trace_pr ('execute_fn `'); + trace_pr_pool_str (hash_text[ex_fn_loc]); + trace_pr_ln (''''); + ecart@/ +case (fn_type[ex_fn_loc]) of + built_in : @<Execute a |built_in| function@>; + wiz_defined : @<Execute a |wiz_defined| function@>; + int_literal : push_lit_stk (fn_info[ex_fn_loc], stk_int); + str_literal : push_lit_stk (hash_text[ex_fn_loc], stk_str); + field : @<Execute a field@>; + int_entry_var : @<Execute an |int_entry_var|@>; + str_entry_var : @<Execute a |str_entry_var|@>; + int_global_var : push_lit_stk (fn_info[ex_fn_loc], stk_int); + str_global_var : @<Execute a |str_global_var|@>; + othercases unknwn_function_class_confusion +endcases; +end; + + +@ +To execute a |wiz_defined| function, we just execute all those +functions in its definition, except that the special marker +|quote_next_fn| means we push the next function onto the stack. + +@<Execute a |wiz_defined| function@>= +begin +wiz_ptr := fn_info[ex_fn_loc]; +while (wiz_functions[wiz_ptr] <> end_of_def) do + begin + if (wiz_functions[wiz_ptr] <> quote_next_fn) then + execute_fn (wiz_functions[wiz_ptr]) + else + begin + incr(wiz_ptr); + push_lit_stk (wiz_functions[wiz_ptr], stk_fn); + end; + incr(wiz_ptr); + end; +end + + +@ +This module pushes the string given by the field onto the literal +stack unless it's |missing|, in which case it pushes a special value +onto the stack. + +@<Execute a field@>= +begin +if (not mess_with_entries) then + bst_cant_mess_with_entries_print + else + begin + field_ptr := cite_ptr*num_fields + fn_info[ex_fn_loc]; + if (field_info[field_ptr] = missing) then + push_lit_stk (hash_text[ex_fn_loc], stk_field_missing) + else + push_lit_stk (field_info[field_ptr], stk_str); + end +end + + +@ +This module pushes the integer given by an |int_entry_var| onto the +literal stack. + +@<Execute an |int_entry_var|@>= +begin +if (not mess_with_entries) then + bst_cant_mess_with_entries_print + else + push_lit_stk (entry_ints[cite_ptr*num_ent_ints+fn_info[ex_fn_loc]], + stk_int); +end + + +@ +This module adds the string given by a |str_entry_var| to |str_pool| +via the execution buffer and pushes it onto the literal stack. + +@<Execute a |str_entry_var|@>= +begin +if (not mess_with_entries) then + bst_cant_mess_with_entries_print + else + begin + str_ent_ptr := cite_ptr*num_ent_strs + fn_info[ex_fn_loc];@/ + ex_buf_ptr := 0; {also serves as |ent_chr_ptr|} + 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]); + ex_buf_length := ex_buf_ptr; + add_pool_buf_and_push; {push this string onto the stack} + end; +end + + +@ +This module pushes the string given by a |str_global_var| onto the +literal stack, but it copies the string to |str_pool| (character by +character) only if it has to---it {\it doesn't\/} have to if the +string is static (that is, if the string isn't at the top, temporary +part of the string pool). + +@<Execute a |str_global_var|@>= +begin +str_glb_ptr := fn_info[ex_fn_loc]; +if (glb_str_ptr[str_glb_ptr] > 0) then {we're dealing with a static string} + push_lit_stk (glb_str_ptr[str_glb_ptr],stk_str) + else + begin + str_room(glb_str_end[str_glb_ptr]); + glob_chr_ptr := 0; + while (glob_chr_ptr < glb_str_end[str_glb_ptr]) do {copy the string} + begin + append_char (global_strs[str_glb_ptr][glob_chr_ptr]); + incr(glob_chr_ptr); + end; + push_lit_stk (make_string, stk_str); {and push it onto the stack} + end; +end + + + +@* The built-in functions. +@^add a built-in function@> +@^biblical procreation@> +@^grade inflation@> +This section gives the all the code for all the built-in functions +(including pre-defined |field|s, |str_entry_var|s, and +|int_global_var|s, which technically aren't classified as |built_in|). +To modify or add one, we needn't go anywhere else (with one exception: +The constant |max_pop|, which gives the maximum number of literals +that any of these functions pops off the stack, is defined earlier +because it's needed earlier; thus, if we need to update it, which will +happen if some new |built_in| functions uses more than |max_pop| +literals from the stack, we'll have to go outside this section). +Adding a |built_in| function entails modifying (at least four of) the +five modules marked by ``add a built-in function'' in the index, in +addition to adding the code to execute the function. + +These variables all begin with |b_| and specify the hash-table +locations of the |built_in| functions, except that |b_default| is +pseudo-|built_in|---either it will point to the no-op \.{skip\$} or to +the \.{.bst}-defined function \.{default.type}; it's used when an +entry has a type that's not defined in the \.{.bst} file. + +@<Globals in the outer block@>= +@!b_equals : hash_loc; {\.{=}} +@!b_greater_than : hash_loc; {\.{>}} +@!b_less_than : hash_loc; {\.{<}} +@!b_plus : hash_loc; {\.{+} (this may be changed to an |a_minus|)} +@!b_minus : hash_loc; {\.{-}} +@!b_concatenate : hash_loc; {\.{*}} +@!b_gets : hash_loc; {\.{:=} (formerly, |b_gat|)} +@!b_add_period : hash_loc; {\.{add.period\$}} +@!b_call_type : hash_loc; {\.{call.type\$}} +@!b_change_case : hash_loc; {\.{change.case\$}} +@!b_chr_to_int : hash_loc; {\.{chr.to.int\$}} +@!b_cite : hash_loc; {\.{cite\$}} +@!b_duplicate : hash_loc; {\.{duplicate\$}} +@!b_empty : hash_loc; {\.{empty\$}} +@!b_format_name : hash_loc; {\.{format.name\$}} +@!b_if : hash_loc; {\.{if\$}} +@!b_int_to_chr : hash_loc; {\.{int.to.chr\$}} +@!b_int_to_str : hash_loc; {\.{int.to.str\$}} +@!b_missing : hash_loc; {\.{missing\$}} +@!b_newline : hash_loc; {\.{newline\$}} +@!b_num_names : hash_loc; {\.{num.names\$}} +@!b_pop : hash_loc; {\.{pop\$}} +@!b_preamble : hash_loc; {\.{preamble\$}} +@!b_purify : hash_loc; {\.{purify\$}} +@!b_quote : hash_loc; {\.{quote\$}} +@!b_skip : hash_loc; {\.{skip\$}} +@!b_stack : hash_loc; {\.{stack\$}} +@!b_substring : hash_loc; {\.{substring\$}} +@!b_swap : hash_loc; {\.{swap\$}} +@!b_text_length : hash_loc; {\.{text.length\$}} +@!b_text_prefix : hash_loc; {\.{text.prefix\$}} +@!b_top_stack : hash_loc; {\.{top\$}} +@!b_type : hash_loc; {\.{type\$}} +@!b_warning : hash_loc; {\.{warning\$}} +@!b_while : hash_loc; {\.{while\$}} +@!b_width : hash_loc; {\.{width\$}} +@!b_write : hash_loc; {\.{write\$}} +@!b_default : hash_loc; {either \.{skip\$} or \.{default.type}} +@# + stat + @!blt_in_loc : array[blt_in_range] of hash_loc; {for execution counts} + @!execution_count : array[blt_in_range] of integer; {the same} + @!total_ex_count : integer; {the sum of all |execution_count|s} + @!blt_in_ptr : blt_in_range; {a pointer into |blt_in_loc|} + tats@/ + + +@ +Where |blt_in_range| gives the legal |built_in| function numbers. + +@<Types in the outer block@>= +@!blt_in_range = 0..num_blt_in_fns; + + +@ +@^add a built-in function@> +These constants all begin with |n_| and are used for the |case| +statement that determines which |built_in| function to execute. + +@d n_equals = 0 {\.{=}} +@d n_greater_than = 1 {\.{>}} +@d n_less_than = 2 {\.{<}} +@d n_plus = 3 {\.{+}} +@d n_minus = 4 {\.{-}} +@d n_concatenate = 5 {\.{*}} +@d n_gets = 6 {\.{:=}} +@d n_add_period = 7 {\.{add.period\$}} +@d n_call_type = 8 {\.{call.type\$}} +@d n_change_case = 9 {\.{change.case\$}} +@d n_chr_to_int = 10 {\.{chr.to.int\$}} +@d n_cite = 11 {\.{cite\$} (this may start a riot)} +@d n_duplicate = 12 {\.{duplicate\$}} +@d n_empty = 13 {\.{empty\$}} +@d n_format_name = 14 {\.{format.name\$}} +@d n_if = 15 {\.{if\$}} +@d n_int_to_chr = 16 {\.{int.to.chr\$}} +@d n_int_to_str = 17 {\.{int.to.str\$}} +@d n_missing = 18 {\.{missing\$}} +@d n_newline = 19 {\.{newline\$}} +@d n_num_names = 20 {\.{num.names\$}} +@d n_pop = 21 {\.{pop\$}} +@d n_preamble = 22 {\.{preamble\$}} +@d n_purify = 23 {\.{purify\$}} +@d n_quote = 24 {\.{quote\$}} +@d n_skip = 25 {\.{skip\$}} +@d n_stack = 26 {\.{stack\$}} +@d n_substring = 27 {\.{substring\$}} +@d n_swap = 28 {\.{swap\$}} +@d n_text_length = 29 {\.{text.length\$}} +@d n_text_prefix = 30 {\.{text.prefix\$}} +@d n_top_stack = 31 {\.{top\$}} +@d n_type = 32 {\.{type\$}} +@d n_warning = 33 {\.{warning\$}} +@d n_while = 34 {\.{while\$}} +@d n_width = 35 {\.{width\$}} +@d n_write = 36 {\.{write\$}} + +@<Constants in the outer block@>= +@!num_blt_in_fns = 37; {one more than the previous number} + + +@ +@^add a built-in function@> +@^important note@> +It's time for us to insert more pre-defined strings into |str_pool| +(and thus the hash table) and to insert the |built_in| functions into +the hash table. The strings corresponding to these functions should +contain no upper-case letters, and they must all be exactly +|longest_pds| characters long. The |build_in| routine (to appear +shortly) does the work. + +Important note: These pre-definitions must not have any glitches or the +program may bomb because the |log_file| hasn't been opened yet. + +@<Pre-define certain strings@>= +build_in('= ',1,b_equals,n_equals); +build_in('> ',1,b_greater_than,n_greater_than); +build_in('< ',1,b_less_than,n_less_than); +build_in('+ ',1,b_plus,n_plus); +build_in('- ',1,b_minus,n_minus); +build_in('* ',1,b_concatenate,n_concatenate); +build_in(':= ',2,b_gets,n_gets); +build_in('add.period$ ',11,b_add_period,n_add_period); +build_in('call.type$ ',10,b_call_type,n_call_type); +build_in('change.case$',12,b_change_case,n_change_case); +build_in('chr.to.int$ ',11,b_chr_to_int,n_chr_to_int); +build_in('cite$ ',5,b_cite,n_cite); +build_in('duplicate$ ',10,b_duplicate,n_duplicate); +build_in('empty$ ',6,b_empty,n_empty); +build_in('format.name$',12,b_format_name,n_format_name); +build_in('if$ ',3,b_if,n_if); +build_in('int.to.chr$ ',11,b_int_to_chr,n_int_to_chr); +build_in('int.to.str$ ',11,b_int_to_str,n_int_to_str); +build_in('missing$ ',8,b_missing,n_missing); +build_in('newline$ ',8,b_newline,n_newline); +build_in('num.names$ ',10,b_num_names,n_num_names); +build_in('pop$ ',4,b_pop,n_pop); +build_in('preamble$ ',9,b_preamble,n_preamble); +build_in('purify$ ',7,b_purify,n_purify); +build_in('quote$ ',6,b_quote,n_quote); +build_in('skip$ ',5,b_skip,n_skip); +build_in('stack$ ',6,b_stack,n_stack); +build_in('substring$ ',10,b_substring,n_substring); +build_in('swap$ ',5,b_swap,n_swap); +build_in('text.length$',12,b_text_length,n_text_length); +build_in('text.prefix$',12,b_text_prefix,n_text_prefix); +build_in('top$ ',4,b_top_stack,n_top_stack); +build_in('type$ ',5,b_type,n_type); +build_in('warning$ ',8,b_warning,n_warning); +build_in('width$ ',6,b_width,n_width); +build_in('while$ ',6,b_while,n_while); +build_in('width$ ',6,b_width,n_width); +build_in('write$ ',6,b_write,n_write); + + +@ +This procedure inserts a |built_in| function into the hash table and +initializes the corresponding pre-defined string (of length at most +|longest_pds|). The array |fn_info| contains a number from 0 through +the number of |built_in| functions minus 1 (i.e., |num_blt_in_fns - 1| +if we're keeping statistics); this number is used by a |case| +statement to execute this function and is used for keeping execution +counts when keeping statistics. + +@<Procedures and functions for handling numbers, characters, and strings@>= +procedure build_in (@!pds:pds_type; @!len:pds_len; var fn_hash_loc:hash_loc; + @!blt_in_num:blt_in_range); +begin +pre_define (pds,len,bst_fn_ilk);@/ +fn_hash_loc := pre_def_loc; {the |pre_define| routine sets |pre_def_loc|} +fn_type[fn_hash_loc] := built_in; +fn_info[fn_hash_loc] := blt_in_num; + stat + blt_in_loc[blt_in_num] := fn_hash_loc;@/ + execution_count[blt_in_num] := 0; {initialize the function-execution count} + tats@/ +end; + + +@ +This is a procedure so that |initialize| is smaller. + +@<Procedures and functions for handling numbers, characters, and strings@>= +procedure pre_def_certain_strings; +begin +@<Pre-define certain strings@>@; +end; + + +@ +These variables all begin with |s_| and specify the locations in +|str_pool| of certain often-used strings that the \.{.bst} commands +need. The |s_preamble| array is big enough to allow an average of one +\.{preamble\$} command per \.{.bib} file. + +@<Globals in the outer block@>= +@!s_null : str_number; {the null string} +@!s_default : str_number; {\.{default.type}, for unknown entry types} +@!s_t : str_number; {\.{t}, for |title_lowers| case conversion} +@!s_l : str_number; {\.{l}, for |all_lowers| case conversion} +@!s_u : str_number; {\.{u}, for |all_uppers| case conversion} +@!s_preamble : array[bib_number] of str_number; + {for the \.{preamble\$} |built_in| function} + + +@ +These constants all begin with |n_| and are used for the |case| +statement that determines which, if any, control sequence we're +dealing with; a control sequence of interest will be either one of the +undotted characters `\.{\\i}' or `\.{\\j}' or one of the foreign +characters in Table~3.2 of the \LaTeX\ manual. + +@d n_i = 0 {\.{i}, for the undotted character \.{\\i}} +@d n_j = 1 {\.{j}, for the undotted character \.{\\j}} +@d n_oe = 2 {\.{oe}, for the foreign character \.{\\oe}} +@d n_oe_upper = 3 {\.{OE}, for the foreign character \.{\\OE}} +@d n_ae = 4 {\.{ae}, for the foreign character \.{\\ae}} +@d n_ae_upper = 5 {\.{AE}, for the foreign character \.{\\AE}} +@d n_aa = 6 {\.{aa}, for the foreign character \.{\\aa}} +@d n_aa_upper = 7 {\.{AA}, for the foreign character \.{\\AA}} +@d n_o = 8 {\.{o}, for the foreign character \.{\\o}} +@d n_o_upper = 9 {\.{O}, for the foreign character \.{\\O}} +@d n_l = 10 {\.{l}, for the foreign character \.{\\l}} +@d n_l_upper = 11 {\.{L}, for the foreign character \.{\\L}} +@d n_ss = 12 {\.{ss}, for the foreign character \.{\\ss}} + + +@ +@^important note@> +@.default.type@> +Here we pre-define a few strings used in executing the \.{.bst} file: +the null string, which is sometimes pushed onto the stack; a string +used for default entry types; and some control sequences used to spot +foreign characters. We also initialize the |s_preamble| array to +empty. These pre-defined strings must all be exactly |longest_pds| +characters long. + +Important note: These pre-definitions must not have any glitches or +the program may bomb because the |log_file| hasn't been opened yet, +and |text_ilk|s should be pre-defined here, not earlier, for +\.{.bst}-function-execution purposes. + +@<Pre-define certain strings@>= +pre_define(' ',0,text_ilk); s_null := hash_text[pre_def_loc]; +fn_type[pre_def_loc] := str_literal;@/ +pre_define('default.type',12,text_ilk); s_default := hash_text[pre_def_loc]; +fn_type[pre_def_loc] := str_literal;@/ +b_default := b_skip; {this may be changed to the \.{default.type} function} +preamble_ptr := 0; {initialize the |s_preamble| array} +pre_define('i ',1,control_seq_ilk); +ilk_info[pre_def_loc] := n_i; +pre_define('j ',1,control_seq_ilk); +ilk_info[pre_def_loc] := n_j; +pre_define('oe ',2,control_seq_ilk); +ilk_info[pre_def_loc] := n_oe; +pre_define('OE ',2,control_seq_ilk); +ilk_info[pre_def_loc] := n_oe_upper; +pre_define('ae ',2,control_seq_ilk); +ilk_info[pre_def_loc] := n_ae; +pre_define('AE ',2,control_seq_ilk); +ilk_info[pre_def_loc] := n_ae_upper; +pre_define('aa ',2,control_seq_ilk); +ilk_info[pre_def_loc] := n_aa; +pre_define('AA ',2,control_seq_ilk); +ilk_info[pre_def_loc] := n_aa_upper; +pre_define('o ',1,control_seq_ilk); +ilk_info[pre_def_loc] := n_o; +pre_define('O ',1,control_seq_ilk); +ilk_info[pre_def_loc] := n_o_upper; +pre_define('l ',1,control_seq_ilk); +ilk_info[pre_def_loc] := n_l; +pre_define('L ',1,control_seq_ilk); +ilk_info[pre_def_loc] := n_l_upper; +pre_define('ss ',2,control_seq_ilk); +ilk_info[pre_def_loc] := n_ss; + + +@ +@^important note@> +@.crossref@> +@.entry.max\$@> +@.global.max\$@> +@.sort.key\$@> +Now we pre-define any built-in |field|s, |str_entry_var|s, and +|int_global_var|s; these strings must all be exactly |longest_pds| +characters long. Note that although these are built-in functions, we +classify them (in the |fn_type| array) otherwise. + +Important note: These pre-definitions must not have any glitches or +the program may bomb because the |log_file| hasn't been opened yet. + +@<Pre-define certain strings@>= +pre_define('crossref ',8,bst_fn_ilk); +fn_type[pre_def_loc] := field;@/ +fn_info[pre_def_loc] := num_fields; {give this |field| a number} +crossref_num := num_fields; +incr(num_fields);@/ +num_pre_defined_fields := num_fields; {that's it for pre-defined |field|s} +pre_define('sort.key$ ',9,bst_fn_ilk); +fn_type[pre_def_loc] := str_entry_var; +fn_info[pre_def_loc] := num_ent_strs; {give this |str_entry_var| a number} +sort_key_num := num_ent_strs; +incr(num_ent_strs);@/ +pre_define('entry.max$ ',10,bst_fn_ilk); +fn_type[pre_def_loc] := int_global_var; +fn_info[pre_def_loc] := ent_str_size; {initialize this |int_global_var|} +pre_define('global.max$ ',11,bst_fn_ilk); +fn_type[pre_def_loc] := int_global_var; +fn_info[pre_def_loc] := glob_str_size; {initialize this |int_global_var|} + + +@ +@^add a built-in function@> +@:this can't happen}{\quad Unknown built-in function@> +This module branches to the code for the appropriate |built_in| +function. Only three---{\.{call.type\$}}, {\.{if\$}}, and +{\.{while\$}}---do a recursive call. + +@<Execute a |built_in| function@>= +begin + stat {update this function's execution count} + incr(execution_count[fn_info[ex_fn_loc]]); + tats@/ +case (fn_info[ex_fn_loc]) of + n_equals : x_equals; + n_greater_than : x_greater_than; + n_less_than : x_less_than; + n_plus : x_plus; + n_minus : x_minus; + n_concatenate : x_concatenate; + n_gets : x_gets; + n_add_period : x_add_period; + n_call_type : @<|execute_fn|({\.{call.type\$}})@>; + n_change_case : x_change_case; + n_chr_to_int : x_chr_to_int; + n_cite : x_cite; + n_duplicate : x_duplicate; + n_empty : x_empty; + n_format_name : x_format_name; + n_if : @<|execute_fn|({\.{if\$}})@>; + n_int_to_chr : x_int_to_chr; + n_int_to_str : x_int_to_str; + n_missing : x_missing; + n_newline : @<|execute_fn|({\.{newline\$}})@>; + n_num_names : x_num_names; + n_pop : @<|execute_fn|({\.{pop\$}})@>; + n_preamble : x_preamble; + n_purify : x_purify; + n_quote : x_quote; + n_skip : @<|execute_fn|({\.{skip\$}})@>; + n_stack : @<|execute_fn|({\.{stack\$}})@>; + n_substring : x_substring; + n_swap : x_swap; + n_text_length : x_text_length; + n_text_prefix : x_text_prefix; + n_top_stack : @<|execute_fn|({\.{top\$}})@>; + n_type : x_type; + n_warning : x_warning; + n_while : @<|execute_fn|({\.{while\$}})@>; + n_width : x_width; + n_write : x_write; + othercases confusion ('Unknown built-in function') +endcases; +end + + +@ +@^add a built-in function@> +@^gymnastics@> +This extra level of module-pointing allows a uniformity of module +names for the |built_in| functions, regardless of whether they do a +recursive call to |execute_fn| or are trivial (a single statement). +Those that do a recursive call are left as part of |execute_fn|, +avoiding \PASCAL's forward procedure mechanism, and those that don't +(except for the single-statement ones) are made into procedures so +that |execute_fn| doesn't get too large. + +@<Procedures and functions for style-file function execution@>= +@<|execute_fn|({\.{=}})@>@; +@<|execute_fn|({\.{>}})@>@; +@<|execute_fn|({\.{<}})@>@; +@<|execute_fn|({\.{+}})@>@; +@<|execute_fn|({\.{-}})@>@; +@<|execute_fn|({\.{*}})@>@; +@<|execute_fn|({\.{:=}})@>@; +@<|execute_fn|({\.{add.period\$}})@>@; +@<|execute_fn|({\.{change.case\$}})@>@; +@<|execute_fn|({\.{chr.to.int\$}})@>@; +@<|execute_fn|({\.{cite\$}})@>@; +@<|execute_fn|({\.{duplicate\$}})@>@; +@<|execute_fn|({\.{empty\$}})@>@; +@<|execute_fn|({\.{format.name\$}})@>@; +@<|execute_fn|({\.{int.to.chr\$}})@>@; +@<|execute_fn|({\.{int.to.str\$}})@>@; +@<|execute_fn|({\.{missing\$}})@>@; +@<|execute_fn|({\.{num.names\$}})@>@; +@<|execute_fn|({\.{preamble\$}})@>@; +@<|execute_fn|({\.{purify\$}})@>@; +@<|execute_fn|({\.{quote\$}})@>@; +@<|execute_fn|({\.{substring\$}})@>@; +@<|execute_fn|({\.{swap\$}})@>@; +@<|execute_fn|({\.{text.length\$}})@>@; +@<|execute_fn|({\.{text.prefix\$}})@>@; +@<|execute_fn|({\.{type\$}})@>@; +@<|execute_fn|({\.{warning\$}})@>@; +@<|execute_fn|({\.{width\$}})@>@; +@<|execute_fn|({\.{write\$}})@>@; +@<|execute_fn| itself@> + + +@ +Now it's time to declare some things for executing |built_in| +functions only. These (and only these) variables are used +recursively, so they can't be global. + +@d end_while = 51 {stop executing the \.{while\$} function} + +@<Declarations for executing |built_in| functions@>= +label end_while; +var r_pop_lt1,@!r_pop_lt2 : integer; {stack literals for \.{while\$}} +@!r_pop_tp1,@!r_pop_tp2 : stk_type; {stack types for \.{while\$}} + + +@ +These are nonrecursive variables that |execute_fn| uses. Declaring +them here (instead of in the previous module) saves execution time and +stack space on most machines. + +@d name_buf == sv_buffer {an alias, a buffer for manipulating names} + +@<Globals in the outer block@>= +@!pop_lit1,@!pop_lit2,@!pop_lit3 : integer; {stack literals} +@!pop_typ1,@!pop_typ2,@!pop_typ3 : stk_type; {stack types} +@!sp_ptr : pool_pointer; {for manipulating |str_pool| strings} +@!sp_xptr1,@!sp_xptr2 : pool_pointer; {more of the same} +@!sp_end : pool_pointer; {marks the end of a |str_pool| string} +@!sp_length,sp2_length : pool_pointer; {lengths of |str_pool| strings} +@!sp_brace_level : integer; {for scanning |str_pool| strings} +@!ex_buf_xptr,@!ex_buf_yptr : buf_pointer; {extra |ex_buf| locations} +@!control_seq_loc : hash_loc; {hash-table loc of a control sequence} +@!preceding_white : boolean; {used in scanning strings} +@!and_found : boolean; {to stop the loop that looks for an ``and''} +@!num_names : integer; {for counting names} +@!name_bf_ptr : buf_pointer; {general |name_buf| location} +@!name_bf_xptr,@!name_bf_yptr : buf_pointer; {and two more} +@!nm_brace_level : integer; {for scanning |name_buf| strings} +@!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} +@!num_tokens : buf_pointer; {this counts name tokens} +@!token_starting : boolean; {used in scanning name tokens} +@!alpha_found : boolean; {used in scanning the format string} +@!double_letter,@!end_of_group,@!to_be_written : boolean; {the same} +@!first_start : buf_pointer; {start-ptr into |name_tok| for the first name} +@!first_end : buf_pointer; {end-ptr into |name_tok| for the first name} +@!last_end : buf_pointer; {end-ptr into |name_tok| for the last name} +@!von_start : buf_pointer; {start-ptr into |name_tok| for the von name} +@!von_end : buf_pointer; {end-ptr into |name_tok| for the von name} +@!jr_end : buf_pointer; {end-ptr into |name_tok| for the jr name} +@!cur_token,@!last_token : buf_pointer; {|name_tok| ptrs for outputting tokens} +@!use_default : boolean; {for the inter-token intra-name part string} +@!num_commas : buf_pointer; {used to determine the name syntax} +@!comma1,@!comma2 : buf_pointer; {ptrs into |name_tok|} +@!num_text_chars : buf_pointer; {special characters count as one} + + +@ +The |built_in| function {\.{=}} pops the top two (integer or string) +literals, compares them, and pushes the integer 1 if they're equal, 0 +otherwise. If they're not either both string or both integer, it +complains and pushes the integer 0. + +@<|execute_fn|({\.{=}})@>= +procedure x_equals; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if (pop_typ1 <> pop_typ2) then + begin + if ((pop_typ1 <> stk_empty) and (pop_typ2 <> stk_empty)) then + begin + print_stk_lit (pop_lit1,pop_typ1); + print (', '); + print_stk_lit (pop_lit2,pop_typ2); + print_newline; + bst_ex_warn ('---they aren''t the same literal types'); + end; + push_lit_stk (0, stk_int); + end +else if ((pop_typ1 <> stk_int) and (pop_typ1 <> stk_str)) then + begin + if (pop_typ1 <> stk_empty) then + begin + print_stk_lit (pop_lit1,pop_typ1); + bst_ex_warn (', not an integer or a string,'); + end; + push_lit_stk (0, stk_int); + end +else if (pop_typ1 = stk_int) then + if (pop_lit2 = pop_lit1) then + push_lit_stk (1, stk_int) + else + push_lit_stk (0, stk_int) +else + if (str_eq_str (pop_lit2,pop_lit1)) then + push_lit_stk (1, stk_int) + else + push_lit_stk (0, stk_int); +end; + + +@ +The |built_in| function {\.{>}} pops the top two (integer) literals, +compares them, and pushes the integer 1 if the second is greater than +the first, 0 otherwise. If either isn't an integer literal, it +complains and pushes the integer 0. + +@<|execute_fn|({\.{>}})@>= +procedure x_greater_than; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if (pop_typ1 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_int); + push_lit_stk (0, stk_int); + end +else if (pop_typ2 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_int); + push_lit_stk (0, stk_int); + end +else + if (pop_lit2 > pop_lit1) then + push_lit_stk (1, stk_int) + else + push_lit_stk (0, stk_int); +end; + + +@ +The |built_in| function {\.{<}} pops the top two (integer) literals, +compares them, and pushes the integer 1 if the second is less than the +first, 0 otherwise. If either isn't an integer literal, it complains +and pushes the integer 0. + +@<|execute_fn|({\.{<}})@>= +procedure x_less_than; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if (pop_typ1 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_int); + push_lit_stk (0, stk_int); + end +else if (pop_typ2 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_int); + push_lit_stk (0, stk_int); + end +else + if (pop_lit2 < pop_lit1) then + push_lit_stk (1, stk_int) + else + push_lit_stk (0, stk_int); +end; + + +@ +The |built_in| function {\.{+}} pops the top two (integer) literals +and pushes their sum. If either isn't an integer literal, it +complains and pushes the integer 0. + +@<|execute_fn|({\.{+}})@>= +procedure x_plus; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if (pop_typ1 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_int); + push_lit_stk (0, stk_int); + end +else if (pop_typ2 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_int); + push_lit_stk (0, stk_int); + end +else + push_lit_stk (pop_lit2+pop_lit1, stk_int); +end; + + +@ +The |built_in| function {\.{-}} pops the top two (integer) literals +and pushes their difference (the first subtracted from the second). +If either isn't an integer literal, it complains and pushes the +integer 0. + +@<|execute_fn|({\.{-}})@>= +procedure x_minus; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if (pop_typ1 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_int); + push_lit_stk (0, stk_int); + end +else if (pop_typ2 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_int); + push_lit_stk (0, stk_int); + end +else + push_lit_stk (pop_lit2-pop_lit1, stk_int); +end; + + +@ +The |built_in| function {\.{*}} pops the top two (string) literals, +concatenates them (in reverse order, that is, the order in which +pushed), and pushes the resulting string back onto the stack. If +either isn't a string literal, it complains and pushes the null +string. + +@<|execute_fn|({\.{*}})@>= +procedure x_concatenate; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if (pop_typ1 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str); + push_lit_stk (s_null, stk_str); + end +else if (pop_typ2 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_str); + push_lit_stk (s_null, stk_str); + end +else + @<Concatenate the two strings and push@>; +end; + + +@ +@^push the literal stack@> +Often both strings will be at the top of the string pool, in which +case we just move some pointers. Furthermore, it's worth doing some +special stuff in case either string is null, since empirically this +seems to happen about $20\%$ of the time. In any case, we don't need +the execution buffer---we simple move the strings around in the string +pool when necessary. + +@<Concatenate the two strings and push@>= +begin +if (pop_lit2 >= cmd_str_ptr) then + if (pop_lit1 >= cmd_str_ptr) then + begin + str_start[pop_lit1] := str_start[pop_lit1+1]; + unflush_string; + incr(lit_stk_ptr); + end + else if (length(pop_lit2) = 0) then + push_lit_stk (pop_lit1, stk_str) + else {|pop_lit2| is nonnull, only |pop_lit1| is below |cmd_str_ptr|} + begin + pool_ptr := str_start[pop_lit2+1]; + str_room (length(pop_lit1)); + sp_ptr := str_start[pop_lit1]; + sp_end := str_start[pop_lit1+1]; + while (sp_ptr < sp_end) do + begin + append_char (str_pool[sp_ptr]); + incr(sp_ptr); + end; + push_lit_stk (make_string, stk_str); {and push it onto the stack} + end +else + @<Concatenate them and push when |pop_lit2 < cmd_str_ptr|@>; +end + + +@ +@^push the literal stack@> +We simply continue the previous module. + +@<Concatenate them and push when |pop_lit2 < cmd_str_ptr|@>= +begin +if (pop_lit1 >= cmd_str_ptr) then + if (length(pop_lit2) = 0) then + begin + unflush_string; + lit_stack[lit_stk_ptr] := pop_lit1; + incr(lit_stk_ptr); + end + else if (length(pop_lit1) = 0) then + incr(lit_stk_ptr) + else {both strings nonnull, only |pop_lit2| is below |cmd_str_ptr|} + begin + sp_length := length(pop_lit1); + sp2_length := length(pop_lit2); + str_room (sp_length + sp2_length); + sp_ptr := str_start[pop_lit1+1]; + sp_end := str_start[pop_lit1]; + sp_xptr1 := sp_ptr + sp2_length; + while (sp_ptr > sp_end) do {slide up |pop_lit1|} + begin + decr(sp_ptr); + decr(sp_xptr1); + str_pool[sp_xptr1] := str_pool[sp_ptr]; + end; + sp_ptr := str_start[pop_lit2]; + sp_end := str_start[pop_lit2+1]; + while (sp_ptr < sp_end) do {slide up |pop_lit2|} + begin + append_char (str_pool[sp_ptr]); + incr(sp_ptr); + end; + pool_ptr := pool_ptr + sp_length; + push_lit_stk (make_string, stk_str); {and push it onto the stack} + end +else + @<Concatenate them and push when |pop_lit1,pop_lit2 < cmd_str_ptr|@>; +end + + +@ +@^push the literal stack@> +Again, we simply continue the previous module. + +@<Concatenate them and push when |pop_lit1,pop_lit2 < cmd_str_ptr|@>= +begin +if (length(pop_lit1) = 0) then + incr(lit_stk_ptr) +else if (length(pop_lit2) = 0) then + push_lit_stk (pop_lit1, stk_str) +else {both strings are nonnull, and both are below |cmd_str_ptr|} + begin + str_room (length(pop_lit1) + length(pop_lit2)); + sp_ptr := str_start[pop_lit2]; + sp_end := str_start[pop_lit2+1]; + while (sp_ptr < sp_end) do {slide up |pop_lit2|} + begin + append_char (str_pool[sp_ptr]); + incr(sp_ptr); + end; + sp_ptr := str_start[pop_lit1]; + sp_end := str_start[pop_lit1+1]; + while (sp_ptr < sp_end) do {slide up |pop_lit1|} + begin + append_char (str_pool[sp_ptr]); + incr(sp_ptr); + end; + push_lit_stk (make_string, stk_str); {and push it onto the stack} + end; +end + + +@ +The |built_in| function {\.{:=}} pops the top two literals and assigns +to the first (which must be an |int_entry_var|, a |str_entry_var|, an +|int_global_var|, or a |str_global_var|) the value of the second; +it complains if the value isn't of the appropriate type. + +@<|execute_fn|({\.{:=}})@>= +procedure x_gets; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if (pop_typ1 <> stk_fn) then + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_fn) +else if ((not mess_with_entries) and + ((fn_type[pop_lit1] = str_entry_var) or + (fn_type[pop_lit1] = int_entry_var))) then + bst_cant_mess_with_entries_print +else + case (fn_type[pop_lit1]) of + int_entry_var : @<Assign to an |int_entry_var|@>; + str_entry_var : @<Assign to a |str_entry_var|@>; + int_global_var : @<Assign to an |int_global_var|@>; + str_global_var : @<Assign to a |str_global_var|@>; + othercases begin + print ('You can''t assign to type '); + print_fn_class (pop_lit1); + bst_ex_warn (', a nonvariable function class'); + end + endcases; +end; + + +@ +This module checks that what we're about to assign is really an +integer, and then assigns. + +@<Assign to an |int_entry_var|@>= +if (pop_typ2 <> stk_int) then + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_int) + else + entry_ints[cite_ptr*num_ent_ints+fn_info[pop_lit1]] := pop_lit2 + + +@ +@.String size exceeded@> +It's time for a complaint if either of the two (entry or global) +string lengths is exceeded. + +@d bst_string_size_exceeded(#) == begin + bst_1print_string_size_exceeded; + print (#); + bst_2print_string_size_exceeded; + end + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure bst_1print_string_size_exceeded; +begin +print ('Warning--you''ve exceeded '); +end; +@# +procedure bst_2print_string_size_exceeded; +begin +print ('-string-size,'); +bst_mild_ex_warn_print; +print_ln ('*Please notify the bibstyle designer*'); +end; + + +@ +@.entry string size exceeded@> +@:String size exceeded}{\quad entry string size@> +This module checks that what we're about to assign is really a +string, and then assigns. + +@<Assign to a |str_entry_var|@>= +begin +if (pop_typ2 <> stk_str) then + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_str) + else + begin + str_ent_ptr := cite_ptr*num_ent_strs + fn_info[pop_lit1]; + ent_chr_ptr := 0; + sp_ptr := str_start[pop_lit2]; + sp_xptr1 := str_start[pop_lit2+1]; + if (sp_xptr1-sp_ptr > ent_str_size) then + begin + bst_string_size_exceeded (ent_str_size:0,', the entry'); + sp_xptr1 := sp_ptr + ent_str_size; + end; + 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; + end +end + + +@ +This module checks that what we're about to assign is really an +integer, and then assigns. + +@<Assign to an |int_global_var|@>= +if (pop_typ2 <> stk_int) then + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_int) + else + fn_info[pop_lit1] := pop_lit2 + + +@ +@.global string size exceeded@> +@:String size exceeded}{\quad global string size@> +This module checks that what we're about to assign is really a +string, and then assigns. + +@<Assign to a |str_global_var|@>= +begin +if (pop_typ2 <> stk_str) then + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_str) + else + begin + str_glb_ptr := fn_info[pop_lit1]; + if (pop_lit2 < cmd_str_ptr) then + glb_str_ptr[str_glb_ptr] := pop_lit2 + else + begin + glb_str_ptr[str_glb_ptr] := 0; + glob_chr_ptr := 0; + sp_ptr := str_start[pop_lit2]; + sp_end := str_start[pop_lit2+1]; + if (sp_end - sp_ptr > glob_str_size) then + begin + bst_string_size_exceeded (glob_str_size:0,', the global'); + sp_end := sp_ptr + glob_str_size; + end; + while (sp_ptr < sp_end) do + begin {copy characters into |global_strs|} + global_strs[str_glb_ptr][glob_chr_ptr] := str_pool[sp_ptr]; + incr(glob_chr_ptr); + incr(sp_ptr); + end; + glb_str_end[str_glb_ptr] := glob_chr_ptr; + end; + end +end + + +@ +The |built_in| function {\.{add.period\$}} pops the top (string) +literal, adds a |period| to a nonnull string if its last +non|right_brace| character isn't a |period|, |question_mark|, or +|exclamation_mark|, and pushes this resulting string back onto the +stack. If the literal isn't a string, it complains and pushes the +null string. + +@<|execute_fn|({\.{add.period\$}})@>= +procedure x_add_period; +label loop_exit; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str); + push_lit_stk (s_null, stk_str); + end +else if (length(pop_lit1) = 0) then {don't add |period| to the null string} + push_lit_stk (s_null, stk_str) +else + @<Add the |period|, if necessary, and push@>; +end; + + +@ +@^push the literal stack@> +Here we scan backwards from the end of the string, skipping +non|right_brace| characters, to see if we have to add the |period|. + +@<Add the |period|, if necessary, and push@>= +begin +sp_ptr := str_start[pop_lit1+1]; +sp_end := str_start[pop_lit1]; +while (sp_ptr > sp_end) do {find a non|right_brace|} + begin + decr(sp_ptr); + if (str_pool[sp_ptr] <> right_brace) then + goto loop_exit; + end; +loop_exit: +case (str_pool[sp_ptr]) of + period, + question_mark, + exclamation_mark : + repush_string; + othercases + @<Add the |period| (it's necessary) and push@> +endcases; +end + + +@ +Ok guys, we really have to do it. + +@<Add the |period| (it's necessary) and push@>= +begin +if (pop_lit1 < cmd_str_ptr) then + begin + str_room (length(pop_lit1)+1); + sp_ptr := str_start[pop_lit1]; + sp_end := str_start[pop_lit1+1]; + while (sp_ptr < sp_end) do {slide |pop_lit1| atop the string pool} + begin + append_char (str_pool[sp_ptr]); + incr(sp_ptr); + end; + end +else {the string is already there} + begin + pool_ptr := str_start[pop_lit1+1]; + str_room (1); + end; +append_char (period); +push_lit_stk (make_string, stk_str); +end + + +@ +The |built_in| function {\.{call.type\$}} executes the function +specified in |type_list| for this entry unless it's |undefined|, in +which case it executes the default function \.{default.type} defined +in the \.{.bst} file, or unless it's |empty|, in which case it does +nothing. + +@<|execute_fn|({\.{call.type\$}})@>= +begin +if (not mess_with_entries) then + bst_cant_mess_with_entries_print + else + if (type_list[cite_ptr] = undefined) then + execute_fn (b_default) + else if (type_list[cite_ptr] = empty) then + do_nothing + else + execute_fn (type_list[cite_ptr]); +end + + +@ +The |built_in| function {\.{change.case\$}} pops the top two (string) +literals; it changes the case of the second according to the +specifications of the first, as follows. (Note: The word `letters' in +the next sentence refers only to those at brace-level~0, the top-most +brace level; no other characters are changed, except perhaps for +special characters, described shortly.) If the first literal is the +string~\.{t}, it converts to lower case all letters except the very +first character in the string, which it leaves alone, and except the +first character following any |colon| and then nonnull |white_space|, +which it also leaves alone; if it's the string~\.{l}, it converts all +letters to lower case; if it's the string~\.{u}, it converts all +letters to upper case; and if it's anything else, it complains and +does no conversion. It then pushes this resulting string. If either +type is incorrect, it complains and pushes the null string; however, +if both types are correct but the specification string (i.e., the +first string) isn't one of the legal ones, it merely pushes the second +back onto the stack, after complaining. (Another note: It ignores +case differences in the specification string; for example, the strings +\.{t} and \.{T} are equivalent for the purposes of this |built_in| +function.) + +@d ok_pascal_i_give_up = 21 + +@<|execute_fn|({\.{change.case\$}})@>= +procedure x_change_case; +label ok_pascal_i_give_up; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if (pop_typ1 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str); + push_lit_stk (s_null, stk_str); + end +else if (pop_typ2 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_str); + push_lit_stk (s_null, stk_str); + end +else + begin + @<Determine the case-conversion type@>; + ex_buf_length := 0; + add_buf_pool (pop_lit2); + @<Perform the case conversion@>; + add_pool_buf_and_push; {push this string onto the stack} + end; +end; + + +@ +First we define a few variables for case conversion. The constant +definitions, to be used in |case| statements, are in order of probable +frequency. + +@d title_lowers = 0 {representing the string \.{t}} +@d all_lowers = 1 {representing the string \.{l}} +@d all_uppers = 2 {representing the string \.{u}} +@d bad_conversion = 3 {representing any illegal case-conversion string} + +@<Globals in the outer block@>= +@!conversion_type : 0..bad_conversion; {the possible cases} +@!prev_colon : boolean; {|true| if just past a |colon|} + + +@ +Now we determine which of the three case-conversion types we're +dealing with: \.{t},~\.{l}, or~\.{u}. + +@<Determine the case-conversion type@>= +begin +case (str_pool[str_start[pop_lit1]]) of + "t","T" : conversion_type := title_lowers; + "l","L" : conversion_type := all_lowers; + "u","U" : conversion_type := all_uppers; + othercases conversion_type := bad_conversion +endcases; +if ((length(pop_lit1) <> 1) or (conversion_type = bad_conversion)) then + begin + conversion_type := bad_conversion; + print_pool_str (pop_lit1); + bst_ex_warn (' is an illegal case-conversion string'); + end; +end + + +@ +This procedure complains if the just-encountered |right_brace| would +make |brace_level| negative. + +@<Procedures and functions for name-string processing@>= +procedure decr_brace_level (@!pop_lit_var : str_number); +begin +if (brace_level = 0) then + braces_unbalanced_complaint (pop_lit_var) + else + decr(brace_level); +end; + + +@ +This complaint often arises because the style designer has to type +lots of braces. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure braces_unbalanced_complaint (@!pop_lit_var : str_number); +begin +print ('Warning--"'); +print_pool_str (pop_lit_var); +bst_mild_ex_warn ('" isn''t a brace-balanced string'); +end; + + +@ +This one makes sure that |brace_level=0| (it's called at a point in a +string where braces must be balanced). + +@<Procedures and functions for name-string processing@>= +procedure check_brace_level (@!pop_lit_var : str_number); +begin +if (brace_level > 0) then + braces_unbalanced_complaint (pop_lit_var); +end; + + +@ +Here's where we actually go through the string and do the case +conversion. + +@<Perform the case conversion@>= +begin +brace_level := 0; {this is the top level} +ex_buf_ptr := 0; {we start with the string's first character} +while (ex_buf_ptr < ex_buf_length) do + begin + if (ex_buf[ex_buf_ptr] = left_brace) then + begin + incr(brace_level); + if (brace_level <> 1) then + goto ok_pascal_i_give_up; + if (ex_buf_ptr + 4 > ex_buf_length) then + goto ok_pascal_i_give_up + else if (ex_buf[ex_buf_ptr+1] <> backslash) then + goto ok_pascal_i_give_up; + if (conversion_type = title_lowers) then + if (ex_buf_ptr = 0) then + goto ok_pascal_i_give_up + else if ((prev_colon) and + (lex_class[ex_buf[ex_buf_ptr-1]] = white_space)) then + goto ok_pascal_i_give_up; + @<Convert a special character@>; +ok_pascal_i_give_up: + prev_colon := false; + end + else if (ex_buf[ex_buf_ptr] = right_brace) then + begin + decr_brace_level (pop_lit2); + prev_colon := false; + end + else + if (brace_level = 0) then + @<Convert a |brace_level = 0| character@>; + incr(ex_buf_ptr); + end; +check_brace_level (pop_lit2); +end + + +@ +@^special character@> +We're dealing with a special character (usually either an undotted +`\i' or `\j', or an accent like one in Table~3.1 of the \LaTeX\ +manual, or a foreign character like one in Table~3.2) if the first +character after the |left_brace| is a |backslash|; the special +character ends with the matching |right_brace|. How we handle what's +in between depends on the special character. In general, this code +will do reasonably well if there is other stuff, too, between braces, +but it doesn't try to do anything special with |colon|s. + +@<Convert a special character@>= +begin +incr(ex_buf_ptr); {skip over the |left_brace|} +while ((ex_buf_ptr < ex_buf_length) and (brace_level > 0)) do + begin + incr(ex_buf_ptr); {skip over the |backslash|} + ex_buf_xptr := ex_buf_ptr; + while ((ex_buf_ptr < ex_buf_length) and + (lex_class[ex_buf[ex_buf_ptr]] = alpha)) do + incr(ex_buf_ptr); {this scans the control sequence} + control_seq_loc := str_lookup(ex_buf,ex_buf_xptr,ex_buf_ptr-ex_buf_xptr, + control_seq_ilk,dont_insert); + if (hash_found) then + @<Convert the accented or foreign character, if necessary@>; + ex_buf_xptr := ex_buf_ptr; + while ((ex_buf_ptr < ex_buf_length) and (brace_level > 0) and + (ex_buf[ex_buf_ptr] <> backslash)) do + begin {this scans to the next control sequence} + if (ex_buf[ex_buf_ptr] = right_brace) then + decr(brace_level) + else if (ex_buf[ex_buf_ptr] = left_brace) then + incr(brace_level); + incr(ex_buf_ptr); + end; + @<Convert a noncontrol sequence@>; + end; +decr(ex_buf_ptr); {unskip the |right_brace|} +end + + +@ +@^control sequence@> +@:this can't happen}{\quad Unknown type of case conversion@> +A control sequence, for the purposes of this program, consists just of +the consecutive alphabetic characters following the |backslash|; it +might be empty (although ones in this section aren't). + +@<Convert the accented or foreign character, if necessary@>= +begin +case (conversion_type) of + title_lowers, + all_lowers : + case (ilk_info[control_seq_loc]) of + n_l_upper, + n_o_upper, + n_oe_upper, + n_ae_upper, + n_aa_upper : + lower_case (ex_buf, ex_buf_xptr, ex_buf_ptr-ex_buf_xptr); + othercases + do_nothing + endcases; + all_uppers : + case (ilk_info[control_seq_loc]) of + n_l, + n_o, + n_oe, + n_ae, + n_aa : + upper_case (ex_buf, ex_buf_xptr, ex_buf_ptr-ex_buf_xptr); + n_i, + n_j, + n_ss : + @<Convert, then remove the control sequence@>; + othercases + do_nothing + endcases; + bad_conversion : + do_nothing; + othercases + case_conversion_confusion +endcases; +end + + +@ +@:this can't happen}{\quad Unknown type of case conversion@> +Another bug complaint. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure case_conversion_confusion; +begin +confusion ('Unknown type of case conversion'); +end; + + +@ +After converting the control sequence, we need to remove the preceding +|backslash| and any following |white_space|. + +@<Convert, then remove the control sequence@>= +begin +upper_case (ex_buf, ex_buf_xptr, ex_buf_ptr-ex_buf_xptr); +while (ex_buf_xptr < ex_buf_ptr) do + begin {remove preceding |backslash| and shift down} + ex_buf[ex_buf_xptr-1] := ex_buf[ex_buf_xptr]; + incr(ex_buf_xptr); + end; +decr(ex_buf_xptr); +while ((ex_buf_ptr < ex_buf_length) and + (lex_class[ex_buf[ex_buf_ptr]] = white_space)) do + incr(ex_buf_ptr); {remove |white_space| trailing the control seq} +tmp_ptr := ex_buf_ptr; +while (tmp_ptr < ex_buf_length) do + begin {more shifting down} + ex_buf[tmp_ptr-(ex_buf_ptr-ex_buf_xptr)] := ex_buf[tmp_ptr]; + incr(tmp_ptr) + end; +ex_buf_length := tmp_ptr - (ex_buf_ptr - ex_buf_xptr); +ex_buf_ptr := ex_buf_xptr; +end + + +@ +@:this can't happen}{\quad Unknown type of case conversion@> +There are no control sequences in what we're about to convert, +so a straight conversion suffices. + +@<Convert a noncontrol sequence@>= +begin +case (conversion_type) of + title_lowers, + all_lowers : + lower_case (ex_buf, ex_buf_xptr, ex_buf_ptr-ex_buf_xptr); + all_uppers : + upper_case (ex_buf, ex_buf_xptr, ex_buf_ptr-ex_buf_xptr); + bad_conversion : + do_nothing; + othercases + case_conversion_confusion +endcases; +end + + +@ +@:this can't happen}{\quad Unknown type of case conversion@> +This code does any needed conversion for an ordinary character; it +won't touch nonletters. + +@<Convert a |brace_level = 0| character@>= +begin +case (conversion_type) of + title_lowers : + begin + if (ex_buf_ptr = 0) then + do_nothing + else if ((prev_colon) and + (lex_class[ex_buf[ex_buf_ptr-1]] = white_space)) then + do_nothing + else + lower_case (ex_buf, ex_buf_ptr, 1); + if (ex_buf[ex_buf_ptr] = colon) then + prev_colon := true + else if (lex_class[ex_buf[ex_buf_ptr]] <> white_space) then + prev_colon := false; + end; + all_lowers : + lower_case (ex_buf, ex_buf_ptr, 1); + all_uppers : + upper_case (ex_buf, ex_buf_ptr, 1); + bad_conversion : + do_nothing; + othercases + case_conversion_confusion +endcases; +end + + +@ +The |built_in| function {\.{chr.to.int\$}} pops the top (string) +literal, makes sure it's a single character, converts it to the +corresponding |ASCII_code| integer, and pushes this integer. If the +literal isn't an appropriate string, it complains and pushes the +integer~0. + +@<|execute_fn|({\.{chr.to.int\$}})@>= +procedure x_chr_to_int; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str); + push_lit_stk (0, stk_int); + end +else if (length(pop_lit1) <> 1) then + begin + print ('"'); + print_pool_str (pop_lit1); + bst_ex_warn ('" isn''t a single character'); + push_lit_stk (0, stk_int); + end +else + push_lit_stk (str_pool[str_start[pop_lit1]], stk_int); + {push the (|ASCII_code|) integer} +end; + + +@ +The |built_in| function {\.{cite\$}} pushes the appropriate string +from |cite_list| onto the stack. + +@<|execute_fn|({\.{cite\$}})@>= +procedure x_cite; +begin +if (not mess_with_entries) then + bst_cant_mess_with_entries_print + else + push_lit_stk (cur_cite_str, stk_str); +end; + + +@ +@^push the literal stack@> +The |built_in| function {\.{duplicate\$}} pops the top literal from +the stack and pushes two copies of it. + +@<|execute_fn|({\.{duplicate\$}})@>= +procedure x_duplicate; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_str) then + begin + push_lit_stk (pop_lit1, pop_typ1); + push_lit_stk (pop_lit1, pop_typ1); + end + else + begin + repush_string; + if (pop_lit1 < cmd_str_ptr) then + push_lit_stk (pop_lit1, pop_typ1) + else + begin + str_room (length(pop_lit1)); + sp_ptr := str_start[pop_lit1]; + sp_end := str_start[pop_lit1+1]; + while (sp_ptr < sp_end) do + begin + append_char (str_pool[sp_ptr]); + incr(sp_ptr); + end; + push_lit_stk (make_string, stk_str); {and push it onto the stack} + end; + end; +end; + + +@ +The |built_in| function {\.{empty\$}} pops the top literal and pushes +the integer 1 if it's a missing field or a string having no +non|white_space| characters, 0 otherwise. If the literal isn't a +missing field or a string, it complains and pushes 0. + +@<|execute_fn|({\.{empty\$}})@>= +procedure x_empty; +label exit; +begin +pop_lit_stk (pop_lit1,pop_typ1); +case (pop_typ1) of + stk_str : @<Push 0 if the string has a non|white_space| char, else 1@>; + stk_field_missing : push_lit_stk (1, stk_int); + stk_empty : push_lit_stk (0, stk_int); + othercases + begin + print_stk_lit (pop_lit1,pop_typ1); + bst_ex_warn (', not a string or missing field,'); + push_lit_stk (0, stk_int); + end +endcases; +exit: +end; + + +@ +When we arrive here we're dealing with a legitimate string. If it has +no characters, or has nothing but |white_space| characters, we push~1, +otherwise we push~0. + +@<Push 0 if the string has a non|white_space| char, else 1@>= +begin +sp_ptr := str_start[pop_lit1]; +sp_end := str_start[pop_lit1+1]; +while (sp_ptr < sp_end) do + begin + if (lex_class[str_pool[sp_ptr]] <> white_space) then + begin + push_lit_stk (0, stk_int); + return; + end; + incr(sp_ptr); + end; +push_lit_stk (1, stk_int); +end + + +@ +The |built_in| function {\.{format.name\$}} pops the top three +literals (they are a string, an integer, and a string literal, in that +order). The last string literal represents a name list (each name +corresponding to a person), the integer literal specifies which name +to pick from this list, and the first string literal specifies how to +format this name, as described in the \BibTeX\ documentation. +Finally, this function pushes the formatted name. If any of the types +is incorrect, it complains and pushes the null string. + +@d von_found = 52 {for when a von token is found} + +@<|execute_fn|({\.{format.name\$}})@>= +procedure x_format_name; +label loop1_exit,@!loop2_exit,@!von_found; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +pop_lit_stk (pop_lit3,pop_typ3); +if (pop_typ1 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str); + push_lit_stk (s_null, stk_str); + end +else if (pop_typ2 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_int); + push_lit_stk (s_null, stk_str); + end +else if (pop_typ3 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit3,pop_typ3,stk_str); + push_lit_stk (s_null, stk_str); + end +else + begin + ex_buf_length := 0; + add_buf_pool (pop_lit3); + @<Isolate the desired name@>; + @<Copy name and count |comma|s to determine syntax@>; + @<Find the parts of the name@>; + ex_buf_length := 0; + add_buf_pool (pop_lit1); + figure_out_the_formatted_name;@/ + add_pool_buf_and_push; {push the formatted string onto the stack} + end; +end; + + +@ +This module skips over undesired names in |pop_lit3| and it throws +away the ``and'' from the end of the name if it exists. When it's +done, |ex_buf_xptr| points to its first character and |ex_buf_ptr| +points just past its last. + +@<Isolate the desired name@>= +begin +ex_buf_ptr := 0; +num_names := 0; +while ((num_names < pop_lit2) and (ex_buf_ptr < ex_buf_length)) do + begin + incr(num_names); + ex_buf_xptr := ex_buf_ptr; + name_scan_for_and (pop_lit3); + end; +if (ex_buf_ptr < ex_buf_length) then {remove the ``and''} + ex_buf_ptr := ex_buf_ptr - 4; +if (num_names < pop_lit2) then + begin + if (pop_lit2 = 1) then + print ('There is no name in "') + else + print ('There aren''t ',pop_lit2:0,' names in "'); + print_pool_str (pop_lit3); + bst_ex_warn ('"'); + end +end + + +@ +This module, starting at |ex_buf_ptr|, looks in |ex_buf| for an +``and'' surrounded by nonnull |white_space|. It stops either at +|ex_buf_length| or just past the ``and'', whichever comes first, +setting |ex_buf_ptr| accordingly. Its parameter |pop_lit_var| is +either |pop_lit3| or |pop_lit1|, depending on whether +{\.{format.name\$}} or {\.{num.names\$}} calls it. + +@<Procedures and functions for name-string processing@>= +procedure name_scan_for_and (@!pop_lit_var : str_number); +begin +brace_level := 0; +preceding_white := false; +and_found := false; +while ((not and_found) and (ex_buf_ptr < ex_buf_length)) do + case (ex_buf[ex_buf_ptr]) of + "a", "A" : + begin + incr(ex_buf_ptr); + if (preceding_white) then + @<See if we have an ``and''@>; {if so, |and_found := true|} + preceding_white := false; + end; + left_brace : + begin + incr(brace_level); + incr(ex_buf_ptr); + @<Skip over |ex_buf| stuff at |brace_level > 0|@>; + preceding_white := false; + end; + right_brace : + begin + decr_brace_level (pop_lit_var); {this checks for an error} + incr(ex_buf_ptr); + preceding_white := false; + end; + othercases + if (lex_class[ex_buf[ex_buf_ptr]] = white_space) then + begin + incr(ex_buf_ptr); + preceding_white := true; + end + else + begin + incr(ex_buf_ptr); + preceding_white := false; + end + endcases; +check_brace_level (pop_lit_var); +end; + + +@ +When we come here |ex_buf_ptr| is just past the |left_brace|, and when +we leave it's either at |ex_buf_length| or just past the matching +|right_brace|. + +@<Skip over |ex_buf| stuff at |brace_level > 0|@>= +while ((brace_level > 0) and (ex_buf_ptr < ex_buf_length)) do + begin + if (ex_buf[ex_buf_ptr] = right_brace) then + decr(brace_level) + else if (ex_buf[ex_buf_ptr] = left_brace) then + incr(brace_level); + incr(ex_buf_ptr); + end + + +@ +When we come here |ex_buf_ptr| is just past the ``a'' or ``A'', and when +we leave it's either at the same place or, if we found an ``and'', at +the following |white_space| character. + +@<See if we have an ``and''@>= +begin +if (ex_buf_ptr <= (ex_buf_length - 3)) then {enough characters are left} + if ((ex_buf[ex_buf_ptr] = "n") or (ex_buf[ex_buf_ptr] = "N")) then + if ((ex_buf[ex_buf_ptr+1] = "d") or (ex_buf[ex_buf_ptr+1] = "D")) then + if (lex_class[ex_buf[ex_buf_ptr+2]] = white_space) then + begin + ex_buf_ptr := ex_buf_ptr + 2; + and_found := true; + end; +end + + +@ +When we arrive here, the desired name is in |ex_buf[ex_buf_xptr]| +through |ex_buf[ex_buf_ptr-1]|. This module does its thing for +characters only at |brace_level = 0|; the rest get processed verbatim. +It removes leading |white_space| (and |sep_char|s), and trailing +|white_space| (and |sep_char|s) and |comma|s, complaining for each +trailing |comma|. It then copies the name into |name_buf|, removing +all |white_space|, |sep_char|s and |comma|s, counting |comma|s, and +constructing a list of name tokens, which are sequences of characters +separated (at |brace_level=0|) by |white_space|, |sep_char|s or +|comma|s. Each name token but the first has an associated +|name_sep_char|, the character that separates it from the preceding +token. If there are too many (more than two) |comma|s, a complaint is +in order. + +@<Copy name and count |comma|s to determine syntax@>= +begin +@<Remove leading and trailing junk, complaining if necessary@>; +name_bf_ptr := 0; +num_commas := 0; +num_tokens := 0;@/ +token_starting := true; {to indicate that a name token is starting} +while (ex_buf_xptr < ex_buf_ptr) do + case (ex_buf[ex_buf_xptr]) of + comma : @<Name-process a |comma|@>; + left_brace : @<Name-process a |left_brace|@>; + right_brace : @<Name-process a |right_brace|@>; + othercases + case (lex_class[ex_buf[ex_buf_xptr]]) of + white_space : @<Name-process a |white_space|@>; + sep_char : @<Name-process a |sep_char|@>; + othercases @<Name-process some other character@> + endcases + endcases; +name_tok[num_tokens] := name_bf_ptr; {this is an end-marker} +end + + +@ +This module removes all leading |white_space| (and |sep_char|s), and +trailing |white_space| (and |sep_char|s) and |comma|s. It complains +for each trailing |comma|. + +@<Remove leading and trailing junk, complaining if necessary@>= +begin +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} +while (ex_buf_ptr > ex_buf_xptr) do {now remove trailing stuff} + case (lex_class[ex_buf[ex_buf_ptr-1]]) of + white_space, + sep_char : + decr(ex_buf_ptr); + othercases + if (ex_buf[ex_buf_ptr-1] = comma) then + begin + print ('Name ',pop_lit2:0,' in "'); + print_pool_str (pop_lit3); + print ('" has a comma at the end'); + bst_ex_warn_print; + decr(ex_buf_ptr); + end + else + goto loop1_exit + endcases; +loop1_exit: + +end + +@ +Here we mark the token number at which this comma has occurred. + +@<Name-process a |comma|@>= +begin +if (num_commas = 2) then + begin + print ('Too many commas in name ',pop_lit2:0,' of "'); + print_pool_str (pop_lit3); + print ('"'); + bst_ex_warn_print; + end + else + begin + incr(num_commas); + if (num_commas = 1) then + comma1 := num_tokens + else + comma2 := num_tokens; {|num_commas = 2|} + name_sep_char[num_tokens] := comma; + end; +incr(ex_buf_xptr); +token_starting := true; +end + + +@ +We copy the stuff up through the matching |right_brace| verbatim. + +@<Name-process a |left_brace|@>= +begin +incr(brace_level); +if (token_starting) then + begin + name_tok[num_tokens] := name_bf_ptr; + incr(num_tokens); + end; +name_buf[name_bf_ptr] := ex_buf[ex_buf_xptr]; +incr(name_bf_ptr); +incr(ex_buf_xptr); +while ((brace_level > 0) and (ex_buf_xptr < ex_buf_ptr)) do + begin + if (ex_buf[ex_buf_xptr] = right_brace) then + decr(brace_level) + else if (ex_buf[ex_buf_xptr] = left_brace) then + incr(brace_level); + name_buf[name_bf_ptr] := ex_buf[ex_buf_xptr]; + incr(name_bf_ptr); + incr(ex_buf_xptr); + end; +token_starting := false; +end + + +@ +We don't copy an extra |right_brace|; this code will almost never be +executed. + +@<Name-process a |right_brace|@>= +begin +if (token_starting) then + begin + name_tok[num_tokens] := name_bf_ptr; + incr(num_tokens); + end; +print ('Name ',pop_lit2:0,' of "'); +print_pool_str (pop_lit3); +bst_ex_warn ('" isn''t brace balanced'); +incr(ex_buf_xptr); +token_starting := false; +end + + +@ +A token will be starting soon in a buffer near you, one way$\ldots$ + +@<Name-process a |white_space|@>= +begin +if (not token_starting) then + name_sep_char[num_tokens] := space; +incr(ex_buf_xptr); +token_starting := true; +end + + +@ +@^user abuse@> +or another. If one of the valid |sep_char|s appears between tokens, +we usually use it instead of a |space|. If the user has been silly +enough to have multiple |sep_char|s, or to have both |white_space| and +a |sep_char|, we use the first such character. + +@<Name-process a |sep_char|@>= +begin +if (not token_starting) then + name_sep_char[num_tokens] := ex_buf[ex_buf_xptr]; +incr(ex_buf_xptr); +token_starting := true; +end + + +@ +For ordinary characters, we just copy the character. + +@<Name-process some other character@>= +begin +if (token_starting) then + begin + name_tok[num_tokens] := name_bf_ptr; + incr(num_tokens); + end; +name_buf[name_bf_ptr] := ex_buf[ex_buf_xptr]; +incr(name_bf_ptr); +incr(ex_buf_xptr); +token_starting := false; +end + + +@ +@:this can't happen}{\quad Illegal number of comma,s@> +Here we set all the pointers for the various parts of the name, +depending on which of the three possible syntaxes this name uses. + +@<Find the parts of the name@>= +begin +if (num_commas = 0) then + begin + first_start := 0; + last_end := num_tokens; + jr_end := last_end; + @<Determine where the first name ends and von name starts and ends@>; + end +else if (num_commas = 1) then + begin + von_start := 0; + last_end := comma1; + jr_end := last_end; + first_start := jr_end; + first_end := num_tokens; + von_name_ends_and_last_name_starts_stuff; + end +else if (num_commas = 2) then + begin + von_start := 0; + last_end := comma1; + jr_end := comma2; + first_start := jr_end; + first_end := num_tokens; + von_name_ends_and_last_name_starts_stuff; + end +else + confusion ('Illegal number of comma,s'); +end + + +@ +When there are no brace-level-0 |comma|s in the name, the von name +starts with the first nonlast token whose first brace-level-0 letter +is in lower case (for the purposes of this determination, an accented +or foreign character at brace-level-1 that's in lower case will do, as +well). A module following this one determines where the von name ends +and the last starts. + +@<Determine where the first name ends and von name starts and ends@>= +begin +von_start := 0; +while (von_start < last_end-1) do + begin + name_bf_ptr := name_tok[von_start]; + name_bf_xptr := name_tok[von_start+1]; + if (von_token_found) then + begin + von_name_ends_and_last_name_starts_stuff; + goto von_found; + end; + incr(von_start); + end; {there's no von name, so} +while (von_start > 0) do {backtrack if there are connected tokens} + begin + if ((lex_class[name_sep_char[von_start]] <> sep_char) or + (name_sep_char[von_start] = tie)) then + goto loop2_exit; + decr(von_start); + end; +loop2_exit: +von_end := von_start; +von_found: +first_end := von_start; +end + + +@ +@^special character@> +It's a von token if there exists a first brace-level-0 letter (or +brace-level-1 special character), and it's in lower case; in this case +we return |true|. The token is in |name_buf|, starting at +|name_bf_ptr| and ending just before |name_bf_xptr|. + +@d return_von_found == begin + von_token_found := true; + return; + end + +@<Procedures and functions for name-string processing@>= +function von_token_found : boolean; +label exit; +begin +nm_brace_level := 0; +von_token_found := false; {now it's easy to exit if necessary} +while (name_bf_ptr < name_bf_xptr) do + if ((name_buf[name_bf_ptr] >= "A") and + (name_buf[name_bf_ptr] <= "Z")) then + return + else if ((name_buf[name_bf_ptr] >= "a") and + (name_buf[name_bf_ptr] <= "z")) then + return_von_found + else if (name_buf[name_bf_ptr] = left_brace) then + begin + incr(nm_brace_level); + incr(name_bf_ptr); + if ((name_bf_ptr + 2 < name_bf_xptr) and + (name_buf[name_bf_ptr] = backslash)) then + @<Check the special character (and |return|)@> + else + @<Skip over |name_buf| stuff at |nm_brace_level > 0|@>; + end + else + incr(name_bf_ptr); +exit: +end; + + +@ +@^special character@> +When we come here |name_bf_ptr| is just past the |left_brace|, +but we always leave by |return|ing. + +@<Check the special character (and |return|)@>= +begin +incr(name_bf_ptr); {skip over the |backslash|} +name_bf_yptr := name_bf_ptr; +while ((name_bf_ptr < name_bf_xptr) and + (lex_class[name_buf[name_bf_ptr]] = alpha)) do + incr(name_bf_ptr); {this scans the control sequence} +control_seq_loc := str_lookup(name_buf,name_bf_yptr,name_bf_ptr-name_bf_yptr, + control_seq_ilk,dont_insert); +if (hash_found) then + @<Handle this accented or foreign character (and |return|)@>; +while ((name_bf_ptr < name_bf_xptr) and (nm_brace_level > 0)) do + begin + if ((name_buf[name_bf_ptr] >= "A") and + (name_buf[name_bf_ptr] <= "Z")) then + return + else if ((name_buf[name_bf_ptr] >= "a") and + (name_buf[name_bf_ptr] <= "z")) then + return_von_found + else if (name_buf[name_bf_ptr] = right_brace) then + decr(nm_brace_level) + else if (name_buf[name_bf_ptr] = left_brace) then + incr(nm_brace_level); + incr(name_bf_ptr); + end; +return; +end + + +@ +@:this can't happen}{\quad Control-sequence hash error@> +The accented or foreign character is either `\.{\\i}' or `\.{\\j}' or +one of the eleven alphabetic foreign characters in Table~3.2 of the +\LaTeX\ manual. + +@<Handle this accented or foreign character (and |return|)@>= +begin +case (ilk_info[control_seq_loc]) of + n_oe_upper, + n_ae_upper, + n_aa_upper, + n_o_upper, + n_l_upper : + return; + n_i, + n_j, + n_oe, + n_ae, + n_aa, + n_o, + n_l, + n_ss : + return_von_found; + othercases + confusion ('Control-sequence hash error') +endcases; +end + + +@ +When we come here |name_bf_ptr| is just past the |left_brace|; when we +leave it's either at |name_bf_xptr| or just past the matching +|right_brace|. + +@<Skip over |name_buf| stuff at |nm_brace_level > 0|@>= +while ((nm_brace_level > 0) and (name_bf_ptr < name_bf_xptr)) do + begin + if (name_buf[name_bf_ptr] = right_brace) then + decr(nm_brace_level) + else if (name_buf[name_bf_ptr] = left_brace) then + incr(nm_brace_level); + incr(name_bf_ptr); + end + + +@ +@^Casey Stengel would be proud@> +@^special character@> +@^Tuesdays@> +The last name starts just past the last token, before the first +|comma| (if there is no |comma|, there is deemed to be one at the end +of the string), for which there exists a first brace-level-0 letter +(or brace-level-1 special character), and it's in lower case, unless +this last token is also the last token before the |comma|, in which +case the last name starts with this token (unless this last token is +connected by a |sep_char| other than a |tie| to the previous token, in +which case the last name starts with as many tokens earlier as are +connected by non|tie|s to this last one (except on Tuesdays +$\ldots\,$), although this module never sees such a case). Note that +if there are any tokens in either the von or last names, then the last +name has at least one, even if it starts with a lower-case letter. + +@<Procedures and functions for name-string processing@>= +procedure von_name_ends_and_last_name_starts_stuff; +label exit; +begin {there may or may not be a von name} +von_end := last_end - 1; +while (von_end > von_start) do + begin + name_bf_ptr := name_tok[von_end-1]; + name_bf_xptr := name_tok[von_end]; + if (von_token_found) then + return; + decr(von_end); + end; +exit: +end; + + +@ +This module uses the information in |pop_lit1| to format the name. +Everything at |sp_brace_level = 0| is copied verbatim to the formatted +string; the rest is described in the succeeding modules. + +@<Figure out the formatted name@>= +begin +ex_buf_ptr := 0; +sp_brace_level := 0; +sp_ptr := str_start[pop_lit1]; +sp_end := str_start[pop_lit1+1]; +while (sp_ptr < sp_end) do + if (str_pool[sp_ptr] = left_brace) then + begin + incr(sp_brace_level); + incr(sp_ptr); + @<Format this part of the name@>; + end + else if (str_pool[sp_ptr] = right_brace) then + begin + braces_unbalanced_complaint (pop_lit1); + incr(sp_ptr); + end + else + begin + append_ex_buf_char_and_check (str_pool[sp_ptr]); + incr(sp_ptr); + end; +if (sp_brace_level > 0) then + braces_unbalanced_complaint (pop_lit1); +ex_buf_length := ex_buf_ptr; +end + + +@ +When we arrive here we're at |sp_brace_level = 1|, just past the +|left_brace|. Letters at this |sp_brace_level| other than those +denoting the parts of the name (i.e., the first letters of `first,' +`last,' `von,' and `jr,' ignoring case) are illegal. We do two passes +over this group; the first determines whether we're to output +anything, and, if we are, the second actually outputs it. + +@<Format this part of the name@>= +begin +sp_xptr1 := sp_ptr; +alpha_found := false; +double_letter := false; +end_of_group := false; +to_be_written := true; +while ((not end_of_group) and (sp_ptr < sp_end)) do + if (lex_class[str_pool[sp_ptr]] = alpha) then + begin + incr(sp_ptr); + @<Figure out what this letter means@>; + end + else if (str_pool[sp_ptr] = right_brace) then + begin + decr(sp_brace_level); + incr(sp_ptr); + end_of_group := true; + end + else if (str_pool[sp_ptr] = left_brace) then + begin + incr(sp_brace_level); + incr(sp_ptr); + skip_stuff_at_sp_brace_level_greater_than_one; + end + else + incr(sp_ptr); +if ((end_of_group) and (to_be_written)) then {do the second pass} + @<Finally format this part of the name@>; +end + + +@ +When we come here |sp_ptr| is just past the |left_brace|, and when we +leave it's either at |sp_end| or just past the matching |right_brace|. + +@<Procedures and functions for name-string processing@>= +procedure skip_stuff_at_sp_brace_level_greater_than_one; +begin +while ((sp_brace_level > 1) and (sp_ptr < sp_end)) do + begin + if (str_pool[sp_ptr] = right_brace) then + decr(sp_brace_level) + else if (str_pool[sp_ptr] = left_brace) then + incr(sp_brace_level); + incr(sp_ptr); + end; +end; + + +@ +We won't output anything for this part of the name if this is a second +occurrence of an |sp_brace_level = 1| letter, if it's an illegal +letter, or if there are no tokens corresponding to this part. We also +determine if we're we to output complete tokens (indicated by a double +letter). + +@<Figure out what this letter means@>= +begin +if (alpha_found) then + begin + brace_lvl_one_letters_complaint; + to_be_written := false; + end + else + begin + case (str_pool[sp_ptr-1]) of + "f","F" : @<Figure out what tokens we'll output for the `first' name@>; + "v","V" : @<Figure out what tokens we'll output for the `von' name@>; + "l","L" : @<Figure out what tokens we'll output for the `last' name@>; + "j","J" : @<Figure out what tokens we'll output for the `jr' name@>; + othercases + begin + brace_lvl_one_letters_complaint; + to_be_written := false; + end + endcases; + if (double_letter) then + incr(sp_ptr); + end; +alpha_found := true; +end + + +@ +At most one of the important letters, perhaps doubled, may appear at +|sp_brace_level = 1|. + +@<Procedures and functions for name-string processing@>= +procedure brace_lvl_one_letters_complaint; +begin +print ('The format string "'); +print_pool_str (pop_lit1); +bst_ex_warn ('" has an illegal brace-level-1 letter'); +end; + + +@ +Here we set pointers into |name_tok| and note whether we'll be dealing +with a full first-name tokens (|double_letter = true|) or +abbreviations (|double_letter = false|). + +@<Figure out what tokens we'll output for the `first' name@>= +begin +cur_token := first_start; +last_token := first_end; +if (cur_token = last_token) then + to_be_written := false; +if ((str_pool[sp_ptr] = "f") or (str_pool[sp_ptr] = "F")) then + double_letter := true; +end + + +@ +The same as above but for von-name tokens. + +@<Figure out what tokens we'll output for the `von' name@>= +begin +cur_token := von_start; +last_token := von_end; +if (cur_token = last_token) then + to_be_written := false; +if ((str_pool[sp_ptr] = "v") or (str_pool[sp_ptr] = "V")) then + double_letter := true; +end + + +@ +The same as above but for last-name tokens. + +@<Figure out what tokens we'll output for the `last' name@>= +begin +cur_token := von_end; +last_token := last_end; +if (cur_token = last_token) then + to_be_written := false; +if ((str_pool[sp_ptr] = "l") or (str_pool[sp_ptr] = "L")) then + double_letter := true; +end + + +@ +The same as above but for jr-name tokens. + +@<Figure out what tokens we'll output for the `jr' name@>= +begin +cur_token := last_end; +last_token := jr_end; +if (cur_token = last_token) then + to_be_written := false; +if ((str_pool[sp_ptr] = "j") or (str_pool[sp_ptr] = "J")) then + double_letter := true; +end + + +@ +This is the second pass over this part of the name; here we actually +write stuff out to |ex_buf|. + +@<Finally format this part of the name@>= +begin +ex_buf_xptr := ex_buf_ptr; +sp_ptr := sp_xptr1; +sp_brace_level := 1; +while (sp_brace_level > 0) do + if ((lex_class[str_pool[sp_ptr]] = alpha) and (sp_brace_level = 1)) then + begin + incr(sp_ptr); + @<Figure out how to output the name tokens, and do it@>; + end + else if (str_pool[sp_ptr] = right_brace) then + begin + decr(sp_brace_level); + incr(sp_ptr); + if (sp_brace_level > 0) then + append_ex_buf_char_and_check (right_brace); + end + else if (str_pool[sp_ptr] = left_brace) then + begin + incr(sp_brace_level); + incr(sp_ptr); + append_ex_buf_char_and_check (left_brace); + end + else + begin + append_ex_buf_char_and_check (str_pool[sp_ptr]); + incr(sp_ptr); + end; +if (ex_buf_ptr > 0) then + if (ex_buf[ex_buf_ptr-1] = tie) then + @<Handle a discretionary |tie|@>; +end + + +@ +When we come here, |sp_ptr| is just past the letter indicating the +part of the name for which we're about to output tokens. When we +leave, it's at the first character of the rest of the group. + +@<Figure out how to output the name tokens, and do it@>= +begin +if (double_letter) then + incr(sp_ptr); +use_default := true; +sp_xptr2 := sp_ptr; +if (str_pool[sp_ptr] = left_brace) then {find the inter-token string} + begin + use_default := false; + incr(sp_brace_level); + incr(sp_ptr); + sp_xptr1 := sp_ptr; + skip_stuff_at_sp_brace_level_greater_than_one; + sp_xptr2 := sp_ptr - 1; + end; +@<Finally output the name tokens@>; +if (not use_default) then + sp_ptr := sp_xptr2 + 1; +end + + +@ +Here, for each token in this part, we output either a full or an +abbreviated token and the inter-token string for all but the last +token of this part. + +@<Finally output the name tokens@>= +while (cur_token < last_token) do + begin + if (double_letter) then + @<Finally output a full token@> + else + @<Finally output an abbreviated token@>; + incr(cur_token); + if (cur_token < last_token) then + @<Finally output the inter-token string@>; + end + + +@ +@:BibTeX capacity exceeded}{\quad buffer size@> +Here we output all the characters in the token, verbatim. + +@<Finally output a full token@>= +begin +name_bf_ptr := name_tok[cur_token]; +name_bf_xptr := name_tok[cur_token+1]; +if (ex_buf_length+(name_bf_xptr-name_bf_ptr) > buf_size) then + buffer_overflow; +while (name_bf_ptr < name_bf_xptr) do + begin + append_ex_buf_char (name_buf[name_bf_ptr]); + incr(name_bf_ptr); + end; +end + + +@ +@^special character@> +Here we output the first alphabetic or special character of the token; +brace level is irrelevant for an alphabetic (but not a special) +character. + +@<Finally output an abbreviated token@>= +begin +name_bf_ptr := name_tok[cur_token]; +name_bf_xptr := name_tok[cur_token+1]; +while (name_bf_ptr < name_bf_xptr) do + begin + if (lex_class[name_buf[name_bf_ptr]] = alpha) then + begin + append_ex_buf_char_and_check (name_buf[name_bf_ptr]); + goto loop_exit; + end + else if ((name_buf[name_bf_ptr] = left_brace) and + (name_bf_ptr + 1 < name_bf_xptr)) then + if (name_buf[name_bf_ptr+1] = backslash) then + @<Finally output a special character and exit loop@>; + incr(name_bf_ptr); + end; +loop_exit: +end + + +@ +@^special character@> +@^user abuse@> +@:BibTeX capacity exceeded}{\quad buffer size@> +We output a special character here even if the user has been silly +enough to make it nonalphabetic (and even if the user has been sillier +still by not having a matching |right_brace|). + +@<Finally output a special character and exit loop@>= +begin +if (ex_buf_ptr + 2 > buf_size) then + buffer_overflow; +append_ex_buf_char (left_brace); +append_ex_buf_char (backslash); +name_bf_ptr := name_bf_ptr + 2; +nm_brace_level := 1; +while ((name_bf_ptr < name_bf_xptr) and (nm_brace_level > 0)) do + begin + if (name_buf[name_bf_ptr] = right_brace) then + decr(nm_brace_level) + else if (name_buf[name_bf_ptr] = left_brace) then + incr(nm_brace_level); + append_ex_buf_char_and_check (name_buf[name_bf_ptr]); + incr(name_bf_ptr); + end; +goto loop_exit; +end + + +@ +@:BibTeX capacity exceeded}{\quad buffer size@> +Here we output either the \.{.bst} given string if it exists, or else +the \.{.bib} |sep_char| if it exists, or else the default string. A +|tie| is the default space character between the last two tokens of +the name part, and between the first two tokens if the first token is +short enough; otherwise, a |space| is the default. + +@d long_token = 3 {a token this length or longer is ``long''} + +@<Finally output the inter-token string@>= +begin +if (use_default) then + begin + if (not double_letter) then + append_ex_buf_char_and_check (period); + if (lex_class[name_sep_char[cur_token]] = sep_char) then + append_ex_buf_char_and_check (name_sep_char[cur_token]) + else if ((cur_token = last_token-1) or + (not enough_text_chars (long_token))) then + append_ex_buf_char_and_check (tie) + else + append_ex_buf_char_and_check (space); + end + else + begin + if (ex_buf_length+(sp_xptr2-sp_xptr1) > buf_size) then + buffer_overflow; + sp_ptr := sp_xptr1; + while (sp_ptr < sp_xptr2) do + begin + append_ex_buf_char (str_pool[sp_ptr]); + incr(sp_ptr); + end + end; +end + + +@ +@^special character@> +This function looks at the string in |ex_buf|, starting at +|ex_buf_xptr| and ending just before |ex_buf_ptr|, and it returns +|true| if there are |enough_chars|, where a special character (even if +it's missing its matching |right_brace|) counts as a single charcter. +This procedure is called only for strings that don't have too many +|right_brace|s. + +@<Procedures and functions for name-string processing@>= +function enough_text_chars (@!enough_chars : buf_pointer) : boolean; +begin +num_text_chars := 0; +ex_buf_yptr := ex_buf_xptr; +while ((ex_buf_yptr < ex_buf_ptr) and (num_text_chars < enough_chars)) do + begin + incr(ex_buf_yptr); + if (ex_buf[ex_buf_yptr-1] = left_brace) then + begin + incr(brace_level); + if ((brace_level = 1) and (ex_buf_yptr < ex_buf_ptr)) then + if (ex_buf[ex_buf_yptr] = backslash) then + begin + incr(ex_buf_yptr); {skip over the |backslash|} + while ((ex_buf_yptr < ex_buf_ptr) and (brace_level > 0)) do + begin + if (ex_buf[ex_buf_yptr] = right_brace) then + decr(brace_level) + else if (ex_buf[ex_buf_yptr] = left_brace) then + incr(brace_level); + incr(ex_buf_yptr); + end; + end; + end + else if (ex_buf[ex_buf_yptr-1] = right_brace) then + decr(brace_level); + incr(num_text_chars); + end; +if (num_text_chars < enough_chars) then + enough_text_chars := false + else + enough_text_chars := true; +end; + + +@ +If the last character output for this name part is a |tie| but the +previous character it isn't, we're dealing with a discretionary |tie|; +thus we replace it by a |space| if there are enough characters in the +rest of the name part. + +@d long_name = 3 {a name this length or longer is ``long''} + +@<Handle a discretionary |tie|@>= +begin +decr(ex_buf_ptr); {remove the previous |tie|} +if (ex_buf[ex_buf_ptr-1] = tie) then {it's not a discretionary |tie|} + do_nothing +else if (not enough_text_chars (long_name)) then {this is a short name part} + incr(ex_buf_ptr) {so restore the |tie|} +else {replace it by a |space|} + append_ex_buf_char (space); +end + + +@ +This is a procedure so that |x_format_name| is smaller. + +@<Procedures and functions for name-string processing@>= +procedure figure_out_the_formatted_name; +label loop_exit; +begin +@<Figure out the formatted name@>; +end; + + +@ +The |built_in| function {\.{if\$}} pops the top three literals (they +are two function literals and an integer literal, in that order); if +the integer is greater than 0, it executes the second literal, else it +executes the first. If any of the types is incorrect, it complains +but does nothing else. + +@<|execute_fn|({\.{if\$}})@>= +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +pop_lit_stk (pop_lit3,pop_typ3); +if (pop_typ1 <> stk_fn) then + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_fn) +else if (pop_typ2 <> stk_fn) then + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_fn) +else if (pop_typ3 <> stk_int) then + print_wrong_stk_lit (pop_lit3,pop_typ3,stk_int) +else + if (pop_lit3 > 0) then + execute_fn (pop_lit2) + else + execute_fn (pop_lit1); +end + + +@ +The |built_in| function {\.{int.to.chr\$}} pops the top (integer) +literal, interpreted as the |ASCII_code| of a single character, +converts it to the corresponding single-character string, and pushes +this string. If the literal isn't an appropriate integer, it +complains and pushes the null string. + +@<|execute_fn|({\.{int.to.chr\$}})@>= +procedure x_int_to_chr; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_int); + push_lit_stk (s_null, stk_str); + end +else if ((pop_lit1 < 0) or (pop_lit1 > 127)) then + begin + bst_ex_warn (pop_lit1:0,' isn''t valid ASCII'); + push_lit_stk (s_null, stk_str); + end +else + begin + str_room(1); + append_char (pop_lit1); + push_lit_stk (make_string, stk_str); + end; +end; + + +@ +The |built_in| function {\.{int.to.str\$}} pops the top (integer) +literal, converts it to its (unique) string equivalent, and pushes +this string. If the literal isn't an integer, it complains and pushes +the null string. + +@<|execute_fn|({\.{int.to.str\$}})@>= +procedure x_int_to_str; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_int); + push_lit_stk (s_null, stk_str); + end +else + begin + int_to_ASCII (pop_lit1, ex_buf, 0, ex_buf_length);@/ + add_pool_buf_and_push; {push this string onto the stack} + end; +end; + + +@ +The |built_in| function {\.{missing\$}} pops the top literal and +pushes the integer 1 if it's a missing field, 0 otherwise. If the +literal isn't a missing field or a string, it complains and pushes 0. +Unlike \.{empty\$}, this function should be called only when +|mess_with_entries| is true. + +@<|execute_fn|({\.{missing\$}})@>= +procedure x_missing; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (not mess_with_entries) then + bst_cant_mess_with_entries_print +else if ((pop_typ1 <> stk_str) and (pop_typ1 <> stk_field_missing)) then + begin + if (pop_typ1 <> stk_empty) then + begin + print_stk_lit (pop_lit1,pop_typ1); + bst_ex_warn (', not a string or missing field,'); + end; + push_lit_stk (0, stk_int); + end +else + if (pop_typ1 = stk_field_missing) then + push_lit_stk (1, stk_int) + else + push_lit_stk (0, stk_int); +end; + + +@ +The |built_in| function {\.{newline\$}} writes whatever has +accumulated in the output buffer |out_buf| onto the \.{.bbl} file. + +@<|execute_fn|({\.{newline\$}})@>= +begin +output_bbl_line; +end + + +@ +The |built_in| function {\.{num.names\$}} pops the top (string) +literal; it pushes the number of names the string represents---one +plus the number of occurrences of the substring ``and'' (ignoring case +differences) surrounded by nonnull |white_space| at the top brace +level. If the literal isn't a string, it complains and pushes the +value 0. + +@<|execute_fn|({\.{num.names\$}})@>= +procedure x_num_names; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str); + push_lit_stk (0, stk_int); + end +else + begin + ex_buf_length := 0; + add_buf_pool (pop_lit1); + @<Determine the number of names@>; + push_lit_stk (num_names, stk_int); + end; +end; + + +@ +This module, while scanning the list of names, counts the occurrences +of ``and'' (ignoring case differences) surrounded by nonnull +|white_space|, and adds 1. + +@<Determine the number of names@>= +begin +ex_buf_ptr := 0; +num_names := 0; +while (ex_buf_ptr < ex_buf_length) do + begin + name_scan_for_and (pop_lit1); + incr(num_names); + end; +end + + +@ +The |built_in| function {\.{pop\$}} pops the top of the stack but +doesn't print it. + +@<|execute_fn|({\.{pop\$}})@>= +begin +pop_lit_stk (pop_lit1,pop_typ1); +end + + +@ +The |built_in| function {\.{preamble\$}} pushes onto the stack the +concatenation of all the \.{preamble} strings read from the database +files. + +@<|execute_fn|({\.{preamble\$}})@>= +procedure x_preamble; +begin +ex_buf_length := 0; +preamble_ptr := 0; +while (preamble_ptr < num_preamble_strings) do + begin + add_buf_pool (s_preamble[preamble_ptr]); + incr(preamble_ptr); + end; +add_pool_buf_and_push; {push the concatenation string onto the stack} +end; + + +@ +@^special character@> +The |built_in| function {\.{purify\$}} pops the top (string) literal, +removes nonalphanumeric characters except for |white_space| and +|sep_char| characters (these get converted to a |space|) and removes +certain alphabetic characters contained in the control sequences +associated with a special character, and pushes the resulting string. +If the literal isn't a string, it complains and pushes the null +string. + +@<|execute_fn|({\.{purify\$}})@>= +procedure x_purify; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str); + push_lit_stk (s_null, stk_str); + end +else + begin + ex_buf_length := 0; + add_buf_pool (pop_lit1); + @<Perform the purification@>; + add_pool_buf_and_push; {push this string onto the stack} + end; +end; + + +@ +@^special character@> +The resulting string has nonalphanumeric characters removed, and each +|white_space| or |sep_char| character converted to a |space|. The next +module handles special characters. This code doesn't complain if the +string isn't brace balanced. + +@<Perform the purification@>= +begin +brace_level := 0; {this is the top level} +ex_buf_xptr := 0; {this pointer is for the purified string} +ex_buf_ptr := 0; {and this one is for the original string} +while (ex_buf_ptr < ex_buf_length) do + begin + case (lex_class[ex_buf[ex_buf_ptr]]) of + white_space, + sep_char : + begin + ex_buf[ex_buf_xptr] := space; + incr(ex_buf_xptr); + end; + alpha, + numeric : + begin + ex_buf[ex_buf_xptr] := ex_buf[ex_buf_ptr]; + incr(ex_buf_xptr); + end; + othercases + if (ex_buf[ex_buf_ptr] = left_brace) then + begin + incr(brace_level); + if ((brace_level = 1) and + (ex_buf_ptr + 1 < ex_buf_length)) then + if (ex_buf[ex_buf_ptr+1] = backslash) then + @<Purify a special character@>; + end + else if (ex_buf[ex_buf_ptr] = right_brace) then + if (brace_level > 0) then + decr(brace_level) + endcases; + incr(ex_buf_ptr); + end; +ex_buf_length := ex_buf_xptr; +end + + +@ +@^special character@> +Special characters (even without a matching |right_brace|) are +purified by removing the control sequences (but restoring the correct +thing for `\.{\\i}' and `\.{\\j}' as well as the eleven alphabetic +foreign characters in Table~3.2 of the \LaTeX\ manual) and removing +all nonalphanumeric characters (including |white_space| and +|sep_char|s). + +@<Purify a special character@>= +begin +incr(ex_buf_ptr); {skip over the |left_brace|} +while ((ex_buf_ptr < ex_buf_length) and (brace_level > 0)) do + begin + incr(ex_buf_ptr); {skip over the |backslash|} + ex_buf_yptr := ex_buf_ptr; {mark the beginning of the control sequence} + while ((ex_buf_ptr < ex_buf_length) and + (lex_class[ex_buf[ex_buf_ptr]] = alpha)) do@/ + incr(ex_buf_ptr); {this scans the control sequence} + control_seq_loc := str_lookup(ex_buf,ex_buf_yptr,ex_buf_ptr-ex_buf_yptr, + control_seq_ilk,dont_insert); + if (hash_found) then + @<Purify this accented or foreign character@>; + while ((ex_buf_ptr < ex_buf_length) and (brace_level > 0) and + (ex_buf[ex_buf_ptr] <> backslash)) do + begin {this scans to the next control sequence} + case (lex_class[ex_buf[ex_buf_ptr]]) of + alpha, + numeric : + begin + ex_buf[ex_buf_xptr] := ex_buf[ex_buf_ptr]; + incr(ex_buf_xptr); + end; + othercases + if (ex_buf[ex_buf_ptr] = right_brace) then + decr(brace_level) + else if (ex_buf[ex_buf_ptr] = left_brace) then + incr(brace_level) + endcases; + incr(ex_buf_ptr); + end; + end; +decr(ex_buf_ptr); {unskip the |right_brace| (or last character)} +end + + +@ +We consider the purified character to be either the first alphabetic +character of its control sequence, or perhaps both alphabetic +characters. + +@<Purify this accented or foreign character@>= +begin +ex_buf[ex_buf_xptr] := ex_buf[ex_buf_yptr]; {the first alphabetic character} +incr(ex_buf_xptr); +case (ilk_info[control_seq_loc]) of + n_oe, + n_oe_upper, + n_ae, + n_ae_upper, + n_ss : + begin {and the second} + ex_buf[ex_buf_xptr] := ex_buf[ex_buf_yptr+1]; + incr(ex_buf_xptr); + end; + othercases + do_nothing +endcases; +end + + +@ +The |built_in| function {\.{quote\$}} pushes the string consisting of +the |double_quote| character. + +@<|execute_fn|({\.{quote\$}})@>= +procedure x_quote; +begin +str_room(1); +append_char (double_quote); +push_lit_stk (make_string, stk_str); +end; + + +@ +The |built_in| function {\.{skip\$}} is a no-op. + +@<|execute_fn|({\.{skip\$}})@>= +begin +do_nothing; +end + + +@ +The |built_in| function {\.{stack\$}} pops and prints the whole stack; +it's meant to be used for style designers while debugging. + +@<|execute_fn|({\.{stack\$}})@>= +begin +pop_whole_stack; +end + + +@ +@^push the literal stack@> +The |built_in| function {\.{substring\$}} pops the top three literals +(they are the two integers literals |pop_lit1| and |pop_lit2| and a +string literal, in that order). It pushes the substring of the (at +most) |pop_lit1| consecutive characters starting at the |pop_lit2|th +character (assuming 1-based indexing) if |pop_lit2| is positive, and +ending at the |-pop_lit2|th character from the end if |pop_lit2| is +negative (where the first character from the end is the last +character). If any of the types is incorrect, it complain and pushes +the null string. + +@<|execute_fn|({\.{substring\$}})@>= +procedure x_substring; +label exit; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +pop_lit_stk (pop_lit3,pop_typ3); +if (pop_typ1 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_int); + push_lit_stk (s_null, stk_str); + end +else if (pop_typ2 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_int); + push_lit_stk (s_null, stk_str); + end +else if (pop_typ3 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit3,pop_typ3,stk_str); + push_lit_stk (s_null, stk_str); + end +else + begin + sp_length := length(pop_lit3); + if (pop_lit1 >= sp_length) then + if ((pop_lit2 = 1) or (pop_lit2 = -1)) then + begin + repush_string; + return; + end; + if ((pop_lit1 <= 0) or (pop_lit2 = 0) or (pop_lit2 > sp_length) or + (pop_lit2 < -sp_length)) then + begin + push_lit_stk (s_null, stk_str); + return; + end + else + @<Form the appropriate substring@>; + end; +exit: +end; + + +@ +@^push the literal stack@> +This module finds the substring as described in the last section, +and slides it into place in the string pool, if necessary. + +@<Form the appropriate substring@>= +begin +if (pop_lit2 > 0) then + begin + if (pop_lit1 > sp_length - (pop_lit2-1)) then + pop_lit1 := sp_length - (pop_lit2-1); + sp_ptr := str_start[pop_lit3] + (pop_lit2-1); + sp_end := sp_ptr + pop_lit1; + if (pop_lit2 = 1) then + if (pop_lit3 >= cmd_str_ptr) then {no shifting---merely change pointers} + begin + str_start[pop_lit3+1] := sp_end; + unflush_string; + incr(lit_stk_ptr); + return; + end; + end +else {|-ex_buf_length <= pop_lit2 < 0|} + begin + pop_lit2 := -pop_lit2; + if (pop_lit1 > sp_length - (pop_lit2-1)) then + pop_lit1 := sp_length - (pop_lit2-1); + sp_end := str_start[pop_lit3+1] - (pop_lit2-1); + sp_ptr := sp_end - pop_lit1; + end; +while (sp_ptr < sp_end) do {shift the substring} + begin + append_char (str_pool[sp_ptr]); + incr(sp_ptr); + end; +push_lit_stk (make_string, stk_str); {and push it onto the stack} +end + + +@ +The |built_in| function {\.{swap\$}} pops the top two literals from +the stack and pushes them back swapped. + +@<|execute_fn|({\.{swap\$}})@>= +procedure x_swap; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if ((pop_typ1 <> stk_str) or (pop_lit1 < cmd_str_ptr)) then + begin + push_lit_stk (pop_lit1, pop_typ1); + if ((pop_typ2 = stk_str) and (pop_lit2 >= cmd_str_ptr)) then + unflush_string; + push_lit_stk (pop_lit2, pop_typ2); + end +else if ((pop_typ2 <> stk_str) or (pop_lit2 < cmd_str_ptr)) then + begin + unflush_string; {this is |pop_lit1|} + push_lit_stk (pop_lit1, stk_str); + push_lit_stk (pop_lit2, pop_typ2); + end +else {bummer, both are recent strings} + @<Swap the two strings (they're at the end of |str_pool|)@>; +end; + + +@ +We have to swap both (a)~the strings at the end of the string pool, +and (b)~their pointers on the literal stack. + +@<Swap the two strings (they're at the end of |str_pool|)@>= +begin +ex_buf_length := 0; +add_buf_pool (pop_lit2); {save the second string} +sp_ptr := str_start[pop_lit1]; +sp_end := str_start[pop_lit1+1]; +while (sp_ptr < sp_end) do {slide the first string down} + begin + append_char (str_pool[sp_ptr]); + incr(sp_ptr); + end; +push_lit_stk (make_string, stk_str); {and push it onto the stack} +add_pool_buf_and_push; {push second string onto the stack} +end + + +@ +@^special character@> +The |built_in| function {\.{text.length\$}} pops the top (string) +literal, and pushes the number of text characters it contains, where +an accented character (more precisely, a ``special character''$\!$, +defined earlier) counts as a single text character, even if it's +missing its matching |right_brace|, and where braces don't count as +text characters. If the literal isn't a string, it complains and +pushes the null string. + +@<|execute_fn|({\.{text.length\$}})@>= +procedure x_text_length; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str); + push_lit_stk (s_null, stk_str); + end +else + begin + num_text_chars := 0; + @<Count the text characters@>; + push_lit_stk (num_text_chars, stk_int); {and push it onto the stack} + end; +end; + + +@ +@^special character@> +Here we determine the number of text characters in the string, where +an entire special character counts as a single text character (even if +it's missing its matching |right_brace|), and where braces don't count +as text characters. + +@<Count the text characters@>= +begin +sp_ptr := str_start[pop_lit1]; +sp_end := str_start[pop_lit1+1]; +sp_brace_level := 0; +while (sp_ptr < sp_end) do + begin + incr(sp_ptr); + if (str_pool[sp_ptr-1] = left_brace) then + begin + incr(sp_brace_level); + if ((sp_brace_level = 1) and (sp_ptr < sp_end)) then + if (str_pool[sp_ptr] = backslash) then + begin + incr(sp_ptr); {skip over the |backslash|} + while ((sp_ptr < sp_end) and (sp_brace_level > 0)) do + begin + if (str_pool[sp_ptr] = right_brace) then + decr(sp_brace_level) + else if (str_pool[sp_ptr] = left_brace) then + incr(sp_brace_level); + incr(sp_ptr); + end; + incr(num_text_chars); + end; + end + else if (str_pool[sp_ptr-1] = right_brace) then + begin + if (sp_brace_level > 0) then + decr(sp_brace_level); + end + else + incr(num_text_chars); + end; +end + + +@ +@^special character@> +The |built_in| function {\.{text.prefix\$}} pops the top two literals +(the integer literal |pop_lit1| and a string literal, in that order). +It pushes the substring of the (at most) |pop_lit1| consecutive text +characters starting from the beginning of the string. This function +is similar to {\.{substring\$}}, but this one considers an accented +character (or more precisely, a ``special character''$\!$, even if +it's missing its matching |right_brace|) to be a single text character +(rather than however many |ASCII_code| characters it actually +comprises), and this function doesn't consider braces to be text +characters; furthermore, this function appends any needed matching +|right_brace|s. If any of the types is incorrect, it complains and +pushes the null string. + +@<|execute_fn|({\.{text.prefix\$}})@>= +procedure x_text_prefix; +label exit; +begin +pop_lit_stk (pop_lit1,pop_typ1); +pop_lit_stk (pop_lit2,pop_typ2); +if (pop_typ1 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_int); + push_lit_stk (s_null, stk_str); + end +else if (pop_typ2 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit2,pop_typ2,stk_str); + push_lit_stk (s_null, stk_str); + end +else if (pop_lit1 <= 0) then + begin + push_lit_stk (s_null, stk_str); + return; + end +else + @<Form the appropriate prefix@>; +exit: +end; + + +@ +@^push the literal stack@> +This module finds the prefix as described in the last section, and +appends any needed matching |right_brace|s. + +@<Form the appropriate prefix@>= +begin +sp_ptr := str_start[pop_lit2]; +sp_end := str_start[pop_lit2+1]; {this may change} +@<Scan the appropriate number of characters@>; +if (pop_lit2 >= cmd_str_ptr) then {no shifting---merely change pointers} + pool_ptr := sp_end +else + while (sp_ptr < sp_end) do {shift the substring} + begin + append_char (str_pool[sp_ptr]); + incr(sp_ptr); + end; +while (sp_brace_level > 0) do {add matching |right_brace|s} + begin + append_char (right_brace); + decr(sp_brace_level); + end; +push_lit_stk (make_string, stk_str); {and push it onto the stack} +end + + +@ +@^special character@> +This section scans |pop_lit1| text characters, where an entire special +character counts as a single text character (even if it's missing its +matching |right_brace|), and where braces don't count as text +characters. + +@<Scan the appropriate number of characters@>= +begin +num_text_chars := 0; +sp_brace_level := 0; +sp_xptr1 := sp_ptr; +while ((sp_xptr1 < sp_end) and (num_text_chars < pop_lit1)) do + begin + incr(sp_xptr1); + if (str_pool[sp_xptr1-1] = left_brace) then + begin + incr(sp_brace_level); + if ((sp_brace_level = 1) and (sp_xptr1 < sp_end)) then + if (str_pool[sp_xptr1] = backslash) then + begin + incr(sp_xptr1); {skip over the |backslash|} + while ((sp_xptr1 < sp_end) and (sp_brace_level > 0)) do + begin + if (str_pool[sp_xptr1] = right_brace) then + decr(sp_brace_level) + else if (str_pool[sp_xptr1] = left_brace) then + incr(sp_brace_level); + incr(sp_xptr1); + end; + incr(num_text_chars); + end; + end + else if (str_pool[sp_xptr1-1] = right_brace) then + begin + if (sp_brace_level > 0) then + decr(sp_brace_level); + end + else + incr(num_text_chars); + end; +sp_end := sp_xptr1; +end + + +@ +The |built_in| function {\.{top\$}} pops and prints the top of the +stack. + +@<|execute_fn|({\.{top\$}})@>= +begin +pop_top_and_print; +end + + +@ +The |built_in| function {\.{type\$}} pushes the appropriate string +from |type_list| onto the stack (unless either it's |undefined| or +|empty|, in which case it pushes the null string). + +@<|execute_fn|({\.{type\$}})@>= +procedure x_type; +begin +if (not mess_with_entries) then + bst_cant_mess_with_entries_print + else + if ((type_list[cite_ptr] = undefined) or + (type_list[cite_ptr] = empty)) then + push_lit_stk (s_null, stk_str) + else + push_lit_stk (hash_text[type_list[cite_ptr]], stk_str); +end; + + +@ +The |built_in| function {\.{warning\$}} pops the top (string) literal +and prints it following a warning message. This is implemented as a +special |built_in| function rather than using the {\.{top\$}} function +so that it can |mark_warning|. + +@<|execute_fn|({\.{warning\$}})@>= +procedure x_warning; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_str) then + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str) +else + begin + print ('Warning--'); + print_lit (pop_lit1,pop_typ1); + mark_warning; + end; +end; + + +@ +The |built_in| function {\.{while\$}} pops the top two (function) +literals, and keeps executing the second as long as the (integer) +value left on the stack by executing the first is greater than 0. If +either type is incorrect, it complains but does nothing else. + +@<|execute_fn|({\.{while\$}})@>= +begin +pop_lit_stk (r_pop_lt1,r_pop_tp1); +pop_lit_stk (r_pop_lt2,r_pop_tp2); +if (r_pop_tp1 <> stk_fn) then + print_wrong_stk_lit (r_pop_lt1,r_pop_tp1,stk_fn) +else if (r_pop_tp2 <> stk_fn) then + print_wrong_stk_lit (r_pop_lt2,r_pop_tp2,stk_fn) +else + loop + begin + execute_fn (r_pop_lt2); {this is the \.{while\$} test} + pop_lit_stk (pop_lit1,pop_typ1); + if (pop_typ1 <> stk_int) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_int); + goto end_while; + end + else + if (pop_lit1 > 0) then + execute_fn (r_pop_lt1) {this is the \.{while\$} body} + else + goto end_while; + end; +end_while: {justifies this |mean_while|} +end + + +@ +@^literal literal@> +@^special character@> +The |built_in| function {\.{width\$}} pops the top (string) literal +and pushes the integer that represents its width in units specified by +the |char_width| array. This function takes the literal literally; +that is, it assumes each character in the string is to be printed as +is, regardless of whether the character has a special meaning to \TeX, +except that special characters (even without their |right_brace|s) are +handled specially. If the literal isn't a string, it complains and +pushes~0. + +@<|execute_fn|({\.{width\$}})@>= +procedure x_width; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_str) then + begin + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str); + push_lit_stk (0, stk_int); + end +else + begin + ex_buf_length := 0; + add_buf_pool (pop_lit1); + string_width := 0; + @<Add up the |char_width|s in this string@>; + push_lit_stk (string_width, stk_int); + end +end; + + +@ +We use the natural width for all but special characters, and we +complain if the string isn't brace-balanced. + +@<Add up the |char_width|s in this string@>= +begin +brace_level := 0; {we're at the top level} +ex_buf_ptr := 0; {and the beginning of string} +while (ex_buf_ptr < ex_buf_length) do + begin + if (ex_buf[ex_buf_ptr] = left_brace) then + begin + incr(brace_level); + if ((brace_level = 1) and (ex_buf_ptr + 1 < ex_buf_length)) then + if (ex_buf[ex_buf_ptr+1] = backslash) then + @<Determine the width of this special character@> + else + string_width := string_width + char_width[left_brace] + else + string_width := string_width + char_width[left_brace]; + end + else if (ex_buf[ex_buf_ptr] = right_brace) then + begin + decr_brace_level (pop_lit1); + string_width := string_width + char_width[right_brace]; + end + else + string_width := string_width + char_width[ex_buf[ex_buf_ptr]]; + incr(ex_buf_ptr); + end; +check_brace_level (pop_lit1); +end + + +@ +@^special character@> +We use the natural widths of all characters except that some +characters have no width: braces, control sequences (except for the +usual 13 accented and foreign characters, whose widths are given in +the next module), and |white_space| following control sequences (even +a null control sequence). + +@<Determine the width of this special character@>= +begin +incr(ex_buf_ptr); {skip over the |left_brace|} +while ((ex_buf_ptr < ex_buf_length) and (brace_level > 0)) do + begin + incr(ex_buf_ptr); {skip over the |backslash|} + ex_buf_xptr := ex_buf_ptr; + while ((ex_buf_ptr < ex_buf_length) and + (lex_class[ex_buf[ex_buf_ptr]] = alpha)) do@/ + incr(ex_buf_ptr); {this scans the control sequence} + if ((ex_buf_ptr < ex_buf_length) and (ex_buf_ptr = ex_buf_xptr)) then + incr(ex_buf_ptr) {this skips a nonalpha control seq} + else + begin + control_seq_loc := str_lookup(ex_buf,ex_buf_xptr, + ex_buf_ptr-ex_buf_xptr,control_seq_ilk,dont_insert); + if (hash_found) then + @<Determine the width of this accented or foreign character@>; + end; + while ((ex_buf_ptr < ex_buf_length) and + (lex_class[ex_buf[ex_buf_ptr]] = white_space)) do + incr(ex_buf_ptr); {this skips following |white_space|} + while ((ex_buf_ptr < ex_buf_length) and (brace_level > 0) and + (ex_buf[ex_buf_ptr] <> backslash)) do + begin {this scans to the next control sequence} + if (ex_buf[ex_buf_ptr] = right_brace) then + decr(brace_level) + else if (ex_buf[ex_buf_ptr] = left_brace) then + incr(brace_level) + else + string_width := string_width + char_width[ex_buf[ex_buf_ptr]]; + incr(ex_buf_ptr); + end; + end; +decr(ex_buf_ptr); {unskip the |right_brace|} +end + + +@ +Five of the 13 possibilities resort to special information not present +in the |char_width| array; the other eight simply use |char_width|'s +information for the first letter of the control sequence. + +@<Determine the width of this accented or foreign character@>= +begin +case (ilk_info[control_seq_loc]) of + n_ss : string_width := string_width + ss_width; + n_ae : string_width := string_width + ae_width; + n_oe : string_width := string_width + oe_width; + n_ae_upper : string_width := string_width + upper_ae_width; + n_oe_upper : string_width := string_width + upper_oe_width; + othercases + string_width := string_width + char_width[ex_buf[ex_buf_xptr]] +endcases; +end + + +@ +The |built_in| function {\.{write\$}} pops the top (string) literal +and writes it onto the output buffer |out_buf| (which will result in +stuff being written onto the \.{.bbl} file if the buffer fills up). If +the literal isn't a string, it complains but does nothing else. + +@<|execute_fn|({\.{write\$}})@>= +procedure x_write; +begin +pop_lit_stk (pop_lit1,pop_typ1); +if (pop_typ1 <> stk_str) then + print_wrong_stk_lit (pop_lit1,pop_typ1,stk_str) +else + add_out_pool (pop_lit1); +end; + + + +@* Cleaning up. +@^clich\'e-\`a-trois@> +@^fat lady@> +@^turn out lights@> +@^Yogi@> +This section does any last-minute printing and ends the program. + +@<Clean up and leave@>= +begin +if ((read_performed) and (not reading_completed)) then + begin + print ('Aborted at line ',bib_line_num:0,' of file '); + print_bib_name; + end; +trace_and_stat_printing; +@<Print the job |history|@>; +a_close (log_file); +{turn out the lights, the fat lady has sung; it's over, Yogi} +end + + +@ +Here we print |trace| and/or |stat| information, if desired. + +@<Procedures and functions for all file I/O, error messages, and such@>= +procedure trace_and_stat_printing; +begin +@# + trace + @<Print all \.{.bib}- and \.{.bst}-file information@>; + @<Print all |cite_list| and entry information@>; + @<Print the |wiz_defined| functions@>; + @<Print the string pool@>; + ecart@/ +@# + stat + @<Print usage statistics@>; + tats@/ +@# +end; + + +@ +This prints information obtained from the \.{.aux} file about the +other files. + +@<Print all \.{.bib}- and \.{.bst}-file information@>= +begin +if (num_bib_files = 1) then + trace_pr_ln ('The 1 database file is') + else + trace_pr_ln ('The ',num_bib_files:0,' database files are'); +if (num_bib_files = 0) then + trace_pr_ln (' undefined') + else + begin + bib_ptr := 0; + while (bib_ptr < num_bib_files) do + begin + trace_pr (' '); + trace_pr_pool_str (cur_bib_str); + trace_pr_pool_str (s_bib_extension); + trace_pr_newline; + incr(bib_ptr); + end; + end; +trace_pr ('The style file is '); +if (bst_str = 0) then + trace_pr_ln ('undefined') + else + begin + trace_pr_pool_str (bst_str); + trace_pr_pool_str (s_bst_extension); + trace_pr_newline; + end; +end + + +@ +In entry-sorted order, this prints an entry's |cite_list| string and, +indirectly, its entry type and entry variables. + +@<Print all |cite_list| and entry information@>= +begin +if (all_entries) then + trace_pr ('all_marker=',all_marker:0,', '); +if (read_performed) then + trace_pr_ln ('old_num_cites=',old_num_cites:0) + else + trace_pr_newline; +trace_pr ('The ',num_cites:0); +if (num_cites = 1) then + trace_pr_ln (' entry:') + else + trace_pr_ln (' entries:'); +if (num_cites = 0) then + trace_pr_ln (' undefined') + else + begin + sort_cite_ptr := 0; + while (sort_cite_ptr < num_cites) do + begin + if (not read_completed) then {we didn't finish the \.{read} command} + cite_ptr := sort_cite_ptr + else + cite_ptr := sorted_cites[sort_cite_ptr]; + trace_pr_pool_str (cur_cite_str); + if (read_performed) then + @<Print entry information@> + else + trace_pr_newline; + incr(sort_cite_ptr); + end; + end; +end + + +@ +This prints information gathered while reading the \.{.bst} and +\.{.bib} files. + +@<Print entry information@>= +begin +trace_pr (', entry-type '); +if (type_list[cite_ptr] = undefined) then + undefined : trace_pr ('unknown') +else if (type_list[cite_ptr] = empty) then + trace_pr ('--- no type found') +else + trace_pr_pool_str (hash_text[type_list[cite_ptr]]); +trace_pr_ln (', has entry strings'); +@<Print entry strings@>; +trace_pr (' has entry integers'); +@<Print entry integers@>; +trace_pr_ln (' and has fields'); +@<Print fields@>; +end + + +@ +This prints, for the current entry, the strings declared by the +\.{entry} command. + +@<Print entry strings@>= +begin +if (num_ent_strs = 0) then + trace_pr_ln (' undefined') +else if (not read_completed) then + trace_pr_ln (' uninitialized') +else + begin + str_ent_ptr := cite_ptr * num_ent_strs; + while (str_ent_ptr < (cite_ptr+1)*num_ent_strs) do + begin + ent_chr_ptr := 0; + trace_pr (' "'); + 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; + trace_pr_ln ('"'); + incr(str_ent_ptr); + end; + end; +end + + +@ +This prints, for the current entry, the integers declared by the +\.{entry} command. + +@<Print entry integers@>= +begin +if (num_ent_ints = 0) then + trace_pr (' undefined') +else if (not read_completed) then + trace_pr (' uninitialized') +else + begin + int_ent_ptr := cite_ptr*num_ent_ints; + while (int_ent_ptr < (cite_ptr+1)*num_ent_ints) do + begin + trace_pr (' ',entry_ints[int_ent_ptr]:0); + incr(int_ent_ptr); + end; + end; +trace_pr_newline; +end + + +@ +This prints the fields stored for the current entry. + +@<Print fields@>= +begin +if (not read_performed) then + trace_pr_ln (' uninitialized') + else + begin + field_ptr := cite_ptr * num_fields; + field_end_ptr := field_ptr + num_fields; + no_fields := true; + while (field_ptr < field_end_ptr) do + begin + if (field_info[field_ptr] <> missing) then + begin + trace_pr (' "'); + trace_pr_pool_str (field_info[field_ptr]); + trace_pr_ln ('"'); + no_fields := false; + end; + incr(field_ptr); + end; + if (no_fields) then + trace_pr_ln (' missing'); + end; +end + + +@ +This gives all the |wiz_defined| functions that appeared in the +\.{.bst} file. + +@<Print the |wiz_defined| functions@>= +begin +trace_pr_ln ('The wiz-defined functions are'); +if (wiz_def_ptr = 0) then + trace_pr_ln (' nonexistent') + else + begin + wiz_fn_ptr := 0; + while (wiz_fn_ptr < wiz_def_ptr) do + begin + if (wiz_functions[wiz_fn_ptr] = end_of_def) then + trace_pr_ln (wiz_fn_ptr:0,'--end-of-def--') + else if (wiz_functions[wiz_fn_ptr] = quote_next_fn) then + trace_pr (wiz_fn_ptr:0,' quote_next_function ') + else + begin + trace_pr (wiz_fn_ptr:0,' `'); + trace_pr_pool_str (hash_text[wiz_functions[wiz_fn_ptr]]); + trace_pr_ln (''''); + end; + incr(wiz_fn_ptr); + end; + end; +end + + +@ +This includes all the `static' strings (that is, those that are also +in the hash table), but none of the dynamic strings (that is, those +put on the stack while executing \.{.bst} commands). + +@<Print the string pool@>= +begin +trace_pr_ln ('The string pool is'); +str_num := 1; +while (str_num < str_ptr) do + begin + trace_pr (str_num:4, str_start[str_num]:6,' "'); + trace_pr_pool_str (str_num); + trace_pr_ln ('"'); + incr(str_num); + end; +end + + +@ +@^statistics@> +These statistics can help determine how large some of the constants +should be and can tell how useful certain |built_in| functions are. +They are written to the same files as tracing information. + +@d stat_pr == trace_pr +@d stat_pr_ln == trace_pr_ln +@d stat_pr_pool_str == trace_pr_pool_str + +@<Print usage statistics@>= +begin +stat_pr ('You''ve used ',num_cites:0); +if (num_cites = 1) then + stat_pr_ln (' entry,') + else + stat_pr_ln (' entries,'); +stat_pr_ln (' ',wiz_def_ptr:0,' wiz_defined-function locations,'); +stat_pr_ln (' ',str_ptr:0,' strings with ',str_start[str_ptr]:0, + ' characters,'); +blt_in_ptr := 0; +total_ex_count := 0; +while (blt_in_ptr < num_blt_in_fns) do + begin + total_ex_count := total_ex_count + execution_count[blt_in_ptr]; + incr(blt_in_ptr); + end; +stat_pr_ln ('and the built_in function-call counts, ', total_ex_count:0, + ' in all, are:'); +blt_in_ptr := 0; +while (blt_in_ptr < num_blt_in_fns) do + begin + stat_pr_pool_str (hash_text[blt_in_loc[blt_in_ptr]]); + stat_pr_ln (' -- ',execution_count[blt_in_ptr]:0); + incr(blt_in_ptr); + end; +end + + +@ +@^bunk, history@> +@^system dependencies@> +@:this can't happen}{\quad History is bunk@> +Some implementations may wish to pass the |history| value to the +operating system so that it can be used to govern whether or not other +programs are started. Here we simply report the history to the user. + +@<Print the job |history|@>= +case (history) of + spotless : do_nothing; + warning_message : begin + if (err_count = 1) then + print_ln ('(There was 1 warning)') + else + print_ln ('(There were ',err_count:0,' warnings)'); + end; + error_message : begin + if (err_count = 1) then + print_ln ('(There was 1 error message)') + else + print_ln ('(There were ',err_count:0, + ' error messages)'); + end; + fatal_message : print_ln ('(That was a fatal error)'); + othercases begin + print ('History is bunk'); + print_confusion; + end +endcases + + + +@* System-dependent changes. +@^system dependencies@> +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. + + + +@* Index. +@.this can't happen@> +Here is where you can find all uses of each identifier in the program, +with underlined entries pointing to where the identifier was defined. +If the identifier is only one letter long, however, you get to see only +the underlined entries. All references are to section numbers instead of +page numbers. + +This index also lists a few error messages and other aspects of the +program that you might want to look up some day. For example, the +entry for ``system dependencies'' lists all sections that should +receive special attention from people who are installing \TeX\ in a +new operating environment. A list of various things that can't happen +appears under ``this can't happen''$\!$. diff --git a/Build/source/extra/bibtex/btxbst.doc b/Build/source/extra/bibtex/btxbst.doc new file mode 100644 index 00000000000..7ea413e8915 --- /dev/null +++ b/Build/source/extra/bibtex/btxbst.doc @@ -0,0 +1,2528 @@ +% BibTeX `plain' family + % version 0.99b for BibTeX versions 0.99a or later, LaTeX version 2.09. + % Copyright (C) 1985, all rights reserved. + % Copying of this file is authorized only if either + % (1) you make absolutely no changes to your copy, including name, or + % (2) if you do make changes, you name it something other than + % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst. + % This restriction helps ensure that all standard styles are identical. + % The file btxbst.doc has the documentation for this style. +% Please notify Oren Patashnik (PATASHNIK@SCORE.STANFORD.EDU) of any bugs in +% these standard styles or in this documentation file. +% +% This is file btxbxt.doc; it helps document bibliography styles, +% and is also a template file that you can use to make +% several different style files, if you have access to a C preprocessor. +% For example, the standard styles were made by doing something like +% cpp -P -DPLAIN btxbst.doc plain.txt +% cpp -P -DUNSRT btxbst.doc unsrt.txt +% cpp -P -DALPHA btxbst.doc alpha.txt +% cpp -P -DABBRV btxbst.doc abbrv.txt +% and then renaming after removing unwanted comments and blank lines. +% If you don't have access, +% you can edit this file by hand to imitate the preprocessor, +% with the following explanation of the C preprocessor constructs used here. +% +% The output of the preprocessor is the same as the input, except that certain +% lines will be excluded (and some blank lines will be added). The sequence +% #if VAR +% lines to be included when VAR is not zero +% #else +% lines to be included when VAR is zero +% #endif +% (with the #-signs appearing in column 1) means that one set or the other of +% the lines are to be included depending on the value of VAR. +% The #else part is optional. Comments can be added after #else and #endif. +% Variables can be set by +% #define VAR value +% and one can also use #ifdef VAR to see if VAR has any value, and #ifndef +% to see if it has none. +% Another #if form used in this file is #if !VAR, which includes the lines +% after the #if only if VAR is zero. +% +% Convention: Use all uppercase identifiers for these preprocessor variables +% so you can spot them easily +% +% The command line to the preprocessor should define one of PLAIN, UNSRT, ALPHA +% or ABBRV (though PLAIN will be used by default if none is given), +% and the following lines will set various boolean variables to control the +% various lines that are chosen from the rest of the file. +% Each boolean variable should be set true (1) or false (0) in each style. +% Here are the current variables, and their meanings: +% LAB_ALPH: an alphabetic label is used (if false then a numeric +% label is used) +% SORTED: the entries should be sorted by label (if nonnumeric) +% and other info, like authors (if false, then +% entries remain in order of occurrence) +% NAME_FULL: the authors, editors, etc., get the full names as +% given in the bibliography file (if false, the first +% names become initials) +% ATIT_LOWER: titles of non-"books" (e.g., articles) should be +% converted to lower-case, except the first letter or +% first letter after a colon +% (if false then they appear as in the database) +% MONTH_FULL: months are spelled out in full (if false, then +% they're abbreviated) +% JOUR_FULL: macro journal names are spelled out in full +% (if false then they are abbreviated, currently +% as they appear in ACM publications) +#ifndef UNSRT +# ifndef ALPHA +# ifndef ABBRV +# define PLAIN 1 +# endif +# endif +#endif +#ifdef PLAIN +% plain style (sorted numbers) +# define LAB_ALPH 0 +# define SORTED 1 +# define NAME_FULL 1 +# define ATIT_LOWER 1 +# define MONTH_FULL 1 +# define JOUR_FULL 1 +#endif +#ifdef UNSRT +% unsrt style (unsorted numbers) +# define LAB_ALPH 0 +# define SORTED 0 +# define NAME_FULL 1 +# define ATIT_LOWER 1 +# define MONTH_FULL 1 +# define JOUR_FULL 1 +#endif +#ifdef ALPHA +% alpha style (sorted short alphabetics) +# define LAB_ALPH 1 +# define SORTED 1 +# define NAME_FULL 1 +# define ATIT_LOWER 1 +# define MONTH_FULL 1 +# define JOUR_FULL 1 +#endif +#ifdef ABBRV +% abbrv style (sorted numbers, with abbreviations) +# define LAB_ALPH 0 +# define SORTED 1 +# define NAME_FULL 0 +# define ATIT_LOWER 1 +# define MONTH_FULL 0 +# define JOUR_FULL 0 +#endif +% +% Entry formatting: Similar to that recommended by Mary-Claire van Leunen +% in "A Handbook for Scholars". Book-like titles are italicized +% (emphasized) and non-book titles are converted to sentence +% capitilization (and not enclosed in quotes). +% This file outputs a \newblock between major blocks of an entry +% (the name \newblock is analogous to the names \newline and \newpage) +% so that the user can obtain an "open" format, which has a line break +% before each block and lines after the first are indented within blocks, +% by giving the optional \documentstyle argument `openbib'; +% The default is the "closed" format---blocks runs together. +% +% Citation alphabetic label format: +% [Knu73] for single author (or editor or key) +% [AHU83] (first letters of last names) for multiple authors +% +% Citation label numberic format: +% [number] +% +% Reference list ordering for sorted, alphabetic lables: +% alphabetical by citation label, then by author(s) or whatever +% passes for author in the absence of one, then by year, +% then title +% +% Reference list ordering for sorted, numeric lables: +% alphabetical by author(s) or whatever passes +% for author in the absence of one, then by year, then title +% +% Reference list ordering for unsorted: +% by the order cited in the text +% +% History +% 12/16/84 (HWT) Original `plain' version, by Howard Trickey. +% 12/23/84 (LL) Some comments made by Leslie Lamport. +% 2/16/85 (OP) Changes based on LL's comments, Oren Patashnik. +% 2/17/85 (HWT) Template file and other standard styles made. +% 3/28/85 (OP) First release, version 0.98b for BibTeX 0.98f. +% 5/ 9/85 (OP) Version 0.98c for BibTeX 0.98i: +% fixed Theoretical Computer Science macro name; +% fixed the format.vol.num.pages function. +% 1/24/88 (OP) Version 0.99a for BibTeX 0.99a, main changes: +% assignment operator (:=) arguments reversed; +% the preamble$ function outputs the database PREAMBLE; +% entry.max$ and global.max$ (built-in) variables replace +% entry.string.max and global.string.max functions; +% alphabetizing by year then title, not just title; +% many unnecessary ties removed; \it ==> \em; +% the `alpha' style uses a superscripted `+' instead of a +% `*' for unnamed names in constructing the label; +% the `abbrv' style now uses "Mar." and "Sept."; +% the functions calc.label and presort now look at just +% the fields they're supposed to; +% BOOKLET, MASTERSTHESIS, TECHREPORT use nonbook titles; +% INBOOK and INCOLLECTION take an optional type (e.g. +% type = "Section"), overriding the default "chapter"; +% BOOK, INBOOK, INCOLLECTION, and PROCEEDINGS now allow +% either volume or number, not just volume; +% INCOLLECTION now allows an edition and series field; +% PROCEEDINGS and INPROCEEDINGS now use the address field +% to tell where a conference was held; +% INPROCEEDINGS and PROCEEDINGS now allow either volume +% or number, and also a series field; +% MASTERSTHESIS and PHDTHESIS accept types other than +% "Master's thesis" and "PhD thesis"; +% UNPUBLISHED now outputs, in one block, note then date; +% MANUAL now prints out the organization in +% the first block if the author field is empty; +% MISC can't be empty---it requires some optional field. +% 3/23/88 (OP) Version 0.99b for BibTeX 0.99c---changed the three +% erroneous occurrences of `cite ' to `cite$ '; this +% change didn't affect the four standard styles, so the +% 0.99a versions of those styles are still current. +% +% The ENTRY declaration +% Like Scribe's (according to pages 231-2 of the April '84 edition), +% but no fullauthor or editors fields because BibTeX does name handling. +% The annote field is commented out here because this family doesn't +% include an annotated bibliography style. And in addition to the fields +% listed here, BibTeX has a built-in crossref field, explained later. + +ENTRY +% Fields: + { address +% Usually the address of a publisher or other type of organization. +% Put information in this field only if it helps the reader find the +% thing---for example you should omit the address of a major +% publisher entirely. For a PROCEEDINGS or an INPROCEEDINGS, +% however, it's the address of the conference; for those two entry +% types, include the publisher's or organization's address, if +% necessary, in the publisher or organization field. +% annote +% Long annotation---for annotated bibliographies (begins sentence). + author +% Name(s) of author(s), in BibTeX name format. + booktitle +% Book title when the thing being referenced isn't the whole book. +% For book entries, the title field should be used instead. + chapter +% Chapter (or section or whatever) number. + edition +% Edition of a book---should be an ordinal (e.g., "Second"). + editor +% Name(s) of editor(s), in BibTeX name format. +% If there is also an author field, then the editor field should be +% for the book or collection that the work appears in. + howpublished +% How something strange has been published (begins sentence). + institution +% Sponsoring institution of a technical report. + journal +% Journal name (macros are provided for many). + key +% Alphabetizing, labeling, and cross-referencing key +% (needed when an entry has no author or editor). + month +% Month (macros are provided). + note +% To help the reader find a reference (begins sentence). + number +% Number of a journal or technical report, or of a work in a series. + organization +% Organization sponsoring a conference (or publishing a manual); if +% the editor (or author) is empty, and if the organization produces +% an awkward label or cross reference, you should put appropriately +% condensed organization information in the key field as well. + pages +% Page number or numbers (use `--' to separate a range, use `+' +% to indicate pages following that don't form a simple range). + publisher +% Publisher name. + school +% School name (for theses). + series +% The name of a series or set of books. +% An individual book will will also have it's own title. + title +% The title of the thing you're referred to. + type +% Type of a Techreport (e.g., "Research Note") to be used instead of +% the default "Technical Report"; or, similarly, the type of a +% thesis; or of a part of a book. + volume +% The volume number of a journal or multivolume work. + year +% The year should contain only numerals (technically, it should end +% with four numerals, after purification; doesn't a begin sentence). + } +% There are no integer entry variables + {} +% These string entry variables are used to form the citation label. +% In a storage pinch, sort.label can be easily computed on the fly. +#if LAB_ALPH +#if SORTED + { label extra.label sort.label } +#else !SORTED +% It doesn't seem like a good idea to use an order-of-citation +% reference list when using alphabetic labels, but when this happens +% we do things a little differently + { label } +#endif SORTED +#else !LAB_ALPH + { label } +#endif LAB_ALPH + +% Each entry function starts by calling output.bibitem, to write the +% \bibitem and its arguments to the .BBL file. Then the various fields +% are formatted and printed by output or output.check. Those functions +% handle the writing of separators (commas, periods, \newblock's), +% taking care not to do so when they are passed a null string. +% Finally, fin.entry is called to add the final period and finish the +% entry. +% +% A bibliographic reference is formatted into a number of `blocks': +% in the open format, a block begins on a new line and subsequent +% lines of the block are indented. A block may contain more than +% one sentence (well, not a grammatical sentence, but something to +% be ended with a sentence ending period). The entry functions should +% call new.block whenever a block other than the first is about to be +% started. They should call new.sentence whenever a new sentence is +% to be started. The output functions will ensure that if two +% new.sentence's occur without any non-null string being output between +% them then there won't be two periods output. Similarly for two +% successive new.block's. +% +% The output routines don't write their argument immediately. +% Instead, by convention, that argument is saved on the stack to be +% output next time (when we'll know what separator needs to come +% after it). Meanwhile, the output routine has to pop the pending +% output off the stack, append any needed separator, and write it. +% +% To tell which separator is needed, we maintain an output.state. +% It will be one of these values: +% before.all just after the \bibitem +% mid.sentence in the middle of a sentence: comma needed +% if more sentence is output +% after.sentence just after a sentence: period needed +% after.block just after a block (and sentence): +% period and \newblock needed. +% Note: These styles don't use after.sentence +% +% VAR: output.state : INTEGER -- state variable for output +% +% The output.nonnull function saves its argument (assumed to be nonnull) +% on the stack, and writes the old saved value followed by any needed +% separator. The ordering of the tests is decreasing frequency of +% occurrence. +% +% output.nonnull(s) == +% BEGIN +% s := argument on stack +% if output.state = mid.sentence then +% write$(pop() * ", ") +% -- "pop" isn't a function: just use stack top +% else +% if output.state = after.block then +% write$(add.period$(pop())) +% newline$ +% write$("\newblock ") +% else +% if output.state = before.all then +% write$(pop()) +% else -- output.state should be after.sentence +% write$(add.period$(pop()) * " ") +% fi +% fi +% output.state := mid.sentence +% fi +% push s on stack +% END +% +% The output function calls output.nonnull if its argument is non-empty; +% its argument may be a missing field (thus, not necessarily a string) +% +% output(s) == +% BEGIN +% if not empty$(s) then output.nonnull(s) +% fi +% END +% +% The output.check function is the same as the output function except that, if +% necessary, output.check warns the user that the t field shouldn't be empty +% (this is because it probably won't be a good reference without the field; +% the entry functions try to make the formatting look reasonable even when +% such fields are empty). +% +% output.check(s,t) == +% BEGIN +% if empty$(s) then +% warning$("empty " * t * " in " * cite$) +% else output.nonnull(s) +% fi +% END +% +% The output.bibitem function writes the \bibitem for the current entry +% (the label should already have been set up), and sets up the separator +% state for the output functions. And, it leaves a string on the stack +% as per the output convention. +% +% output.bibitem == +% BEGIN +% newline$ +% write$("\bibitem[") % for alphabetic labels, +% write$(label) % these three lines +% write$("]{") % are used +% write$("\bibitem{") % this line for numeric labels +% write$(cite$) +% write$("}") +% push "" on stack +% output.state := before.all +% END +% +% The fin.entry function finishes off an entry by adding a period to the +% string remaining on the stack. If the state is still before.all +% then nothing was produced for this entry, so the result will look bad, +% but the user deserves it. (We don't omit the whole entry because the +% entry was cited, and a bibitem is needed to define the citation label.) +% +% fin.entry == +% BEGIN +% write$(add.period$(pop())) +% newline$ +% END +% +% The new.block function prepares for a new block to be output, and +% new.sentence prepares for a new sentence. +% +% new.block == +% BEGIN +% if output.state <> before.all then +% output.state := after.block +% fi +% END +% +% new.sentence == +% BEGIN +% if output.state <> after.block then +% if output.state <> before.all then +% output.state := after.sentence +% fi +% fi +% END +% + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +% the variables s and t are temporary string holders + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ +#if LAB_ALPH + "\bibitem[" write$ + label write$ + "]{" write$ +#else + "\bibitem{" write$ +#endif LAB_ALPH + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +% This function finishes all entries. + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +% These three functions pop one or two (integer) arguments from the stack +% and push a single one, either 0 or 1. +% The 'skip$ in the `and' and `or' functions are used because +% the corresponding if$ would be idempotent + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +% Sometimes we begin a new block only if the block will be big enough. The +% new.block.checka function issues a new.block if its argument is nonempty; +% new.block.checkb does the same if either of its TWO arguments is nonempty. + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +% The new.sentence.check functions are analogous. + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +% Here are some functions for formatting chunks of an entry. +% By convention they either produce a string that can be followed by +% a comma or period (using add.period$, so it is OK to end in a period), +% or they produce the null string. +% +% A useful utility is the field.or.null function, which checks if the +% argument is the result of pushing a `missing' field (one for which no +% assignment was made when the current entry was read in from the database) +% or the result of pushing a string having no non-white-space characters. +% It returns the null string if so, otherwise it returns the field string. +% Its main (but not only) purpose is to guarantee that what's left on the +% stack is a string rather than a missing field. +% +% field.or.null(s) == +% BEGIN +% if empty$(s) then return "" +% else return s +% END +% +% Another helper function is emphasize, which returns the argument emphazised, +% if that is non-empty, otherwise it returns the null string. Italic +% corrections aren't used, so this function should be used when punctation +% will follow the result. +% +% emphasize(s) == +% BEGIN +% if empty$(s) then return "" +% else return "{\em " * s * "}" +% +% The format.names function formats the argument (which should be in +% BibTeX name format) into "First Von Last, Junior", separated by commas +% and with an "and" before the last (but ending with "et~al." if the last +% of multiple authors is "others"). This function's argument should always +% contain at least one name. +% +% VAR: nameptr, namesleft, numnames: INTEGER +% pseudoVAR: nameresult: STRING (it's what's accumulated on the stack) +% +% format.names(s) == +% BEGIN +% nameptr := 1 +% numnames := num.names$(s) +% namesleft := numnames +% while namesleft > 0 +% do +% % for full names: +% t := format.name$(s, nameptr, "{ff~}{vv~}{ll}{, jj}") +% % for abbreviated first names: +% t := format.name$(s, nameptr, "{f.~}{vv~}{ll}{, jj}") +% if nameptr > 1 then +% if namesleft > 1 then nameresult := nameresult * ", " * t +% else if numnames > 2 +% then nameresult := nameresult * "," +% fi +% if t = "others" +% then nameresult := nameresult * " et~al." +% else nameresult := nameresult * " and " * t +% fi +% fi +% else nameresult := t +% fi +% nameptr := nameptr + 1 +% namesleft := namesleft - 1 +% od +% return nameresult +% END +% +% The format.authors function returns the result of format.names(author) +% if the author is present, or else it returns the null string +% +% format.authors == +% BEGIN +% if empty$(author) then return "" +% else return format.names(author) +% fi +% END +% +% Format.editors is like format.authors, but it uses the editor field, +% and appends ", editor" or ", editors" +% +% format.editors == +% BEGIN +% if empty$(editor) then return "" +% else +% if num.names$(editor) > 1 then +% return format.names(editor) * ", editors" +% else +% return format.names(editor) * ", editor" +% fi +% fi +% END +% +% Other formatting functions are similar, so no "comment version" will be +% given for them. +% +% The `pop$' in this function gets rid of the duplicate `empty' value and +% the `skip$' returns the duplicate field value + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } +#if NAME_FULL + { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't := +#else + { s nameptr "{f.~}{vv~}{ll}{, jj}" format.name$ 't := +#endif NAME_FULL + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +% The format.title function is used for non-book-like titles. +% For most styles we convert to lowercase (except for the very first letter, +% and except for the first one after a colon (followed by whitespace)), +% and hope the user has brace-surrounded words that need to stay capitilized; +% for some styles, however, we leave it as it is in the database. + +FUNCTION {format.title} +{ title empty$ + { "" } +#if ATIT_LOWER + { title "t" change.case$ } +#else + 'title +#endif ATIT_LOWER + if$ +} + +% By default, BibTeX sets the global integer variable global.max$ to the BibTeX +% constant glob_str_size, the maximum length of a global string variable. +% Analogously, BibTeX sets the global integer variable entry.max$ to +% ent_str_size, the maximum length of an entry string variable. +% The style designer may change these if necessary (but this is unlikely) + +% The n.dashify function makes each single `-' in a string a double `--' +% if it's not already +% +% pseudoVAR: pageresult: STRING (it's what's accumulated on the stack) +% +% n.dashify(s) == +% BEGIN +% t := s +% pageresult := "" +% while (not empty$(t)) +% do +% if (first character of t = "-") +% then +% if (next character isn't) +% then +% pageresult := pageresult * "--" +% t := t with the "-" removed +% else +% while (first character of t = "-") +% do +% pageresult := pageresult * "-" +% t := t with the "-" removed +% od +% fi +% else +% pageresult := pageresult * the first character +% t := t with the first character removed +% fi +% od +% return pageresult +% END + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +% The format.date function is for the month and year, but we give a warning if +% there's an empty year but the month is there, and we return the empty string +% if they're both empty. + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +% The format.btitle is for formatting the title field when it is a book-like +% entry---the style used here keeps it in uppers-and-lowers and emphasizes it. + +FUNCTION {format.btitle} +{ title emphasize +} + +% For several functions we'll need to connect two strings with a +% tie (~) if the second one isn't very long (fewer than 3 characters). +% The tie.or.space.connect function does that. It concatenates the two +% strings on top of the stack, along with either a tie or space between +% them, and puts this concatenation back onto the stack: +% +% tie.or.space.connect(str1,str2) == +% BEGIN +% if text.length$(str2) < 3 +% then return the concatenation of str1, "~", and str2 +% else return the concatenation of str1, " ", and str2 +% END + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +% The either.or.check function complains if both fields or an either-or pair +% are nonempty. +% +% either.or.check(t,s) == +% BEGIN +% if empty$(s) then +% warning$(can't use both " * t * " fields in " * cite$) +% fi +% END + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +% The format.bvolume function is for formatting the volume and perhaps +% series name of a multivolume work. If both a volume and a series field +% are there, we assume the series field is the title of the whole multivolume +% work (the title field should be the title of the thing being referred to), +% and we add an "of <series>". This function is called in mid-sentence. + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +% The format.number.series function is for formatting the series name +% and perhaps number of a work in a series. This function is similar to +% format.bvolume, although for this one the series must exist (and the +% volume must not exist). If the number field is empty we output either +% the series field unchanged if it exists or else the null string. +% If both the number and series fields are there we assume the series field +% gives the name of the whole series (the title field should be the title +% of the work being one referred to), and we add an "in <series>". +% We capitilize Number when this function is used at the beginning of a block. + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +% The format.edition function appends " edition" to the edition, if present. +% We lowercase the edition (it should be something like "Third"), because +% this doesn't start a sentence. + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +% The format.pages function is used for formatting a page range in a book +% (and in rare circumstances, an article). +% +% The multi.page.check function examines the page field for a "-" or "," or "+" +% so that format.pages can use "page" instead of "pages" if none exists. +% Note: global.max$ here means "take the rest of the string" +% +% VAR: multiresult: INTEGER (actually, a boolean) +% +% multi.page.check(s) == +% BEGIN +% t := s +% multiresult := false +% while ((not multiresult) and (not empty$(t))) +% do +% if (first character of t = "-" or "," or "+") +% then multiresult := true +% else t := t with the first character removed +% fi +% od +% return multiresult +% END + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +% This function doesn't begin a sentence so "pages" isn't capitalized. +% Other functions that use this should keep that in mind. + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +% The format.vol.num.pages function is for the volume, number, and page range +% of a journal article. We use the format: vol(number):pages, with some +% variations for empty fields. This doesn't begin a sentence. + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + + +% The format.chapter.pages, if the chapter is present, puts whatever is in the +% type field (or else "chapter" if type is empty) in front of a chapter number. +% It then appends the pages, if present. This doesn't begin a sentence. + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +% The format.in.ed.booktitle function is used for starting out a sentence +% that begins "In <booktitle>", putting an editor before the title if one +% exists. + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +% The function empty.misc.check complains if all six fields are empty, and +% if there's been no sorting or alphabetic-label complaint. + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and +#if SORTED + key empty$ not and +#else !SORTED +#if LAB_ALPH + key empty$ not and +#endif LAB_ALPH +#endif SORTED + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +% The function format.thesis.type returns either the (case-changed) type field, +% if it is defined, or else the default string already on the stack +% (like "Master's thesis" or "PhD thesis"). + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +% The function format.tr.number makes a string starting with "Technical Report" +% (or type, if that field is defined), followed by the number if there is one; +% it returns the starting part (with a case change) even if there is no number. +% This is used at the beginning of a sentence. + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +% Now come the cross-referencing functions (these are invoked because +% one entry in the database file(s) cross-references another, by giving +% the other entry's database key in a `crossref' field). This feature +% allows one or more titled things that are part of a larger titled +% thing to cross-reference the larger thing. These styles allow for +% five posibilities: (1) an ARTICLE may cross-reference an ARTICLE; +% (2) a BOOK, (3) INBOOK, or (4) INCOLLECTION may cross-reference a BOOK; +% or (5) an INPROCEEDINGS may cross-reference a PROCEEDINGS. +% Each of these is explained in more detail later. +% +% An ARTICLE entry type may cross reference another ARTICLE (this is +% intended for when an entire journal is devoted to a single topic--- +% but since there is no JOURNAL entry type, the journal, too, should be +% classified as an ARTICLE but without the author and title fields). +% This will result in two warning messages for the journal's entry +% if it's included in the reference list, but such is life. +% +% format.article.crossref == +% BEGIN +% if empty$(key) then +% if empty$(journal) then +% warning$("need key or journal for " * cite$ * +% " to crossref " * crossref) +% return(" \cite{" * crossref * "}") +% else +% return("In " * emphazise.correct (journal) * +% " \cite{" * crossref * "}") +% fi +% else +% return("In " * key * " \cite{" * crossref * "}") +% fi +% END +% +% The other cross-referencing functions are similar, so no "comment version" +% will be given for them. + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "In {\em " journal * "\/}" * } + if$ + } + { "In " key * } + if$ + " \cite{" * crossref * "}" * +} + +% We use just the last names of editors for a cross reference: either +% "editor", or "editor1 and editor2", or "editor1 et~al." depending on +% whether there are one, or two, or more than two editors. + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +% A BOOK (or INBOOK) entry type (assumed to be for a single volume in a +% multivolume work) may cross reference another BOOK (the entire multivolume). +% Usually there will be an editor, in which case we use that to construct the +% cross reference; otherwise we use a nonempty key field or else the series +% field (since the series gives the title of the multivolume work). + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +% An INCOLLECTION entry type may cross reference a BOOK (assumed to be the +% collection), or an INPROCEEDINGS may cross reference a PROCEEDINGS. +% Often there will be an editor, in which case we use that to construct +% the cross reference; otherwise we use a nonempty key field or else +% the booktitle field (which gives the cross-referenced work's title). + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "In {\em " booktitle * "\/}" * } + if$ + } + { "In " key * } + if$ + } + { "In " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +% Now we define the type functions for all entry types that may appear +% in the .BIB file---e.g., functions like `article' and `book'. These +% are the routines that actually generate the .BBL-file output for +% the entry. These must all precede the READ command. In addition, the +% style designer should have a function `default.type' for unknown types. +% Note: The fields (within each list) are listed in order of appearance, +% except as described for an `inbook' or a `proceedings'. +% +% The article function is for an article in a journal. An article may +% CROSSREF another article. +% Required fields: author, title, journal, year +% Optional fields: volume, number, pages, month, note +% +% article == +% BEGIN +% output.bibitem +% output.check(format.authors,"author") +% new.block +% output.check(format.title,"title") +% new.block +% if missing$(crossref) then +% output.check(emphasize(journal),"journal") +% output(format.vol.num.pages) +% output.check(format.date,"year") +% else +% output.nonnull(format.article.crossref) +% output(format.pages) +% fi +% new.block +% output(note) +% fin.entry +% END +% +% The book function is for a whole book. A book may CROSSREF another book. +% Required fields: author or editor, title, publisher, year +% Optional fields: volume or number, series, address, edition, month, +% note +% +% book == +% BEGIN +% if empty$(author) then output.check(format.editors,"author and editor") +% else output.check(format.authors,"author") +% if missing$(crossref) then +% either.or.check("author and editor",editor) +% fi +% fi +% new.block +% output.check(format.btitle,"title") +% if missing$(crossref) then +% output(format.bvolume) +% new.block +% output(format.number.series) +% new.sentence +% output.check(publisher,"publisher") +% output(address) +% else +% new.block +% output.nonnull(format.book.crossref) +% fi +% output(format.edition) +% output.check(format.date,"year") +% new.block +% output(note) +% fin.entry +% END +% +% The other entry functions are all quite similar, so no "comment version" +% will be given for them. + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +% A booklet is a bound thing without a publisher or sponsoring institution. +% Required: title +% Optional: author, howpublished, address, month, year, note + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +% For the conference entry type, see inproceedings. + +% An inbook is a piece of a book: either a chapter and/or a page range. +% It may CROSSREF a book. If there's no volume field, the type field +% will come before number and series. +% Required: author or editor, title, chapter and/or pages, publisher,year +% Optional: volume or number, series, type, address, edition, month, note + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +% An incollection is like inbook, but where there is a separate title +% for the referenced thing (and perhaps an editor for the whole). +% An incollection may CROSSREF a book. +% Required: author, title, booktitle, publisher, year +% Optional: editor, volume or number, series, type, chapter, pages, +% address, edition, month, note + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +% An inproceedings is an article in a conference proceedings, and it may +% CROSSREF a proceedings. If there's no address field, the month (& year) +% will appear just before note. +% Required: author, title, booktitle, year +% Optional: editor, volume or number, series, pages, address, month, +% organization, publisher, note + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ + { organization publisher new.sentence.checkb + organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +% The conference function is included for Scribe compatibility. + +FUNCTION {conference} { inproceedings } + +% A manual is technical documentation. +% Required: title +% Optional: author, organization, address, edition, month, year, note + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + new.block + note output + fin.entry +} + +% A mastersthesis is a Master's thesis. +% Required: author, title, school, year +% Optional: type, address, month, note + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +% A misc is something that doesn't fit elsewhere. +% Required: at least one of the `optional' fields +% Optional: author, title, howpublished, month, year, note + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +% A phdthesis is like a mastersthesis. +% Required: author, title, school, year +% Optional: type, address, month, note + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +% A proceedings is a conference proceedings. +% If there is an organization but no editor field, the organization will +% appear as the first optional field (we try to make the first block nonempty); +% if there's no address field, the month (& year) will appear just before note. +% Required: title, year +% Optional: editor, volume or number, series, address, month, +% organization, publisher, note + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + { publisher new.sentence.checka } + { organization publisher new.sentence.checkb + organization output + } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + new.block + note output + fin.entry +} + +% A techreport is a technical report. +% Required: author, title, institution, year +% Optional: type, number, address, month, note + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +% An unpublished is something that hasn't been published. +% Required: author, title, note +% Optional: month, year + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +% We use entry type `misc' for an unknown type; BibTeX gives a warning. + +FUNCTION {default.type} { misc } + +% Here are macros for common things that may vary from style to style. +% Users are encouraged to use these macros. +% +% Months are either written out in full or abbreviated + +#if MONTH_FULL + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +#else !MONTH_FULL + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sept."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +#endif MONTH_FULL + +% Journals are either written out in full or abbreviated; +% the abbreviations are like those found in ACM publications. +% +% To get a completely different set of abbreviations, it may be best to make +% a separate .bib file with nothing but those abbreviations; users could then +% include that file name as the first argument to the \bibliography command + +#if JOUR_FULL + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +#else !JOUR_FULL + +MACRO {acmcs} {"ACM Comput. Surv."} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Commun. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Softw. Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput.-Aided Design Integrated Circuits"} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Comput. Syst. Sci."} + +MACRO {scp} {"Sci. Comput. Programming"} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Gr."} + +MACRO {toms} {"ACM Trans. Math. Softw."} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Prog. Lang. Syst."} + +MACRO {tcs} {"Theoretical Comput. Sci."} + +#endif JOUR_FULL + +% Now we read in the .BIB entries. + +READ + +% The sortify function converts to lower case after purify$ing; it's +% used in sorting and in computing alphabetic labels after sorting +% +% The chop.word(w,len,s) function returns either s or, if the first len +% letters of s equals w (this comparison is done in the third line of the +% function's definition), it returns that part of s after w. + +#if SORTED + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +#else !SORTED +#if LAB_ALPH + +% We need the chop.word stuff for the dubious unsorted-list-with-labels case. + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +#endif LAB_ALPH +#endif SORTED + +% This long comment applies only to alphabetic labels +% +% The format.lab.names function makes a short label by using the initials of +% the von and Last parts of the names (but if there are more than four names, +% (i.e., people) it truncates after three and adds a superscripted "+"; +% it also adds such a "+" if the last of multiple authors is "others"). +% If there is only one name, and its von and Last parts combined have just +% a single name-token ("Knuth" has a single token, "Brinch Hansen" has two), +% we take the first three letters of the last name. The boolean +% et.al.char.used tells whether we've used a superscripted "+", so that we +% know whether to include a LaTeX macro for it. +% +% format.lab.names(s) == +% BEGIN +% numnames := num.names$(s) +% if numnames > 1 then +% if numnames > 4 then +% namesleft := 3 +% else +% namesleft := numnames +% nameptr := 1 +% nameresult := "" +% while namesleft > 0 +% do +% if (name_ptr = numnames) and +% format.name$(s, nameptr, "{ff }{vv }{ll}{ jj}") = "others" +% then nameresult := nameresult * "{\etalchar{+}}" +% et.al.char.used := true +% else nameresult := nameresult * +% format.name$(s, nameptr, "{v{}}{l{}}") +% nameptr := nameptr + 1 +% namesleft := namesleft - 1 +% od +% if numnames > 4 then +% nameresult := nameresult * "{\etalchar{+}}" +% et.al.char.used := true +% else +% t := format.name$(s, 1, "{v{}}{l{}}") +% if text.length$(t) < 2 then % there's just one name-token +% nameresult := text.prefix$(format.name$(s,1,"{ll}"),3) +% else +% nameresult := t +% fi +% fi +% return nameresult +% END +% +% Exactly what fields we look at in constructing the primary part of the label +% depends on the entry type; this selectivity (as opposed to, say, always +% looking at author, then editor, then key) helps ensure that "ignored" fields, +% as described in the LaTeX book, really are ignored. Note that MISC is part +% of the deepest `else' clause in the nested part of calc.label; thus, any +% unrecognized entry type in the database is handled correctly. +% +% There is one auxiliary function for each of the four different sequences of +% fields we use. The first of these functions looks at the author field, and +% then, if necessary, the key field. The other three functions, which might +% look at two fields and the key field, are similar, except that the key field +% takes precedence over the organization field (for labels---not for sorting). +% +% The calc.label function calculates the preliminary label of an entry, which +% is formed by taking three letters of information from the author or editor or +% key or organization field (depending on the entry type and on what's empty, +% but ignoring a leading "The " in the organization), and appending the last +% two characters (digits) of the year. It is an error if the appropriate fields +% among author, editor, organization, and key are missing, and we use +% the first three letters of the cite$ in desperation when this happens. +% The resulting label has the year part, but not the name part, purify$ed +% (purify$ing the year allows some sorting shenanigans by the user). +% +% This function also calculates the version of the label to be used in sorting. +% +% The final label may need a trailing 'a', 'b', etc., to distinguish it from +% otherwise identical labels, but we can't calculated those "extra.label"s +% until after sorting. +% +% calc.label == +% BEGIN +% if type$ = "book" or "inbook" then +% author.editor.key.label +% else if type$ = "proceedings" then +% editor.key.organization.label +% else if type$ = "manual" then +% author.key.organization.label +% else +% author.key.label +% fi fi fi +% label := label * substring$(purify$(field.or.null(year)), -1, 2) +% % assuming we will also sort, we calculate a sort.label +% sort.label := sortify(label), but use the last four, not two, digits +% END + +#if LAB_ALPH + +INTEGERS { et.al.char.used } + +FUNCTION {initialize.et.al.char.used} +{ #0 'et.al.char.used := +} + +EXECUTE {initialize.et.al.char.used} + +FUNCTION {format.lab.names} +{ 's := + s num.names$ 'numnames := + numnames #1 > + { numnames #4 > + { #3 'namesleft := } + { numnames 'namesleft := } + if$ + #1 'nameptr := + "" + { namesleft #0 > } + { nameptr numnames = + { s nameptr "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { "{\etalchar{+}}" * + #1 'et.al.char.used := + } + { s nameptr "{v{}}{l{}}" format.name$ * } + if$ + } + { s nameptr "{v{}}{l{}}" format.name$ * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + numnames #4 > + { "{\etalchar{+}}" * + #1 'et.al.char.used := + } + 'skip$ + if$ + } + { s #1 "{v{}}{l{}}" format.name$ + duplicate$ text.length$ #2 < + { pop$ s #1 "{ll}" format.name$ #3 text.prefix$ } + 'skip$ + if$ + } + if$ +} + +FUNCTION {author.key.label} +{ author empty$ + { key empty$ +#if SORTED + { cite$ #1 #3 substring$ } +#else !SORTED % need warning here because we won't give it later + { "for label, need author or key in " cite$ * warning$ + cite$ #1 #3 substring$ + } +#endif SORTED + { key #3 text.prefix$ } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {author.editor.key.label} +{ author empty$ + { editor empty$ + { key empty$ +#if SORTED + { cite$ #1 #3 substring$ } +#else !SORTED % need warning here because we won't give it later + { "for label, need author, editor, or key in " cite$ * warning$ + cite$ #1 #3 substring$ + } +#endif SORTED + { key #3 text.prefix$ } + if$ + } + { editor format.lab.names } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {author.key.organization.label} +{ author empty$ + { key empty$ + { organization empty$ +#if SORTED + { cite$ #1 #3 substring$ } +#else !SORTED % need warning here because we won't give it later + { "for label, need author, key, or organization in " cite$ * + warning$ + cite$ #1 #3 substring$ + } +#endif SORTED + { "The " #4 organization chop.word #3 text.prefix$ } + if$ + } + { key #3 text.prefix$ } + if$ + } + { author format.lab.names } + if$ +} + +FUNCTION {editor.key.organization.label} +{ editor empty$ + { key empty$ + { organization empty$ +#if SORTED + { cite$ #1 #3 substring$ } +#else !SORTED % need warning here because we won't give it later + { "for label, need editor, key, or organization in " cite$ * + warning$ + cite$ #1 #3 substring$ + } +#endif SORTED + { "The " #4 organization chop.word #3 text.prefix$ } + if$ + } + { key #3 text.prefix$ } + if$ + } + { editor format.lab.names } + if$ +} + +FUNCTION {calc.label} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.key.label + { type$ "proceedings" = + 'editor.key.organization.label + { type$ "manual" = + 'author.key.organization.label + 'author.key.label + if$ + } + if$ + } + if$ + duplicate$ + year field.or.null purify$ #-1 #2 substring$ + * + 'label := + year field.or.null purify$ #-1 #4 substring$ + * + sortify 'sort.label := +} + +% It doesn't seem like a particularly good idea to use an order-of-citation +% reference list when using alphabetic labels, but we need to have a +% special pass to calculate labels when this happens. + +#if !SORTED + +ITERATE {calc.label} + +#endif !SORTED + +#endif LAB_ALPH + +% When sorting, we compute the sortkey by executing "presort" on each entry. +% The presort key contains a number of "sortify"ed strings, concatenated +% with multiple blanks between them. This makes things like "brinch per" +% come before "brinch hansen per". +% +% The fields used here are: the sort.label for alphabetic labels (as set by +% calc.label), followed by the author names (or editor names or organization +% (with a leading "The " removed) or key field, depending on entry type and on +% what's empty), followed by year, followed by the first bit of the title +% (chopping off a leading "The ", "A ", or "An "). +% Names are formatted: Von Last First Junior. +% The names within a part will be separated by a single blank +% (such as "brinch hansen"), two will separate the name parts themselves +% (except the von and last), three will separate the names, +% four will separate the names from year (and from label, if alphabetic), +% and four will separate year from title. +% +% The sort.format.names function takes an argument that should be in +% BibTeX name format, and returns a string containing " "-separated +% names in the format described above. The function is almost the same +% as format.names. + +#if SORTED + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ +#if NAME_FULL + s nameptr "{vv{ } }{ll{ }}{ ff{ }}{ jj{ }}" format.name$ 't := +#else + s nameptr "{vv{ } }{ll{ }}{ f{ }}{ jj{ }}" format.name$ 't := +#endif NAME_FULL + nameptr numnames = t "others" = and + { "et al" * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +% The sort.format.title function returns the argument, +% but first any leading "A "'s, "An "'s, or "The "'s are removed. +% The chop.word function uses s, so we need another string variable, t + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +% The auxiliary functions here, for the presort function, are analogous to +% the ones for calc.label; the same comments apply, except that the +% organization field takes precedence here over the key field. For sorting +% purposes, we still remove a leading "The " from the organization field. + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} + +% There is a limit, entry.max$, on the length of an entry string variable +% (which is what its sort.key$ is), so we take at most that many characters +% of the constructed key, and hope there aren't many references that match +% to that many characters! + +FUNCTION {presort} +#if LAB_ALPH +{ calc.label + sort.label + " " + * + type$ "book" = +#else !LAB_ALPH +{ type$ "book" = +#endif LAB_ALPH + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ +#if LAB_ALPH + * +#endif LAB_ALPH + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +% And now we can sort + +SORT + +#endif SORTED + +% This long comment applies only to alphabetic labels, when sorted +% +% Now comes the final computation for alphabetic labels, putting in the 'a's +% and 'b's and so forth if required. This involves two passes: a forward +% pass to put in the 'b's, 'c's and so on, and a backwards pass +% to put in the 'a's (we don't want to put in 'a's unless we know there +% are 'b's). +% We have to keep track of the longest (in width$ terms) label, for use +% by the "thebibliography" environment. +% +% VAR: longest.label, last.sort.label, next.extra: string +% longest.label.width, last.extra.num: integer +% +% initialize.longest.label == +% BEGIN +% longest.label := "" +% last.sort.label := int.to.chr$(0) +% next.extra := "" +% longest.label.width := 0 +% last.extra.num := 0 +% END +% +% forward.pass == +% BEGIN +% if last.sort.label = sort.label then +% last.extra.num := last.extra.num + 1 +% extra.label := int.to.chr$(last.extra.num) +% else +% last.extra.num := chr.to.int$("a") +% extra.label := "" +% last.sort.label := sort.label +% fi +% END +% +% reverse.pass == +% BEGIN +% if next.extra = "b" then +% extra.label := "a" +% fi +% label := label * extra.label +% if width$(label) > longest.label.width then +% longest.label := label +% longest.label.width := width$(label) +% fi +% next.extra := extra.label +% END + +#if LAB_ALPH + +#if SORTED + +STRINGS { longest.label last.sort.label next.extra } + +INTEGERS { longest.label.width last.extra.num } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #0 int.to.chr$ 'last.sort.label := + "" 'next.extra := + #0 'longest.label.width := + #0 'last.extra.num := +} + +FUNCTION {forward.pass} +{ last.sort.label sort.label = + { last.extra.num #1 + 'last.extra.num := + last.extra.num int.to.chr$ 'extra.label := + } + { "a" chr.to.int$ 'last.extra.num := + "" 'extra.label := + sort.label 'last.sort.label := + } + if$ +} + +FUNCTION {reverse.pass} +{ next.extra "b" = + { "a" 'extra.label := } + 'skip$ + if$ + label extra.label * 'label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ + extra.label 'next.extra := +} + +EXECUTE {initialize.longest.label} + +ITERATE {forward.pass} + +REVERSE {reverse.pass} + +#else !SORTED + +% It still doesn't seem like a good idea to use an order-of-citation +% reference list when using alphabetic labels, but when this happens we +% must compute the longest label + +STRINGS { longest.label } + +INTEGERS { longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +#endif SORTED + +#else !LAB_ALPH + +% Now comes the computation for numeric labels. +% We use either the sorted order or original order. +% We still have to keep track of the longest (in width$ terms) label, for use +% by the "thebibliography" environment. + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +#endif LAB_ALPH + +% Now we're ready to start writing the .BBL file. +% We begin, if necessary, with a LaTeX macro for unnamed names in an alphabetic +% label; next comes stuff from the `preamble' command in the database files. +% Then we give an incantation containing the command +% \begin{thebibliography}{...} +% where the `...' is the longest label. +% +% We also call init.state.consts, for use by the output routines. + +FUNCTION {begin.bib} +#if LAB_ALPH +{ et.al.char.used + { "\newcommand{\etalchar}[1]{$^{#1}$}" write$ newline$ } + 'skip$ + if$ + preamble$ empty$ +#else !LAB_ALPH +{ preamble$ empty$ +#endif LAB_ALPH + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +% Now we produce the output for all the entries + +ITERATE {call.type$} + +% Finally, we finish up by writing the `\end{thebibliography}' command. + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/Build/source/extra/bibtex/btxdoc.bbl b/Build/source/extra/bibtex/btxdoc.bbl new file mode 100644 index 00000000000..9d25371c069 --- /dev/null +++ b/Build/source/extra/bibtex/btxdoc.bbl @@ -0,0 +1,23 @@ +\begin{thebibliography}{1} + +\bibitem{chicago} +{\em The Chicago Manual of Style}, pages 400--401. +\newblock University of Chicago Press, thirteenth edition, 1982. + +\bibitem{latex} +Leslie Lamport. +\newblock {\em {\LaTeX \rm:} {A} Document Preparation System}. +\newblock Addison-Wesley, 1986. + +\bibitem{btxhak} +Oren Patashnik. +\newblock Designing {\BibTeX} styles. +\newblock The part of \BibTeX's documentation that's not meant for general + users, 8~February 1988. + +\bibitem{van-leunen} +Mary-Claire van Leunen. +\newblock {\em A Handbook for Scholars}. +\newblock Knopf, 1979. + +\end{thebibliography} diff --git a/Build/source/extra/bibtex/btxdoc.bib b/Build/source/extra/bibtex/btxdoc.bib new file mode 100644 index 00000000000..ad5329829ef --- /dev/null +++ b/Build/source/extra/bibtex/btxdoc.bib @@ -0,0 +1,90 @@ +Copyright (C) 1988, all rights reserved. + +@COMMENT(You may put a comment in a `comment' command, + the way you would with SCRIBE.) + +Or you may dispense with the command and simply give the comment, +as long as it's not within an entry. + +If you really want to put a comment inside an entry, simply +make up a never-to-be-used field. + +@FAKE-ENTRY + {fake-database-key, + never-to-be-used-field = "Even if this were a real entry, + I could still have a comment inside an entry + by making up a fake field" + } + +@string (SCRIBE-NOTE = {Chapter twelve and appendices E8 through E10 deal + with bibliographies}) + +The next entry shows some of the syntactically legal things that +those with the inclination may use.@ + +MaNuAl (scribe, + TITLE="Scribe Document Production System + + + User Manual", + ORGANIZATION = {Unilogic,}#" Ltd"# {. + }, + ADDRESS = "Pittsburgh", + MONTH +=aPR + ,YEAR=1984, + note = scribe-note, +) May the inclination not be with you. + + +@MISC{prime-number-theorem, + author = "Charles Louis Xavier Joseph de la Vall{\'e}e Poussin", + note = "A strong form of the prime number theorem, 19th century" } + +@INBOOK{chicago, + title = "The Chicago Manual of Style", + publisher = "University of Chicago Press", + edition = "Thirteenth", + year = 1982, + pages = "400--401", + key = "Chicago" } + +@BOOK{texbook, + author = "Donald E. Knuth", + title= "The {{\TeX}book}", + publisher = "Addison-Wesley", + year = 1984 } + +@BOOK{latex, + author = "Leslie Lamport", + title = "{\LaTeX \rm:} {A} Document Preparation System", + publisher = "Addison-Wesley", + year = 1986 } + +@UNPUBLISHED{btxdoc, + author = "Oren Patashnik", + title = "{{\BibTeX ing}}", + note = "Documentation for general {\BibTeX} users", + month = "8~" # feb, + year = 1988 } + +@UNPUBLISHED{btxhak, + author = "Oren Patashnik", + title = "Designing {\BibTeX} Styles", + note = "The part of \BibTeX's documentation + that's not meant for general users", + month = "8~" # feb, + year = 1988 } + +@BOOK{strunk-and-white, + author = "Strunk, Jr., William and E. B. White", + title = "The Elements of Style", + publisher = "Macmillan", + edition = "Third", + year = 1979 } + +@BOOK{van-leunen, + title = "A Handbook for Scholars", + author = "Mary-Claire van Leunen", + publisher = "Knopf", + year = 1979 } diff --git a/Build/source/extra/bibtex/btxdoc.tex b/Build/source/extra/bibtex/btxdoc.tex new file mode 100644 index 00000000000..52723e08b69 --- /dev/null +++ b/Build/source/extra/bibtex/btxdoc.tex @@ -0,0 +1,1117 @@ +% Copyright (C) 1988, all rights reserved. + +\def\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} + +\title{B\kern-.05em{\large I}\kern-.025em{\large B}\kern-.08em\TeX ing} +\author{Oren Patashnik} +\date{February 8, 1988} + +\documentstyle{article} +\begin{document} + +\maketitle + +\section{Overview} + +[This document will be expanded when \BibTeX\ version 1.00 comes out. +Please report typos, omissions, inaccuracies, +and especially unclear explanations +to me ({\tt patashnik@SCORE.STANFORD.EDU}). +Suggestions for improvements are wanted and welcome.] + +This documentation, for \BibTeX\ version 0.99b, +is meant for general \BibTeX\ users; +bibliography-style designers should read this document +and then read ``Designing \BibTeX\ Styles''~\cite{btxhak}, +which is meant for just them. + +This document has three parts: +Section~\ref{differences} +describes the differences between versions 0.98i and 0.99b +of \BibTeX\ and between the corresponding versions of the standard styles; +Section~\ref{latex-appendix} +updates Appendix~B.2 of the \LaTeX\ book~\cite{latex}; +and Section~\ref{odds-and-ends} +gives some general and specific tips +that aren't documented elsewhere. +It's assumed throughout that you're familiar with +the relevant sections of the \LaTeX\ book. + +This documentation also serves as sample input to help +\BibTeX\ implementors get it running. +For most documents, this one included, you produce the reference list by: +running \LaTeX\ on the document (to produce the {\tt aux} file(s)), +then running \BibTeX\ (to produce the {\tt bbl} file), +then \LaTeX\ twice more (first to find the information in the {\tt bbl} file +and then to get the forward references correct). +In very rare circumstances you may need an extra \BibTeX/\LaTeX\ run. + +\BibTeX\ version 0.99b should be used with \LaTeX\ version 2.09, +for which the closed bibliography format is the default; +to get the open format, use the optional document style {\tt openbib} +(in an open format there's a line break between major blocks of a +reference-list entry; in a closed format the blocks run together).] + +Note: \BibTeX\ 0.99b is not compatible with the old style files; +nor is \BibTeX\ 0.98i compatible with the new ones +(the new \BibTeX, however, is compatible with old database files). + +Note for implementors: \BibTeX\ provides logical-area names +\hbox{\tt TEXINPUTS:} for bibliography-style files and +\hbox{\tt TEXBIB:} for database files it can't otherwise find. + + +\section{Changes} +\label{differences} + +This section describes the differences between +\BibTeX\ versions 0.98i and 0.99b, and also between +the corresponding standard styles. +There were a lot of differences; +there will be a lot fewer between 0.99 and 1.00. + + +\subsection{New \BibTeX\ features} +\label{features} + +The following list explains \BibTeX's new features and how to use them. +\begin{enumerate} + +\item +With the single command `\hbox{\verb|\nocite{*}|}' +you can now include in the reference list +every entry in the database files, without having to explicitly +\verb|\cite| or \hbox{\verb|\nocite|} each entry. +Giving this command, in essence, +\hbox{\verb|\nocite|}s +all the enties in the database, in database order, +at the very spot in your document +where you give the command. + +\item +\label{concat} +You can now have as a field value (or an {\tt @STRING} definition) +the concatenation of several strings. +For example if you've defined +\begin{verbatim} + @STRING( WGA = " World Gnus Almanac" ) +\end{verbatim} +then it's easy to produce nearly-identical +{\tt title} fields for different entries: +\begin{verbatim} + @BOOK(almanac-66, + title = 1966 # WGA, + . . . + @BOOK(almanac-67, + title = 1967 # WGA, +\end{verbatim} +and so on. Or, you could have a field like +\begin{verbatim} + month = "1~" # jan, +\end{verbatim} +which would come out something like +`\hbox{\verb|1~January|}' or `\hbox{\verb|1~Jan.|}' in the {\tt bbl} file, +depending on how your bibliography style defines +the {\tt jan} abbreviation. +You may concatenate as many strings as you like +(except that there's a limit to the overall length +of the resulting field); +just be sure to put the concatenation character `{\tt\#}'$\!$, +surrounded by optional spaces or newlines, +between each successive pair of strings. + +\item +\BibTeX\ has a new cross-referencing feature, +explained by an example. +Suppose you say \hbox{\verb|\cite{no-gnats}|} in your document, +and suppose you have these two entries in your database file: +\begin{verbatim} + @INPROCEEDINGS(no-gnats, + crossref = "gg-proceedings", + author = "Rocky Gneisser", + title = "No Gnats Are Taken for Granite", + pages = "133-139") + . . . + @PROCEEDINGS(gg-proceedings, + editor = "Gerald Ford and Jimmy Carter", + title = "The Gnats and Gnus 1988 Proceedings", + booktitle = "The Gnats and Gnus 1988 Proceedings") +\end{verbatim} +Two things happen. +First, the special \hbox{\tt crossref} field tells \BibTeX\ +that the \hbox{\tt no-gnats} entry should inherit +any fields it's missing from +the entry it cross references, \hbox{\tt gg-proceedings}. +In this case it in inherits the two fields +\hbox{\tt editor} and \hbox{\tt booktitle}. +Note that, in the standard styles at least, +the \hbox{\tt booktitle} field is irrelevant +for the \hbox{\tt PROCEEDINGS} entry type. +The \hbox{\tt booktitle} field appears here +in the \hbox{\tt gg-proceedings} entry +only so that the entries that cross reference it +may inherit the field. +No matter how many papers from this meeting exist in the database, +this \hbox{\tt booktitle} field need only appear once. + +The second thing that happens: +\BibTeX\ automatically puts the entry \hbox{\tt gg-proceedings} +into the reference list if it's cross +referenced by two or more entries that you +\verb|\cite| or \hbox{\verb|\nocite|}, +even if you don't \verb|\cite| or \hbox{\verb|\nocite|} +the \hbox{\tt gg-proceedings} entry itself. +So \hbox{\tt gg-proceedings} will automatically appear +on the reference list if one other entry +besides \hbox{\tt no-gnats} cross references it. + +To guarantee that this scheme works, however, +a cross-referenced entry must occur later in the database files +than every entry that cross-references it. +Thus, putting all cross-referenced entries at the end makes sense. +(Moreover, you may not reliably nest cross references; +that is, a cross-referenced entry may +not itself reliably cross reference an entry. +This is almost certainly not something you'd +want to do, though.) + +One final note: +This cross-referencing feature is completely unrelated +to the old \BibTeX's cross referencing, +which is still allowed. +Thus, having a field like +\begin{verbatim} + note = "Jones \cite{jones-proof} improves the result" +\end{verbatim} +is not affected by the new feature. + +\item +\BibTeX\ now handles accented characters. +For example if you have an entry with the two fields +\begin{verbatim} + author = "Kurt G{\"o}del", + year = 1931, +\end{verbatim} +and if you're using the \hbox{\tt alpha} bibliography style, +then \BibTeX\ will construct the label +\hbox{[G{\"o}d31]} for this entry, which is what you'd want. +To get this feature to work you must place the entire accented +character in braces; +in this case either \hbox{\verb|{\"o}|} +or \hbox{\verb|{\"{o}}|} will do. +Furthermore these braces must not themselves be +enclosed in braces (other than the ones that might delimit +the entire field or the entire entry); +and there must be a backslash +as the very first character inside the braces. +Thus neither \hbox{\verb|{G{\"{o}}del}|} +nor \hbox{\verb|{G\"{o}del}|} will work for this example. + +This feature handles all the accented characters and +all but the nonbackslashed foreign symbols found in Tables +3.1 and~3.2 of the \LaTeX\ book. +This feature behaves similarly for ``accents'' you might define; +we'll see an example shortly. +For the purposes of counting letters in labels, +\BibTeX\ considers everything contained inside the braces +as a single letter. + +\item +\BibTeX\ also handles hyphenated names. +For example if you have an entry with +\begin{verbatim} + author = "Jean-Paul Sartre", +\end{verbatim} +and if you're using the \hbox{\tt abbrv} style, +then the result is `J.-P. Sartre'$\!$. + +\item +\label{preamble} +There's now an \hbox{\verb|@PREAMBLE|} command +for the database files. +This command's syntax is just like \hbox{\verb|@STRING|}'s, +except that there is no name or equals-sign, just the string. +Here's an example: +\begin{verbatim} + @PREAMBLE{ "\newcommand{\noopsort}[1]{} " + # "\newcommand{\singleletter}[1]{#1} " } +\end{verbatim} +(note the use of concatenation here, too). +The standard styles output whatever information you give this command +(\LaTeX\ macros most likely) directly to the {\tt bbl} file. +We'll look at one possible use of this command, +based on the \hbox{\verb|\noopsort|} command just defined. + +The issue here is sorting (alphabetizing). +\BibTeX\ does a pretty good job, +but occasionally weird circumstances conspire to confuse \BibTeX: +Suppose that you have entries in your database for +the two books in a two-volume set by the same author, +and that you'd like volume~1 to appear +just before volume~2 in your reference list. +Further suppose that there's now a second edition of volume~1, +which came out in 1973, say, +but that there's still just one edition of volume~2, +which came out in 1971. +Since the {\tt plain} standard style +sorts by author and then year, +it will place volume~2 first +(because its edition came out two years earlier) +unless you help \BibTeX. +You can do this by using the {\tt year} fields below +for the two volumes: +\begin{verbatim} + year = "{\noopsort{a}}1973" + . . . + year = "{\noopsort{b}}1971" +\end{verbatim} +According to the definition of \hbox{\verb|\noopsort|}, +\LaTeX\ will print nothing but the true year for these fields. +But \BibTeX\ will be perfectly happy pretending that +\hbox{\verb|\noopsort|} specifies some fancy accent +that's supposed to adorn the `a' and the~`b'; +thus when \BibTeX\ sorts it will pretend that +`a1973' and `b1971' are the real years, +and since `a' comes before~`b'$\!$, it will place volume~1 before volume~2, +just what you wanted. +By the way, if this author has any other works included +in your database, you'd probably want to use instead something like +\hbox{\verb|{\noopsort{1968a}}1973|} and +\hbox{\verb|{\noopsort{1968b}}1971|}, +so that these two books would come out in a reasonable spot +relative to the author's other works +(this assumes that 1968 results in a reasonable spot, +say because that's when the first edition of volume~1 appeared). + +There is a limit to the number of \hbox{\verb|@PREAMBLE|} commands +you may use, but you'll never exceed this limit if +you restrict yourself to one per database file; +this is not a serious restriction, +given the concatenation feature (item~\ref{concat}). + +\item +\BibTeX's sorting algorithm is now stable. +This means that if two entries have identical sort keys, +those two entries will appear in citation order. +(The bibliography styles construct these sort keys---% +usually the author information followed by the year and the title.) + +\item +\BibTeX\ no longer does case conversion for file names; +this will make \BibTeX\ easier to install on Unix systems, for example. + +\item +It's now easier to add code for processing a +command-line {\tt aux}-file name. + +\end{enumerate} + + +\subsection{Changes to the standard styles} + +This section describes changes to the standard styles +({\tt plain}, {\tt unsrt}, {\tt alpha}, {\tt abbrv}) +that affect ordinary users. +Changes that affect style designers appear in +the document ``Designing \BibTeX\ Styles''~\cite{btxhak}. +\begin{enumerate} + +\item +In general, sorting is now by ``author''$\!$, then year, then title---% +the old versions didn't use the year field. +(The {\tt alpha} style, however, sorts first by label, +then ``author''$\!$, year, and title.) +The quotes around author mean that some entry types +might use something besides the author, like the editor or organization. + +\item +Many unnecessary ties (\verb|~|) have been removed. +\LaTeX\ thus will produce slightly fewer +`\hbox{\tt Underfull} \verb|\hbox|' messages +when it's formatting the reference list. + +\item +Emphasizing (\hbox{\verb|{\em ...}|}) +has replaced italicizing (\hbox{\verb|{\it ...}|}). +This will almost never result in a difference +between the old output and the new. + +\item +The {\tt alpha} style now uses a superscripted~`$^{+}$' instead of a~`*' +to represent names omitted in constructing the label. +If you really liked it the way it was, however, +or if you want to omit the character entirely, +you don't have to modify the style file---% +you can override the~`$^{+}$' by +redefining the \hbox{\verb|\etalchar|} command +that the {\tt alpha} style writes onto the {\tt bbl} file +(just preceding the \hbox{\verb|\thebibliography|} environment); +use \LaTeX's \hbox{\verb|\renewcommand|} inside +a database \hbox{\tt @PREAMBLE} command, +described in the previous subsection's item~\ref{preamble}. + +\item +The {\tt abbrv} style now uses `Mar.' and `Sept.'\ +for those months rather than `March' and `Sep.' + +\item +The standard styles use \BibTeX's new cross-referencing feature +by giving a \verb|\cite| of the cross-referenced entry and by +omitting from the cross-referencing entry +(most of the) information that appears +in the cross-referenced entry. +These styles do this when +a titled thing (the cross-referencing entry) +is part of a larger titled thing (the cross-referenced entry). +There are five such situations: +when (1)~an \hbox{\tt INPROCEEDINGS} +(or \hbox{\tt CONFERENCE}, which is the same) +cross references a \hbox{\tt PROCEEDINGS}; +when (2)~a {\tt BOOK}, (3)~an \hbox{\tt INBOOK}, +or (4)~an \hbox{\tt INCOLLECTION} +cross references a {\tt BOOK} +(in these cases, the cross-referencing entry is a single +volume in a multi-volume work); +and when (5)~an \hbox{\tt ARTICLE} +cross references an \hbox{\tt ARTICLE} +(in this case, the cross-referenced entry is really a journal, +but there's no \hbox{\tt JOURNAL} entry type; +this will result in warning messages about +an empty \hbox{\tt author} and \hbox{\tt title} for the journal---% +you should just ignore these warnings). + +\item +The \hbox{\tt MASTERSTHESIS} and \hbox{\tt PHDTHESIS} +entry types now take an optional {\tt type} field. +For example you can get the standard styles to +call your reference a `Ph.D.\ dissertation' +instead of the default `PhD thesis' by including a +\begin{verbatim} + type = "{Ph.D.} dissertation" +\end{verbatim} +in your database entry. + +\item +Similarly, the \hbox{\tt INBOOK} and \hbox{\tt INCOLLECTION} +entry types now take an optional {\tt type} field, +allowing `section~1.2' instead of the default `chapter~1.2'$\!$. +You get this by putting +\begin{verbatim} + chapter = "1.2", + type = "Section" +\end{verbatim} +in your database entry. + +\item +The \hbox{\tt BOOKLET}, \hbox{\tt MASTERSTHESIS}, +and \hbox{\tt TECHREPORT} entry types now format +their \hbox{\tt title} fields as if they were +\hbox{\tt ARTICLE} \hbox{\tt title}s +rather than \hbox{\tt BOOK} \hbox{\tt title}s. + +\item +The \hbox{\tt PROCEEDINGS} and \hbox{\tt INPROCEEDINGS} +entry types now use the \hbox{\tt address} field +to tell where a conference was held, +rather than to give the address +of the publisher or organization. +If you want to include the +publisher's or organization's address, +put it in the \hbox{\tt publisher} +or \hbox{\tt organization} field. + +\item +The \hbox{\tt BOOK}, \hbox{\tt INBOOK}, \hbox{\tt INCOLLECTION}, +and \hbox{\tt PROCEEDINGS} entry types now allow either +\hbox{\tt volume} or \hbox{\tt number} (but not both), +rather than just \hbox{\tt volume}. + +\item +The \hbox{\tt INCOLLECTION} entry type now allows +a \hbox{\tt series} and an \hbox{\tt edition} field. + +\item +The \hbox{\tt INPROCEEDINGS} and \hbox{\tt PROCEEDINGS} +entry types now allow either a \hbox{\tt volume} or \hbox{\tt number}, +and also a \hbox{\tt series} field. + +\item +The \hbox{\tt UNPUBLISHED} entry type now outputs, +in one block, the \hbox{\tt note} field +followed by the date information. + +\item +The \hbox{\tt MANUAL} entry type now prints out +the \hbox{\tt organization} in the first block +if the \hbox{\tt author} field is empty. + +\item +The {\tt MISC} entry type now issues a warning +if all the optional fields are empty +(that is, if the entire entry is empty). + +\end{enumerate} + + +\section{The Entries} +\label{latex-appendix} + +This section is simply a corrected version of +Appendix~B.2 of the \LaTeX\ book~\cite{latex}, +\copyright~1986, by Addison-Wesley. +The basic scheme is the same, only a few details have changed. + + +\subsection{Entry Types} + +When entering a reference in the database, the first thing to decide +is what type of entry it is. No fixed classification scheme can be +complete, but \BibTeX\ provides enough entry types to handle almost +any reference reasonably well. + +References to different types of publications contain different +information; a reference to a journal article might include the volume +and number of the journal, which is usually not meaningful for a book. +Therefore, database entries of different types have different fields. +For each entry type, the fields are divided into three classes: +\begin{description} + +\item[required] +Omitting the field will produce a warning message +and, rarely, a badly formatted bibliography entry. +If the required information is not meaningful, +you are using the wrong entry type. +However, if the required information is meaningful +but, say, already included is some other field, +simply ignore the warning. + +\item[optional] +The field's information will be used if present, +but can be omitted without causing any formatting problems. +You should include the optional field if it will help the reader. + +\item[ignored] +The field is ignored. +\BibTeX\ ignores any field that is not required or optional, so you can include +any fields you want in a \hbox{\tt bib} file entry. It's a good idea +to put all relevant information about +a reference in its \hbox{\tt bib} file entry---even information that +may never appear in the bibliography. For example, if you want to +keep an abstract of a paper in a computer file, put it in an \hbox{\tt +abstract} field in the paper's \hbox{\tt bib} file entry. The +\hbox{\tt bib} file is likely to be as good a place as any for the +abstract, and it is possible to design a bibliography style for +printing selected abstracts. +Note: Misspelling a field name will +result in its being ignored, +so watch out for typos +(especially for optional fields, +since \BibTeX\ won't warn you when those are missing). + +\end{description} + +The following are the standard entry types, along with their required +and optional fields, that are used by the standard bibliography styles. +The fields within each class (required or optional) +are listed in order of occurrence in the output, +except that a few entry types may perturb the order slightly, +depending on what fields are missing. +These entry types are similar to those adapted by Brian Reid +from the classification scheme of van~Leunen~\cite{van-leunen} +for use in the {\em Scribe\/} system. +The meanings of the individual fields are explained in the next section. +Some nonstandard bibliography styles may ignore some optional fields +in creating the reference. +Remember that, when used in the \hbox{\tt bib} +file, the entry-type name is preceded by an \hbox{\tt @} character. + +\begin{description} +\sloppy + +\item[article\hfill] An article from a journal or magazine. +Required fields: \hbox{\tt author}, \hbox{\tt title}, \hbox{\tt journal}, +\hbox{\tt year}. +Optional fields: \hbox{\tt volume}, \hbox{\tt number}, +\hbox{\tt pages}, \hbox{\tt month}, \hbox{\tt note}. + +\item[book\hfill] A book with an explicit publisher. +Required fields: \hbox{\tt author} or \hbox{\tt editor}, +\hbox{\tt title}, \hbox{\tt publisher}, \hbox{\tt year}. +Optional fields: \hbox{\tt volume} or \hbox{\tt number}, \hbox{\tt series}, +\hbox{\tt address}, \hbox{\tt edition}, \hbox{\tt month}, +\hbox{\tt note}. + +\item[booklet\hfill] A work that is printed and bound, +but without a named publisher or sponsoring institution. +Required field: \hbox{\tt title}. +Optional fields: \hbox{\tt author}, \hbox{\tt howpublished}, +\hbox{\tt address}, \hbox{\tt month}, \hbox{\tt year}, \hbox{\tt note}. + +\item[conference\hfill] The same as {\tt INPROCEEDINGS}, +included for {\em Scribe\/} compatibility. + +\item[inbook\hfill] A part of a book, +which may be a chapter (or section or whatever) and/or a range of pages. +Required fields: \hbox{\tt author} or \hbox{\tt editor}, \hbox{\tt title}, +\hbox{\tt chapter} and/or \hbox{\tt pages}, \hbox{\tt publisher}, +\hbox{\tt year}. +Optional fields: \hbox{\tt volume} or \hbox{\tt number}, \hbox{\tt series}, +\hbox{\tt type}, \hbox{\tt address}, +\hbox{\tt edition}, \hbox{\tt month}, \hbox{\tt note}. + +\item[incollection\hfill] A part of a book having its own title. +Required fields: \hbox{\tt author}, \hbox{\tt title}, \hbox{\tt booktitle}, +\hbox{\tt publisher}, \hbox{\tt year}. +Optional fields: \hbox{\tt editor}, \hbox{\tt volume} or \hbox{\tt number}, +\hbox{\tt series}, \hbox{\tt type}, \hbox{\tt chapter}, \hbox{\tt pages}, +\hbox{\tt address}, \hbox{\tt edition}, \hbox{\tt month}, \hbox{\tt note}. + +\item[inproceedings\hfill] An article in a conference proceedings. +Required fields: \hbox{\tt author}, \hbox{\tt title}, \hbox{\tt booktitle}, +\hbox{\tt year}. +Optional fields: \hbox{\tt editor}, \hbox{\tt volume} or \hbox{\tt number}, +\hbox{\tt series}, \hbox{\tt pages}, \hbox{\tt address}, \hbox{\tt month}, +\hbox{\tt organization}, \hbox{\tt publisher}, \hbox{\tt note}. + +\item[manual\hfill] Technical documentation. Required field: \hbox{\tt title}. +Optional fields: \hbox{\tt author}, \hbox{\tt organization}, +\hbox{\tt address}, \hbox{\tt edition}, \hbox{\tt month}, \hbox{\tt year}, +\hbox{\tt note}. + +\item[mastersthesis\hfill] A Master's thesis. +Required fields: \hbox{\tt author}, \hbox{\tt title}, \hbox{\tt school}, +\hbox{\tt year}. +Optional fields: \hbox{\tt type}, \hbox{\tt address}, \hbox{\tt month}, +\hbox{\tt note}. + +\item[misc\hfill] Use this type when nothing else fits. +Required fields: none. +Optional fields: \hbox{\tt author}, \hbox{\tt title}, \hbox{\tt howpublished}, +\hbox{\tt month}, \hbox{\tt year}, \hbox{\tt note}. + +\item[phdthesis\hfill] A PhD thesis. +Required fields: \hbox{\tt author}, \hbox{\tt title}, \hbox{\tt school}, +\hbox{\tt year}. +Optional fields: \hbox{\tt type}, \hbox{\tt address}, \hbox{\tt month}, +\hbox{\tt note}. + +\item[proceedings\hfill] The proceedings of a conference. +Required fields: \hbox{\tt title}, \hbox{\tt year}. +Optional fields: \hbox{\tt editor}, \hbox{\tt volume} or \hbox{\tt number}, +\hbox{\tt series}, \hbox{\tt address}, \hbox{\tt month}, +\hbox{\tt organization}, \hbox{\tt publisher}, \hbox{\tt note}. + + +\item[techreport\hfill] A report published by a school or other institution, +usually numbered within a series. +Required fields: \hbox{\tt author}, +\hbox{\tt title}, \hbox{\tt institution}, \hbox{\tt year}. +Optional fields: \hbox{\tt type}, \hbox{\tt number}, \hbox{\tt address}, +\hbox{\tt month}, \hbox{\tt note}. + +\item[unpublished\hfill] A document having an author and title, +but not formally published. +Required fields: \hbox{\tt author}, \hbox{\tt title}, \hbox{\tt note}. +Optional fields: \hbox{\tt month}, \hbox{\tt year}. + +\end{description} + +In addition to the fields listed above, each entry type also has an +optional \hbox{\tt key} field, used in some styles +for alphabetizing, for cross referencing, +or for forming a \hbox{\verb|\bibitem|} label. +You should include a \hbox{\tt key} field for any entry whose +``author'' information is missing; +the ``author'' information is usually the \hbox{\tt author} field, +but for some entry types it can be the \hbox{\tt editor} +or even the \hbox{\tt organization} field +(Section~\ref{odds-and-ends} describes this in more detail). +Do not confuse the \hbox{\tt key} field with the key that appears in the +\hbox{\verb|\cite|} command and at the beginning of the database entry; +this field is named ``key'' only for compatibility with {\it Scribe}. + + +\subsection{Fields} + +Below is a description of all fields +recognized by the standard bibliography styles. +An entry can also contain other fields, which are ignored by those styles. +\begin{description} + +\item[address\hfill] +Usually the address of the \hbox{\tt publisher} or other type +of institution. +For major publishing houses, +van~Leunen recommends omitting the information entirely. +For small publishers, on the other hand, you can help the +reader by giving the complete address. + +\item[annote\hfill] +An annotation. +It is not used by the standard bibliography styles, +but may be used by others that produce an annotated bibliography. + +\item[author\hfill] +The name(s) of the author(s), +in the format described in the \LaTeX\ book. + +\item[booktitle\hfill] +Title of a book, part of which is being cited. +See the \LaTeX\ book for how to type titles. +For book entries, use the \hbox{\tt title} field instead. + +\item[chapter\hfill] +A chapter (or section or whatever) number. + +\item[crossref\hfill] +The database key of the entry being cross referenced. + +\item[edition\hfill] +The edition of a book---for example, ``Second''$\!$. +This should be an ordinal, and +should have the first letter capitalized, as shown here; +the standard styles convert to lower case when necessary. + +\item[editor\hfill] +Name(s) of editor(s), typed as indicated in the \LaTeX\ book. +If there is also an \hbox{\tt author} field, then +the \hbox{\tt editor} field gives the editor of the book or collection +in which the reference appears. + +\item[howpublished\hfill] +How something strange has been published. +The first word should be capitalized. + +\item[institution\hfill] +The sponsoring institution of a technical report. + +\item[journal\hfill] +A journal name. +Abbreviations are provided for many journals; see the {\it Local Guide}. + +\item[key\hfill] +Used for alphabetizing, cross referencing, and creating a label when +the ``author'' information +(described in Section~\ref{odds-and-ends}) is missing. +This field should not be confused with the key that appears in the +\hbox{\verb|\cite|} command and at the beginning of the database entry. + +\item[month\hfill] +The month in which the work was +published or, for an unpublished work, in which it was written. +You should use the standard three-letter abbreviation, +as described in Appendix B.1.3 of the \LaTeX\ book. + +\item[note\hfill] +Any additional information that can help the reader. +The first word should be capitalized. + +\item[number\hfill] +The number of a journal, magazine, technical report, +or of a work in a series. +An issue of a journal or magazine is usually +identified by its volume and number; +the organization that issues a +technical report usually gives it a number; +and sometimes books are given numbers in a named series. + +\item[organization\hfill] +The organization that sponsors a conference or that publishes a \hbox{manual}. + +\item[pages\hfill] +One or more page numbers or range of numbers, +such as \hbox{\tt 42--111} or \hbox{\tt 7,41,73--97} or \hbox{\tt 43+} +(the `{\tt +}' in this last example indicates pages following +that don't form a simple range). +To make it easier to maintain {\em Scribe\/}-compatible databases, +the standard styles convert a single dash (as in \hbox{\tt 7-33}) +to the double dash used in \TeX\ to denote number ranges +(as in \hbox{\tt 7--33}). + +\item[publisher\hfill] +The publisher's name. + +\item[school\hfill] +The name of the school where a thesis was written. + +\item[series\hfill] +The name of a series or set of books. +When citing an entire book, the the \hbox{\tt title} field +gives its title and an optional \hbox{\tt series} field gives the +name of a series or multi-volume set +in which the book is published. + +\item[title\hfill] +The work's title, typed as explained in the \LaTeX\ book. + +\item[type\hfill] +The type of a technical report---for example, +``Research Note''$\!$. + +\item[volume\hfill] +The volume of a journal or multivolume book. + +\item[year\hfill] +The year of publication or, for +an unpublished work, the year it was written. +Generally it should consist of four numerals, such as {\tt 1984}, +although the standard styles can handle any {\tt year} whose +last four nonpunctuation characters are numerals, +such as `\hbox{(about 1984)}'$\!$. + +\end{description} + + +\section{Helpful Hints} +\label{odds-and-ends} + +This section gives some random tips +that aren't documented elsewhere, +at least not in this detail. +They are, roughly, in order +of least esoteric to most. +First, however, a brief spiel. + +I understand that there's often little choice in choosing +a bibliography style---journal~$X$ says you must use style~$Y$ +and that's that. +If you have a choice, however, I strongly recommend that you +choose something like the {\tt plain} standard style. +Such a style, van~Leunen~\cite{van-leunen} argues convincingly, +encourages better writing than the alternatives---% +more concrete, more vivid. + +{\em The Chicago Manual of Style\/}~\cite{chicago}, +on the other hand, +espouse the author-date system, +in which the citation might appear in the text as `(Jones, 1986)'$\!$. +I argue that this system, +besides cluttering up the +text with information that may or may not be relevant, +encourages the passive voice and vague writing. +Furthermore the strongest arguments for +using the author-date system---like ``it's the most practical''---% +fall flat on their face with the advent +of computer-typesetting technology. +For instance the {\em Chicago Manual\/} contains, +right in the middle of page~401, this anachronism: +``The chief disadvantage of [a style like {\tt plain}] is that additions +or deletions cannot be made after the manuscript is typed without changing +numbers in both text references and list.'' +\LaTeX, obviously, sidesteps the disadvantage. + +Finally, the logical deficiencies of the author-date style +are quite evident once you've written a program to implement it. +For example, in a large bibliography, +using the standard alphabetizing scheme, +the entry for `(Aho et~al., 1983b)' +might be half a page later than the one for `(Aho et~al., 1983a)'$\!$. +Fixing this problem results in even worse ones. +What a mess. +(I have, unfortunately, programmed such a style, +and if you're saddled with an unenlightened publisher +or if you don't buy my propaganda, +it's available from the Rochester style collection.) + +Ok, so the spiel wasn't very brief; +but it made me feel better, +and now my blood pressure is back to normal. +Here are the tips for using \BibTeX\ +with the standard styles +(although many of them hold for nonstandard styles, too). +\begin{enumerate} + +\item +With \BibTeX's style-designing language +you can program general database manipulations, +in addition to bibliography styles. +For example it's a fairly easy task for someone familiar with the language +to produce a database-key/author index of all the entries in a database. +Consult the {\em Local Guide\/} to see +what tools are available on your system. + +\item +The standard style's thirteen entry types +do reasonably well at formatting most entries, +but no scheme with just thirteen formats +can do everything perfectly. +Thus, you should feel free to be creative +in how you use these entry types +(but if you have to be too creative, +there's a good chance you're using the wrong entry type). + +\item +Don't take the field names too seriously. +Sometimes, for instance, you might have to include +the publisher's address along with the publisher's name +in the \hbox{\tt publisher} field, +rather than putting it in the \hbox{\tt address} field. +Or sometimes, difficult entries work best when you +make judicious use of the {\tt note} field. + +\item +Don't take the warning messages too seriously. +Sometimes, for instance, the year appears in the title, +as in {\em The 1966 World Gnus Almanac}. +In this case it's best to omit the {\tt year} field +and to ignore \BibTeX's warning message. + +\item +If you have too many names to list in an +\hbox{\tt author} or \hbox{\tt editor} field, +you can end the list with ``and others''; +the standard styles appropriately append an ``et~al.'' + +\item +In general, if you want to keep \BibTeX\ from changing +something to lower case, you enclose it in braces. +You might not get the effect you want, however, +if the very first character after the left brace is a backslash. +The ``special characters'' item later in this section explains. + +\item +For {\em Scribe\/} compatibility, the database files +allow an \hbox{\tt @COMMENT} command; it's not really +needed because \BibTeX\ allows in the database files +any comment that's not within an entry. +If you want to comment out an entry, +simply remove the `{\tt @}' character preceding the entry type. + +\item +The standard styles have journal abbreviations that are +computer-science oriented; +these are in the style files primarily for the example. +If you have a different set of journal abbreviations, +it's sensible to put them in \hbox{\tt @STRING} commands +in their own database file and to list this database file +as an argument to \LaTeX's \hbox{\verb|\bibliography|} command +(but you should list this argument before the ones that +specify real database entries). + +\item +It's best to use the three-letter abbreviations for the month, +rather than spelling out the month yourself. +This lets the bibliography style be consistent. +And if you want to include information for the day of the month, +the {\tt month} field is usually the best place. +For example +\begin{verbatim} + month = jul # "~4," +\end{verbatim} +will probably produce just what you want. + +\item +If you're using the \hbox{\tt unsrt} style +(references are listed in order of citation) +along with the \hbox{\verb|\nocite{*}|} feature +(all entries in the database are included), +the placement of the \hbox{\verb|\nocite{*}|} command +within your document file will determine the reference order. +According to the rule given in Section~\ref{features}: +If the command is placed at the beginning of the document, +the entries will be listed in exactly the order +they occur in the database; +if it's placed at the end, +the entries that you explicitly +\hbox{\verb|\cite|} or \hbox{\verb|\nocite|} +will occur in citation order, +and the remaining database entries will be in database order. + +\item +For theses, van Leunen recommends not giving +the school's department after the name of the degree, +since schools, not departments, issue degrees. +If you really think that giving the department information +will help the reader find the thesis, +put that information in the \hbox{\tt address} field. + +\item +The \hbox{\tt MASTERSTHESIS} and \hbox{\tt PHDTHESIS} entry types +are so named for {\em Scribe\/} compatibility; +\hbox{\tt MINORTHESIS} and \hbox{\tt MAJORTHESIS} +probably would have been better names. +Keep this in mind when trying to classify +a non-U.S.\ thesis. + +\item +Here's yet another suggestion for what to do when an author's +name appears slightly differently in two publications. +Suppose, for example, two journals articles use these fields. +\begin{verbatim} + author = "Donald E. Knuth" + . . . + author = "D. E. Knuth" +\end{verbatim} +There are two possibilities. +You could (1)~simply leave them as is, +or (2)~assuming you know for sure that +these authors are one and the same person, +you could list both in the form that the author prefers +(say, `Donald~E.\ Knuth'). +In the first case, the entries might be alphabetized incorrectly, +and in the second, the slightly altered name might +foul up somebody's electronic library search. +But there's a third possibility, which is the one I prefer. +You could convert the second journal's field to +\begin{verbatim} + author = "D[onald] E. Knuth" +\end{verbatim} +This avoids the pitfalls of the previous two solutions, +since \BibTeX\ alphabetizes this as if the brackets weren't there, +and since the brackets clue the reader in that a full first name +was missing from the original. +Of course it introduces another pitfall---`D[onald]~E.\ Knuth' looks ugly---% +but in this case I think the increase in accuracy outweighs +the loss in aesthetics. + +\item +\LaTeX's comment character `{\tt\%}' is not a comment character +in the database files. + +\item +Here's a more complete description of +the ``author'' information referred to in previous sections. +For most entry types the ``author'' information +is simply the \hbox{\tt author} field. +However: +For the \hbox{\tt BOOK} and \hbox{\tt INBOOK} entry types +it's the \hbox{\tt author} field, but if there's no author +then it's the \hbox{\tt editor} field; +for the \hbox{\tt MANUAL} entry type +it's the \hbox{\tt author} field, but if there's no author +then it's the \hbox{\tt organization} field; +and for the \hbox{\tt PROCEEDINGS} entry type +it's the \hbox{\tt editor} field, but if there's no editor +then it's the \hbox{\tt organization} field. + +\item +When creating a label, +the \hbox{\tt alpha} style uses the ``author'' information described above, +but with a slight change---% +for the \hbox{\tt MANUAL} and \hbox{\tt PROCEEDINGS} entry types, +the {\tt key} field takes precedence over the \hbox{\tt organization} field. +Here's a situation where this is useful. +\begin{verbatim} + organization = "The Association for Computing Machinery", + key = "ACM" +\end{verbatim} +Without the {\tt key} field, the \hbox{\tt alpha} style +would make a label from the first three letters of information +in the \hbox{\tt organization} field; +\hbox{\tt alpha} knows to strip off the `\hbox{\tt The }'$\!$, +but it would still form a label like `\hbox{[Ass86]}'$\!$, +which, however intriguing, is uninformative. +Including the {\tt key} field, as above, +would yield the better label `\hbox{[ACM86]}'$\!$. + +You won't always need the {\tt key} field to override the +\hbox{\tt organization}, though: +With +\begin{verbatim} + organization = "Unilogic, Ltd.", +\end{verbatim} +for instance, the \hbox{\tt alpha} style would +form the perfectly reasonable label `\hbox{[Uni86]}'$\!$. + +\item +Section~\ref{features} discusses accented characters. +To \BibTeX, an accented character is really a special case +of a ``special character''$\!$, +which consists of everything from a left brace at the top-most level, +immediately followed by a backslash, +up through the matching right brace. +For example in the field +\begin{verbatim} + author = "\AA{ke} {Jos{\'{e}} {\'{E}douard} G{\"o}del" +\end{verbatim} +there are just two special characters, +`\hbox{\verb|{\'{E}douard}|}' and `\hbox{\verb|{\"o}|}' +(the same would be true if the pair of double quotes +delimiting the field were braces instead). +In general, \BibTeX\ will not do any processing +of a \TeX\ or \LaTeX\ control sequence inside a special character, +but it {\em will\/} process other characters. +Thus a style that converts all titles to lower case +would convert +\begin{verbatim} + The {\TeX BOOK\NOOP} Experience +\end{verbatim} +to +\begin{verbatim} + The {\TeX book\NOOP} experience +\end{verbatim} +(the `{\tt The}' is still capitalized +because it's the first word of the title). + +This special-character scheme is useful for handling accented characters, +for getting \BibTeX's alphabetizing to do what you want, +and, since \BibTeX\ counts an entire special character as just one letter, +for stuffing extra characters inside labels. +The file \hbox{\tt XAMPL.BIB} distributed with \BibTeX\ +gives examples of all three uses. + +\item +This final item of the section describes \BibTeX's names +(which appear in the \hbox{\tt author} or \hbox{\tt editor} field) +in slightly more detail than what +appears in Appendix~B of the \LaTeX\ book. +In what follows, a ``name'' corresponds to a person. +(Recall that you separate multiple names in a single field +with the word ``and''$\!$, surrounded by spaces, +and not enclosed in braces. +This item concerns itself with the structure of a single name.) + +Each name consists of four parts: First, von, Last, and~Jr; +each part consists of a (possibly empty) list of name-tokens. +The Last part will be nonempty if any part is, +so if there's just one token, it's always a Last token. + +Recall that Per Brinch~Hansen's name should be typed +\begin{verbatim} + "Brinch Hansen, Per" +\end{verbatim} +The First part of his name has the single token ``Per''; +the Last part has two tokens, ``Brinch'' and ``Hansen''; +and the von and Jr parts are empty. +If you had typed +\begin{verbatim} + "Per Brinch Hansen" +\end{verbatim} +instead, \BibTeX\ would (erroneously) think ``Brinch'' were a First-part token, +just as ``Paul'' is a First-part token in ``John~Paul Jones''$\!$, +so this erroneous form would have two First tokens and one Last token. + +Here's another example: +\begin{verbatim} + "Charles Louis Xavier Joseph de la Vall{\'e}e Poussin" +\end{verbatim} +This name has four tokens in the First part, two in the von, and +two in the Last. +Here \BibTeX\ knows where one part ends and the other begins because +the tokens in the von part begin with lower-case letters. + +In general, it's a von token if the first letter at brace-level~0 +is in lower case. +Since technically everything +in a ``special character'' is at brace-level~0, +you can trick \BibTeX\ into thinking that +a token is or is not a von token by prepending a dummy +special character whose first letter past the \TeX\ control sequence +is in the desired case, upper or lower. + +To summarize, \BibTeX\ allows three possible forms for the name: +\begin{verbatim} + "First von Last" + "von Last, First" + "von Last, Jr, First" +\end{verbatim} +You may almost always use the first form; +you shouldn't if either there's a Jr part, +or the Last part has multiple tokens but there's no von part. + +\end{enumerate} + +\bibliography{btxdoc} +\bibliographystyle{plain} +\end{document} diff --git a/Build/source/extra/bibtex/btxdoc.xua b/Build/source/extra/bibtex/btxdoc.xua new file mode 100644 index 00000000000..4f0e0bbce2e --- /dev/null +++ b/Build/source/extra/bibtex/btxdoc.xua @@ -0,0 +1,28 @@ +\relax +\citation{btxhak} +\citation{latex} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {1}Overview}{1}} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {2}Changes}{2}} +\newlabel{differences}{{2}{2}} +\@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {2.1}New {\string\prm\space B\kern -.05em{\string\psc\space i\kern -.025em b}\kern -.08em T\kern -.1667em\lower .7ex\hbox {E}\kern -.125emX}\ features}{2}} +\newlabel{features}{{2.1}{2}} +\newlabel{concat}{{2}{2}} +\newlabel{preamble}{{6}{4}} +\citation{btxhak} +\@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {2.2}Changes to the standard styles}{5}} +\citation{latex} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {3}The Entries}{7}} +\newlabel{latex-appendix}{{3}{7}} +\@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {3.1}Entry Types}{7}} +\citation{van-leunen} +\@writefile{toc}{\string\contentsline\space {subsection}{\string\numberline\space {3.2}Fields}{9}} +\citation{van-leunen} +\citation{chicago} +\@writefile{toc}{\string\contentsline\space {section}{\string\numberline\space {4}Helpful Hints}{11}} +\newlabel{odds-and-ends}{{4}{11}} +\bibdata{btxdoc} +\bibcite{chicago}{1} +\bibcite{latex}{2} +\bibcite{btxhak}{3} +\bibcite{van-leunen}{4} +\bibstyle{plain} diff --git a/Build/source/extra/bibtex/btxhak.tex b/Build/source/extra/bibtex/btxhak.tex new file mode 100644 index 00000000000..ce620544811 --- /dev/null +++ b/Build/source/extra/bibtex/btxhak.tex @@ -0,0 +1,623 @@ +% Copyright (C) 1988, all rights reserved. + +\def\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} + +\title{Designing B\kern-.05em{\large I}\kern-.025em{\large B}\kern-.08em\TeX\ + Styles} +\author{Oren Patashnik} +\date{February 8, 1988} + +\documentstyle{article} +\begin{document} + +\maketitle + +\setcounter{section}{4} +\section{Bibliography-style hacking} +\label{style} + +This document starts (and ends) with Section~\ref{style}, +because in reality it is the final section of ``\BibTeX ing''~\cite{btxdoc}, +the general documentation for \BibTeX. +But that document was meant for all \BibTeX\ users, +while this one is just for style designers, +so the two are physically separate. +Still, you should be completely familiar with ``\BibTeX ing''$\!$, +and all references in this document +to sections and section numbers +assume that the two documents are one. + +This section, +along with the standard-style documentation file \hbox{\tt btxbst.doc}, +should explain how to modify +existing style files and to produce new ones. +If you're a serious style hacker you should be familiar +with van~Leunen~\cite{van-leunen} for points of style, +with Lamport~\cite{latex} and Knuth~\cite{texbook} for formatting matters, +and perhaps with {\em Scribe\/}~\cite{scribe} for compatibility details. +And while you're at it, if you don't read the great little book by Strunk and +White~\cite{strunk-and-white}, you should at least look at its +entries in the database and the reference list +to see how \BibTeX\ handles multiple names. + +To create a new style, +it's best to start with an existing style that's close to yours, +and then modify that. +This is true even if you're simply updating an old style +for \BibTeX\ version 0.99 +(I've updated four nonstandard styles, +so I say this with some experience). +If you want to insert into a new style +some function you'd written for an old (version 0.98i) style, +keep in mind that the order of the arguments to +the assignment ({\tt :=}) function has been reversed. +When you're finished with your style, +you may want to try running it on the entire \hbox{\tt XAMPL.BIB} database +to make sure it handles all the standard entry types. + +If you find any bugs in the standard styles, +or if there are things you'd like to do +with bibliography-style files but can't, +please complain to Oren Patashnik. + + +\subsection{General description} + +You write bibliography styles in a postfix stack language. It's +not too hard to figure out how by looking at the standard-style documentation, +but this description fills in a few details (it will fill in more +details if there's a demand for it). + +Basically the style file is a program, written in an unnamed language, that +tells \BibTeX\ how to format the entries that will go in the reference list +(henceforth ``the entries'' will be ``the entry list'' +or simply ``the list''$\!$, context permitting). +This programming language has ten commands, described in the next subsection. +These commands manipulate the language's objects: +constants, variables, functions, the stack, and the entry list. +(Warning: The terminology in this documentation, +chosen for ease of explanation, is slightly different from \BibTeX's. +For example, this documentation's ``variables'' and ``functions'' +are both ``functions'' to \BibTeX. +Keep this in mind when interpreting \BibTeX's error messages.) + +There are two types of functions: {\it built-in\/} ones that \BibTeX\ provides +(these are described in Section~\ref{built-in-fns}), and ones you define +using either the \hbox{\tt MACRO} or \hbox{\tt FUNCTION} command. + +Your most time-consuming task, as a style designer, +will be creating or modifying functions +using the \hbox{\tt FUNCTION} command +(actually, becoming familiar with the references listed above will be +more time consuming, but assume for the moment that that's done). + +Let's look at a sample function fragment. +Suppose you have a string variable named \hbox{\tt label} +and an integer variable named \hbox{\tt lab.width}, +and suppose you want to append the character `{\tt a}' to \hbox{\tt label} +and to increment \hbox{\tt lab.width}: +\begin{verbatim} + . . . + label "a" * 'label := % label := label * "a" + lab.width #1 + 'lab.width := % lab.width := lab.width + 1 + . . . +\end{verbatim} +In the first line, +\hbox{\tt label} pushes that variable's value onto the stack. +Next, the {\tt "a"} pushes the string constant `{\tt a}' onto the stack. +Then the built-in function {\tt *} pops the top two strings and +pushes their concatenation. +The \hbox{\tt 'label} pushes that variable's name onto the stack. +And finally, the built-in function {\tt :=} pops +the variable name and the concatenation and performs the assignment. +\BibTeX\ treats the stuff following the {\tt \%} as a comment +in the style file. +The second line is similar except that it uses {\tt \#1}, +with no spaces intervening between the `{\tt \#}' and the `{\tt 1}'$\!$, +to push this integer constant. + +The nonnull spacing here is arbitrary: multiple spaces, tabs, or newlines +are equivalent to a single one (except that you're probably better off +not having blank lines within commands, as explained shortly). + +For string constants, absolutely any printing character +is legal between two consecutive double quotes, but \BibTeX\ here +(and only here) treats upper- and lower-case equivalents as different. +Furthermore, spacing {\em is\/} relevant within a string constant, +and you mustn't split a string constant across lines +(that is, the beginning and ending double quotes must be on the same line). + +Variable and function names may not begin with a numeral and +may not contain any of the ten restricted characters +on page~143 of the \LaTeX\ book, +but may otherwise contain any printing characters. +Also, \BibTeX\ considers upper- and lower-case equivalents to be the same. + +Integers and strings are the only value types for constants and variables +(booleans are implemented simply as 0-or-1 integers). +There are three kinds of variables: +\begin{description} + +\item[global variables\hfill] These are either integer- or string-valued, +declared using an \hbox{\tt INTEGERS} or \hbox{\tt STRINGS} command. + +\item[entry variables\hfill] These are either integer- or string-valued, +declared using the \hbox{\tt ENTRY} command. +Each has a value for each entry on the list +(example: a variable \hbox{\tt label} might store +the label string you'll use for the entry). + +\item[fields\hfill] These are string-valued, read-only variables +that store the information from the database file; +their values are set by the \hbox{\tt READ} command. +As with entry variables, each has a value for each entry. +\end{description} + + +\subsection{Commands} + +There are ten style-file commands: +Five (\hbox{\tt ENTRY}, \hbox{\tt FUNCTION}, \hbox{\tt INTEGERS}, +\hbox{\tt MACRO}, and \hbox{\tt STRINGS}) +declare and define variables and functions; +one (\hbox{\tt READ}) reads in the database information; +and four (\hbox{\tt EXECUTE}, \hbox{\tt ITERATE}, \hbox{\tt REVERSE}, +and \hbox{\tt SORT}) manipulate the entries and produce output. +Although the command names appear here in upper case, +\BibTeX\ ignores case differences. + +Some restrictions: +There must be exactly one \hbox{\tt ENTRY} and one \hbox{\tt READ} command; +the \hbox{\tt ENTRY} command, all \hbox{\tt MACRO} commands, +and certain \hbox{\tt FUNCTION} commands +(see next subsection's description of \hbox{\tt call.type\$}) +must precede the \hbox{\tt READ} command; +and the \hbox{\tt READ} command must precede the four that +manipulate the entries and produce output. + +Also it's best (but not essential) to leave at least one blank line +between commands and to leave no blank lines within a command; +this helps \BibTeX\ recover from any syntax errors you make. + +You must enclose each argument of every command in braces. +Look at the standard-style documentation +for syntactic issues not described in this section. +Here are the ten commands: +\begin{description} + +\item[\hbox{\tt ENTRY}\hfill] +Declares the fields and entry variables. +It has three arguments, each a (possibly empty) list of variable names. +The three lists are of: +fields, integer entry variables, and string entry variables. +There is an additional field that \BibTeX\ automatically +declares, \hbox{\tt crossref}, used for cross referencing. +And there is an additional string entry variable automatically declared, +\hbox{\tt sort.key\$}, used by the \hbox{\tt SORT} command. +Each of these variables has a value for each entry on the list. + +\item[\hbox{\tt EXECUTE}\hfill] +Executes a single function. +It has one argument, the function name. + +\item[\hbox{\tt FUNCTION}\hfill] +Defines a new function. +It has two arguments; the first is the function's name and the +second is its definition. +You must define a function before using it; +recursive functions are thus illegal. + +\item[\hbox{\tt INTEGERS}\hfill] +Declares global integer variables. +It has one argument, a list of variable names. +There are two such automatically-declared variables, +\hbox{\tt entry.max\$} and \hbox{\tt global.max\$}, +used for limiting the lengths of string variables. +You may have any number of these commands, but a variable's declaration +must precede its use. + +\item[\hbox{\tt ITERATE}\hfill] +Executes a single function, once +for each entry in the list, in the list's current order +(initially the list is in citation order, but the \hbox{\tt SORT} +command may change this). +It has one argument, the function name. + +\item[\hbox{\tt MACRO}\hfill] +Defines a string macro. +It has two arguments; the first is the macro's name, which is treated like +any other variable or function name, +and the second is its definition, which must be double-quote-delimited. +You must have one for each three-letter month abbreviation; +in addition, you should have one for common journal names. +The user's database may override any definition you define using this command. +If you want to define a string the user can't touch, +use the \hbox{\tt FUNCTION} command, which has a compatible syntax. + +\item[\hbox{\tt READ}\hfill] +Dredges up from the database file +the field values for each entry in the list. +It has no arguments. +If a database entry doesn't have a value for a field +(and probably no database entry will have a value for every field), +that field variable is marked as missing for the entry. + +\item[\hbox{\tt REVERSE}\hfill] +Exactly the same as the +\hbox{\tt ITERATE} command except that it executes the function +on the entry list in reverse order. + +\item[\hbox{\tt SORT}\hfill] +Sorts the entry list using +the values of the string entry variable \hbox{\tt sort.key\$}. +It has no arguments. + +\item[\hbox{\tt STRINGS}\hfill] +Declares global string variables. +It has one argument, a list of variable names. +You may have any number of these commands, but a variable's declaration +must precede its use. +\end{description} + + +\subsection{The built-in functions} +\label{built-in-fns} + +Before we get to the built-in functions, +a few words about some other built-in objects. +There is one built-in string entry variable, \hbox{\tt sort.key\$}, +which the style program must set if the style is to do sorting. +There is one built-in field, \hbox{\tt crossref}, +used for the cross referencing feature +described in Section~4. +And there are two built-in integer global variables, +\hbox{\tt entry.max\$} and \hbox{\tt global.max\$}, +which are set by default to some internal \BibTeX\ constants; +you should truncate strings to these lengths before +you assign to string variables, +so as to not generate any \BibTeX\ warning messages. + +There are currently 37 built-in functions. +Every built-in function with a letter in its name ends with a `{\tt \$}'$\!$. +In what follows, ``first''$\!$, ``second''$\!$, +and so on refer to the order popped. +A ``literal'' is an element on the stack, and it will be either +an integer value, a string value, a variable or function name, +or a special value denoting a missing field. +If any popped literal has an incorrect type, \BibTeX\ complains and pushes +the integer 0 or the null string, depending on whether the function +was supposed to push an integer or string. +\begin{description} + +\item[\hbox{\tt >}\hfill] +Pops the top two (integer) literals, +compares them, and pushes the integer 1 if the second is greater than +the first, 0 otherwise. + +\item[\hbox{\tt <}\hfill] +Analogous. + +\item[\hbox{\tt =}\hfill] +Pops the top two (both integer or both string) literals, +compares them, +and pushes the integer 1 if they're equal, 0 otherwise. + +\item[\hbox{\tt +}\hfill] +Pops the top two (integer) literals and pushes their sum. + +\item[\hbox{\tt -}\hfill] +Pops the top two (integer) literals and pushes their difference +(the first subtracted from the second). + +\item[\hbox{\tt *}\hfill] +Pops the top two (string) literals, +concatenates them (in reverse order, that is, the order in which +pushed), and pushes the resulting string. + +\item[\hbox{\tt :=}\hfill] +Pops the top two literals and assigns +to the first (which must be a global or entry variable) +the value of the second. + +\item[\hbox{\tt add.period\$}\hfill] +Pops the top (string) literal, +adds a `{\tt .}' to it if the last non`{\tt \}}' character +isn't a `{\tt .}'$\!$, `{\tt ?}', or `{\tt !}'$\!$, +and pushes this resulting string. + +\item[\hbox{\tt call.type\$}\hfill] +Executes the function whose name is the entry type of an entry. +For example if an entry is of type {\tt book}, this function executes +the {\tt book} function. +When given as an argument to the \hbox{\tt ITERATE} command, +\hbox{\tt call.type\$} actually produces the output for the entries. +For an entry with an unknown type, +it executes the function \hbox{\tt default.type}. +Thus you should define (before the \hbox{\tt READ} command) one function +for each standard entry type as well as a \hbox{\tt default.type} function. + +\item[\hbox{\tt change.case\$}\hfill] +Pops the top two (string) literals; +it changes the case of the second according to the +specifications of the first, as follows. (Note: The word `letters' in +the next sentence refers only to those at brace-level~0, the top-most +brace level; no other characters are changed, except perhaps for +``special characters''$\!$, described in Section~4.) +If the first literal is the +string~`{\tt t}'$\!$, it converts to lower case all letters except the very +first character in the string, which it leaves alone, and except the +first character following any colon and then nonnull white space, +which it also leaves alone; if it's the string~`{\tt l}'$\!$, it converts all +letters to lower case; and if it's the string~`{\tt u}'$\!$, it converts all +letters to upper case. +It then pushes this resulting string. If either +type is incorrect, it complains and pushes the null string; however, +if both types are correct but the specification string (i.e., the +first string) isn't one of the legal ones, it merely pushes the second +back onto the stack, after complaining. (Another note: It ignores +case differences in the specification string; for example, the strings +{\tt t} and {\tt T} are equivalent for the purposes of this built-in +function.) + +\item[\hbox{\tt chr.to.int\$}\hfill] +Pops the top (string) literal, +makes sure it's a single character, converts it to the +corresponding ASCII integer, and pushes this integer. + +\item[\hbox{\tt cite\$}\hfill] +Pushes the string that was the +\hbox{\verb|\cite|}-command argument for this entry. + +\item[\hbox{\tt duplicate\$}\hfill] +Pops the top literal from the stack and pushes two copies of it. + +\item[\hbox{\tt empty\$}\hfill] +Pops the top literal and pushes +the integer 1 if it's a missing field or a string having no +non-white-space characters, 0 otherwise. + +\item[\hbox{\tt format.name\$}\hfill] +Pops the top three literals +(they are a string, an integer, and a string literal). +The last string literal represents a name list (each name +corresponding to a person), the integer literal specifies which name +to pick from this list, and the first string literal specifies how to +format this name, as explained in the next subsection. +Finally, this function pushes the formatted name. + +\item[\hbox{\tt if\$}\hfill] +Pops the top three literals (they +are two function literals and an integer literal, in that order); +if the integer is greater than 0, it executes the second literal, +else it executes the first. + +\item[\hbox{\tt int.to.chr\$}\hfill] +Pops the top (integer) literal, +interpreted as the ASCII integer value of a single character, +converts it to the corresponding single-character string, and pushes +this string. + +\item[\hbox{\tt int.to.str\$}\hfill] +Pops the top (integer) literal, +converts it to its (unique) string equivalent, and pushes this string. + +\item[\hbox{\tt missing\$}\hfill] +Pops the top literal and +pushes the integer 1 if it's a missing field, 0~otherwise. + +\item[\hbox{\tt newline\$}\hfill] +Writes onto the {\tt bbl} file +what's accumulated in the output buffer. +It writes a blank line if and only if the output buffer is empty. +Since \hbox{\tt write\$} does reasonable line breaking, you should use +this function only when you want a blank line or an explicit line break. + +\item[\hbox{\tt num.names\$}\hfill] +Pops the top (string) literal +and pushes the number of names the string represents---one plus +the number of occurrences of the substring ``and'' (ignoring case differences) +surrounded by nonnull white-space at the top brace level. + +\item[\hbox{\tt pop\$}\hfill] +Pops the top of the stack but +doesn't print it; this gets rid of an unwanted stack literal. + +\item[\hbox{\tt preamble\$}\hfill] +Pushes onto the stack the concatenation of all the +\hbox{\tt @PREAMBLE} strings read from the database files. + +\item[\hbox{\tt purify\$}\hfill] +Pops the top (string) literal, +removes nonalphanumeric characters except for white-space characters and +hyphens and ties (these all get converted to a space), removes +certain alphabetic characters contained in the control sequences +associated with a ``special character''$\!$, and pushes the resulting string. + +\item[\hbox{\tt quote\$}\hfill] +Pushes the string consisting of the double-quote character. + +\item[\hbox{\tt skip\$}\hfill] +Is a no-op. + +\item[\hbox{\tt stack\$}\hfill] +Pops and prints the whole stack; +it's meant to be used for style designers while debugging. + +\item[\hbox{\tt substring\$}\hfill] +Pops the top three literals +(they are the two integers literals {\it len\/} and {\it start}, and a +string literal, in that order). +It pushes the substring of the (at most) {\it len\/} consecutive characters +starting at the {\it start\/}th character (assuming 1-based indexing) +if {\it start\/} is positive, and ending at the $-${\it start\/}th character +from the end if {\it start\/} is negative +(where the first character from the end is the last character). + +\item[\hbox{\tt swap\$}\hfill] +Swaps the top two literals on the stack. + +\item[\hbox{\tt text.length\$}\hfill] +Pops the top (string) literal, +and pushes the number of text characters it contains, where an +accented character (more precisely, a ``special character''$\!$, +defined in Section~4) +counts as a single text character, even if it's missing +its matching right brace, and where braces don't count as +text characters. + +\item[\hbox{\tt text.prefix\$}\hfill] +Pops the top two literals +(the integer literal {\it len\/} and a string literal, in that order). +It pushes the substring of the (at most) {\it len\/} consecutive text +characters starting from the beginning of the string. This function +is similar to \hbox{\tt substring\$}, but this one considers +a ``special character''$\!$, even if +it's missing its matching right brace, to be a single text character +(rather than however many ASCII characters it actually comprises), +and this function doesn't consider braces to be text characters; +furthermore, this function appends any needed matching right braces. + +\item[\hbox{\tt top\$}\hfill] +Pops and prints the top of the stack on the terminal and log file. +It's useful for debugging. + +\item[\hbox{\tt type\$}\hfill] +Pushes the current entry's type (book, article, etc.), +but pushes the null string +if the type is either unknown or undefined. + +\item[\hbox{\tt warning\$}\hfill] +Pops the top (string) literal +and prints it following a warning message. +This also increments a count of the number of warning messages issued. + +\item[\hbox{\tt while\$}\hfill] +Pops the top two (function) literals, +and keeps executing the second as long as the (integer) +literal left on the stack by executing the first is greater than 0. + +\item[\hbox{\tt width\$}\hfill] +Pops the top (string) literal +and pushes the integer that represents its width in some relative units +(currently, hundredths of a point, as specified by the June 1987 version +of the $cmr10$ font; the only white-space character with nonzero width +is the space). +This function takes the literal literally; +that is, it assumes each character in the string is to be printed as +is, regardless of whether the character has a special meaning to \TeX, +except that ``special characters'' (even without their right braces) are +handled specially. +This is meant to be used for comparing widths of label strings. + +\item[\hbox{\tt write\$}\hfill] +Pops the top (string) literal +and writes it on the output buffer (which will result in +stuff being written onto the {\tt bbl} file when the buffer fills up). + +\end{description} + +Note that the built-in functions \hbox{\tt while\$} and \hbox{\tt if\$} +require two function literals on the stack. +You get them there either by immediately preceding the name of a function +by a single quote, or, if you don't feel like defining a new function with +the \hbox{\tt FUNCTION} command, +by simply giving its definition (that is, giving what would be the second +argument to the \hbox{\tt FUNCTION} command, including the surrounding braces). +For example the following function fragment appends the character `{\tt a}' +if the string variable named \hbox{\tt label} is nonnull: +\begin{verbatim} + . . . + label "" = + 'skip$ + { label "a" * 'label := } + if$ + . . . +\end{verbatim} +A function whose name you quote needn't be built in +like \hbox{\tt skip\$} above---it may, for example, +be a field name or a function you've defined earlier. + + +\subsection{Name formatting} + +What's in a name? +Section~4 pretty much describes this. +Each name consists of four parts: First, von, Last, and Jr; +each consists of a list of name-tokens, +and any list but Last's may be empty for a nonnull name. +This subsection describes the format string you must supply to +the built-in function \hbox{\tt format.name\$}. + +Let's look at an example of a very long name. +Suppose a database entry~\cite{prime-number-theorem} has the field +\begin{verbatim} + author = "Charles Louis Xavier Joseph de la Vall{\'e}e Poussin" +\end{verbatim} +and suppose you want this formatted ``last name comma initials''$\!$. +If you use the format string +\begin{verbatim} + "{vv~}{ll}{, jj}{, f}?" +\end{verbatim} +\BibTeX\ will produce +\begin{verbatim} + de~la Vall{\'e}e~Poussin, C.~L. X.~J? +\end{verbatim} +as the formatted string. + +Let's look at this example in detail. +There are four brace-level~1 {\em pieces\/} to this format string, +one for each part of a name. +If the corresponding part of a name isn't present (the Jr part for this name), +everything in that piece is ignored. +Anything at brace-level~0 is output verbatim +(the presumed typo `{\tt ?}' for this name is at brace-level~0), +but you probably won't use this feature much. + +Within each piece a double letter tells \BibTeX\ to use whole tokens, and +a single letter, to abbreviate them (these letters must be at brace-level~1); +everything else within the piece is used verbatim +(well, almost everything---read on). +The tie at the end of the von part (in \hbox{\verb|{vv~}|}) +is a discretionary tie---\BibTeX\ will output a tie at that point +if it thinks there's a need for one; +otherwise it will output a space. +If you really, really, want a tie there, +regardless of what \BibTeX\ thinks, use two of them +(only one will be output); that is, use \hbox{\verb|{vv~~}|}. +A tie is discretionary only if it's the last character of the piece; +anywhere else it's treated as an ordinary character. + +\BibTeX\ puts default strings {\em between\/} tokens of a name part: +For whole tokens it uses either a space or a tie, +depending on which one it thinks is best, +and for abbreviated tokens it uses a period followed by +either a space or a tie. +However it doesn't use this default string after the last token in a list; +hence there's no period following the `J' for our example. +You should have used +\begin{verbatim} + "{vv~}{ll}{, jj}{, f.}" +\end{verbatim} +to get \BibTeX\ to produce the same formatted string but with the question +mark replaced by a period. +Note that the period should go inside the First-name piece, +rather than where the question mark was, in case a name has no First part. + +If you want to override \BibTeX's default between-token strings, you +must explicitly specify a string. +For example suppose you want a label to contain the first letter from each +token in the von and Last parts, with no spaces; +you should use the format string +\begin{verbatim} + "{v{}}{l{}}" +\end{verbatim} +so that \BibTeX\ will produce `{\tt dlVP}' as the formatted string. +You must give a string for each piece whose default you want overridden +(the example here uses the null string for both pieces), and this string +must immediately follow either the single or double letter for the piece. +You may not have any other letters at brace-level~1 in the format string. + +\bibliography{btxdoc} +\bibliographystyle{plain} +\end{document} diff --git a/Build/source/extra/bibtex/btxmac.tex b/Build/source/extra/bibtex/btxmac.tex new file mode 100644 index 00000000000..b45b7e591ec --- /dev/null +++ b/Build/source/extra/bibtex/btxmac.tex @@ -0,0 +1,842 @@ +%% @texfile{ +%% author = "Karl Berry and Oren Patashnik", +%% version = "0.99k", +%% date = "13 Nov 1995", +%% filename = "btxmac.tex", +%% address = "Please use electronic mail", +%% checksum = "842 4571 33524", +%% email = "opbibtex@cs.stanford.edu", +%% codetable = "ISO/ASCII", +%% supported = "yes", +%% docstring = "Defines macros that make BibTeX work with plain TeX", +%% } +% BibTeX-for-TeX macros, version 0.99k, for BibTeX 0.99c, TeX 3.0 or later. +% Copyright (C) 1990-92,95 by Karl Berry & Oren Patashnik; all rights reserved. +% You may copy this file provided: that it's accompanied by the +% "BibTeXing" document, whose text is contained in the file `btxdoc.tex'; +% that any documentation you write for these macros also gives a +% reference for "BibTeXing"; and that either you make absolutely no +% changes to your copy, or if you do make changes, (1) you name the file +% something other than `btxmac.tex' and you remove all occurrences of +% `btxmac.tex' from the file, (2) you put, somewhere in the first twenty +% lines of the file, your name, along with an electronic address at which +% others who might use the file may reach you, and (3) you remove each +% occurrence of Oren's name and electronic address from this file. These +% restrictions help ensure that all standard versions of these macros are +% identical, and that Oren doesn't get deluged with inappropriate e-mail. +% +% This file, btxmac.tex, contains TeX macros that allow BibTeX, a +% bibliography program that was originally designed for use with LaTeX, +% to work with plain TeX. Please report any bugs (outright goofs, +% improvable macros, misfeatures, or unclear documentation) to Oren +% Patashnik (opbibtex@cs.stanford.edu). These macros will become frozen +% shortly after BibTeX version 1.00 is released. +% +% AMS-TEX WARNING: We tried very hard, for version .99i of these macros, +% to make them compatible with AmS-TeX. We succeeded to the extent +% that, if you use one of the standard bibliography styles, you probably +% won't notice any problems with version 0.99i of btxmac.tex. But +% ultimately we failed, in that the inherent incompatibilities between +% plain TeX and AmS-TeX kept making these macros break, for certain +% inputs or certain styles. Examples: (1) AmS-TeX treats at-signs as +% special, in ways that plain TeX and LaTeX don't, so that, for example, +% you can't have any `@' characters in an argument to the \cite command, +% the way you can in TeX or LaTeX; (2) AmS-TeX decided that plain TeX's +% and LaTeX's macron-accent control sequence `\=' should be undefined; +% so you'll need to define `\=' to be `\B' to get the xampl.bib example +% suggested below to work with AmS-TeX; (3) AmS-TeX redefines the tie +% character `~' of plain TeX, and AmS-TeX's `amsppt' style redefines +% plain TeX's `\nobreak' macro, so that if you use an author-date style +% like `apalike' and you have a multiple-author reference for which the +% author-date style automatically produces a citation in the text like +% `(Jones et~al., 1992)' you will throw AmS-TeX's `amsppt' style into +% an infinite loop, exceeding its input stack size. In practice, such +% incompatibilities surface infrequently; but it is now clear to us that +% it's not worth the effort (perhaps it's not even possible) to make the +% btxmac.tex macros robust when used both with plain TeX and Ams-TeX. +% If the BibTeX/AmS-TeX results attainable with the current btxmac.tex +% macros are sufficient, fine. But if there's a demand for more robust +% BibTeX/AmS-TeX behavior, then someone who's very familiar with the +% AmS-TeX package should probably make an amsbtxmc.tex version of the +% macros (remembering to follow the copyright restrictions above). +% Until then, if you're an AmS-TeX user, or a LaTeX or plain TeX user +% sharing files with an AmS-TeX user, beware. +% END OF AMS-TEX WARNING. +% +% To use these macros you should be familiar with how BibTeX interacts +% with LaTeX, since BibTeX's interaction with TeX is very similar; that +% interaction is explained in the LaTeX manual. It also helps to +% have read "BibTeXing", the documentation that accompanies BibTeX. +% Then, if you want, you should redefine any of the macros that begin +% with `\bbl' or `\biblabel' or `\print' that you need to get formatting +% different from the default (the default settings are designed to +% accompany a bibliography style like BibTeX's standard style `plain'). +% The macros you might want to change are described briefly a few +% paragraphs hence. [To get started without reading any documentation, +% try running the nine-line .tex file below through TeX and BibTeX. +% Remember the general scheme: Running (La)TeX writes information on +% the .aux (auxiliary) file; then running BibTeX reads information from +% the .aux, .bst (style), and .bib (database) files, and writes +% information (the bibliography) on a .bbl file; then running (La)TeX +% incorporates the bibliography; then running (La)TeX once more fixes +% the remaining forward references into the bibliography. Thus, to get +% everything incorporated into your output, you'll have to run (La)TeX, +% BibTeX, (La)TeX, (La)TeX. (Standup, sitdown, fight, fight, fight.)] +% +% These macros can stand alone or they can be \input into a macro +% package, like Eplain, that is sufficiently compatible with plain TeX. +% To use these macros to format the 0.99 version of the xampl.bib file +% that's distributed with BibTeX (that version of the file has no +% self-identification), you'll need to define \mbox, which is a LaTeX +% command, to be \hbox, as in the example below. +% +% Here's a nine-line plain TeX file for trying out btxmac.tex; of course +% you'll have to remove the comment characters at the beginning of each +% line, and, depending on your system, you might have to take steps so +% that BibTeX can "see" the files xampl.bib and plain.bst (BibTeX will +% give you two empty-field warning messages that you should ignore). +% +% \def\mbox#1{\leavevmode\hbox{#1}} +% \input btxmac +% \noindent This cites Aamport's gnominious article~\cite{article-full}. +% \medskip +% \leftline{\bf References} +% \nocite{*} % put all database entries into the reference list +% \bibliography{xampl} % specify the database files; here, just xampl.bib +% \bibliographystyle{plain} % specify plain.bst as the style file +% \bye +% +% +% HISTORY +% +% Karl Berry wrote the original version of these macros in 1989 and +% 1990, for use in his `Eplain' package. Oren Patashnik modified them +% slightly in July 1990, as part of the official BibTeX distribution. +% +% 1-Aug-90 Version 0.99a, not released to the general public. +% 14-Aug-90 0.99b, first general release. +% 26-Aug-90 0.99c, made \@undefinedmessage work with other macro packages. +% 6-Sep-90 0.99d, allowed for general formatting of bibliography labels, +% for general formatting of (in-text) citations, and for +% changing certain catcodes while reading the .aux file. +% 14-Nov-90 0.99e, changed the way \@setletters works, made some \new...'s +% non-outer, and changed the way Eplain reads this file. +% 12-Dec-90 0.99f, made \@resetnumerals change the `,' and `.' catcodes; and +% added \biblabelextrahang, \@getoptionalarg, and \bblsc. +% 11-Mar-91 0.99g, made a few minor changes required by the way Eplain reads +% this file, but no functional changes. +% 24-Apr-91 0.99h, inhibited the reading and writing of the .aux file if it +% isn't used or if the \noauxfile macro is defined, and +% removed some .aux-file-opening detritus; printed the +% cite-key of undefined citations in \tt font; changed the +% catcode of `_' inside \cite; and called \@resetnumerals +% from inside a group. +% 29-Feb-92 0.99i, made these macros semi-compatible with AmS-TeX; removed +% \@resetnumerals, \@setletters, \@tokstostring, and +% friends; changed the way \cite handles catcodes; changed +% \@getoptionalarg, and had \bibitem and \newcommand use +% it; added \@futurenonspacelet and (to facilitate the use +% of multiple reference lists) \bblfilebasename; changed +% \biblabelprint to use the new macros \biblabelprecontents +% and \biblabelpostcontents, and to, by default, right- +% justify numeric labels; and renamed \biblabelextrahang to +% the more descriptive \biblabelextraspace. +% 14-Mar-92 0.99j, made 0.99i's use of `\\' local to btxmac.tex. +% 13-Nov-95 0.99k, defined \begin and \end (while reading bbl file) only if +% it wasn't already defined. +% +% +% The LaTeX-related commands defined in this file include (a) the four +% commands that a user types (\bibliography, \bibliographystyle, \cite, +% and \nocite); (b) the three commands that BibTeX looks for in the .aux +% file (\bibdata, \bibstyle, and \citation---there is a fourth command +% that BibTeX looks for, but that command is related to LaTeX's \include +% facility, so these macros ignore that command); and (c) a LaTeX +% command (\newcommand) that's written by one of the four standard +% bibliography styles (alpha). The definitions here are not exactly the +% same as the corresponding LaTeX definitions (those eight LaTeX +% definitions depend on a significant fraction of LaTeX itself). But +% the only substantial differences are with \newcommand, which here, +% without complaining, lets you redefine a preexisting control sequence +% (in LaTeX, \newcommand won't let you redefine a preexisting command), +% and which here doesn't make the control sequences it defines \long (in +% LaTeX, that happens automatically); there may also be other minor +% differences. To summarize: Unless you know what you're doing, you +% shouldn't define any control sequences with these eight names: +% +% \bibdata +% \bibliography +% \bibliographystyle +% \bibstyle +% \citation +% \cite +% \newcommand +% \nocite +% +% There are three other commands written by one or more of the four +% standard (plain, abbrv, alpha, unsrt) or four semistandard (acm, +% apalike, ieeetr, siam) bibliography styles; they take effect only +% within the bibliography, and are redefinable, as explained later: +% +% \em +% \newblock +% \sc +% +% There's one control sequence you might want to use (but not redefine) +% in redefining \biblabelprint: +% +% \biblabelwidth +% +% There are fifteen other control sequences (explained later in more detail) +% that the macros of this file will use if you define them---you should +% define them after the \input btxmac command but before the \bibliography +% command. The first six begin with `\bbl' and affect fonts, spacing, +% perhaps other characteristics of the bibliography, and which .bbl files +% get read; the next five begin with `\biblabel' and determine how labels +% are formatted in the bibliography; and the last four begin with `\print' +% and determine how the in-text citations are formatted: +% +% \bblem +% \bblfilebasename +% \bblhook +% \bblnewblock +% \bblrm +% \bblsc +% \biblabelcontents +% \biblabelprecontents +% \biblabelprint +% \biblabelpostcontents +% \biblabelextraspace +% \printbetweencitations +% \printcitefinish +% \printcitenote +% \printcitestart +% +% If it's defined before the \input btxmac command, the control sequence +% below inhibits the reading and writing of the .aux file(s), and the +% issuing of related warning messages. Any definition will do. This +% feature might help when you're working on draft stages of a document: +% +% \noauxfile +% +% +% Here's another control sequence (it's described later) that you +% probably won't want to redefine unless you are writing another macro +% package; if you do redefine it, however, do it before the \input btxmac +% command (and notice that it has an `@' in its name): +% +% \@undefinedmessage +% +% Any other control sequence in this file that might conflict with +% something you've defined will have an `@' in its name, so such conflicts +% are unlikely; but if you're worried about a specific control sequence +% name, do a text search of this file to look for it. +% +% +% So to start things off we turn `@' into a letter (category code 11), +% keeping track of the old category code for future restoration. +% (Simply resetting it to 12 when we leave these macros is +% insufficient.) The use of `\cite' as a temporary control sequence is +% a kludge, but it's a reasonably simple way to accomplish what we need +% without possibly overwriting something (without an `@' in its name) +% that might already be defined. +% +\edef\cite{\the\catcode`@}% +\catcode`@ = 11 +\let\@oldatcatcode = \cite +\chardef\@letter = 11 +\chardef\@other = 12 +% +% +% Next come some things that will be useful later. +% +% Make an outer definition into an inner one (due to Chris Thompson). +% The arguments should be the control sequence to be defined, and the +% new of the \outer control sequence, as characters; the control +% sequence #1 is defined to be just the same as \csname#2\endcsname, but +% not \outer. For example, \@innerdef\innernewcount{newcount} would +% define \innernewcount to be a non-outer version of \newcount. +% +\def\@innerdef#1#2{\edef#1{\expandafter\noexpand\csname #2\endcsname}}% +% +% We use \@innerdef to make some of our allocations local, because +% Eplain includes our code inside a conditional. We put @'s in the +% names to minimize the (already small) chance of conflicts. +% +\@innerdef\@innernewcount{newcount}% +\@innerdef\@innernewdimen{newdimen}% +\@innerdef\@innernewif{newif}% +\@innerdef\@innernewwrite{newwrite}% +% +% +% Swallow one parameter. +% +\def\@gobble#1{}% +% +% +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\@undefined + \let\@linenumber = \empty % Pre-3.0. +\else + \def\@linenumber{\the\inputlineno:\space}% +\fi +% +% +% The following macro \@futurenonspacelet (from the TeXbook) behaves +% essentially like \futurelet except that it discards any implicit or +% explicit space tokens that intervene before a nonspace is scanned: +% +\def\@futurenonspacelet#1{\def\cs{#1}% + \afterassignment\@stepone\let\@nexttoken= +}% +\begingroup % The grouping here avoids stepping on an outside use of `\\'. +\def\\{\global\let\@stoken= }% +\\ % now \@stoken is a space token (\\ is a control symbol, so that + % space after it is seen). +\endgroup +\def\@stepone{\expandafter\futurelet\cs\@steptwo}% +\def\@steptwo{\expandafter\ifx\cs\@stoken\let\@@next=\@stepthree + \else\let\@@next=\@nexttoken\fi \@@next}% +\def\@stepthree{\afterassignment\@stepone\let\@@next= }% +% +% +% \@getoptionalarg\CS gets an optional argument from the input, enclosed +% in brackets, then expands \CS. We set \@optionalarg to \empty if we +% don't find one, otherwise to the text of the argument. This assumes +% the brackets don't have a funny category code. +% +\def\@getoptionalarg#1{% + \let\@optionaltemp = #1% + \let\@optionalnext = \relax + \@futurenonspacelet\@optionalnext\@bracketcheck +}% +% +% The \expandafter's in this macro let us avoid the use of \aftergroup, +% which is somewhat more expensive. +% +\def\@bracketcheck{% + \ifx [\@optionalnext + \expandafter\@@getoptionalarg + \else + \let\@optionalarg = \empty + % We can't do the \temp after the \fi, because then the \temp gets + % in the way of reading the optional argument from the input, if + % we do have one. + \expandafter\@optionaltemp + \fi +}% +% +\def\@@getoptionalarg[#1]{% + \def\@optionalarg{#1}% + \@optionaltemp +}% +% +% +% From LaTeX. +% +\def\@nnil{\@nil}% +\def\@fornoop#1\@@#2#3{}% +% +\def\@for#1:=#2\do#3{% + \edef\@fortmp{#2}% + \ifx\@fortmp\empty \else + \expandafter\@forloop#2,\@nil,\@nil\@@#1{#3}% + \fi +}% +% +\def\@forloop#1,#2,#3\@@#4#5{\def#4{#1}\ifx #4\@nnil \else + #5\def#4{#2}\ifx #4\@nnil \else#5\@iforloop #3\@@#4{#5}\fi\fi +}% +% +\def\@iforloop#1,#2\@@#3#4{\def#3{#1}\ifx #3\@nnil + \let\@nextwhile=\@fornoop \else + #4\relax\let\@nextwhile=\@iforloop\fi\@nextwhile#2\@@#3{#4}% +}% +% +% +% This macro tests if a file \jobname.#1 exists, and sets \if@fileexists +% appropriately. If an optional argument is given, it is used as the +% root part of the filename instead of \jobname. +% +\@innernewif\if@fileexists +% +\def\@testfileexistence{\@getoptionalarg\@finishtestfileexistence}% +\def\@finishtestfileexistence#1{% + \begingroup + \def\extension{#1}% + \immediate\openin0 = + \ifx\@optionalarg\empty\jobname\else\@optionalarg\fi + \ifx\extension\empty \else .#1\fi + \space + \ifeof 0 + \global\@fileexistsfalse + \else + \global\@fileexiststrue + \fi + \immediate\closein0 + \endgroup +}% +% +% +%% [[[start of BibTeX-specific stuff]]] +% +% Now come the four main LaTeX commands and their associated .aux +% commands. Just as in LaTeX, \bibliographystyle defines the BibTeX +% style name (.bst file, that is), and \bibliography defines the +% database (.bib) file(s). The corresponding .aux-file commands are +% \bibstyle and \bibdata, which are there only for BibTeX's (but not +% LaTeX's) use. +% +\def\bibliographystyle#1{% + \@readauxfile + \@writeaux{\string\bibstyle{#1}}% +}% +\let\bibstyle = \@gobble +% +% As well as writing the \bibdata command to tell BibTeX which .bib +% files to read, we read the .bbl file that BibTeX (or a person, +% conceivably) has produced. We use \bblfilebasename as the root of the +% filename to read; this defaults to \jobname. +% +\let\bblfilebasename = \jobname +\def\bibliography#1{% + \@readauxfile + \@writeaux{\string\bibdata{#1}}% + \@testfileexistence[\bblfilebasename]{bbl}% + \if@fileexists + % We just output a non-discardable item (the `whatsit' with the + % \bibdata command). This means that the glue that will be + % inserted next (\parskip or \baselineskip, most likely) will be a + % legal breakpoint. Most likely, this is after some kind of + % heading, where we don't want to allow a page break. So: + \nobreak + \@readbblfile + \fi +}% +\let\bibdata = \@gobble +% +% The \nocite{label,label,...} command writes its argument to \@auxfile, +% unless instructed not to, but produces no text in the document. Both +% the \nocite and \cite commands produce \citation commands in the .aux file. +% +\def\nocite#1{% + \@readauxfile + \@writeaux{\string\citation{#1}}% +}% +% +\@innernewif\if@notfirstcitation +% +% \cite[note]{label,label,...} produces the citations for the labels as +% well. If the optional argument `note' is present, it's added after +% the labels. Since \cite calls \nocite to do its .aux-file writing, +% \cite doesn't need to call \@readauxfile (\nocite does). +% +\def\cite{\@getoptionalarg\@cite}% +% +% Typeset the citations for the labels in #1, followed by the note, if +% it exists. To change the citation's format in the text, redefine one +% or more `\print...' macros, whose defaults appear later in this file. +% +\def\@cite#1{% + % Remember the optional argument, in case one of the macros we call + % below ends up looking for an optional argument itself. For + % example, if a \cite[note] triggers reading the .aux file, then the + % [note] would be clobbered, since \@testfileexistence looks for an + % optional arg. + \let\@citenotetext = \@optionalarg + % Start printing the text, beginning with a left bracket by default. + \printcitestart + % It's complicated, but because \nocite puts a `whatsit' onto the list, + % \nocite should follow \printcitestart. It's conceivable, but very + % unlikely, that this `whatsit' will cause a problem (glue that doesn't + % disappear when you want it to is the most likely symptom), requiring + % a change either to \printcitestart or to the label that the .bst file + % produces. + \nocite{#1}% + \@notfirstcitationfalse + \@for \@citation :=#1\do + {% + \expandafter\@onecitation\@citation\@@ + }% + \ifx\empty\@citenotetext\else + \printcitenote{\@citenotetext}% + \fi + \printcitefinish +}% +% +\def\@onecitation#1\@@{% + \if@notfirstcitation + \printbetweencitations + \fi + % + \expandafter \ifx \csname\@citelabel{#1}\endcsname \relax + \if@citewarning + \message{\@linenumber Undefined citation `#1'.}% + \fi + % Give it a dummy definition: + \expandafter\gdef\csname\@citelabel{#1}\endcsname{% + {\tt + \escapechar = -1 + \nobreak\hskip0pt + \expandafter\string\csname#1\endcsname + \nobreak\hskip0pt + }% + }% + \fi + % Now produce the text, whether it was undefined or not. + \csname\@citelabel{#1}\endcsname + \@notfirstcitationtrue +}% +% +% Given a label `foo', the macro `\b@foo' is supposed to +% hold the text that should be produced. +% +\def\@citelabel#1{b@#1}% +% +% So, how does a citation label get defined? When we read the .bbl file +% (below), a \bibitem writes out a \@citedef command. And when we read +% the \@citedef, we define \@citelabel{#1}, where #1 is the user's +% label. +% +\def\@citedef#1#2{\expandafter\gdef\csname\@citelabel{#1}\endcsname{#2}}% +% +% +% Reading the .bbl file also produces the typeset bibliography. Please +% notice, however, that we do not produce the title for the references +% (e.g., `References'), as LaTeX does. The formatting and spacing of +% that title, whether it should go into the headline, and so on, are all +% things determined by your format. We cannot know those things in +% advance. If you wish, you can define \bblhook to produce the title. +% Or just do it before the \bibliography command. +% +\def\@readbblfile{% + % Define a counter to tell us which item number we are on, unless + % we've already defined it (because the document has more than one + % bibliography). + \ifx\@itemnum\@undefined + \@innernewcount\@itemnum + \fi + % + \begingroup + % If another package has already defined \begin, don't define our + % own simplistic \begin and \end; assume they want to take care of + % it themselves. (That way, their \begin's and \end's for other + % things can be used in the bib files.) + \ifx\begin\@undefined + \def\begin##1##2{% + % ##1 is just `thebibliography'. + % ##2 is the widest label. + % We set (new dimen) \biblabelwidth based on the widest label + \setbox0 = \hbox{\biblabelcontents{##2}}% + \biblabelwidth = \wd0 + }% + \let\end = \@gobble % The arg is `thebibliography' again. + \fi + % + % Here we have two possibilities: + % \bibitem[typesetlabel]{citationlabel} + % \bibitem{citationlabel} + % If we have the second of these, the citations are numbered, starting + % from one; we use our own count register \@itemnum for this. + % + \@itemnum = 0 + \def\bibitem{\@getoptionalarg\@bibitem}% + \def\@bibitem{% + \ifx\@optionalarg\empty + \expandafter\@numberedbibitem + \else + \expandafter\@alphabibitem + \fi + }% + \def\@alphabibitem##1{% + % Need \xdef here for various reasons. + \expandafter \xdef\csname\@citelabel{##1}\endcsname {\@optionalarg}% + % Left-justify alpha labels, unless \biblabel{pre,post}contents + % are already defined. + \ifx\biblabelprecontents\@undefined + \let\biblabelprecontents = \relax + \fi + \ifx\biblabelpostcontents\@undefined + \let\biblabelpostcontents = \hss + \fi + \@finishbibitem{##1}% + }% + % + \def\@numberedbibitem##1{% + \advance\@itemnum by 1 + \expandafter \xdef\csname\@citelabel{##1}\endcsname{\number\@itemnum}% + % Right-justify numeric labels, unless \biblabel{pre,post}contents + % are already defined. + \ifx\biblabelprecontents\@undefined + \let\biblabelprecontents = \hss + \fi + \ifx\biblabelpostcontents\@undefined + \let\biblabelpostcontents = \relax + \fi + \@finishbibitem{##1}% + }% + % + \def\@finishbibitem##1{% + \biblabelprint{\csname\@citelabel{##1}\endcsname}% + \@writeaux{\string\@citedef{##1}{\csname\@citelabel{##1}\endcsname}}% + \ignorespaces + }% + % + % Do the printing (we're producing the bibliography, remember). + % + \let\em = \bblem + \let\newblock = \bblnewblock + \let\sc = \bblsc + % Punctuation won't affect spacing; + \frenchspacing + % the penalties below are from LaTeX's [article,book,report].sty; + \clubpenalty = 4000 \widowpenalty = 4000 + % the next two values come from LaTeX's \sloppy command; + \tolerance = 10000 \hfuzz = .5pt + \everypar = {\hangindent = \biblabelwidth + \advance\hangindent by \biblabelextraspace}% + \bblrm + % the \parskip is a guess at what looks good; + \parskip = 1.5ex plus .5ex minus .5ex + % and the space between label and text comes from LaTeX's \labelsep. + \biblabelextraspace = .5em + \bblhook + % + \input \bblfilebasename.bbl + \endgroup +}% +% +% The widest label's width is useful for redefining \biblabelprint; +% you redefine \biblabelwidth, in effect, by redefining the +% \biblabelcontents macro that appears below. And \biblabelextraspace, +% which is redefinable inside \bblhook, is added to \biblabelwidth to +% determine the amount of hanging indentation. +% +\@innernewdimen\biblabelwidth +\@innernewdimen\biblabelextraspace +% +% Now come the main macros that are related to the printing of the +% bibliography. Since you might want to redefine them, they are given +% default definitions outside of \@readbblfile. +% +% The first one controls the printing of a bibliography entry's label. +% If you change it, make sure that it starts with something like +% \noindent or \indent or \leavevmode that puts TeX into horizontal mode +% (even if the label itself is empty); otherwise, the hanging +% indentation will get messed up in certain circumstances. +% +\def\biblabelprint#1{% + \noindent + \hbox to \biblabelwidth{% + \biblabelprecontents + \biblabelcontents{#1}% + \biblabelpostcontents + }% + \kern\biblabelextraspace +}% +% +% If you are using numeric labels, and you want them left-justified +% (numeric labels by default are right-justified), do something like: +% \def\biblabelprecontents{\relax} +% \def\biblabelpostcontents{\hss} +% +% By default the labels are typeset in \bblrm, and enclosed in brackets. +% +\def\biblabelcontents#1{{\bblrm [#1]}}% +% +% The main text, too, is typeset using \bblrm, which is \rm by default. +% +\def\bblrm{\rm}% +% +% Emphasis for producing, e.g., titles, is done with \it by default. +% +\def\bblem{\it}% +% +% Some styles use a caps-and-small-caps font for author names. LaTeX +% defines an \sc command but plain TeX doesn't, so we need one here. +% The definition below doesn't load the font unless it's needed, but it +% tries to load only the 10pt version, because it might not exist at +% other point sizes. +% +\def\bblsc{\ifx\@scfont\@undefined + \font\@scfont = cmcsc10 + \fi + \@scfont +}% +% +% The major parts of an entry are separated with \bblnewblock. The +% numbers below are taken from LaTeX's `article' style. +% +\def\bblnewblock{\hskip .11em plus .33em minus .07em }% +% +% Here's where you stick any other bibliography-formatting goodies, or +% redefine the values above. +% +\let\bblhook = \empty +% +% +% Here are the four default definitions for formatting the in-text +% citations. These are what you redefine (after your \input btxmac but +% before your \bibliography) to get parens instead of brackets, or +% superscripts, or footnotes, or whatever. +% +\def\printcitestart{[}% left bracket +\def\printcitefinish{]}% right bracket +\def\printbetweencitations{, }% comma, space +\def\printcitenote#1{, #1}% comma, space, note (if it exists) +% +% That scheme is pretty flexible. For example you could use +% \def\printcitestart{\unskip $^\bgroup} +% \def\printcitefinish{\egroup$} +% \def\printbetweencitations{,} +% \def\printcitenote#1{\hbox{\sevenrm\space (#1)}} +% \font\eighttt = cmtt8 +% \scriptfont\ttfam = \eighttt +% to get superscripted in-text citations. (The scriptfont stuff +% exists only to print an undefined citation; it's in cmtt8 because +% there is no cmtt7.) To get something radically different, however, +% you'll have to define your own \cite command. +% +% When we read `\citation' from the .aux file, it means nothing. +% +\let\citation = \@gobble +% +% +% Now comes the stuff for dealing with LaTeX's \newcommand. As +% mentioned earlier, this \newcommand will redefine a preexisting +% command; that's different from how LaTeX's \newcommand behaves. +% +\@innernewcount\@numparams +% +% \newcommand{\foo}[n]{text} defines the control sequence \foo to have +% n parameters, and replacement text `text'. +% +\def\newcommand#1{% + \def\@commandname{#1}% + \@getoptionalarg\@continuenewcommand +}% +% +% Figure out if this definition has parameters. +% +\def\@continuenewcommand{% + % If no optional argument, we have zero parameters. Otherwise, we + % have that many. + \@numparams = \ifx\@optionalarg\empty 0\else\@optionalarg \fi \relax + \@newcommand +}% +% +% \@numparams is how many arguments this command has. The name of the +% command is \@commandname. The replacement text for the new macro is #1. +% +\def\@newcommand#1{% + \def\@startdef{\expandafter\edef\@commandname}% + \ifnum\@numparams=0 + \let\@paramdef = \empty + \else + \ifnum\@numparams>9 + \errmessage{\the\@numparams\space is too many parameters}% + \else + \ifnum\@numparams<0 + \errmessage{\the\@numparams\space is too few parameters}% + \else + \edef\@paramdef{% + % This is disgusting, but \loop doesn't work inside \edef, + % because \body isn't defined. + \ifcase\@numparams + \empty No arguments. + \or ####1% + \or ####1####2% + \or ####1####2####3% + \or ####1####2####3####4% + \or ####1####2####3####4####5% + \or ####1####2####3####4####5####6% + \or ####1####2####3####4####5####6####7% + \or ####1####2####3####4####5####6####7####8% + \or ####1####2####3####4####5####6####7####8####9% + \fi + }% + \fi + \fi + \fi + \expandafter\@startdef\@paramdef{#1}% +}% +% +%% [[[end of BibTeX-specific stuff]]] +% +% +% Names of references (arguments given in the \cite and \nocite +% commands) and file names (arguments given in the \bibliography and +% \bibliographystyle commands) are recorded in \jobname.aux, called the +% \@auxfile in these macros. Here's how they get read in. +% +\def\@readauxfile{% + \if@auxfiledone \else % remember: \@auxfiledonetrue if \noauxfile is defined + \global\@auxfiledonetrue + \@testfileexistence{aux}% + \if@fileexists + \begingroup + % Because we might be in horizontal mode when \@readauxfile + % is called (if it's in response to a \cite or \nocite), we + % want to ignore all the would-be spaces at the ends of + % lines in the aux file. Fortunately, it's highly unlikely + % an end-of-line might actually be desired. + % And because we don't change the category code of anything + % but @, primitives like \gdef can't be used to define labels + % in the aux file. The solution adopted by btxmac.tex is to + % write `\@citedef{LABEL}{DEFINITION}' to the aux file, and + % use \csname on LABEL. + \endlinechar = -1 + \catcode`@ = 11 + \input \jobname.aux + \endgroup + \else + \message{\@undefinedmessage}% + \global\@citewarningfalse + \fi + \immediate\openout\@auxfile = \jobname.aux + \fi +}% +% +% The \@readauxfile macro does all that work the first time it's called. +% Since it's called once for every \cite, \nocite, \bibliography, and +% \bibliographystyle command that the user issues, we need to remember +% whether the work's been done. It's considered done if we're not to do +% it---that is, if \noauxfile is defined. +% +\newif\if@auxfiledone +\ifx\noauxfile\@undefined \else \@auxfiledonetrue\fi +% +% It's conceivable you'd want to change how other characters are read; +% to do that, change their category code before doing \input btxmac. +% +% +% After reading the .aux file, \@readauxfile opens it for writing. +% The \@writeaux macro does the actual writing (as long as +% \noauxfile is undefined). +% +\@innernewwrite\@auxfile +\def\@writeaux#1{\ifx\noauxfile\@undefined \write\@auxfile{#1}\fi}% +% +% +% A macro package that uses btxmac.tex might define +% \@undefinedmessage (before doing an \input btxmac). +% +\ifx\@undefinedmessage\@undefined + \def\@undefinedmessage{No .aux file; I won't give you warnings about + undefined citations.}% +\fi +% +% Even if citations are undefined, we want to complain only if +% \@citewarningtrue. The default is to set \@citewarningtrue unless +% \noauxfile is defined. Again, a macro package that uses +% btxmac.tex might want to redefine this. +% +\@innernewif\if@citewarning +\ifx\noauxfile\@undefined \@citewarningtrue\fi +% +% +% Finally, before leaving we restore @'s old category code. +% +\catcode`@ = \@oldatcatcode diff --git a/Build/source/extra/bibtex/ftp.cs.stanford.edu/pub/tex/.listing b/Build/source/extra/bibtex/ftp.cs.stanford.edu/pub/tex/.listing new file mode 100644 index 00000000000..a2ddb6d0c11 --- /dev/null +++ b/Build/source/extra/bibtex/ftp.cs.stanford.edu/pub/tex/.listing @@ -0,0 +1,54 @@ +drwxr-xr-x 29 ftp users 4096 Mar 18 2008 .
+drwxr-xr-x 49 500 500 4096 Dec 11 2008 ..
+drwxr-xr-x 7 ftp users 2048 Feb 5 1992 ams
+drwxr-xr-x 2 ftp users 2048 Oct 30 1989 archive
+drwxr-xr-x 2 ftp users 2048 May 2 1991 bibtex
+-rw-r--r-- 1 ftp users 15030 Jun 18 1993 bst-files.shar.gz
+-rw-r--r-- 1 ftp users 1444 Jan 9 1990 CHANGES.Jan90
+-rw-r--r-- 1 ftp users 928 Mar 26 1990 CHANGES.Mar90
+-rw-r--r-- 1 ftp users 11188 Jun 18 1993 chart.tar.gz
+drwxr-xr-x 2 ftp users 6144 Feb 12 2009 cm
+drwxr-xr-x 4 ftp users 2048 Apr 8 1991 contrib
+drwxr-xr-x 2 ftp users 2048 Apr 1 1992 cweb
+-rwxr--r-- 1 ftp users 491970 Jun 23 2003 DIFFS.june03
+-rw-r--r-- 1 ftp users 85271 Jun 13 1995 DIFFS.june95
+-rw-r--r-- 1 ftp users 86847 Mar 27 1991 DIFFS.Mar91
+-rw-r--r-- 1 ftp users 402618 Mar 26 1992 DIFFS.Mar92
+-rw-r--r-- 1 ftp users 159439 Sep 21 1990 DIFFS.Sept90
+-rw-r--r-- 1 ftp users 32037 Jun 18 1993 diss.shar.gz
+drwxr-xr-x 11 ftp users 2048 Nov 19 1989 dist
+drwxr-xr-x 2 ftp users 2048 Jun 23 1993 eplain
+drwxr-xr-x 2 ftp users 2048 Aug 19 2003 errata
+drwxr-xr-x 2 ftp users 2048 Aug 19 2003 etc
+-rw-r--r-- 1 ftp users 31165 Jun 18 1993 font-hints.txt
+drwxr-xr-x 2 ftp users 6144 Sep 25 1990 fonts
+drwxr-xr-x 2 ftp users 20480 Mar 19 1990 gf
+-rw-r--r-- 1 ftp users 7349 Jun 18 1993 grapher.tar.gz
+drwxr-xr-x 2 ftp users 2048 Nov 3 1992 icons
+drwxr-xr-x 2 ftp users 8192 Sep 19 1989 imagen
+-rw-r--r-- 1 ftp users 379963 Jun 18 1993 imaketex202a.tar.gz
+-rw-r--r-- 1 ftp users 269 Jun 18 1993 imaketex.README
+-rw-r--r-- 1 ftp users 570 Jul 18 1996 latex.README
+drwxr-xr-x 2 ftp users 2048 Aug 19 2003 lib
+drwxr-xr-x 2 ftp users 2048 Oct 1 1989 ln03
+drwxr-xr-x 17 ftp users 2048 Mar 18 2008 local
+drwxr-xr-x 2 ftp users 2048 Aug 19 2003 mf
+drwxr-xr-x 2 ftp users 2048 Aug 19 2003 mfware
+drwxr-xr-x 3 ftp users 2048 Feb 13 1991 patches
+drwxr-xr-x 2 ftp users 2048 Jun 23 1993 ptc
+-rw-r--r-- 1 ftp users 3670 Jul 18 1996 README
+-rw-r--r-- 1 ftp users 1297 Dec 14 2007 README.KNUTH
+-rw-r--r-- 1 ftp users 138 Dec 7 1993 README.UNIX_TEX
+drwxr-xr-x 2 ftp users 2048 Aug 19 2003 tex
+-rw-r--r-- 1 ftp users 3097368 Jun 23 2003 tex03.tar.gz
+-rw-r--r-- 1 3732 man 3230185 Mar 24 2008 tex08.tar.gz
+-rw-r--r-- 1 ftp users 2813883 Aug 11 1998 tex98.tar.gz
+drwxr-xr-x 2 ftp users 16384 Jul 22 1990 texhax
+-rw-r--r-- 1 ftp users 498283 Jun 18 1993 texinc.tar.gz
+-rw-r--r-- 1 ftp users 0 Mar 13 1991 tex.log
+-rw-r--r-- 1 ftp users 515 Jun 17 2000 texmf.cnf
+drwxr-xr-x 2 ftp users 2048 Aug 19 2003 texware
+drwxr-xr-x 2 ftp users 2048 Sep 7 1993 tugboat
+drwxr-xr-x 7 ftp users 2048 Oct 27 1989 unsupported
+drwxr-xr-x 2 ftp users 2048 Aug 19 2003 web
+-rw-r--r-- 1 ftp users 570 Jul 18 1996 web2c.README
diff --git a/Build/source/extra/bibtex/ieeetr.bst b/Build/source/extra/bibtex/ieeetr.bst new file mode 100644 index 00000000000..e582e8cc06d --- /dev/null +++ b/Build/source/extra/bibtex/ieeetr.bst @@ -0,0 +1,970 @@ +% IEEE Transactions bibliography style (29-Jan-88 version) +% numeric labels, order-of-reference, IEEE abbreviations, +% quotes around article titles, commas separate all fields +% except after book titles and before "notes". Otherwise, +% much like the "plain" family, from which this is adapted. +% +% History +% 9/30/85 (HWT) Original version, by Howard Trickey. +% 1/29/88 (OP&HWT) Updated for BibTeX version 0.99a, Oren Patashnik; +% THIS `ieeetr' VERSION DOES NOT WORK WITH BIBTEX 0.98i. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.quote after.sentence + after.quoted.block after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.quote := + #3 'after.sentence := + #4 'after.quoted.block := + #5 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.quote = + { " " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { output.state after.quoted.block = + { write$ + newline$ + "\newblock " write$ + } + { add.period$ " " * write$ } + if$ + } + if$ + } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {blank.sep} +{ after.quote 'output.state := +} + +FUNCTION {fin.entry} +{ output.state after.quoted.block = + 'skip$ + 'add.period$ + if$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { output.state after.quote = + { after.quoted.block 'output.state := } + { after.block 'output.state := } + if$ + } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{f.~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " {\em et~al.}" * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", eds." * } + { ", ed." * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { "``" title "t" change.case$ * ",''" * } + if$ +} + +FUNCTION {format.title.p} +{ title empty$ + { "" } + { "``" title "t" change.case$ * ".''" * } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ title emphasize +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "vol.~" volume * + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "no.~" } + { "No.~" } + if$ + number * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { edition "l" change.case$ "~ed." * } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pp.~" pages n.dashify * } + { "p.~" pages * } + if$ + } + if$ +} + +FUNCTION {format.volume} +{ volume empty$ + { "" } + { "vol.~" volume * } + if$ +} + +FUNCTION {format.number} +{ number empty$ + { "" } + { "no.~" number * } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "ch.~" chapter * } + { type "l" change.case$ chapter tie.or.space.connect } + if$ + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { "in " booktitle emphasize * + editor empty$ + 'skip$ + { " (" * format.editors * ")" * } + if$ + } + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + output.state after.block = + { type "t" change.case$ } + { type "l" change.case$ } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Tech. Rep." } + 'type + if$ + number empty$ + { "l" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.addr.pub} +{ publisher empty$ + { "" } + { address empty$ + { "" } + { address ": " * } + if$ + publisher * + } + if$ +} + +FUNCTION {format.paddress} +{ address empty$ + { "" } + { "(" address * ")" * } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "in {\em " journal * "\/}" * } + if$ + } + { "in " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " {\em et~al.}" * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " {\em et~al.}" * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Vol.~" volume * + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "in {\em " booktitle * "\/}" * } + if$ + } + { "in " key * } + if$ + } + { "in " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + blank.sep + crossref missing$ + { journal emphasize "journal" output.check + format.volume output + month empty$ + { format.number output } + 'skip$ + if$ + format.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + format.addr.pub "publisher" output.check + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + title empty$ + { "empty title in " cite$ * warning$ + howpublished new.sentence.checka + } + { howpublished empty$ not + address empty$ month empty$ year empty$ and and + or + { format.title.p output.nonnull } + { format.title output.nonnull } + if$ + blank.sep + } + if$ + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + format.addr.pub "publisher" output.check + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + blank.sep + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + format.addr.pub "publisher" output.check + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + blank.sep + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.paddress output + format.pages output + organization output + publisher output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + blank.sep + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title empty$ + { howpublished new.sentence.checka } + { howpublished empty$ not + month empty$ year empty$ and + or + { format.title.p output.nonnull } + { format.title output.nonnull } + if$ + blank.sep + } + if$ + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + format.btitle "title" output.check + format.bvolume output + format.number.series output + format.paddress output + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + blank.sep + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + format.title.p "title" output.check + blank.sep + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sept."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications ACM"} + +MACRO {ibmjrd} {"IBM J. Research and Development"} + +MACRO {ibmsj} {"IBM Systems~J."} + +MACRO {ieeese} {"IEEE Trans. Software Engineering"} + +MACRO {ieeetc} {"IEEE Trans. Computers"} + +MACRO {ieeetcad} + {"IEEE Trans. Computer-Aided Design"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"J.~ACM"} + +MACRO {jcss} {"J.~Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM J. Computing"} + +MACRO {tocs} {"ACM Trans. Computer Systems"} + +MACRO {tods} {"ACM Trans. Database Systems"} + +MACRO {tog} {"ACM Trans. Graphics"} + +MACRO {toms} {"ACM Trans. Mathematical Software"} + +MACRO {toois} {"ACM Trans. Office Information Systems"} + +MACRO {toplas} {"ACM Trans. Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/Build/source/extra/bibtex/plain.bst b/Build/source/extra/bibtex/plain.bst new file mode 100644 index 00000000000..436410a8272 --- /dev/null +++ b/Build/source/extra/bibtex/plain.bst @@ -0,0 +1,1097 @@ +% BibTeX standard bibliography style `plain' + % version 0.99a for BibTeX versions 0.99a or later, LaTeX version 2.09. + % Copyright (C) 1985, all rights reserved. + % Copying of this file is authorized only if either + % (1) you make absolutely no changes to your copy, including name, or + % (2) if you do make changes, you name it something other than + % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst. + % This restriction helps ensure that all standard styles are identical. + % The file btxbst.doc has the documentation for this style. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { title "t" change.case$ } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ title emphasize +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "In {\em " journal * "\/}" * } + if$ + } + { "In " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "In {\em " booktitle * "\/}" * } + if$ + } + { "In " key * } + if$ + } + { "In " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ + { organization publisher new.sentence.checkb + organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + { publisher new.sentence.checka } + { organization publisher new.sentence.checkb + organization output + } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ + s nameptr "{vv{ } }{ll{ }}{ ff{ }}{ jj{ }}" format.name$ 't := + nameptr numnames = t "others" = and + { "et al" * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} + +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/Build/source/extra/bibtex/siam.bst b/Build/source/extra/bibtex/siam.bst new file mode 100644 index 00000000000..86b86d984f8 --- /dev/null +++ b/Build/source/extra/bibtex/siam.bst @@ -0,0 +1,1035 @@ +% SIAM bibliography style (29-Jan-88 version) +% numeric labels, alphabetic order, Mathematical Reviews abbreviations, +% names in \sc, titles in italics, book titles mixed upper-lower and article +% titles lowercase, commas separate all fields except before "notes". +% +% History +% 1/30/86 (HWT) Original version, by Howard Trickey. +% 6/15/87 (HWT) Fix format.editors---Martin Costabel. +% 1/29/88 (OP&HWT) Updated for BibTeX version 0.99a, Oren Patashnik; +% THIS `siam' VERSION DOES NOT WORK WITH BIBTEX 0.98i. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + 'write$ + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +FUNCTION {scapify} +{ duplicate$ empty$ + { pop$ "" } + { "{\sc " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{f.~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +STRINGS { last.authors } + +FUNCTION {init.last.authors} +{ "" 'last.authors := +} + +FUNCTION {format.authors} +{ author empty$ + { "" 'last.authors := + "" + } + { author last.authors = + { "\leavevmode\vrule height 2pt depth -1.6pt width 23pt" } + { author format.names scapify } + if$ + author 'last.authors := + } + if$ +} + +FUNCTION {format.organization} +{ organization empty$ + { "" 'last.authors := + "" + } + { organization last.authors = + { "\leavevmode\vrule height 2pt depth -1.6pt width 23pt" } + { organization scapify } + if$ + organization 'last.authors := + } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" 'last.authors := + "" + } + { editor last.authors = + { "\leavevmode\vrule height 2pt depth -1.6pt width 23pt" } + { editor format.names scapify } + if$ + editor num.names$ #1 > + { ", eds." * } + { ", ed." * } + if$ + editor 'last.authors := + } + if$ +} + +FUNCTION {format.ineditors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", eds." * } + { ", ed." * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { title "t" change.case$ emphasize } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ title emphasize +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "vol.~" volume * + series empty$ + 'skip$ + { " of " * series * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { "no.~" number * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { edition "l" change.case$ "~ed." * } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pp.~" pages n.dashify * } + { "p.~" pages * } + if$ + } + if$ +} + +FUNCTION {format.vol.year} +{ volume field.or.null + year empty$ + { "empty year in " cite$ * warning$ } + { " (" year * ")" * * } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "ch.~" chapter * } + { type "l" change.case$ chapter tie.or.space.connect } + if$ + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "in " booktitle * } + { "in " booktitle * ", " * format.ineditors * } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + key empty$ not and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "l" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Tech. Rep." } + 'type + if$ + number empty$ + { "l" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "in " journal * } + if$ + } + { "in " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "in " + } + { "vol.~" volume * + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { series * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "in " booktitle * } + if$ + } + { "in " key * } + if$ + } + { "in " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + crossref missing$ + { journal "journal" output.check + format.vol.year output + } + { format.article.crossref output.nonnull } + if$ + format.pages output + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.number.series output + publisher "publisher" output.check + address output + } + { format.book.crossref output.nonnull } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + format.title "title" output.check + howpublished new.block.checka + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.number.series output + publisher "publisher" output.check + address output + } + { format.book.crossref output.nonnull } + if$ + format.edition output + format.date "year" output.check + format.chapter.pages "chapter and pages" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull } + if$ + format.chapter.pages output + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + address empty$ + { organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull } + if$ + format.pages output + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { format.organization output } + { format.authors output.nonnull } + if$ + format.btitle "title" output.check + author empty$ + 'skip$ + { organization output } + if$ + address output + format.edition output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + format.btitle "title" output.check + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { format.organization output } + { format.editors output.nonnull } + if$ + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + 'skip$ + { organization output } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"Jan."} + +MACRO {feb} {"Feb."} + +MACRO {mar} {"Mar."} + +MACRO {apr} {"Apr."} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"Aug."} + +MACRO {sep} {"Sept."} + +MACRO {oct} {"Oct."} + +MACRO {nov} {"Nov."} + +MACRO {dec} {"Dec."} + +MACRO {acmcs} {"ACM Comput. Surveys"} + +MACRO {acta} {"Acta Inf."} + +MACRO {cacm} {"Comm. ACM"} + +MACRO {ibmjrd} {"IBM J. Res. Dev."} + +MACRO {ibmsj} {"IBM Syst.~J."} + +MACRO {ieeese} {"IEEE Trans. Softw. Eng."} + +MACRO {ieeetc} {"IEEE Trans. Comput."} + +MACRO {ieeetcad} + {"IEEE Trans. Comput.-Aided Design Integrated Circuits"} + +MACRO {ipl} {"Inf. Process. Lett."} + +MACRO {jacm} {"J.~Assoc. Comput. Mach."} + +MACRO {jcss} {"J.~Comput. System Sci."} + +MACRO {scp} {"Sci. Comput. Programming"} + +MACRO {sicomp} {"SIAM J. Comput."} + +MACRO {tocs} {"ACM Trans. Comput. Syst."} + +MACRO {tods} {"ACM Trans. Database Syst."} + +MACRO {tog} {"ACM Trans. Gr."} + +MACRO {toms} {"ACM Trans. Math. Softw."} + +MACRO {toois} {"ACM Trans. Office Inf. Syst."} + +MACRO {toplas} {"ACM Trans. Prog. Lang. Syst."} + +MACRO {tcs} {"Theoretical Comput. Sci."} + +READ + +FUNCTION {sortify} +{ purify$ + "l" change.case$ +} + +INTEGERS { len } + +FUNCTION {chop.word} +{ 's := + 'len := + s #1 len substring$ = + { s len #1 + global.max$ substring$ } + 's + if$ +} + +FUNCTION {sort.format.names} +{ 's := + #1 'nameptr := + "" + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { nameptr #1 > + { " " * } + 'skip$ + if$ + s nameptr "{vv{ } }{ll{ }}{ f{ }}{ jj{ }}" format.name$ 't := + nameptr numnames = t "others" = and + { "et al" * } + { t sortify * } + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {sort.format.title} +{ 't := + "A " #2 + "An " #3 + "The " #4 t chop.word + chop.word + chop.word + sortify + #1 global.max$ substring$ +} + +FUNCTION {author.sort} +{ author empty$ + { key empty$ + { "to sort, need author or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.editor.sort} +{ author empty$ + { editor empty$ + { key empty$ + { "to sort, need author, editor, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { editor sort.format.names } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {author.organization.sort} +{ author empty$ + { organization empty$ + { key empty$ + { "to sort, need author, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { author sort.format.names } + if$ +} + +FUNCTION {editor.organization.sort} +{ editor empty$ + { organization empty$ + { key empty$ + { "to sort, need editor, organization, or key in " cite$ * warning$ + "" + } + { key sortify } + if$ + } + { "The " #4 organization chop.word sortify } + if$ + } + { editor sort.format.names } + if$ +} + +FUNCTION {presort} +{ type$ "book" = + type$ "inbook" = + or + 'author.editor.sort + { type$ "proceedings" = + 'editor.organization.sort + { type$ "manual" = + 'author.organization.sort + 'author.sort + if$ + } + if$ + } + if$ + " " + * + year field.or.null sortify + * + " " + * + title field.or.null + sort.format.title + * + #1 entry.max$ substring$ + 'sort.key$ := +} + +ITERATE {presort} + +SORT + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +EXECUTE {init.last.authors} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/Build/source/extra/bibtex/unsrt.bst b/Build/source/extra/bibtex/unsrt.bst new file mode 100644 index 00000000000..bbbbd4221b6 --- /dev/null +++ b/Build/source/extra/bibtex/unsrt.bst @@ -0,0 +1,951 @@ +% BibTeX standard bibliography style `unsrt' + % version 0.99a for BibTeX versions 0.99a or later, LaTeX version 2.09. + % Copyright (C) 1985, all rights reserved. + % Copying of this file is authorized only if either + % (1) you make absolutely no changes to your copy, including name, or + % (2) if you do make changes, you name it something other than + % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst. + % This restriction helps ensure that all standard styles are identical. + % The file btxbst.doc has the documentation for this style. + +ENTRY + { address + author + booktitle + chapter + edition + editor + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { title "t" change.case$ } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ title emphasize +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "In {\em " journal * "\/}" * } + if$ + } + { "In " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "In {\em " booktitle * "\/}" * } + if$ + } + { "In " key * } + if$ + } + { "In " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ + { organization publisher new.sentence.checkb + organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + { publisher new.sentence.checka } + { organization publisher new.sentence.checkb + organization output + } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/Build/source/extra/bibtex/xampl.bib b/Build/source/extra/bibtex/xampl.bib new file mode 100644 index 00000000000..dfd1269022d --- /dev/null +++ b/Build/source/extra/bibtex/xampl.bib @@ -0,0 +1,356 @@ +@preamble{ "\newcommand{\noopsort}[1]{} " + # "\newcommand{\printfirst}[2]{#1} " + # "\newcommand{\singleletter}[1]{#1} " + # "\newcommand{\switchargs}[2]{#2#1} " } + +@ARTICLE{article-minimal, + author = {L[eslie] A. Aamport}, + title = {The Gnats and Gnus Document Preparation System}, + journal = {\mbox{G-Animal's} Journal}, + year = 1986, +} + +@ARTICLE{article-full, + author = {L[eslie] A. Aamport}, + title = {The Gnats and Gnus Document Preparation System}, + journal = {\mbox{G-Animal's} Journal}, + year = 1986, + volume = 41, + number = 7, + pages = "73+", + month = jul, + note = "This is a full ARTICLE entry", +} + +The KEY field is here to override the KEY field in the journal being +cross referenced (so is the NOTE field, in addition to its imparting +information). + +@ARTICLE{article-crossref, + crossref = {WHOLE-JOURNAL}, + key = "", + author = {L[eslie] A. Aamport}, + title = {The Gnats and Gnus Document Preparation System}, + pages = "73+", + note = "This is a cross-referencing ARTICLE entry", +} + +@ARTICLE{whole-journal, + key = "GAJ", + journal = {\mbox{G-Animal's} Journal}, + year = 1986, + volume = 41, + number = 7, + month = jul, + note = {The entire issue is devoted to gnats and gnus + (this entry is a cross-referenced ARTICLE (journal))}, +} + +@INBOOK{inbook-minimal, + author = "Donald E. Knuth", + title = "Fundamental Algorithms", + publisher = "Addison-Wesley", + year = "{\noopsort{1973b}}1973", + chapter = "1.2", +} + +@INBOOK{inbook-full, + author = "Donald E. Knuth", + title = "Fundamental Algorithms", + volume = 1, + series = "The Art of Computer Programming", + publisher = "Addison-Wesley", + address = "Reading, Massachusetts", + edition = "Second", + month = "10~" # jan, + year = "{\noopsort{1973b}}1973", + type = "Section", + chapter = "1.2", + pages = "10--119", + note = "This is a full INBOOK entry", +} + +@INBOOK{inbook-crossref, + crossref = "whole-set", + title = "Fundamental Algorithms", + volume = 1, + series = "The Art of Computer Programming", + edition = "Second", + year = "{\noopsort{1973b}}1973", + type = "Section", + chapter = "1.2", + note = "This is a cross-referencing INBOOK entry", +} + +@BOOK{book-minimal, + author = "Donald E. Knuth", + title = "Seminumerical Algorithms", + publisher = "Addison-Wesley", + year = "{\noopsort{1973c}}1981", +} + +@BOOK{book-full, + author = "Donald E. Knuth", + title = "Seminumerical Algorithms", + volume = 2, + series = "The Art of Computer Programming", + publisher = "Addison-Wesley", + address = "Reading, Massachusetts", + edition = "Second", + month = "10~" # jan, + year = "{\noopsort{1973c}}1981", + note = "This is a full BOOK entry", +} + +@BOOK{book-crossref, + crossref = "whole-set", + title = "Seminumerical Algorithms", + volume = 2, + series = "The Art of Computer Programming", + edition = "Second", + year = "{\noopsort{1973c}}1981", + note = "This is a cross-referencing BOOK entry", +} + +@BOOK{whole-set, + author = "Donald E. Knuth", + publisher = "Addison-Wesley", + title = "The Art of Computer Programming", + series = "Four volumes", + year = "{\noopsort{1973a}}{\switchargs{--90}{1968}}", + note = "Seven volumes planned (this is a cross-referenced set of BOOKs)", +} + +@BOOKLET{booklet-minimal, + key = "Kn{\printfirst{v}{1987}}", + title = "The Programming of Computer Art", +} + +@BOOKLET{booklet-full, + author = "Jill C. Knvth", + title = "The Programming of Computer Art", + howpublished = "Vernier Art Center", + address = "Stanford, California", + month = feb, + year = 1988, + note = "This is a full BOOKLET entry", +} + +@INCOLLECTION{incollection-minimal, + author = "Daniel D. Lincoll", + title = "Semigroups of Recurrences", + booktitle = "High Speed Computer and Algorithm Organization", + publisher = "Academic Press", + year = 1977, +} + +@INCOLLECTION{incollection-full, + author = "Daniel D. Lincoll", + title = "Semigroups of Recurrences", + editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", + booktitle = "High Speed Computer and Algorithm Organization", + number = 23, + series = "Fast Computers", + chapter = 3, + type = "Part", + pages = "179--183", + publisher = "Academic Press", + address = "New York", + edition = "Third", + month = sep, + year = 1977, + note = "This is a full INCOLLECTION entry", +} + +@INCOLLECTION{incollection-crossref, + crossref = "whole-collection", + author = "Daniel D. Lincoll", + title = "Semigroups of Recurrences", + pages = "179--183", + note = "This is a cross-referencing INCOLLECTION entry", +} + +@BOOK{whole-collection, + editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh", + title = "High Speed Computer and Algorithm Organization", + booktitle = "High Speed Computer and Algorithm Organization", + number = 23, + series = "Fast Computers", + publisher = "Academic Press", + address = "New York", + edition = "Third", + month = sep, + year = 1977, + note = "This is a cross-referenced BOOK (collection) entry", +} + +@MANUAL{manual-minimal, + key = "Manmaker", + title = "The Definitive Computer Manual", +} + +@MANUAL{manual-full, + author = "Larry Manmaker", + title = "The Definitive Computer Manual", + organization = "Chips-R-Us", + address = "Silicon Valley", + edition = "Silver", + month = apr # "-" # may, + year = 1986, + note = "This is a full MANUAL entry", +} + +@MASTERSTHESIS{mastersthesis-minimal, + author = "{\'{E}}douard Masterly", + title = "Mastering Thesis Writing", + school = "Stanford University", + year = 1988, +} + +@MASTERSTHESIS{mastersthesis-full, + author = "{\'{E}}douard Masterly", + title = "Mastering Thesis Writing", + school = "Stanford University", + type = "Master's project", + address = "English Department", + month = jun # "-" # aug, + year = 1988, + note = "This is a full MASTERSTHESIS entry", +} + +@MISC{misc-minimal, + key = "Missilany", + note = "This is a minimal MISC entry", +} + +@MISC{misc-full, + author = "Joe-Bob Missilany", + title = "Handing out random pamphlets in airports", + howpublished = "Handed out at O'Hare", + month = oct, + year = 1984, + note = "This is a full MISC entry", +} + +@STRING{STOC-key = "OX{\singleletter{stoc}}"} + +@STRING{ACM = "The OX Association for Computing Machinery"} + +@STRING{STOC = " Symposium on the Theory of Computing"} + +@INPROCEEDINGS{inproceedings-minimal, + author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", + title = "On Notions of Information Transfer in {VLSI} Circuits", + booktitle = "Proc. Fifteenth Annual ACM" # STOC, + year = 1983, +} + +@INPROCEEDINGS{inproceedings-full, + author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", + title = "On Notions of Information Transfer in {VLSI} Circuits", + editor = "Wizard V. Oz and Mihalis Yannakakis", + booktitle = "Proc. Fifteenth Annual ACM" # STOC, + number = 17, + series = "All ACM Conferences", + pages = "133--139", + month = mar, + year = 1983, + address = "Boston", + organization = ACM, + publisher = "Academic Press", + note = "This is a full INPROCEDINGS entry", +} + +@INPROCEEDINGS{inproceedings-crossref, + crossref = "whole-proceedings", + author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis", + title = "On Notions of Information Transfer in {VLSI} Circuits", + organization = "", + pages = "133--139", + note = "This is a cross-referencing INPROCEEDINGS entry", +} + +@PROCEEDINGS{proceedings-minimal, + key = STOC-key, + title = "Proc. Fifteenth Annual" # STOC, + year = 1983, +} + +@PROCEEDINGS{proceedings-full, + editor = "Wizard V. Oz and Mihalis Yannakakis", + title = "Proc. Fifteenth Annual" # STOC, + number = 17, + series = "All ACM Conferences", + month = mar, + year = 1983, + address = "Boston", + organization = ACM, + publisher = "Academic Press", + note = "This is a full PROCEEDINGS entry", +} + +@PROCEEDINGS{whole-proceedings, + key = STOC-key, + organization = ACM, + title = "Proc. Fifteenth Annual" # STOC, + address = "Boston", + year = 1983, + booktitle = "Proc. Fifteenth Annual ACM" # STOC, + note = "This is a cross-referenced PROCEEDINGS", +} + +@PHDTHESIS{phdthesis-minimal, + author = "F. Phidias Phony-Baloney", + title = "Fighting Fire with Fire: Festooning {F}rench Phrases", + school = "Fanstord University", + year = 1988, +} + +@PHDTHESIS{phdthesis-full, + author = "F. Phidias Phony-Baloney", + title = "Fighting Fire with Fire: Festooning {F}rench Phrases", + school = "Fanstord University", + type = "{PhD} Dissertation", + address = "Department of French", + month = jun # "-" # aug, + year = 1988, + note = "This is a full PHDTHESIS entry", +} + +@TECHREPORT{techreport-minimal, + author = "Tom Terrific", + title = "An {$O(n \log n / \! \log\log n)$} Sorting Algorithm", + institution = "Fanstord University", + year = 1988, +} + +@TECHREPORT{techreport-full, + author = "Tom T{\'{e}}rrific", + title = "An {$O(n \log n / \! \log\log n)$} Sorting Algorithm", + institution = "Fanstord University", + type = "Wishful Research Result", + number = "7", + address = "Computer Science Department, Fanstord, California", + month = oct, + year = 1988, + note = "This is a full TECHREPORT entry", +} + +@UNPUBLISHED{unpublished-minimal, + author = "Ulrich {\"{U}}nderwood and Ned {\~N}et and Paul {\={P}}ot", + title = "Lower Bounds for Wishful Research Results", + note = "Talk at Fanstord University (this is a minimal UNPUBLISHED entry)", +} + +@UNPUBLISHED{unpublished-full, + author = "Ulrich {\"{U}}nderwood and Ned {\~N}et and Paul {\={P}}ot", + title = "Lower Bounds for Wishful Research Results", + month = nov # ", " # dec, + year = 1988, + note = "Talk at Fanstord University (this is a full UNPUBLISHED entry)", +} + +@MISC{random-note-crossref, + key = {Volume-2}, + note = "Volume~2 is listed under Knuth \cite{book-full}" +} |