1# -*- mode: Perl -*-
2# /=====================================================================\ #
3# |  natbib                                                             | #
4# | Implementation for LaTeXML                                          | #
5# |=====================================================================| #
6# | Part of LaTeXML:                                                    | #
7# |  Public domain software, produced as part of work done by the       | #
8# |  United States Government & not subject to copyright in the US.     | #
9# |---------------------------------------------------------------------| #
10# | Bruce Miller <bruce.miller@nist.gov>                        #_#     | #
11# | http://dlmf.nist.gov/LaTeXML/                              (o o)    | #
12# \=========================================================ooo==U==ooo=/ #
13package LaTeXML::Package::Pool;
14use strict;
15use warnings;
16use LaTeXML::Package;
17
18#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19# natbib
20#   following natbib.pdf document
21# The basic support function for citation styles is in LaTeX.pool
22# Other formatting support is in Post::MakeBibliography
23#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
24
25#======================================================================
26# 5. Package Options
27
28# The kind of citation
29DeclareOption('numbers', sub {
30    setCitationStyle(numbers => 1);
31    ExecuteOptions('square', 'comma', 'nobibstyle'); });
32DeclareOption('super', sub {
33    setCitationStyle(super => 1, open => Tokens(), close => Tokens());
34    ExecuteOptions('nobibstyle'); });
35DeclareOption('authoryear', sub {
36    setCitationStyle(authoryear => 1);
37    ExecuteOptions('round', 'semicolon', 'bibstyle'); });
38# # The kind of braces around citations
39DeclareOption('round', sub {
40    setCitationStyle(round => 1);
41    ExecuteOptions('nobibstyle'); });
42DeclareOption('curly', sub {
43    setCitationStyle(curly => 1);
44    ExecuteOptions('nobibstyle'); });
45DeclareOption('square', sub {
46    setCitationStyle(square => 1);
47    ExecuteOptions('nobibstyle'); });
48DeclareOption('angle', sub {
49    setCitationStyle(angle => 1);
50    ExecuteOptions('nobibstyle'); });
51
52# The kind of separator between multiple citations
53DeclareOption('comma', sub {
54    setCitationStyle(comma => 1);
55    ExecuteOptions('nobibstyle'); });
56DeclareOption('semicolon', sub {
57    setCitationStyle(semicolon => 1);
58    ExecuteOptions('nobibstyle'); });
59DeclareOption('colon', sub {
60    ExecuteOptions('semicolon'); });    # SIC!
61
62# This disables any future \bibstyle found in the aux file (or from \bibliographystyle)
63DeclareOption('nobibstyle', sub {
64    Let('\bibstyle', '\@gobble'); });
65DeclareOption('bibstyle', sub {
66    Let('\bibstyle', '\@citestyle'); });
67
68# sorting options
69DeclareOption('sort',          sub { });
70DeclareOption('sort&compress', sub { });
71DeclareOption('compress',      sub { });
72
73DeclareOption('longnamesfirst', sub { });
74
75DeclareOption('openbib', sub { });
76DeclareOption('sectionbib', sub {
77    AssignMapping('BACKMATTER_ELEMENT', 'ltx:bibliography' => 'ltx:section'); });
78DeclareOption('nonamebreak', sub { });
79
80# They _say_ round & semicolon but ...
81#ExecuteOptions('round','semicolon','authoryear');
82#ExecuteOptions('square','comma','authoryear');
83setCitationStyle(round => 1, semicolon => 1);
84
85# NOTE \bibliographystyle puts \bibstyle in the *.aux, read at the beginning!
86# Normally, \bibliography appears at the end next to the bibliography.... it's TOO LATE!
87# [FUTURE: Maybe this can be encoded as attributes on ltx:bibliography ???
88#  But then we need to put in stub elements to be filled in by CrossRef! Ugh]
89# In any case, \bibstyle may get redefined by options, so define it now!
90DefMacro('\bibstyle{}', sub {
91    my $style = T_CS('\bibstyle@' . ToString($_[1]));
92    (LookupDefinition($style) ? ($style) : (T_CS('\relax'))); });
93#AtBeginDocument{\global\let\bibstyle=\@gobble}
94Let('\@citestyle', '\bibstyle');
95
96# # They _say_ round & semicolon but ...
97ExecuteOptions('round', 'semicolon', 'authoryear');
98# ExecuteOptions('square','comma','authoryear');
99AssignValue(CITE_STYLE => 'authoryear');    # the default?
100
101ProcessOptions();
102#======================================================================
103# 2.3 Basic Citation Commands
104
105# Leverage the definitions in LaTeX.pool.
106
107# Note that LaTeX's \cite command is treated almost equivalent to \citet in authoryear mode,
108# but like \citep in numbers mode.
109DefMacro('\cite OptionalMatch:* [][] Semiverbatim', sub {
110    my ($gullet, $star, $pre, $post, $keys) = @_;
111    my ($style, $open, $close, $ns, $ay)
112      = map { LookupValue($_) } qw(CITE_STYLE CITE_OPEN CITE_CLOSE CITE_NOTE_SEPARATOR CITE_AY_SEPARATOR);
113    if (!$post) { ($pre, $post) = (undef, $pre); }
114    $pre  = undef unless $pre  && $pre->unlist;
115    $post = undef unless $post && $post->unlist;
116    my $author = ($star ? "FullAuthors" : "Authors");
117    if ($style eq 'numbers') {
118      Invocation(T_CS('\@@cite'),
119        Tokens(Explode('cite')),
120        Tokens($open, ($pre ? ($pre, T_SPACE) : ()),
121          Invocation(T_CS('\@@bibref'), Tokens(Explode("Number")), $keys, undef, undef),
122          ($post ? ($ns, T_SPACE, $post) : ()),
123          $close)); }
124    elsif ($style eq 'super') {
125      Invocation(T_CS('\@@cite'),
126        Tokens(Explode('cite')),
127        Tokens(($pre ? ($pre, T_SPACE) : ()), Invocation(T_CS('\textsuperscript'),
128            Invocation(T_CS('\@@bibref'), Tokens(Explode("Number")), $keys,
129              undef, undef)),
130          ($post ? (T_SPACE, $post) : ()))); }
131    else {
132      # Appears to be textual, unless pre or post phrase, then parenthetical (!)
133      if ($pre || $post) {
134        Invocation(T_CS('\@@cite'),
135          Tokens(Explode('cite')),
136          Tokens($open->unlist, ($pre ? ($pre, T_SPACE) : ()),
137            Invocation(T_CS('\@@bibref'),
138              Tokens(Explode($author . "Phrase1Year")),
139              $keys,
140              Invocation(T_CS('\@@citephrase'),
141                Tokens($ay->unlist, T_SPACE)), undef),
142            ($post ? ($ns, T_SPACE, $post) : ()), $close)); }
143      else {
144        Invocation(T_CS('\@@cite'),
145          Tokens(Explode('cite')),
146          Invocation(T_CS('\@@bibref'),
147            Tokens(Explode($author . " Phrase1YearPhrase2")),
148            $keys,
149            Invocation(T_CS('\@@citephrase'), $open),
150            Invocation(T_CS('\@@citephrase'), $close))); } }
151}, locked => 1);
152
153DefMacro('\citet OptionalMatch:* [][] Semiverbatim', sub {
154    my ($gullet, $star, $pre, $post, $keys) = @_;
155    my ($style, $open, $close, $ns)
156      = map { LookupValue($_) } qw(CITE_STYLE CITE_OPEN CITE_CLOSE CITE_NOTE_SEPARATOR);
157    if (!$post) { ($pre, $post) = (undef, $pre); }
158    $pre  = undef unless $pre  && $pre->unlist;
159    $post = undef unless $post && $post->unlist;
160    my $author = ($star ? "FullAuthors" : "Authors");
161    if ($style eq 'numbers') {
162      Invocation(T_CS('\@@cite'),
163        Tokens(Explode('citet')),
164        Tokens(    #($pre ? ($pre, T_SPACE) : ()),
165          Invocation(T_CS('\@@bibref'),
166            Tokens(Explode("$author Phrase1NumberPhrase2")),
167            $keys,
168            Invocation(T_CS('\@@citephrase'),
169              Tokens($open, ($pre ? ($pre, T_SPACE) : ()))),
170            Invocation(T_CS('\@@citephrase'),
171              Tokens(($post ? ($ns->unlist, T_SPACE, $post->unlist) : ()), $close->unlist))
172          )))->unlist; }
173    elsif ($style eq 'super') {
174      Invocation(T_CS('\@@cite'),
175        Tokens(Explode('citet')),
176        Tokens(($pre ? ($pre, T_SPACE) : ()),
177          Invocation(T_CS('\@@bibref'),
178            Tokens(Explode("$author Phrase1SuperPhrase2")),
179            $keys, undef, undef)->unlist,
180          ($post ? ($ns, T_SPACE, $post->unlist) : ()))); }
181    else {
182      Invocation(T_CS('\@@cite'),
183        Tokens(Explode('citet')),
184        Invocation(T_CS('\@@bibref'),
185          Tokens(Explode("$author Phrase1YearPhrase2")),
186          $keys,
187          Invocation(T_CS('\@@citephrase'),
188            Tokens($open, ($pre ? ($pre, T_SPACE) : ()))),
189          Invocation(T_CS('\@@citephrase'),
190            Tokens(($post ? ($ns, T_SPACE, $post) : ()), $close)))); }
191}, locked => 1);
192
193DefMacro('\citep OptionalMatch:* [][] Semiverbatim', sub {
194    my ($gullet, $star, $pre, $post, $keys) = @_;
195    my ($style, $open, $close, $ns, $ay)
196      = map { LookupValue($_) } qw(CITE_STYLE CITE_OPEN CITE_CLOSE
197      CITE_NOTE_SEPARATOR CITE_AY_SEPARATOR);
198    if (!$post) { ($pre, $post) = (undef, $pre); }
199    $pre  = undef unless $pre  && $pre->unlist;
200    $post = undef unless $post && $post->unlist;
201    my $author = ($star ? "FullAuthors" : "Authors");
202
203    if ($style eq 'numbers') {
204      Invocation(T_CS('\@@cite'),
205        Tokens(Explode('citep')),
206        Tokens($open, ($pre ? ($pre, T_SPACE) : ()),
207          Invocation(T_CS('\@@bibref'), Tokens(Explode("Number")), $keys, undef, undef),
208          ($post ? ($ns, T_SPACE, $post) : ()), $close)); }
209    elsif ($style eq 'super') {
210      Invocation(T_CS('\@@cite'),
211        Tokens(Explode('citep')),
212        Tokens(($pre ? ($pre, T_SPACE) : ()),
213          Invocation(T_CS('\@@bibref'), Tokens(Explode("Super")), $keys, undef, undef),
214          ($post ? (T_SPACE, $post) : ()))); }
215    else {
216      Invocation(T_CS('\@@cite'),
217        Tokens(Explode('citep')),
218        Tokens($open->unlist, ($pre ? ($pre, T_SPACE) : ()),
219          Invocation(T_CS('\@@bibref'),
220            Tokens(Explode("${author}Phrase1Year")),
221            $keys,
222            Invocation(T_CS('\@@citephrase'), Tokens($ay->unlist, T_SPACE)),
223            undef),
224          ($post ? ($ns, T_SPACE, $post) : ()), $close)); }
225}, locked => 1);
226
227#======================================================================
228# 2.4 Extended Citation Commands
229DefMacro('\@@cite@noparens', sub {
230    AssignValue(CITE_OPEN  => Tokens());
231    AssignValue(CITE_CLOSE => Tokens()); });
232
233# The next two are the same as \citet, \citep, but redefine open & close to empty.
234DefMacro('\citealt OptionalMatch:* [][] Semiverbatim', sub {
235    my ($gullet, $star, $pre, $post, $keys) = @_;
236    (T_CS('\bgroup'), T_CS('\@@cite@noparens'),
237      Invocation(T_CS('\citet'), $star, $pre, $post, $keys)->unlist,
238      T_CS('\egroup')); });
239
240DefMacro('\citealp OptionalMatch:* [][] Semiverbatim', sub {
241    my ($gullet, $star, $pre, $post, $keys) = @_;
242    (T_CS('\bgroup'), T_CS('\@@cite@noparens'),
243      Invocation(T_CS('\citep'), $star, $pre, $post, $keys)->unlist,
244      T_CS('\egroup')); });
245
246DefMacro('\citenum Semiverbatim', sub {    # No optional ?
247    my ($gullet, $keys) = @_;
248    Invocation(T_CS('\@@cite'),
249      Tokens(Explode('citenum')),
250      Tokens(Invocation(T_CS('\@@bibref'), Tokens(Explode("Number")), $keys, undef, undef))); });
251
252# Sorta right, but would like to avoid the nested <ltx:cite>!
253# maybe can neutralize \@@cite?
254DefMacro('\citetext', '\@@cite');
255
256DefMacro('\citeauthor OptionalMatch:* [][] Semiverbatim', sub {
257    my ($gullet, $star, $pre, $post, $keys) = @_;
258    my $author = ($star ? "FullAuthors" : "Authors");
259    if (!$post) { ($pre, $post) = (undef, $pre); }
260    $pre  = undef unless $pre  && $pre->unlist;
261    $post = undef unless $post && $post->unlist;
262    my $ns = LookupValue('CITE_NOTE_SEPARATOR');
263    Invocation(T_CS('\@@cite'),
264      Tokens(Explode('citeauthor')),
265      Tokens(    # ($pre ? ($pre, T_SPACE) : ()),
266        Invocation(T_CS('\@@bibref'), Tokens(Explode($author)), $keys, undef, undef),
267        ($post ? ($ns, T_SPACE, $post) : ()))); });
268
269DefMacro('\citefullauthor [][] Semiverbatim', sub {
270    my ($gullet, $pre, $post, $keys) = @_;
271    if (!$post) { ($pre, $post) = (undef, $pre); }
272    $pre  = undef unless $pre  && $pre->unlist;
273    $post = undef unless $post && $post->unlist;
274    my $ns = LookupValue('CITE_NOTE_SEPARATOR');
275    Invocation(T_CS('\@@cite'),
276      Tokens(Explode('citefullauthor')),
277      Tokens(    # ($pre ? ($pre, T_SPACE) : ()),
278        Invocation(T_CS('\@@bibref'), Tokens(Explode("FullAuthors")), $keys, undef, undef),
279        ($post ? ($ns, T_SPACE, $post) : ()))); });
280
281DefMacro('\citeyear [][] Semiverbatim', sub {
282    my ($gullet, $pre, $post, $keys) = @_;
283    if (!$post) { ($pre, $post) = (undef, $pre); }
284    $pre  = undef unless $pre  && $pre->unlist;
285    $post = undef unless $post && $post->unlist;
286    my $ns = LookupValue('CITE_NOTE_SEPARATOR');
287    Invocation(T_CS('\@@cite'),
288      Tokens(Explode('citeyear')),
289      Tokens(    # ($pre ? ($pre, T_SPACE) : ()),
290        Invocation(T_CS('\@@bibref'), Tokens(Explode("Year")), $keys, undef, undef),
291        ($post ? ($ns, T_SPACE, $post) : ()))); });
292
293DefMacro('\citeyearpar [][] Semiverbatim', sub {
294    my ($gullet, $pre, $post, $keys) = @_;
295    my ($open, $close) = map { LookupValue($_) } qw(CITE_OPEN CITE_CLOSE);
296    if (!$post) { ($pre, $post) = (undef, $pre); }
297    $pre  = undef unless $pre  && $pre->unlist;
298    $post = undef unless $post && $post->unlist;
299    my $ns = LookupValue('CITE_NOTE_SEPARATOR');
300    Invocation(T_CS('\@@cite'),
301      Tokens(Explode('citeyearpar')),
302      Tokens($open,
303        ($pre ? ($pre, T_SPACE) : ()),
304        Invocation(T_CS('\@@bibref'), Tokens(Explode("Year")), $keys, undef, undef),
305        ($post ? ($ns, T_SPACE, $post) : ()),
306        $close)); });
307
308#======================================================================
309# 2.5 Forcing Upper Cased Name
310# These are SUPPOSED to capitalize the first letter, .. but
311DefMacro('\Citet',      '\citet');
312DefMacro('\Citep',      '\citep');
313DefMacro('\Citealt',    '\citealt');
314DefMacro('\Citealp',    '\citealp');
315DefMacro('\Citeauthor', '\citeauthor');
316
317#======================================================================
318# 2.6 Citation Aliasing
319# Citation aliasing is achieved with
320#   \defcitealias{key}{text}
321#   \citetalias{key}  ==>> text
322#   \citepalias{key}  ==>> (text)
323
324# should end the defined key with \@extra@b@citeb ???
325
326DefPrimitive('\defcitealias Semiverbatim {}', sub {
327    my ($gullet, $key, $text) = @_;
328    DefMacroI(T_CS('\al@' . ToString($key)), undef, $text); });
329
330# These use the above defined text to fill in the bibref
331# (which will still be a link to the bibitem!)
332DefMacro('\citetalias [][] Semiverbatim', sub {
333    my ($gullet, $pre, $post, $key) = @_;
334    my ($open, $close) = map { LookupValue($_) } qw(CITE_OPEN CITE_CLOSE);
335    if (!$post) { ($pre, $post) = (undef, $pre); }
336    $pre  = undef unless $pre  && $pre->unlist;
337    $post = undef unless $post && $post->unlist;
338    Invocation(T_CS('\@@cite'),
339      Tokens(Explode('citealias')),
340      Tokens(($pre ? ($pre, T_SPACE) : ()),
341        Invocation(T_CS('\@@bibref'),
342          Tokens(Explode("Phrase1")),
343          $key,
344          Invocation(T_CS('\@@citephrase'), T_CS('\al@' . ToString($key)))),
345        ($post ? (T_SPACE, $post) : ()))); });
346
347DefMacro('\citepalias [][] Semiverbatim', sub {
348    my ($gullet, $pre, $post, $key) = @_;
349    my ($open, $close, $ns) = map { LookupValue($_) } qw(CITE_OPEN CITE_CLOSE CITE_NOTE_SEPARATOR);
350    Invocation(T_CS('\@@cite'),
351      Tokens(Explode('citepalias')),
352      Tokens($open,
353        ($pre ? ($pre, T_SPACE) : ()),
354        Invocation(T_CS('\@@bibref'),
355          Tokens(Explode("Phrase1")),
356          $key,
357          Invocation(T_CS('\@@citephrase'), T_CS('\al@' . ToString($key)))),
358        ($post ? ($ns, T_SPACE, $post) : ()),
359        $close)); });
360
361#======================================================================
362# 2.9 Selecting Citation Punctuation
363DefKeyVal('natbib', 'authoryear', '', 'true');
364DefKeyVal('natbib', 'numbers',    '', 'true');
365DefKeyVal('natbib', 'super',      '', 'true');
366DefKeyVal('natbib', 'round',      '', 'true');
367DefKeyVal('natbib', 'square',     '', 'true');
368DefKeyVal('natbib', 'open',       '');
369DefKeyVal('natbib', 'close',      '');
370DefKeyVal('natbib', 'semicolon',  '');
371DefKeyVal('natbib', 'comma',      '');
372DefKeyVal('natbib', 'citesep',    '');
373DefKeyVal('natbib', 'aysep',      '');
374DefKeyVal('natbib', 'yysep',      '');
375DefKeyVal('natbib', 'notesep',    '');
376
377AssignValue(CITE_AY_SEPARATOR => T_OTHER(','));
378
379sub setCitationStyle {
380  my (@pairs) = @_;
381  while (@pairs) {
382    my ($key, $value) = (shift(@pairs), shift(@pairs));
383    $key = ToString(Digest($key)) if ref $key;
384    if    ($key eq 'authoryear') { AssignValue(CITE_STYLE => 'authoryear'); }
385    elsif ($key eq 'numbers')    { AssignValue(CITE_STYLE => 'numbers'); }
386    elsif ($key eq 'super')      { AssignValue(CITE_STYLE => 'super'); }
387    elsif ($key eq 'round')      { AssignValue(CITE_OPEN  => T_OTHER('('));
388      AssignValue(CITE_CLOSE => T_OTHER(')')); }
389    elsif ($key eq 'square') { AssignValue(CITE_OPEN => T_OTHER('['));
390      AssignValue(CITE_CLOSE => T_OTHER(']')); }
391    elsif ($key eq 'curly') { AssignValue(CITE_OPEN => T_OTHER('{'));
392      AssignValue(CITE_CLOSE => T_OTHER('}')); }
393    elsif ($key eq 'angle') { AssignValue(CITE_OPEN => T_OTHER('<'));
394      AssignValue(CITE_CLOSE => T_OTHER('>')); }
395    elsif ($key eq 'open')      { AssignValue(CITE_OPEN           => $value); }
396    elsif ($key eq 'close')     { AssignValue(CITE_CLOSE          => $value); }
397    elsif ($key eq 'semicolon') { AssignValue(CITE_SEPARATOR      => T_OTHER(';')); }
398    elsif ($key eq 'comma')     { AssignValue(CITE_SEPARATOR      => T_OTHER(',')); }
399    elsif ($key eq 'aysep')     { AssignValue(CITE_AY_SEPARATOR   => $value); }
400    elsif ($key eq 'yysep')     { AssignValue(CITE_YY_SEPARATOR   => $value); }
401    elsif ($key eq 'notesep')   { AssignValue(CITE_NOTE_SEPARATOR => $value); }
402    else {
403      Warn('unexpected', $key, undef, "Unexpected Citation Style keyword '$key'"); } }
404  return; }
405
406DefPrimitive('\setcitestyle RequiredKeyVals:natbib', sub {
407    setCitationStyle($_[1]->getPairs); });
408
409DefPrimitive('\bibpunct[]{}{}{}{}{}{}', sub {
410    my ($stomach, $notesep, $open, $close, $sep, $style, $aysep, $yysep) = @_;
411    $style = ToString(Digest($style));
412    AssignValue(CITE_OPEN      => $open);
413    AssignValue(CITE_CLOSE     => $close);
414    AssignValue(CITE_SEPARATOR => $sep);
415    AssignValue(CITE_STYLE => ($style eq 'n' ? 'numbers' : ($style eq 's' ? 'super' : 'authoryear')));
416    AssignValue(CITE_AY_SEPARATOR   => $aysep);
417    AssignValue(CITE_YY_SEPARATOR   => $yysep);
418    AssignValue(CITE_NOTE_SEPARATOR => $notesep) if $notesep;
419    return; });
420
421DefMacro('\citestyle{}', '\@citestyle{#1}\let\bibstyle\@gobble');
422
423DefMacro('\bibstyle@chicago',    '\bibpunct{(}{)}{;}{a}{,}{,}');
424DefMacro('\bibstyle@named',      '\bibpunct{[}{]}{;}{a}{,}{,}');
425DefMacro('\bibstyle@agu',        '\bibpunct{[}{]}{;}{a}{,}{,~}');    #Amer. Geophys. Union
426DefMacro('\bibstyle@copernicus', '\bibpunct{(}{)}{;}{a}{,}{,}');     #Copernicus Publications
427Let('\bibstyle@egu', '\bibstyle@copernicus');
428Let('\bibstyle@egs', '\bibstyle@copernicus');
429DefMacro('\bibstyle@agsm',     '\bibpunct{(}{)}{,}{a}{}{,}\gdef\harvardand{\&}');
430DefMacro('\bibstyle@kluwer',   '\bibpunct{(}{)}{,}{a}{}{,}\gdef\harvardand{\&}');
431DefMacro('\bibstyle@dcu',      '\bibpunct{(}{)}{;}{a}{;}{,}\gdef\harvardand{and}');
432DefMacro('\bibstyle@aa',       '\bibpunct{(}{)}{;}{a}{}{,}');        # Astronomy & Astrophysics
433DefMacro('\bibstyle@pass',     '\bibpunct{(}{)}{;}{a}{,}{,}');       #Planet. & Space Sci
434DefMacro('\bibstyle@anngeo',   '\bibpunct{(}{)}{;}{a}{,}{,}');       #Annales Geophysicae
435DefMacro('\bibstyle@nlinproc', '\bibpunct{(}{)}{;}{a}{,}{,}');       #Nonlin.Proc.Geophys.
436DefMacro('\bibstyle@cospar',   '\bibpunct{/}{/}{,}{n}{}{}');
437DefMacro('\bibstyle@esa',      '\bibpunct{(Ref.~}{)}{,}{n}{}{}');
438DefMacro('\bibstyle@nature',   '\bibpunct{}{}{,}{s}{}{\textsuperscript{,}}');
439DefMacro('\bibstyle@plain',    '\bibpunct{[}{]}{,}{n}{}{,}');
440Let('\bibstyle@alpha', '\bibstyle@plain');
441Let('\bibstyle@abbrv', '\bibstyle@plain');
442Let('\bibstyle@unsrt', '\bibstyle@plain');
443DefMacro('\bibstyle@plainnat', '\bibpunct{[}{]}{,}{a}{,}{,}');
444Let('\bibstyle@abbrvnat', '\bibstyle@plainnat');
445Let('\bibstyle@unsrtnat', '\bibstyle@plainnat');
446
447#======================================================================
448# 2.12 Other Formatting Options
449# mostly ignored...
450DefMacro('\bibsection',  '');
451DefMacro('\bibpreamble', '');
452DefMacro('\bibfont',     '');
453DefMacro('\citenumfont', '');
454DefMacro('\bibnumfmt{}', '#1');
455DefRegister('\bibhang', Dimension(0));
456DefRegister('\bibsep',  Dimension(0));
457
458#======================================================================
459# 2.13 Automatic Indexing of Citations
460# Ignored, but could be done...
461# However, it is basically equivalent to backrefs which are
462# automatically handled in MakeBibliography, anyway...
463RawTeX('\newif\ifciteindex');
464DefMacro('\citeindextrue',  '');
465DefMacro('\citeindexfalse', '');
466DefMacro('\citeindextype',  '');
467
468#======================================================================
469# 2.17 Long Author List on First Citation
470#  Ignored (for now...)
471DefMacro('\shortcites Semiverbatim', '');
472
473#======================================================================
474# Less Documented
475#  For manually formatted bibliographies, the following magical incantations
476# will be recognized to deliniate the author and year:
477#   \bibitem[Jones et al.(1990)]{key}...
478#   \bibitem[Jones et al.(1990)Jones, Baker, and Williams]{key}...
479#   \bibitem[Jones et al., 1990]{key}...
480#   \bibitem[\protect\citeauthoryear{Jones, Baker, and Williams}{Jones et al.}{1990}]{key}...
481#   \bibitem[\protect\citeauthoryear{Jones et al.}{1990}]{key}...
482#   \bibitem[\protect\astroncite{Jones et al.}{1990}]{key}...
483#   \bibitem[\protect\citename{Jones et al., }1990]{key}...
484#   \harvarditem[Jones et al.]{Jones, Baker, and Williams}{1990}{key}...
485
486DefMacro('\bibitem', '\reset@natbib@cites\refstepcounter{@bibitem}\@ifnextchar[{\@lbibitem}{\@lbibitem[\the@bibitem]}', locked => 1);
487
488RawTeX(<<'EOTeX');
489%%%
490\def\citeauthoryear#1#2#3(@)(@)\@nil#4{%
491  \if\relax#3\relax
492    \NAT@wrout{\the@bibitem}{#2}{#1}{}{#4}\else
493    \NAT@wrout{\the@bibitem}{#3}{#2}{#1}{#4}\fi}
494\let\natbib@citeauthoryear\citeauthoryear
495\def\astroncite#1#2(@)(@)\@nil#3{%
496  \NAT@wrout{\the@bibitem}{#2}{#1}{}{#3}}
497\let\natbib@astroncite\astroncite
498\def\citename#1#2(@)(@)\@nil#3{%
499  \expandafter\NAT@apalk#1#2, \@nil{#3}}
500\let\natbib@citename\citename
501\newcommand\harvarditem[4][]{%
502  \if\relax#1\relax\bibitem[#2(#3)]{#4}\else\bibitem[#1(#3)#2]{#4}\fi }
503%%%%
504\newcommand\NAT@ifcmd{\futurelet\NAT@temp\NAT@ifxcmd}
505\newcommand\NAT@ifxcmd{\ifx\NAT@temp\relax\else\expandafter\NAT@bare\fi}
506\def\NAT@bare#1(#2)#3(@)#4\@nil#5{%
507  \if @#2%
508    \expandafter\NAT@apalk#1, , \@nil{#5}\else
509    \NAT@wrout{\the@bibitem}{#2}{#1}{#3}{#5}\fi}
510\def\NAT@apalk#1, #2, #3\@nil#4{%
511  \if\relax#2\relax\NAT@wrout{#1}{}{}{}{#4}\else\NAT@wrout{\the@bibitem}{#2}{#1}{}{#4}\fi}
512%%%%
513EOTeX
514# Sometimes, perversely, redefined, so re-redefine them now...
515DefPrimitiveI('\reset@natbib@cites', undef, sub {
516    Let('\citeauthoryear', '\natbib@citeauthoryear');
517    Let('\astroncite',     '\natbib@astroncite');
518    Let('\citename',       '\natbib@citename'); });
519
520# By this time, \NAT@wrout should look like:
521# \NAT@wrout{number}{year}{authors}{fullauthors}{bibkey}
522# So, we'll do one extra step, and format the refnum form
523DefMacro('\NAT@wrout{}{}{}{} Semiverbatim', sub {
524    my ($gullet, $number, $year, $authors, $fullauthors, $key) = @_;
525    my ($style, $open, $close) = map { LookupValue($_) } qw(CITE_STYLE CITE_OPEN CITE_CLOSE);
526    $style = 'number' unless $authors->unlist && $year->unlist;
527    if ($style eq 'number') {
528      Invocation(T_CS('\NAT@@wrout'), $number, $year, $authors, $fullauthors,
529        Tokens($open, $number, $close),
530        $key)->unlist; }
531    else {
532      Invocation(T_CS('\NAT@@wrout'), $number, $year, $authors, $fullauthors,
533        Tokens($authors, T_SPACE, $open, $year, $close),
534        $key)->unlist; } });
535
536DefConstructor('\NAT@@wrout{}{}{}{}{} Semiverbatim',
537  "<ltx:tags>"
538    . "?#1(<ltx:tag role='number'>#1</ltx:tag>)"
539    . "?#2(<ltx:tag role='year'>#2</ltx:tag>)"
540    . "?#3(<ltx:tag role='authors'>#3</ltx:tag>)"
541    . "?#4(<ltx:tag role='fullauthors'>#4</ltx:tag>)"
542    . "?#5(<ltx:tag role='refnum'>#5</ltx:tag>)"
543    . "?#6(<ltx:tag role='key'>#6</ltx:tag>)"
544    . "</ltx:tags>",
545  # Allow plain & in here ???
546  bounded => 1, beforeDigest => sub { Let(T_ALIGN, '\&'); }
547);
548
549# see arXiv:cond-mat/0003435 for
550# an infinite loop we run into when this isn't locked
551# \@@lbibitem is a DefConstructor, so the connection should be kept
552DefMacro('\@lbibitem[]{}', '\@@lbibitem{#2}\NAT@ifcmd#1(@)(@)\@nil{#2}\newblock', locked => 1);
553
554# Similar to the one defined in LaTeX.pool, but the bibtag's have been setup above.
555DefConstructor('\@@lbibitem Semiverbatim',
556  "<ltx:bibitem key='#key' xml:id='#id'>",
557  afterDigest => sub {
558    my $key = CleanBibKey($_[1]->getArg(1));
559    my $id  = ToString(Expand(T_CS('\the@bibitem@ID')));
560    $_[1]->setProperties(key => $key, id => $id); });
561
562#======================================================================
563# These macros allow you to get the pieces used in the current style
564# but don't seem to be used in natbib, so redefining them does nothing.
565DefMacro('\citestarts',     sub { LookupValue('CITE_OPEN')->unlist; });
566DefMacro('\citeends',       sub { LookupValue('CITE_CLOSE')->unlist; });
567DefMacro('\betweenauthors', 'and');
568
569DefMacro('\harvardleft',      sub { LookupValue('CITE_OPEN')->unlist; });
570DefMacro('\harvardright',     sub { LookupValue('CITE_CLOSE')->unlist; });
571DefMacro('\harvardyearleft',  sub { LookupValue('CITE_OPEN')->unlist; });
572DefMacro('\harvardyearright', sub { LookupValue('CITE_CLOSE')->unlist; });
573DefMacro('\harvardand',       'and');
574
575DefConstructor('\harvardurl Semiverbatim',
576  "<ltx:ref href='#href'>#1</ltx:ref>",
577  properties => sub { (href => CleanURL(ToString($_[1]))); });
578
579Let('\citeN',      '\cite');
580Let('\shortcite',  '\cite');
581Let('\citeasnoun', '\cite');
582
583DefMacro('\natexlab{}', '#1');    # ????
584
5851;
586