summaryrefslogtreecommitdiff
path: root/macros/optex/base/usebib.opm
diff options
context:
space:
mode:
Diffstat (limited to 'macros/optex/base/usebib.opm')
-rw-r--r--macros/optex/base/usebib.opm620
1 files changed, 448 insertions, 172 deletions
diff --git a/macros/optex/base/usebib.opm b/macros/optex/base/usebib.opm
index ab2f106811..cb38eea7e8 100644
--- a/macros/optex/base/usebib.opm
+++ b/macros/optex/base/usebib.opm
@@ -1,139 +1,285 @@
%% This is part of the OpTeX project, see http://petr.olsak.net/optex
-\_codedecl \MakeReference {Reading bib databases <2022-02-04>} % loaded on demand by \usebib
+\_codedecl \readbibs {Reading bib databases <2023-06-25>} % loaded on demand by \usebib
\_doc -----------------------------
- Loading the `librarian.tex` macro package. See `texdoc librarian`
- for more information about it.
+ First, we implement the scanner of `.bib` files. Unfortunately, the format of
+ these files isn't \TeX/ friendly, so we must to do more work.
+ \`\readbibs` `{<bib-bases>}` reads <bib-bases> files
+ (i.e. the Bib\TeX/ format).
+ \_cod -----------------------------
+
+\_newcount\_aunum
+\_newcount\_NameCount
+\_def\_eaddto#1#2{\_ea\_addto\_ea#1\_ea{#2}}
+
+\_def\_readbibs #1{%
+ \_ifcsname _be:\_bibp*\_endcsname \_def\_citelist{}\_fi % \_citelist will be created
+ \_begingroup
+ \_everyeof{@{}}\_foreach#1,\_do##1,{\_ea\_nextat\_input{##1.bib}}%
+ \_endgroup
+}
+\_public \readbibs ;
- We want to ignore `\errmessage` and we want not to create `\jobname.lbr`
- file.
+ \_doc -----------------------------
+ The \`\_nextat` macro skips the text in the `.bib` file to the next `@`, and starts
+ the \`\_bibentry` macro which reads `@<entry type>{<data>}` from the `.bib` file.
+ Each reference entry is conveted to the \`\_entrydata`
+ macro and then `\_glet \_be:<bib-part>/<label> = \_entrydata` is done.
+ The \^`\_entrydata` includes key-value pairs, as described in the
+ section~\ref[readbibs].
\_cod -----------------------------
-\_def\errmessage#1{}
-\_def\newwrite#1{\_csname lb@restoreat\_endcsname \_endinput}
-\_def\_tmpb{\_catcode`\_=12 \_input librarian \_catcode`\_=11 }\_tmpb
-\_let\errmessage=\_errmessage
-\_let\newwrite=\_newwrite
+\_long\_def\_nextat#1@{\_bgroup\_catcode` =9 \_ea\_egroup\_bibentry}
+\_def\_bibentry #1#{\_ifx^#1^\_else \_afterfi{\_bibentryA{#1}}\_fi}
+\_def\_bibentryA #1#2{\_lowercase{\_def\_entrytype{#1}}%
+ \_ismacro\_entrytype{comment}\_iffalse % comment is ignored
+ \_ismacro\_entrytype{texcode}\_iftrue % TeX code is processed
+ \_endgroup #2\_begingroup \_everyeof{@{}}\_else
+ \_ismacro\_entrytype{string}\_iftrue % string is reported as unsupported
+ \_opwarning{\_string\usebib: @STRING entry isn't supported, try to use @TEXCODE}%
+ \_else
+ \_edef\_entrydata{[@]{\_entrytype}}%
+ {\_bibentryB #2\_fin}% % read a "normal" bib entry
+ \_fi\_fi\_fi
+ \_nextat
+}
+\_def\_bibentryB #1#2,#3\_fin{\_def\_citekey{#1#2}\_def\_bibentryC{\_nextfield #3,\_fin}%
+ \_ifcsname _be:\_bibp*\_endcsname
+ \_bibentryC
+ \_global\_addto\_citelist{\_citeI[#1#2]}
+ \_else
+ \_ea\_ifx \_begincsname _be:\_bibp#1#2\_endcsname \_empty
+ \_bibentryC
+ \_fi\_fi
+}
+\_def\_bibentryF {% finalize entry
+ \_preparebibsorting
+ \_global\_ea\_let \_csname _be:\_bibp\_citekey\_endcsname = \_entrydata
+}
-\_private \BibFile \ReadList \SortList \SortingOrder \NameCount \AbbreviateFirstname
- \CreateField \RetrieveFieldInFor \RetrieveFieldIn \RetrieveField ;
+ \_doc -----------------------------
+ \`\_nextfield` reads next field name and saves it to the \`\_fieldname`
+ and then reads field data and saves it to the \`\_fielddata`.
+ \_cod -----------------------------
+
+\_def\_nextfield #1{\_ifx,#1\_ea\_nextfield % skip commas from previous field
+ \_else \_ifx\_fin#1\_ea\_ea\_ea\_bibentryF % finalize bib entry
+ \_else \_def\_fieldname{#1}\_ea\_ea\_ea\_nextfieldA % first letter of fieldname found
+ \_fi\_fi
+}
+\_def\_nextfieldA #1{% next letters of field name until = is found
+ \_ifx=#1\_afterfi{\_nospacefuturelet\_next\_nextfieldB}%
+ \_else \_addto\_fieldname{#1}%
+ \_ea\_nextfieldA \_fi
+}
+\_def\_nextfieldB {% reading field data
+ \_casesof\_next
+ " {\_nextfieldC}% name = "data",
+ \_bgroup {\_nextfieldD}% name = {data},
+ \_finc {\_nextfieldE}% name = data,
+}
+\_def\_nextfieldC "#1"{\_nextfieldD{#1}}
+\_def\_nextfieldD #1{\_def\_fielddata{#1}\_nextfieldF}
+\_def\_nextfieldE #1,{\_nextfieldD{#1}}
+
+\_def\_nextfieldF{% finalize field
+ \_lowercase\_ea{\_ea\_def\_ea\_fieldname\_ea{\_fieldname}}% case insensitive field name
+ \_ifcsname _fia:\_fieldname\_endcsname \_edef\_fieldname{\_cs{_fia:\_fieldname}}\_fi
+ \_eaddto\_entrydata{\_ea[\_fieldname]}%
+ \_ismacro\_fieldname{author}\_iftrue \_ea\_auscan\_ea{\_fielddata}[author]\_else
+ \_ismacro\_fieldname{editor}\_iftrue \_ea\_auscan\_ea{\_fielddata}[editor]\_else
+ \_eaddto\_entrydata{\_ea{\_fielddata}}\_fi\_fi
+ \_sdef{_fd:\_fieldname\_ea}\_ea{\_fielddata}%
+ \_nextfield
+}
\_doc -----------------------------
- The `\usebib` command.
+ \`\_fieldalias``{<new-name>}{<given-name>}`
+ defines `\_fia:<new_name>` as <given-name>.
\_cod -----------------------------
-\_def\_usebib/#1 (#2) #3 {%
- \_let\_citeI=\_relax \_xdef\_citelist{\_trycs{_ctlst:\_bibp}{}\_trycs{_ctlstB:\_bibp}{}}%
- \_global \_ea\_let \_csname _ctlst:\_bibp\_endcsname =\_write
- \_ifx\_citelist\_empty
- \_opwarning{No cited items. \_noexpand\usebib ignored}%
- \_else
- \_bgroup \_par
- \_emergencystretch=.3\_hsize
- \_def\_optexbibstyle{#2}%
- \_setctable\_optexcatcodes
- \_input bib-#2.opm
- \_the \_bibtexhook
- \_ifcsname _mt:bib.and:\_cs{_lan:\_the\_language}\_endcsname \_else
- \_opwarning{\_string\usebib: No phrases for language
- "\_cs{_lan:\_the\_language}" (using "en")}%
- \_language=0 \_chardef\_documentlanguage=0
- \_fi
- \_def\_tmp##1[*]##2\_relax{\_def\_tmp{##2}}\_ea\_tmp\_citelist[*]\_relax
- \_ifx\_tmp\_empty\_else % there was \nocite[*] used.
- \_setbox0=\_vbox{\_hsize=\_maxdimen \_def\_citelist{}\_adef@{\_readbibentry}%
- \_input #3.bib
- \_ea}\_ea\_def\_ea\_citelist\_ea{\_citelist}%
- \_fi
- \_def\_citeI[##1]{\_csname lb@cite\_endcsname{##1}{\_bibp}{}{}}\_citelist
- \_BibFile{#3}%
- \_if s#1\_SortList{\_bibp}\_fi
- \_ReadList{\_bibp}%
- \_restorectable
- \_egroup
- \_fi
+\_def\_fieldalias#1#2{\_lowercase{\_sxdef{_fia:#1}{#2}}}
+
+ \_doc -----------------------------
+ The \`\_auscan``{<authors/editors-names>}[<field-name>]` reads the specific Bib\TeX/
+ format menitoned in section~\ref[readbibs] and converts them to
+ `{<Lastname>}{<Firstname>}{<Von>}{<Junior>}` for each author/editor. The result
+ includes $4k$ subfields (where $k$ is number of the authors/editors) and
+ it is saved to the `\_entrydata` and the
+ `[authornum]{`$k$`}` or `[editornum]{`$k$`}` is added.
+
+ The \`\_auscanA` macro does the loop over authors separated by `and`.
+ Each single author has its `\_tmpb` macro with `X` and `x`. Each letter
+ corresponds to single word of the name (`X`: begins with uppercase, `x`:
+ begins with lowercase). For example Leonardo Piero da Vinci has `\_tmpb`
+ macro `XXxX.`. If there are commas in after some words, then these commas
+ are in `\_tmpb` macro too, for example da Vinci, Piero Leonardo has its
+ `\_tmpb` macro `xX,XX.`. The number of commas is saved to `\_tmpnum`.
+ The \`\_auscanB` macro does a slight modifications of the `\_tmpb` macro as
+ mentioned in comments. Then the macro
+ \`\_auscanD``<tpmb-pattern>;{<WordA>}{<WordB>}{<WordC>}...` is executed.
+ It saves given words due to the `\_tmpb` pattern to the macros
+ `\_Lastname`, `\_Firstname`, `\_Von`, `\_Junior` in a loop. Finally, the contents of
+ these macros are saved to `\_fiedldata` and then to the `\_entrydata`.
+ \_cod -----------------------------
+
+\_def\_auscan#1[#2]{\_def\_auname{}\_def\_fielddata{}\_def\_tmpb{}\_aunum=0\_tmpnum=0
+ \_auscanA #1 and {}
+ \_eaddto\_entrydata{\_ea{\_fielddata}[#2num]}%
+ \_eaddto\_entrydata{\_ea{\_the\_aunum}}%
+}
+\_def\_auscanA #1 {%
+ \_ifx^#1^\_else
+ \_isequal{#1}{and}\_iftrue
+ \_incr\_aunum
+ \_addto\_tmpb{.}%
+ \_auscanB
+ \_ea\_auscanX \_auname
+ \_def\_auname{}\_def\_tmpb{}\_tmpnum=0
+ \_else
+ \_lowercase{\_isequal{#1}}{#1}\_iftrue \_addto\_tmpb{x}\_else \_addto\_tmpb{X}\_fi
+ \_def\_tmp{#1^}\_isinlist\_tmp{,^}%
+ \_iftrue
+ \_ea\_auscanC\_tmp \_addto\_tmpb{,}\_incr\_tmpnum
+ \_else
+ \_def\_tmp{#1}%
+ \_fi
+ \_eaddto\_auname{\_ea{\_tmp}}%
+ \_fi
+ \_ea\_auscanA
+ \_fi
+}
+\_def\_auscanB{%
+ \_ifcase\_tmpnum % 0 commas: XXX. -> XX:X. ; XxxXX. -> X:xxXX. ; xXX. -> :xXX. ; First:Last
+ \_isinlist\_tmpb{x}\_iffalse \_replstring\_tmpb{X.}{:X.}\_else
+ \_ea\_auscanT\_tmpb;\_iffalse \_replstring\_tmpb{Xx}{X:x}\_fi\_fi
+ \_or % 1 comma: XX,XXX -> XX,,XXX, Junior part is empty
+ \_replstring\_tmpb{,}{,,}\_tmpnum=2
+ \_fi % 2 commas: XX,XX,XXX no changes, generic format: Last, Junior, First
+ \_def\_Firstname{}\_def\_Lastname{}\_def\_Von{}\_def\_Junior{}%
}
-\_def\_readbibentry#1#{\_readbibentryA}
-\_def\_readbibentryA#1{\_readbibentryB#1,,\_relax!.}
-\_def\_readbibentryB#1#2,#3\_relax!.{\_addto\_citelist{\_citeI[#1#2]}}
+\_def\_auscanT #1#2;\_iffalse{\_ifx#1x\_def\_tmpb{:x#2}\_else} % xXX. -> :xXX.
+\_def\_auscanX {\_ea\_auscanD\_tmpb;}
+\_def\_auscanD #1#2;{%
+ \_def\_tmpb{#2}%
+ \_casesof #1
+ . {\_auscanF} % dot is last character, do final job
+ , {\_decr\_tmpnum \_auscanX} % Lastname->Junior or Junior->Firstname
+ : {\_tmpnum=2 \_auscanX} % Firstname->Lastname
+ X {\_auscanE\_Firstname\_Junior\_Lastname} % add data due to the \tmpnum value
+ x {\_auscanE\_Firstname\_Junior\_Von} % Von instead Lastname
+ \_finc {}%
+}
+\_def\_auscanE#1#2#3{\_ifcase\_tmpnum \_ea\_auscanS\_ea#1\_or \_ea\_auscanS\_ea#2\_else
+ \_ea\_auscanS\_ea#3\_fi}
+\_def\_auscanS#1#2{% #1=\Firstname or \Lastname or etc., #2=word to be inserted
+ \_ifx#1\_empty \_def#1{#2}\_else \_addto#1{ #2}\_fi
+ \_auscanX
+}
+\_def\_auscanF{% final work of \auscanX
+ \_eaddto\_fielddata{\_ea{\_Lastname}}\_eaddto\_fielddata{\_ea{\_Firstname}}%
+ \_eaddto\_fielddata{\_ea{\_Von}}\_eaddto\_fielddata{\_ea{\_Junior}}%
+}
+\_def\_auscanC #1,^{\_def\_tmp{#1}} % removing final comma: Word,^ -> Word
\_doc -----------------------------
- Corrections in librarian macros.
+ The \^`\_citelist` includes \`\_citeI``[<label>]`
+ commands. The \^`\usebib` macro runs this lists in order to print references.
+ Each \^`\_citeI``[<label>]` prints single bib entry given by the <label>.
+ It opens a group, sets macros `\_fd:<field-name>` to `<field-data>` and runs
+ \^`\_printentry`. Finally, it closes \TeX/ group,
+ so all macros `\_fd:<field-name>` have their initial (undefined) value.\nl
+ The \`\_getfield``[<field-name>]\macro` does `\def\macro{<field-data>}`.
+ If the field isn't declared then the `\macro` is empty.
\_cod -----------------------------
-\_tmpnum=\_catcode`\@ \_catcode`\@=11
-\_def\lb@checkmissingentries#1,{% we needn't \errmessage here, only \opmacwarning
- \_def\lb@temp{#1}%
- \_unless\_ifx\lb@temp\lb@eoe
- \lb@ifcs{#1}{fields}%
- {}%
- {\_opwarning{\_string\usebib: entry [#1] isn't found in .bib}}%
- \_ea\lb@checkmissingentries
- \_fi
+\_def\_citeI[#1]{%
+ \_begingroup
+ \_ea\_ifx \_begincsname _be:\_bibp#1\_endcsname \_empty
+ \_opwarning{\_string\usebib: entry [#1] isn't found in .bib}%
+ \_global\_slet{_bes:#1}{_relax}%
+ \_else
+ \_ea\_ea\_ea\_foreach \_csname _be:\_bibp#1\_endcsname \_do[##1]##2{\_sdef{_fd:##1}{##2}}%
+ \_def\_entrykey{#1}%
+ \_printentry
+ \_fi
+ \_endgroup
}
-\_def\lb@readentry#1#2#3,{% space before key have to be ingnored
- \_def\lb@temp{#2#3}% we need case sensitive keys
- \_def\lb@next{\_ea\lb@gotoat\lb@gobbletoeoe}%
- \lb@ifcs\lb@temp{requested}%
- {\_let\lb@entrykey\lb@temp
- \lb@ifcs\lb@entrykey{fields}{}%
- {\lb@defcs\lb@entrykey{fields}{}%
- \_lowercase{\lb@addfield{entrytype}{#1}}%
- \_let\lb@next\lb@analyzeentry}}{}%
- \lb@next
+\_def\_getfield[#1]#2{%
+ \_ifcsname _fd:#1\_endcsname
+ \_ea\_ea\_ea \_def \_ea\_ea\_ea #2\_ea\_ea\_ea {\_csname _fd:#1\_endcsname}%
+ \_else \_def#2{}%
+ \_fi
}
-\_let\lb@compareA=\lb@compare
-\_let\lb@preparesortA=\lb@preparesort
-\_def\lb@compare#1\lb@eoe#2\lb@eoe{% SpecialSort:
- \_ifx\lb@sorttype\lb@namestring
- \_ifx\_sortfield\_undefined \lb@compareA#1\lb@eoe#2\lb@eoe
- \_else
- \_ea\_RetrieveFieldInFor\_ea{\_sortfield}\lb@entrykey\lb@temp
- \_ifx\lb@temp\_empty \_toks1={#1\lb@eoe}\_else \_toks1=\_ea{\lb@temp\lb@eoe}\_fi
- \_ea\_RetrieveFieldInFor\_ea{\_sortfield}\lb@currententry\lb@temp
- \_ifx\lb@temp\_empty \_toks2={#2\lb@eoe}\_else \_toks2=\_ea{\lb@temp\lb@eoe}\_fi
- \_edef\lb@temp{\_noexpand\lb@compareA\_space\_the\_toks1 \_space\_the\_toks2}\lb@temp
- \_fi
- \_else \lb@compareA#1\lb@eoe#2\lb@eoe \_fi
+
+ \_doc -----------------------------
+ \`\_preparebibsorting` is called repeatedly for each bib entry when its reading from
+ `.bib` file is finished. Its main goal is to do
+ `\gdef\_bes:<citekey> {\;<sorting-rule>^^^<citekey>}`.
+ Note that the part of the control sequence name after `^^^` is ignored during sorting.
+ The default \^`\_preparebibsorting`
+ macro creates <sorting-rule> in the form: <Lastnames> <Firstnames> <Von>
+ <Junior> of the first author followed by <year> from `year` field.\nl
+ \`\_dobibsorting``\_citelist` sorts the \^`\_citelist` and runs it.
+ \_cod -----------------------------
+
+\_def\_preparebibsorting{%
+ \_getfield[sortedby]\_sortedby
+ \_ifx\_sortedby\_empty % explicitly given [sortedby] field has precedence
+ \_def\_sortedby{}%
+ \_getfield[author]\_tmp % sorting by author firstly
+ \_ifx\_tmp\_empty \_else \_ea\_preparebibsortingA\_tmp \_fin \_fi
+ \_getfield[year]\_tmp % soering by year secondly
+ \_ifx\_tmp\_empty \_else \_eaddto\_sortedby{\_tmp}\_fi
+ \_edef\_sortedby{\_sortedby}% we need to run macros aka \"e etc.
+ \_edef\_sortedby{\_ea\_removeoutbraces\_sortedby {\_fin}}% remove braces
+ \_fi
+ \_sxdef{_bes:\_citekey\_ea}\_ea{\_csname;\_detokenize\_ea{\_sortedby}^^^\_citekey\_endcsname}%
+}
+\_def\_preparebibsortingA#1#2#3#4#5\_fin {% names of the first author used by sorting:
+ \_def\_sortedby{#1 }% Lastname
+ \_ifx^#2^\_else \_addto\_sortedby{#2 }\_fi % Firstname
+ \_ifx^#3^\_else \_addto\_sortedby{#3 }\_fi % Von
+ \_ifx^#4^\_else \_addto\_sortedby{#4 }\_fi % Junior
+}
+\_def\_dobibsorting{%
+ {\_def\_citeI[##1]{\_ea\_citeIs\_csname _bes:##1\_endcsname{##1}}%
+ \_edef\_citelist{\_ea}\_citelist % converting \_citelist
+ \_dosorting\_citelist \_ea}%
}
-\_def\lb@preparesort#1#2\lb@eoe{%
- \_if#1-%
- \_def\lb@sorttype{#2}%
- \_else
- \_def\lb@sorttype{#1#2}%
- \_fi
- \lb@preparesortA#1#2\lb@eoe
+\_def\_citeIs#1#2{\_eaddto\_citelist{#1}%
+ \_ea\_gdef#1{\_citeI[#2]\_ea\_glet#1=\_undefined \_glet#1=\_undefined}%
}
-\_def\_SpecialSort#1{\_def\_sortfield{#1}}
-\_def\WriteImmediateInfo#1{} % the existence of .lbr file bocks new reading of .bib
-\_catcode`\@=\_tmpnum
\_doc -----------------------------
- Main action per each entry.
+ The \`\_printentry` macro prints bibliographic reference entry.
+ It prints <bibnum> or <bimark> (including hyperlinks) and they are
+ followed by printing the entry data. The format is given by the \^`\_printbib`
+ macro and by `\_print:<entrytype>` declared in the bib-style file.
\_cod -----------------------------
-\_def\MakeReference{\_par \_bibskip
- \_bibgl\_advance\_bibnum by1
+\_def\_printentry {\_par \_bibskip
+ \_bibgl\_incr\_bibnum
\_isdefined{_bim:\_bibp\_the\_bibnum}\_iftrue
\_edef\_tmpb{\_csname _bim:\_bibp\_the\_bibnum\_endcsname}%
\_bibmark=\_ea{\_tmpb}%
\_else \_bibmark={}\_fi
- \_edef\_tmpb{\EntryKey}%
- \_noindent \_dbib\EntryKey
+ \_edef\_tmpb{\_entrykey}%
+ \_noindent \_dbib\_entrykey
\_printbib
{%
- \_RetrieveFieldIn{entrytype}\_entrytype
+ \_getfield[@]\_entrytype
\_csname _print:BEGIN\_endcsname
\_isdefined{_print:\_entrytype}\_iftrue
\_csname _print:\_entrytype\_endcsname
\_else
\_ifx\_entrytype\_empty \_else
- \_opwarning{Entrytype @\_entrytype\_space from [\EntryKey] undefined}%
+ \_opwarning{Entrytype @\_entrytype\_space from [\_entrykey] undefined}%
\_csname _print:misc\_endcsname
\_fi\_fi
\_csname _print:END\_endcsname
- \_wbib \EntryKey {\_the\_bibnum}{\_the\_bibmark}%
+ \_wbib \_entrykey {\_the\_bibnum}{\_the\_bibmark}%
}\_par
}
@@ -147,13 +293,13 @@
\_def\_bibfieldname{#2#3}%
\_if!#2\_relax
\_def\_bibfieldname{#3}%
- \_RetrieveFieldIn{#3}\_bibfield
+ \_getfield[#3]\_bibfield
+ \_getfield[#3num]\_namecount % total persons in the author/editor fields
\_ifx\_bibfield\_empty\_else
- \_RetrieveFieldIn{#3number}\_namecount
- \_def\_bibfield{\_csname _Read#3\_ea\_endcsname \_csname _pp:#3\_endcsname}%
+ \_def\_bibfield{\_loopauthors{#3}}% read author/edior field in a loop
\_fi
\_else
- \_RetrieveFieldIn{#2#3}\_bibfield
+ \_getfield[#2#3]\_bibfield
\_fi
\_if^#1^%
\_ifx\_bibfield\_empty \_ea\_ea\_ea \_doemptyfield
@@ -163,36 +309,119 @@
}
\_def\_dofullfield#1#2{\_def\_dofield##1{#1}\_ea\_dofield\_ea{\_bibfield}}
\_def\_doemptyfield#1#2{\_def\_dofield##1{#2}\_ea\_dofield\_ea{\_bibfield}}
-\_let\_Readauthor=\ReadAuthor \_let\_Readeditor=\ReadEditor
-\_def\_bprintaA #1#2{\_ifx\_bibfield\_empty #2\_else\_bprintaB #1**\_eee\_fi}
-\_def\_bprintaB #1*#2*#3\_eee{\_if^#3^#1\_else\_ea\_bprintaC\_ea{\_bibfield}{#1}{#2}\_fi}
+\_def\_bprintaA #1#2{\_ifx\_bibfield\_empty #2\_else\_bprintaB #1**\_fin\_fi}
+\_def\_bprintaB #1*#2*#3\_fin{\_ifx^#3^#1\_else\_ea\_bprintaC\_ea{\_bibfield}{#1}{#2}\_fi}
\_def\_bprintaC #1#2#3{#2#1#3}
\_def\_bprintc#1#2{\_bprintcA#1#2**\_relax}
\_def\_bprintcA#1#2*#3*#4\_relax{\_ifx#1\_empty \_else \_if^#4^#2\_else#2#1#3\_fi\_fi}
\_def\_bprintv [#1]#2#3{\_def\_tmpa{#2}\_def\_tmpb{#3}\_bprintvA #1,,}
\_def\_bprintvA #1,{%
\_if^#1^\_tmpb\_else
- \_RetrieveFieldIn{#1}\_tmp
+ \_getfield[#1]\_tmp
\_ifx \_tmp\_empty
\_else \_tmpa \_def\_tmpb{}\_def\_tmpa{}%
\_fi
\_ea \_bprintvA
\_fi
}
-\_sdef{_pp:author}{\_letNames\_authorname}
-\_sdef{_pp:editor}{\_letNames\_editorname}
-\_def\_letNames{\_let\_Firstname=\Firstname \_let\_Lastname=\Lastname
- \_let\_Von=\Von \_let\_Junior=\Junior
-}
\_doc -----------------------------
- Various macros + multilingual. Note that \`\_nobibwarnlist` is used in
- \`\_bibwarning` and it is set by \^`\nobibwarning` macro.
+ \`\_loopauthors``{<field-name>}` does a loop over all authors/editors in
+ the `author` or `editor` field. The \`\_namecount`
+ (total nuber of authors/editors) was defined in
+ \^`\_bprintb`. Then for each author/edtor it do:
+ \begitems
+ * Set \`\_NameCount` to the position number of the currently processed author/editor.
+ * Define \`\_Lastname`, \`\_Firstname`, \`\_Junior`, \`\_Von`, \`\_After` macros.
+ * Run \^`\_authorname` or \^`\_editorname` macro (defined in the bib style file).
+ \enditems
+ \_cod -----------------------------
+
+\_def\_loopauthors #1{%
+ \_NameCount=0
+ \_ea\_ea\_ea\_foreach\_csname _fd:#1\_endcsname \_do ##1##2##3##4{%
+ \_advance\_NameCount by1
+ \_def\_Lastname{##1}\_def\_Firstname{##2}\_def\_Von{##3}\_def\_Junior{##4}%
+ \_csname _#1ini\_endcsname \_csname _#1name\_endcsname
+}}
+\_def\_authorini{} % ready for \_AbbreviateFirstname or similar...
+\_def\_editorini{}
+
+ \_doc -----------------------------
+ \`\_bibwarning` can be used if the manatory field is missing.
+ Note that \`\_nobibwarnlist` is used here, it is set by \^`\nobibwarning` macro.
\_cod -----------------------------
\_def\_bibwarning{%
- \_ea\_isinlist \_ea\_nobibwarnlist\_ea{\_ea,\EntryKey,}\_iffalse
- \_opwarning{Missing field "\_bibfieldname" in [\EntryKey]}\_fi}
+ \_ea\_isinlist \_ea\_nobibwarnlist\_ea{\_ea,\_entrykey,}\_iffalse
+ \_opwarning{Missing field "\_bibfieldname" in [\_entrykey]}\_fi}
+
+ \_doc -----------------------------
+ \`\_AbbreviateFirstname`, \`\_RetrieveFieldIn`, \`\_RetrieveField` are here only for
+ backward comaptibility with previous macros based on the librarian package.
+ The \`\_CreateField`, \`\_SortingOrder`, and \`\_SpecialSort` are dummy
+ macros because the sorting is implemented by a slightly different way
+ than in librarian package.
+ \_cod -----------------------------
+
+\_def\_AbbreviateFirstname{\_addto\_authorini{\_abbrevnames\_Firstname}}
+\_def\_abbrevnames#1{% Karolina Pondelickova-Maslova -> K. P.-M.
+ \_edef#1{\_ea\_foreach #1 \_do ##1##2 {##1.%
+ \_foreach ##2-{}\_do ####1-####2{\_ifx^####2^\_else-####2.\_fi} }^%
+ }\_replstring#1{ ^}{}%
+}
+\_def\_RetrieveFieldIn#1{\_getfield[#1]}
+\_def\_RetrieveField#1{\_trycs{_fd:#1}{}}
+\_def\_CreateField#1{}
+\_def\_SortingOrder#1#2{}
+\_def\_SpecialSort#1{}
+
+ \_doc -----------------------------
+ The \^`\usebib` command is defined as `\input{usebib.opm}\_usebib` in the
+ format. So, the command is re-defined here and it is run again with the new
+ meaning.\nl
+ The \^`\usebib` macro defined here reads `\_ctlst:<bibpart>/` and `\_ctlstB:<bibpart>/`
+ (they include a list of `\_citeI[<label>]`) and merges them to a single \`\_citelist`.
+ The `\_be:<bibpart>/<label>` is set to empty for each member of the `\_citelist`.
+ Then the style file is read in a group,
+ the \^`\readbibs` macro reads given `.bib` files and resulting `\_citelist`
+ is processed: i.e.\ the macros \^`\_citeI` print desired entries.
+ \_cod -----------------------------
+
+\_def\_usebib/#1 (#2) #3 {%
+ \_ifcsname _ctlst:\_bibp\_endcsname
+ \_slet{_citelist}{_ctlst:\_bibp}\_else \_def\_citelist{}\_fi
+ \_ea \_foreach\_citelist \_do ##1[##2]{\_sdef{_be:\_bibp##2}{}}%
+ \_ifcsname _ctlstB:\_bibp\_endcsname
+ \_ea\_ea\_ea\_foreach \_csname _ctlstB:\_bibp\_endcsname \_do ##1[##2]{%
+ \_ifcsname _be:\_bibp##2\_endcsname
+ \_else \_addto\_citelist{\_citeI[##2]}\_sdef{_be:\_bibp##2}{}%
+ \_fi
+ }%
+ \_fi
+ \_global \_ea\_let \_csname _ctlst:\_bibp\_endcsname =\_write
+ \_ifx\_citelist\_empty
+ \_opwarning{No cited items. \_noexpand\usebib ignored}%
+ \_else
+ \_bgroup
+ \_par
+ \_emergencystretch=.3\_hsize
+ \_def\_optexbibstyle{#2}%
+ \_setctable\_optexcatcodes
+ \_input bib-#2.opm
+ \_the \_bibtexhook
+ \_ifcsname _mt:bib.and:\_cs{_lan:\_the\_language}\_endcsname \_else
+ \_opwarning{\_string\usebib: No phrases for language
+ "\_cs{_lan:\_the\_language}" (using "en")}%
+ \_language=0 \_chardef\_documentlanguage=0
+ \_fi
+ \_ifx#1c\_def\_preparebibsorting{}\_def\_dobibsorting{}\_fi
+ \_readbibs {#3}%
+ \_dobibsorting\_citelist
+ \_restorectable
+ \_egroup
+ \_fi
+}
\_endcode
@@ -201,7 +430,7 @@
The file `usebib.opm` implements the command
\~`\usebib/<sorttype> (<style>) <bibfiles>`
where `<sorttype>` is one letter `c` (references ordered by citation order in
-the text) or `s` (references ordered by key in the style file),
+the text) or `s` (references sorted usually by authors and years),
`<style>` is the part of the name `bib-<style>.opm` of the style file
and `<bibfiles>` are one or more `.bib` file names without suffix separated by
comma without space. Example:
@@ -209,11 +438,10 @@ comma without space. Example:
\begtt
\usebib/s (simple) mybase,yourbase
\endtt
-
This command reads the `<bibfiles>` directly and creates the list of
bibliographic references (only those declared by \~`\cite[]` or
-\~`\nocite[]` in the text). The formatting of such references is defined in the style
-file.
+\~`\nocite[]` in the document). The formatting of such references is defined in
+the style~file.
The principle \"first entry wins" is used. Suppose `\usebib/s (simple) local,global`.
If an entry with the same label is declared in `local.bib` and in
@@ -231,6 +459,7 @@ Old `.bib` files may use the obscure notation for accents like `{\"o}`.
Recommendation: convert such old files to Unicode encoding. If you are
unable to do this then you can set \^`\bibtexhook={`\^`\oldaccents}`.
+
\secc Notes for bib-style writers
The `.bib` files include records in the format:
@@ -244,7 +473,10 @@ The `.bib` files include records in the format:
\endtt
%
see the file `demo/op-biblist.bib` for a real example. The <entry-types> and
-<field-names> are case insensitive.
+<field-names> are case insensitive. More field-names can behave equally if the
+\^`\_fieldalias``{<new-field-name>}{<given-field-name>}` is used in a style
+file. If a <new-field-name> is declared by this command and it is used in the `.bib`
+file then the effect is the same as if it was used the <given-field-name>.
Ancient Bib\TeX/ has read such files and has generated files appropriate for
reading by \LaTeX. It has worked with a set of <entry-types>, see the www
@@ -277,12 +509,12 @@ macros for a more comfortable setting of printing rules:
* The part <if not defined> can include
the \^`\_bibwarning` command if the <field-name> is mandatory.
* \^`\_bprintb` `[<field-name>] {<if defined>} {<if not defined>}`. The same as
- `\_bprinta`, but the `##1` parameter is used instead `*`. Differences: `##1`
+ \^`\_bprinta`, but the `##1` parameter is used instead `*`. Differences: `##1`
parameter can be used more than once and can be enclosed in nested
braces. The `*` parameter can be used at most once and cannot be enclosed
- in braces. Warning: if the `\_bprintb` commands are nested (`\_bprintb` in
- `\_bprintb`), then you need to write the `####1` parameter for internal `\_bprintb`.
- But if `\_bprinta` commands are nested then the parameter is not duplicated.
+ in braces. Warning: if the \^`\_bprintb` commands are nested (`\_bprintb` in
+ \^`\_bprintb`), then you need to write the `####1` parameter for internal `\_bprintb`.
+ But if \^`\_bprinta` commands are nested then the parameter is not duplicated.
* \^`\_bprintc` `\macro {<if non-empty>}`. The <if non-empty> part is executed if
`\macro` is non-empty. The `*` parameter can be used, it is replaced by
the `\macro`.
@@ -317,17 +549,17 @@ in order to declare the format of printing each individual name.
The following control sequences can be used in these macros:
\begitems
-* `\_NameCount`: the number of the currently processed author in the list
-* `\_namecont`: the total number of the authors in the list
-* `\_Lastname`, `\_Firstname`, `\_Von`, `\_Junior`: the parts of the name.
+* \^`\_NameCount`: the number of the currently processed author in the list
+* \^`\_namecount`: the total number of the authors in the list
+* \^`\_Lastname`, \^`\_Firstname`, \^`\_Von`, \^`\_Junior`: the parts of the name.
\enditems
-The whole style file is read in the group during the `\usebib` command is executed
+The whole style file is read in the group during the \^`\usebib` command is executed
before typesetting the reference list. Each definition or setting is local
here.
The auto-generated phrases (dependent on current language) can be used in
-bib-style files by `\_mtext{bib.<identifier>}`, where <ident> is an identifier of
+bib-style files by `\_mtext{bib.<identifier>}`, where <identifier> is an identifier of
the phrase and the phrase itself is defined by
`\_sdef{_mt:bib.<identifier>:<language>}{<phrase>}`. See section~\ref[langphrases]
for more detail. Phrases for <identifiers>:
@@ -335,24 +567,14 @@ and, etal, edition, citedate, volume, number, prepages, postpages, editor,
editors, available, availablealso, bachthesis, masthesis, phdthesis
are defined already, see the end of section~\ref[langphrases].
-If you are using non-standard field-names in .bib database and bib-style,
-you have to declare them by `\_CreateField {<fieldname>}`.
-
-You can declare `\_SortingOrder` in the manner documented by librarian package.
-
-User or author of the bib-style can create the hidden field which has a
-precedence while sorting names. Example:
-
-\begtt
-\CreateField {sortedby}
-\SpecialSort {sortedby}
-\endtt
+The `sortedby` field is declared by \~`\readbibs` as a special field where
+sorting phrase can be specified. If it is present then it has precedence
+before default sorting phrase generated by \~`\_preparebibsorting` from the
+lastname, firstnames of the first author and from the year.
Suppose that the .bib file includes:
\begtt
-...
author = "Jan Chadima",
sortedby = "Hzzadima Jan",
-...
\endtt
Now, this author is sorted between H and I, because the Ch digraph in this
name has to be sorted by this rule.
@@ -361,37 +583,91 @@ If you need (for example) to place the auto-citations before other citations,
then you can mark your entries in `.bib` file by `sortedby = "@"`, because this
character is sorted before `A`.
+If you want to declare a different sorting rule, you can re-define the
+\^`\_preparebibsorting` macro. The example is in the
+\ulink[http://petr.olsak.net/optex/optex-tricks.html\#reverseyear]{\OpTeX/ trick 0113}.
+
+\secc[readbibs] Direct reading of `.bib` files
+
+\^`\readbibs` `{<bib-bases>}` is internally used (by \^`\usebib`)
+for reading `.bib` databases in Bib\TeX/ format. The <bib-bases> is
+comma separated list of file names (without `.bib` extension, without
+spaces). These files are read and \^`\readbibs` defines macros
+`\_be:<bibpart>/<label>`, where <label> is the label of the reference record.
+These macros include key-value pairs `[<field name>]{<field data>}`.
+The first pair is `[@]{<entry type>}`.
+For example, if we have in the `.bib` file:
+\begtt
+@Book { tbn,
+ author = "Petr Olšák",
+ TITle = {\TeX{}book naruby},
+ publisher = "Konvoj",
+ year = 2001,
+}
+\endtt
+and the \^`\bibpart` is empty (default value)
+then the `\_be:/tbn` macro is defined with the content:
+\begtt
+[@]{BOOK}[author]{{Olšák}{Petr}{}{}}[authornum]{1}[title]{\TeX{}book naruby}%
+[publisher]{Konvoj}[year]{2001}
+\endtt
+If you do `\slet{tmp}{_be:/tbn}` then you can print the data (for example) by:
+\begtt
+\ea\foreach \tmp \do [#1]#2{\wterm{field-name: "#1", data: "#2"}}
+\endtt
+or you can do `\ea\foreach \tmp \do [#1]#2{\sdef{bib-field:#1}{#2}}` to enable
+direct acces to the scanned data.
+
+Note that entry type and field names are converted lower-case by the `\readbibs` macro.
+
+There are two special entry types: `@COMMENT{<ignored text>}` and
+`@TEXCODE{<processed text>}`. The <ignored text> is ignored, the
+<processed text> is executed by \TeX/. The definitions of macros used in other
+entries in data of fields can be here. If the `\usebib` is used then
+the <processed text> is executed inside a
+\TeX/ group, so the assignment is locally valid only during creating the
+reference list. The BiB\TeX/'s `@STRING{}` isn't supported. All others entry
+types are interpreted as a {\em reference entry} and they are interpreted as
+described above. An optional balanced text between entries in `.bib` files
+is ignored.
+
+If the macro `\_be:<bibpart>/*` is defined then the \^`\readbibs` macro reads
+all entries from `.bib` files and creates \~`\_citelist`. If the
+`\_be:<bibpart>/*` is undefined then
+the \^`\readbibs` macro reads only entries with <label> where
+`\_be:<bibpart>/<label>` is set to the empty macro. After reading, the
+macros `\_be:<bibpart>/<label>` are globally re-defined as described above.
+
+The \^`\readbibs` macro doesn't convert fields data, but there are two exceptions:
+author and editor fields. These fields have very specific format with
+various alternatives, see \url{https://nwalsh.com/tex/texhelp/bibtx-23.html}.
+Shortly speaking, more authors are divided by the `and` keyword and names of a single
+author must be separated to four subfields: <Lastnames>, <Firstnames>, <Von>,
+<Junior>. Only the <Lastnames> subfield must be nonempty. The input can look like
+\begtt
+Leonardo Piero da Vinci
+or
+da Vinci, Leonardo Piero
+\endtt
+and both these variants are converted to `{Vinci}{Leonardo Piero}{da}{}`.
+The <Von> part is rekognized as a word with only lowercase letters. In
+general, the name can be written without commas: <Firstnames> <Von>
+<Lastnames> or with single comma: <Von> <Lastnames>, <Firstnames> or with two
+commas: <Von> <Lastnames>, <Junior>, <Firstnames> and all these variants are
+converted to the quaternion `{<Lastnames>}{<Firstnames>}{<Von>}{<Junior>}`
+by the \^`\readbibs` macro.
+If there are more than single author, then each author is saved in four
+subfields side by side, so you have 4 or 8 or 12 etc.\ subfildeds in the
+author/editor data field. You can read them by
+`\foreach <author-data>\do #1#2#3#4{...}`.
+
\_endinput
History:
--------
-2022-02-04 reading tail of languages.opm removed
-2021-04-30 \RetrieveField declared as private, bug fixed.
-2021-04-13 \bibpart implemented
-2021-04-13 \_bibgl introduced (used by \slides)
-2021-03-12 \_citelistB added before first test.
-2021-02-15 \_expandafter -> \_ea
-Apr. 2014: released in OPmac
-Jan. 2016: "first entry wins" implemented
-Apr. 2016: \readentry -> \readbibentry, \usebib->\MakeReference
-Feb. 2018: \input librarian does not create \jobname.lbr
-
-% Source:
-
-% opmac-bib
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Petr Olsak, version Feb. 2018 (beta)
-
-% This is module for OPmac macros, see http://petr.olsak.net/opmac.html
-% The command:
-% \usebib/<sorttype> (<style>) (bibfiles>
-% for direct reading .bib files by OPmac macros (without bibTeX) is implemented here.
-% The implementation depends on librarian.tex package by Paul Isambert.
-% Use:
-% \input opmac \input opmac-bib
-% or simply:
-% \input opmac-bib
-% before using the command \usebib.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% end
-
+2023-06-25: \_fieldalias introduced
+2023-06-07: bug fix (\_namecount declaration)
+2023-06-06: \_slet{_bes:#1}{_relax}: bugfix when label not found and sorting
+2023-06-05: @TEXCODE introduced + more consistent doc
+2023-06-02: macros re-implemeted, librarian package no more needed.
+2018 - 2023-06-01 usebib.opm based on librarian package, like in OPmac.