3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
10 * \author Jürgen Spitzmüller
12 * Full author contact details are available in file CREDITS.
17 #include "BiblioInfo.h"
19 #include "BufferParams.h"
20 #include "buffer_funcs.h"
23 #include "InsetIterator.h"
25 #include "output_xhtml.h"
26 #include "Paragraph.h"
27 #include "TextClass.h"
28 #include "TocBackend.h"
30 #include "support/convert.h"
31 #include "support/debug.h"
32 #include "support/docstream.h"
33 #include "support/gettext.h"
34 #include "support/lassert.h"
35 #include "support/lstrings.h"
36 #include "support/regex.h"
37 #include "support/textutils.h"
43 using namespace lyx::support;
50 // Remove placeholders from names
51 docstring renormalize(docstring const & input)
53 docstring res = subst(input, from_ascii("$$space!"), from_ascii(" "));
54 return subst(res, from_ascii("$$comma!"), from_ascii(","));
58 // gets the "prename" and "family name" from an author-type string
59 pair<docstring, docstring> nameParts(docstring const & iname)
62 return make_pair(docstring(), docstring());
64 // First we check for goupings (via {...}) and replace blanks and
65 // commas inside groups with temporary placeholders
68 docstring::const_iterator p = iname.begin();
69 while (p != iname.end()) {
70 // count grouping level
75 // generate string with probable placeholders
76 if (*p == ' ' && gl > 0)
77 name += from_ascii("$$space!");
78 else if (*p == ',' && gl > 0)
79 name += from_ascii("$$comma!");
85 // Now we look for a comma, and take the last name to be everything
86 // preceding the right-most one, so that we also get the "jr" part.
87 vector<docstring> pieces = getVectorFromString(name);
88 if (pieces.size() > 1)
89 // whether we have a jr. part or not, it's always
90 // the first and last item (reversed)
91 return make_pair(renormalize(pieces.back()), renormalize(pieces.front()));
93 // OK, so now we want to look for the last name. We're going to
94 // include the "von" part. This isn't perfect.
95 // Split on spaces, to get various tokens.
96 pieces = getVectorFromString(name, from_ascii(" "));
97 // No space: Only a family name given
98 if (pieces.size() < 2)
99 return make_pair(from_ascii(""), renormalize(pieces.back()));
100 // If we get two pieces, assume the last one is the last name
101 if (pieces.size() == 2)
102 return make_pair(renormalize(pieces.front()), renormalize(pieces.back()));
104 // More than 3 pieces: Now we look for the first piece that
105 // begins with a lower case letter (the "von-part").
107 vector<docstring>::const_iterator it = pieces.begin();
108 vector<docstring>::const_iterator const en = pieces.end();
110 for (; it != en; ++it) {
113 char_type const c = (*it)[0];
114 // If the piece starts with a lower case char, we assume
115 // this is the "von-part" (family name prefix) and thus part
116 // of the family name.
119 // If this is the last piece, then what we now have is
123 // Nothing of the former, so add this piece to the prename
131 // Reconstruct the family name.
132 // Note that if we left the loop with because it + 1 == en,
133 // then this will still do the right thing, i.e., make surname
134 // just be the last piece.
137 for (; it != en; ++it) {
144 return make_pair(renormalize(prename), renormalize(surname));
148 docstring constructName(docstring const & name, string const scheme)
150 // re-constructs a name from name parts according
152 docstring const prename = nameParts(name).first;
153 docstring const surname = nameParts(name).second;
154 docstring result = from_ascii(scheme);
155 result = subst(result, from_ascii("%prename%"), prename);
156 result = subst(result, from_ascii("%surname%"), surname);
161 bool multipleAuthors(docstring const author)
163 vector<docstring> const authors =
164 getVectorFromString(author, from_ascii(" and "));
165 return authors.size() > 1;
169 // converts a string containing LaTeX commands into unicode
171 docstring convertLaTeXCommands(docstring const & str)
176 bool scanning_cmd = false;
177 bool scanning_math = false;
178 bool escaped = false; // used to catch \$, etc.
179 while (!val.empty()) {
180 char_type const ch = val[0];
182 // if we're scanning math, we output everything until we
183 // find an unescaped $, at which point we break out.
190 scanning_math = false;
196 // if we're scanning a command name, then we just
197 // discard characters until we hit something that
200 if (isAlphaASCII(ch)) {
205 // so we're done with this command.
206 // now we fall through and check this character.
207 scanning_cmd = false;
210 // was the last character a \? If so, then this is something like:
211 // \\ or \$, so we'll just output it. That's probably not always right...
213 // exception: output \, as THIN SPACE
215 ret.push_back(0x2009);
226 scanning_math = true;
230 // we just ignore braces
231 if (ch == '{' || ch == '}') {
236 // we're going to check things that look like commands, so if
237 // this doesn't, just output it.
244 // ok, could be a command of some sort
245 // let's see if it corresponds to some unicode
246 // unicodesymbols has things in the form: \"{u},
247 // whereas we may see things like: \"u. So we'll
248 // look for that and change it, if necessary.
249 // FIXME: This is a sort of mini-tex2lyx.
250 // Use the real tex2lyx instead!
251 static lyx::regex const reg("^\\\\\\W\\w");
252 if (lyx::regex_search(to_utf8(val), reg)) {
253 val.insert(3, from_ascii("}"));
254 val.insert(2, from_ascii("{"));
258 docstring const cnvtd = Encodings::fromLaTeXCommand(val,
259 Encodings::TEXT_CMD, termination, rem);
260 if (!cnvtd.empty()) {
261 // it did, so we'll take that bit and proceed with what's left
266 // it's a command of some sort
275 // Escape '<' and '>' and remove richtext markers (e.g. {!this is richtext!}) from a string.
276 docstring processRichtext(docstring const & str, bool richtext)
281 bool scanning_rich = false;
282 while (!val.empty()) {
283 char_type const ch = val[0];
284 if (ch == '{' && val.size() > 1 && val[1] == '!') {
285 // beginning of rich text
286 scanning_rich = true;
290 if (scanning_rich && ch == '!' && val.size() > 1 && val[1] == '}') {
292 scanning_rich = false;
300 // we need to escape '<' and '>'
308 } else if (!scanning_rich /* && !richtext */)
310 // else the character is discarded, which will happen only if
311 // richtext == false and we are scanning rich text
320 //////////////////////////////////////////////////////////////////////
324 //////////////////////////////////////////////////////////////////////
326 BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type)
327 : is_bibtex_(true), bib_key_(key), entry_type_(type), info_(),
333 docstring const BibTeXInfo::getAuthorOrEditorList(Buffer const * buf,
334 bool full, bool forceshort) const
336 docstring author = operator[]("author");
338 author = operator[]("editor");
340 return getAuthorList(buf, author, full, forceshort);
344 docstring const BibTeXInfo::getAuthorList(Buffer const * buf,
345 docstring const & author, bool const full, bool const forceshort,
346 bool const allnames, bool const beginning) const
348 // Maxnames treshold depend on engine
349 size_t maxnames = buf ?
350 buf->params().documentClass().max_citenames() : 2;
353 docstring const opt = label();
358 docstring const remainder = trim(split(opt, authors, '('));
359 if (remainder.empty())
360 // in this case, we didn't find a "(",
361 // so we don't have author (year)
369 // FIXME Move this to a separate routine that can
370 // be called from elsewhere.
372 // OK, we've got some names. Let's format them.
373 // Try to split the author list on " and "
374 vector<docstring> const authors =
375 getVectorFromString(author, from_ascii(" and "));
379 CiteEngineType const engine_type = buf ? buf->params().citeEngineType()
380 : ENGINE_TYPE_DEFAULT;
382 // These are defined in the styles
384 buf ? buf->params().documentClass().getCiteMacro(engine_type, "_etal")
386 string const namesep =
387 buf ? buf->params().documentClass().getCiteMacro(engine_type, "_namesep")
389 string const lastnamesep =
390 buf ? buf->params().documentClass().getCiteMacro(engine_type, "_lastnamesep")
392 string const pairnamesep =
393 buf ? buf->params().documentClass().getCiteMacro(engine_type, "_pairnamesep")
395 string firstnameform =
396 buf ? buf->params().documentClass().getCiteMacro(engine_type, "!firstnameform")
397 : "%surname%, %prename%";
399 firstnameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!firstbynameform")
400 : "%prename% %surname%";
401 string othernameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!othernameform")
402 : "%surname%, %prename%";
404 othernameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!otherbynameform")
405 : "%prename% %surname%";
407 // Shorten the list (with et al.) if forceshort is set
408 // and the list can actually be shortened, else if maxcitenames
409 // is passed and full is not set.
410 bool shorten = forceshort && authors.size() > 1;
411 vector<docstring>::const_iterator it = authors.begin();
412 vector<docstring>::const_iterator en = authors.end();
413 for (size_t i = 0; it != en; ++it, ++i) {
414 if (i >= maxnames && !full) {
418 if (*it == "others") {
419 retval += buf ? buf->B_(etal) : from_ascii(etal);
422 if (i > 0 && i == authors.size() - 1) {
423 if (authors.size() == 2)
424 retval += buf ? buf->B_(pairnamesep) : from_ascii(pairnamesep);
426 retval += buf ? buf->B_(lastnamesep) : from_ascii(lastnamesep);
428 retval += buf ? buf->B_(namesep) : from_ascii(namesep);
430 retval += (i == 0) ? constructName(*it, firstnameform)
431 : constructName(*it, othernameform);
433 retval += nameParts(*it).second;
437 retval = constructName(authors[0], firstnameform) + (buf ? buf->B_(etal) : from_ascii(etal));
439 retval = nameParts(authors[0]).second + (buf ? buf->B_(etal) : from_ascii(etal));
442 return convertLaTeXCommands(retval);
446 docstring const BibTeXInfo::getYear() const
449 // first try legacy year field
450 docstring year = operator[]("year");
453 // now try biblatex's date field
454 year = operator[]("date");
455 // Format is [-]YYYY-MM-DD*/[-]YYYY-MM-DD*
456 // We only want the years.
457 static regex const yreg("[-]?([\\d]{4}).*");
458 static regex const ereg(".*/[-]?([\\d]{4}).*");
460 string const date = to_utf8(year);
461 if (!regex_match(date, sm, yreg))
462 // cannot parse year.
464 year = from_ascii(sm[1]);
465 // check for an endyear
466 if (regex_match(date, sm, ereg))
467 year += char_type(0x2013) + from_ascii(sm[1]);
471 docstring const opt = label();
476 docstring tmp = split(opt, authors, '(');
478 // we don't have author (year)
481 tmp = split(tmp, year, ')');
488 docstring parseOptions(docstring const & format, string & optkey,
489 docstring & ifpart, docstring & elsepart);
491 // Calls parseOptions to deal with an embedded option, such as:
492 // {%number%[[, no.~%number%]]}
493 // which must appear at the start of format. ifelsepart gets the
494 // whole of the option, and we return what's left after the option.
495 // we return format if there is an error.
496 docstring parseEmbeddedOption(docstring const & format, docstring & ifelsepart)
498 LASSERT(format[0] == '{' && format[1] == '%', return format);
502 docstring const rest = parseOptions(format, optkey, ifpart, elsepart);
503 if (format == rest) { // parse error
504 LYXERR0("ERROR! Couldn't parse `" << format <<"'.");
507 LASSERT(rest.size() <= format.size(),
508 { ifelsepart = docstring(); return format; });
509 ifelsepart = format.substr(0, format.size() - rest.size());
514 // Gets a "clause" from a format string, where the clause is
515 // delimited by '[[' and ']]'. Returns what is left after the
516 // clause is removed, and returns format if there is an error.
517 docstring getClause(docstring const & format, docstring & clause)
519 docstring fmt = format;
522 // we'll remove characters from the front of fmt as we
524 while (!fmt.empty()) {
525 if (fmt[0] == ']' && fmt.size() > 1 && fmt[1] == ']') {
530 // check for an embedded option
531 if (fmt[0] == '{' && fmt.size() > 1 && fmt[1] == '%') {
533 docstring const rest = parseEmbeddedOption(fmt, part);
535 LYXERR0("ERROR! Couldn't parse embedded option in `" << format <<"'.");
540 } else { // it's just a normal character
549 // parse an options string, which must appear at the start of the
550 // format parameter. puts the parsed bits in optkey, ifpart, and
551 // elsepart and returns what's left after the option is removed.
552 // if there's an error, it returns format itself.
553 docstring parseOptions(docstring const & format, string & optkey,
554 docstring & ifpart, docstring & elsepart)
556 LASSERT(format[0] == '{' && format[1] == '%', return format);
558 docstring fmt = format.substr(2);
559 size_t pos = fmt.find('%'); // end of key
560 if (pos == string::npos) {
561 LYXERR0("Error parsing `" << format <<"'. Can't find end of key.");
564 optkey = to_utf8(fmt.substr(0, pos));
565 fmt = fmt.substr(pos + 1);
566 // [[format]] should be next
567 if (fmt[0] != '[' || fmt[1] != '[') {
568 LYXERR0("Error parsing `" << format <<"'. Can't find '[[' after key.");
572 docstring curfmt = fmt;
573 fmt = getClause(curfmt, ifpart);
575 LYXERR0("Error parsing `" << format <<"'. Couldn't get if clause.");
579 if (fmt[0] == '}') // we're done, no else clause
580 return fmt.substr(1);
582 // else part should follow
583 if (fmt[0] != '[' || fmt[1] != '[') {
584 LYXERR0("Error parsing `" << format <<"'. Can't find else clause.");
589 fmt = getClause(curfmt, elsepart);
591 if (fmt == curfmt || fmt[0] != '}') {
592 LYXERR0("Error parsing `" << format <<"'. Can't find end of option.");
595 return fmt.substr(1);
602 Bug #9131 revealed an oddity in how we are generating citation information
603 when more than one key is given. We end up building a longer and longer format
604 string as we go, which we then have to re-parse, over and over and over again,
605 rather than generating the information for the individual keys and then putting
606 all of that together. We do that to deal with the way separators work, from what
607 I can tell, but it still feels like a hack. Fixing this would require quite a
608 bit of work, however.
610 docstring BibTeXInfo::expandFormat(docstring const & format,
611 BibTeXInfoList const xrefs, int & counter, Buffer const & buf,
612 CiteItem const & ci, bool next, bool second) const
614 // incorrect use of macros could put us in an infinite loop
615 static int const max_passes = 5000;
616 // the use of overly large keys can lead to performance problems, due
617 // to eventual attempts to convert LaTeX macros to unicode. See bug
618 // #8944. By default, the size is limited to 128 (in CiteItem), but
619 // for specific purposes (such as XHTML export), it needs to be enlarged
620 // This is perhaps not the best solution, but it will have to do for now.
621 size_t const max_keysize = ci.max_key_size;
622 odocstringstream ret; // return value
624 bool scanning_key = false;
625 bool scanning_rich = false;
627 CiteEngineType const engine_type = buf.params().citeEngineType();
628 docstring fmt = format;
629 // we'll remove characters from the front of fmt as we
631 while (!fmt.empty()) {
632 if (counter > max_passes) {
633 LYXERR0("Recursion limit reached while parsing `"
638 char_type thischar = fmt[0];
639 if (thischar == '%') {
640 // beginning or end of key
643 scanning_key = false;
644 // so we replace the key with its value, which may be empty
648 buf.params().documentClass().getCiteMacro(engine_type, key);
649 fmt = from_utf8(val) + fmt.substr(1);
652 } else if (key[0] == '_') {
653 // a translatable bit
655 buf.params().documentClass().getCiteMacro(engine_type, key);
656 docstring const trans =
657 translateIfPossible(from_utf8(val), buf.params().language->code());
660 docstring const val =
661 getValueForKey(key, buf, ci, xrefs, max_keysize);
663 ret << from_ascii("{!<span class=\"bib-" + key + "\">!}");
666 ret << from_ascii("{!</span>!}");
674 else if (thischar == '{') {
675 // beginning of option?
677 LYXERR0("ERROR: Found `{' when scanning key in `" << format << "'.");
680 if (fmt.size() > 1) {
682 // it is the beginning of an optional format
686 docstring const newfmt =
687 parseOptions(fmt, optkey, ifpart, elsepart);
688 if (newfmt == fmt) // parse error
691 docstring const val =
692 getValueForKey(optkey, buf, ci, xrefs);
693 if (optkey == "next" && next)
694 ret << ifpart; // without expansion
695 else if (optkey == "second" && second) {
697 ret << expandFormat(ifpart, xrefs, newcounter, buf,
699 } else if (!val.empty()) {
701 ret << expandFormat(ifpart, xrefs, newcounter, buf,
703 } else if (!elsepart.empty()) {
705 ret << expandFormat(elsepart, xrefs, newcounter, buf,
708 // fmt will have been shortened for us already
712 // beginning of rich text
713 scanning_rich = true;
715 ret << from_ascii("{!");
719 // we are here if '{' was not followed by % or !.
720 // So it's just a character.
723 else if (scanning_rich && thischar == '!'
724 && fmt.size() > 1 && fmt[1] == '}') {
726 scanning_rich = false;
728 ret << from_ascii("!}");
731 else if (scanning_key)
732 key += char(thischar);
736 } catch (EncodingException & /* e */) {
737 LYXERR0("Uncodable character '" << docstring(1, thischar) << " in citation label!");
743 LYXERR0("Never found end of key in `" << format << "'!");
747 LYXERR0("Never found end of rich text in `" << format << "'!");
754 docstring const & BibTeXInfo::getInfo(BibTeXInfoList const xrefs,
755 Buffer const & buf, CiteItem const & ci) const
757 bool const richtext = ci.richtext;
759 if (!richtext && !info_.empty())
761 if (richtext && !info_richtext_.empty())
762 return info_richtext_;
765 BibTeXInfo::const_iterator it = find(from_ascii("ref"));
770 CiteEngineType const engine_type = buf.params().citeEngineType();
771 DocumentClass const & dc = buf.params().documentClass();
772 docstring const & format =
773 from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_)));
775 info_ = expandFormat(format, xrefs, counter, buf,
779 // this probably shouldn't happen
784 info_richtext_ = convertLaTeXCommands(processRichtext(info_, true));
785 return info_richtext_;
788 info_ = convertLaTeXCommands(processRichtext(info_, false));
793 docstring const BibTeXInfo::getLabel(BibTeXInfoList const xrefs,
794 Buffer const & buf, docstring const & format,
795 CiteItem const & ci, bool next, bool second) const
800 loclabel = expandFormat(format, xrefs, counter, buf, ci, next, second);
802 if (!loclabel.empty() && !next) {
803 loclabel = processRichtext(loclabel, ci.richtext);
804 loclabel = convertLaTeXCommands(loclabel);
811 docstring const & BibTeXInfo::operator[](docstring const & field) const
813 BibTeXInfo::const_iterator it = find(field);
816 static docstring const empty_value = docstring();
821 docstring const & BibTeXInfo::operator[](string const & field) const
823 return operator[](from_ascii(field));
827 docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
828 CiteItem const & ci, BibTeXInfoList const xrefs, size_t maxsize) const
830 // anything less is pointless
831 LASSERT(maxsize >= 16, maxsize = 16);
833 bool cleanit = false;
834 if (prefixIs(oldkey, "clean:")) {
835 key = oldkey.substr(6);
839 docstring ret = operator[](key);
840 if (ret.empty() && !xrefs.empty()) {
841 vector<BibTeXInfo const *>::const_iterator it = xrefs.begin();
842 vector<BibTeXInfo const *>::const_iterator en = xrefs.end();
843 for (; it != en; ++it) {
844 if (*it && !(**it)[key].empty()) {
852 // FIXME: dialog, textbefore and textafter have nothing to do with this
853 if (key == "dialog" && ci.context == CiteItem::Dialog)
854 ret = from_ascii("x"); // any non-empty string will do
855 else if (key == "export" && ci.context == CiteItem::Export)
856 ret = from_ascii("x"); // any non-empty string will do
857 else if (key == "ifstar" && ci.Starred)
858 ret = from_ascii("x"); // any non-empty string will do
859 else if (key == "ifqualified" && ci.isQualified)
860 ret = from_ascii("x"); // any non-empty string will do
861 else if (key == "entrytype")
863 else if (prefixIs(key, "ifentrytype:")
864 && from_ascii(key.substr(12)) == entry_type_)
865 ret = from_ascii("x"); // any non-empty string will do
866 else if (key == "key")
868 else if (key == "label")
870 else if (key == "modifier" && modifier_ != 0)
872 else if (key == "numericallabel")
874 else if (prefixIs(key, "ifmultiple:")) {
875 // Return whether we have multiple authors
876 docstring const kind = operator[](from_ascii(key.substr(11)));
877 if (multipleAuthors(kind))
878 ret = from_ascii("x"); // any non-empty string will do
880 else if (prefixIs(key, "abbrvnames:")) {
881 // Special key to provide abbreviated name list,
882 // with respect to maxcitenames. Suitable for Bibliography
884 docstring const kind = operator[](from_ascii(key.substr(11)));
885 ret = getAuthorList(&buf, kind, false, false, true);
886 if (ci.forceUpperCase && isLowerCase(ret[0]))
887 ret[0] = uppercase(ret[0]);
888 } else if (prefixIs(key, "fullnames:")) {
889 // Return a full name list. Suitable for Bibliography
891 docstring const kind = operator[](from_ascii(key.substr(10)));
892 ret = getAuthorList(&buf, kind, true, false, true);
893 if (ci.forceUpperCase && isLowerCase(ret[0]))
894 ret[0] = uppercase(ret[0]);
895 } else if (prefixIs(key, "forceabbrvnames:")) {
896 // Special key to provide abbreviated name lists,
897 // irrespective of maxcitenames. Suitable for Bibliography
899 docstring const kind = operator[](from_ascii(key.substr(15)));
900 ret = getAuthorList(&buf, kind, false, true, true);
901 if (ci.forceUpperCase && isLowerCase(ret[0]))
902 ret[0] = uppercase(ret[0]);
903 } else if (prefixIs(key, "abbrvbynames:")) {
904 // Special key to provide abbreviated name list,
905 // with respect to maxcitenames. Suitable for further names inside a
906 // bibliography item // (such as "ed. by ...")
907 docstring const kind = operator[](from_ascii(key.substr(11)));
908 ret = getAuthorList(&buf, kind, false, false, true, false);
909 if (ci.forceUpperCase && isLowerCase(ret[0]))
910 ret[0] = uppercase(ret[0]);
911 } else if (prefixIs(key, "fullbynames:")) {
912 // Return a full name list. Suitable for further names inside a
913 // bibliography item // (such as "ed. by ...")
914 docstring const kind = operator[](from_ascii(key.substr(10)));
915 ret = getAuthorList(&buf, kind, true, false, true, false);
916 if (ci.forceUpperCase && isLowerCase(ret[0]))
917 ret[0] = uppercase(ret[0]);
918 } else if (prefixIs(key, "forceabbrvbynames:")) {
919 // Special key to provide abbreviated name lists,
920 // irrespective of maxcitenames. Suitable for further names inside a
921 // bibliography item // (such as "ed. by ...")
922 docstring const kind = operator[](from_ascii(key.substr(15)));
923 ret = getAuthorList(&buf, kind, false, true, true, false);
924 if (ci.forceUpperCase && isLowerCase(ret[0]))
925 ret[0] = uppercase(ret[0]);
926 } else if (key == "abbrvciteauthor") {
927 // Special key to provide abbreviated author or
928 // editor names (suitable for citation labels),
929 // with respect to maxcitenames.
930 ret = getAuthorOrEditorList(&buf, false, false);
931 if (ci.forceUpperCase && isLowerCase(ret[0]))
932 ret[0] = uppercase(ret[0]);
933 } else if (key == "fullciteauthor") {
934 // Return a full author or editor list (for citation labels)
935 ret = getAuthorOrEditorList(&buf, true, false);
936 if (ci.forceUpperCase && isLowerCase(ret[0]))
937 ret[0] = uppercase(ret[0]);
938 } else if (key == "forceabbrvciteauthor") {
939 // Special key to provide abbreviated author or
940 // editor names (suitable for citation labels),
941 // irrespective of maxcitenames.
942 ret = getAuthorOrEditorList(&buf, false, true);
943 if (ci.forceUpperCase && isLowerCase(ret[0]))
944 ret[0] = uppercase(ret[0]);
945 } else if (key == "bibentry") {
946 // Special key to provide the full bibliography entry: see getInfo()
947 CiteEngineType const engine_type = buf.params().citeEngineType();
948 DocumentClass const & dc = buf.params().documentClass();
949 docstring const & format =
950 from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_), false));
952 ret = expandFormat(format, xrefs, counter, buf, ci, false, false);
953 } else if (key == "textbefore")
955 else if (key == "textafter")
957 else if (key == "curpretext")
958 ret = ci.getPretexts()[bib_key_];
959 else if (key == "curposttext")
960 ret = ci.getPosttexts()[bib_key_];
961 else if (key == "year")
966 ret = html::cleanAttr(ret);
968 // make sure it is not too big
969 support::truncateWithEllipsis(ret, maxsize);
974 //////////////////////////////////////////////////////////////////////
978 //////////////////////////////////////////////////////////////////////
982 // A functor for use with sort, leading to case insensitive sorting
983 class compareNoCase: public binary_function<docstring, docstring, bool>
986 bool operator()(docstring const & s1, docstring const & s2) const {
987 return compare_no_case(s1, s2) < 0;
994 vector<docstring> const BiblioInfo::getXRefs(BibTeXInfo const & data, bool const nested) const
996 vector<docstring> result;
997 if (!data.isBibTeX())
999 // Legacy crossref field. This is not nestable.
1000 if (!nested && !data["crossref"].empty()) {
1001 docstring const xrefkey = data["crossref"];
1002 result.push_back(xrefkey);
1003 // However, check for nested xdatas
1004 BiblioInfo::const_iterator it = find(xrefkey);
1006 BibTeXInfo const & xref = it->second;
1007 vector<docstring> const nxdata = getXRefs(xref, true);
1008 if (!nxdata.empty())
1009 result.insert(result.end(), nxdata.begin(), nxdata.end());
1012 // Biblatex's xdata field. Infinitely nestable.
1013 // XData field can consist of a comma-separated list of keys
1014 vector<docstring> const xdatakeys = getVectorFromString(data["xdata"]);
1015 if (!xdatakeys.empty()) {
1016 vector<docstring>::const_iterator xit = xdatakeys.begin();
1017 vector<docstring>::const_iterator xen = xdatakeys.end();
1018 for (; xit != xen; ++xit) {
1019 docstring const xdatakey = *xit;
1020 result.push_back(xdatakey);
1021 BiblioInfo::const_iterator it = find(xdatakey);
1023 BibTeXInfo const & xdata = it->second;
1024 vector<docstring> const nxdata = getXRefs(xdata, true);
1025 if (!nxdata.empty())
1026 result.insert(result.end(), nxdata.begin(), nxdata.end());
1034 vector<docstring> const BiblioInfo::getKeys() const
1036 vector<docstring> bibkeys;
1037 BiblioInfo::const_iterator it = begin();
1038 for (; it != end(); ++it)
1039 bibkeys.push_back(it->first);
1040 sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
1045 vector<docstring> const BiblioInfo::getFields() const
1047 vector<docstring> bibfields;
1048 set<docstring>::const_iterator it = field_names_.begin();
1049 set<docstring>::const_iterator end = field_names_.end();
1050 for (; it != end; ++it)
1051 bibfields.push_back(*it);
1052 sort(bibfields.begin(), bibfields.end());
1057 vector<docstring> const BiblioInfo::getEntries() const
1059 vector<docstring> bibentries;
1060 set<docstring>::const_iterator it = entry_types_.begin();
1061 set<docstring>::const_iterator end = entry_types_.end();
1062 for (; it != end; ++it)
1063 bibentries.push_back(*it);
1064 sort(bibentries.begin(), bibentries.end());
1069 docstring const BiblioInfo::getAuthorOrEditorList(docstring const & key, Buffer const & buf) const
1071 BiblioInfo::const_iterator it = find(key);
1074 BibTeXInfo const & data = it->second;
1075 return data.getAuthorOrEditorList(&buf, false);
1079 docstring const BiblioInfo::getCiteNumber(docstring const & key) const
1081 BiblioInfo::const_iterator it = find(key);
1084 BibTeXInfo const & data = it->second;
1085 return data.citeNumber();
1089 docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) const
1091 BiblioInfo::const_iterator it = find(key);
1094 BibTeXInfo const & data = it->second;
1095 docstring year = data.getYear();
1097 // let's try the crossrefs
1098 vector<docstring> const xrefs = getXRefs(data);
1102 vector<docstring>::const_iterator it = xrefs.begin();
1103 vector<docstring>::const_iterator en = xrefs.end();
1104 for (; it != en; ++it) {
1105 BiblioInfo::const_iterator const xrefit = find(*it);
1106 if (xrefit == end())
1108 BibTeXInfo const & xref_data = xrefit->second;
1109 year = xref_data.getYear();
1115 if (use_modifier && data.modifier() != 0)
1116 year += data.modifier();
1121 docstring const BiblioInfo::getYear(docstring const & key, Buffer const & buf, bool use_modifier) const
1123 docstring const year = getYear(key, use_modifier);
1125 return buf.B_("No year");
1130 docstring const BiblioInfo::getInfo(docstring const & key,
1131 Buffer const & buf, CiteItem const & ci) const
1133 BiblioInfo::const_iterator it = find(key);
1135 return docstring(_("Bibliography entry not found!"));
1136 BibTeXInfo const & data = it->second;
1137 BibTeXInfoList xrefptrs;
1138 vector<docstring> const xrefs = getXRefs(data);
1139 if (!xrefs.empty()) {
1140 vector<docstring>::const_iterator it = xrefs.begin();
1141 vector<docstring>::const_iterator en = xrefs.end();
1142 for (; it != en; ++it) {
1143 BiblioInfo::const_iterator const xrefit = find(*it);
1144 if (xrefit != end())
1145 xrefptrs.push_back(&(xrefit->second));
1148 return data.getInfo(xrefptrs, buf, ci);
1152 docstring const BiblioInfo::getLabel(vector<docstring> keys,
1153 Buffer const & buf, string const & style, CiteItem const & ci) const
1155 size_t max_size = ci.max_size;
1156 // shorter makes no sense
1157 LASSERT(max_size >= 16, max_size = 16);
1159 // we can't display more than 10 of these, anyway
1160 bool const too_many_keys = keys.size() > 10;
1164 CiteEngineType const engine_type = buf.params().citeEngineType();
1165 DocumentClass const & dc = buf.params().documentClass();
1166 docstring const & format = from_utf8(dc.getCiteFormat(engine_type, style, false, "cite"));
1167 docstring ret = format;
1168 vector<docstring>::const_iterator key = keys.begin();
1169 vector<docstring>::const_iterator ken = keys.end();
1170 for (int i = 0; key != ken; ++key, ++i) {
1171 BiblioInfo::const_iterator it = find(*key);
1172 BibTeXInfo empty_data;
1173 empty_data.key(*key);
1174 BibTeXInfo & data = empty_data;
1175 vector<BibTeXInfo const *> xrefptrs;
1178 vector<docstring> const xrefs = getXRefs(data);
1179 if (!xrefs.empty()) {
1180 vector<docstring>::const_iterator it = xrefs.begin();
1181 vector<docstring>::const_iterator en = xrefs.end();
1182 for (; it != en; ++it) {
1183 BiblioInfo::const_iterator const xrefit = find(*it);
1184 if (xrefit != end())
1185 xrefptrs.push_back(&(xrefit->second));
1189 ret = data.getLabel(xrefptrs, buf, ret, ci, key + 1 != ken, i == 1);
1193 ret.push_back(0x2026);//HORIZONTAL ELLIPSIS
1194 support::truncateWithEllipsis(ret, max_size);
1199 bool BiblioInfo::isBibtex(docstring const & key) const
1202 split(key, key1, ',');
1203 BiblioInfo::const_iterator it = find(key1);
1206 return it->second.isBibTeX();
1210 vector<docstring> const BiblioInfo::getCiteStrings(
1211 vector<docstring> const & keys, vector<CitationStyle> const & styles,
1212 Buffer const & buf, CiteItem const & ci) const
1215 return vector<docstring>();
1218 vector<docstring> vec(styles.size());
1219 for (size_t i = 0; i != vec.size(); ++i) {
1220 style = styles[i].name;
1221 vec[i] = getLabel(keys, buf, style, ci);
1228 void BiblioInfo::mergeBiblioInfo(BiblioInfo const & info)
1230 bimap_.insert(info.begin(), info.end());
1231 field_names_.insert(info.field_names_.begin(), info.field_names_.end());
1232 entry_types_.insert(info.entry_types_.begin(), info.entry_types_.end());
1238 // used in xhtml to sort a list of BibTeXInfo objects
1239 bool lSorter(BibTeXInfo const * lhs, BibTeXInfo const * rhs)
1241 docstring const lauth = lhs->getAuthorOrEditorList();
1242 docstring const rauth = rhs->getAuthorOrEditorList();
1243 docstring const lyear = lhs->getYear();
1244 docstring const ryear = rhs->getYear();
1245 docstring const ltitl = lhs->operator[]("title");
1246 docstring const rtitl = rhs->operator[]("title");
1247 return (lauth < rauth)
1248 || (lauth == rauth && lyear < ryear)
1249 || (lauth == rauth && lyear == ryear && ltitl < rtitl);
1255 void BiblioInfo::collectCitedEntries(Buffer const & buf)
1257 cited_entries_.clear();
1258 // We are going to collect all the citation keys used in the document,
1259 // getting them from the TOC.
1260 // FIXME We may want to collect these differently, in the first case,
1261 // so that we might have them in order of appearance.
1262 set<docstring> citekeys;
1263 shared_ptr<Toc const> toc = buf.tocBackend().toc("citation");
1264 Toc::const_iterator it = toc->begin();
1265 Toc::const_iterator const en = toc->end();
1266 for (; it != en; ++it) {
1267 if (it->str().empty())
1269 vector<docstring> const keys = getVectorFromString(it->str());
1270 citekeys.insert(keys.begin(), keys.end());
1272 if (citekeys.empty())
1275 // We have a set of the keys used in this document.
1276 // We will now convert it to a list of the BibTeXInfo objects used in
1278 vector<BibTeXInfo const *> bi;
1279 set<docstring>::const_iterator cit = citekeys.begin();
1280 set<docstring>::const_iterator const cen = citekeys.end();
1281 for (; cit != cen; ++cit) {
1282 BiblioInfo::const_iterator const bt = find(*cit);
1283 if (bt == end() || !bt->second.isBibTeX())
1285 bi.push_back(&(bt->second));
1288 sort(bi.begin(), bi.end(), lSorter);
1290 // Now we can write the sorted keys
1291 vector<BibTeXInfo const *>::const_iterator bit = bi.begin();
1292 vector<BibTeXInfo const *>::const_iterator ben = bi.end();
1293 for (; bit != ben; ++bit)
1294 cited_entries_.push_back((*bit)->key());
1298 void BiblioInfo::makeCitationLabels(Buffer const & buf)
1300 collectCitedEntries(buf);
1301 CiteEngineType const engine_type = buf.params().citeEngineType();
1302 bool const numbers = (engine_type & ENGINE_TYPE_NUMERICAL);
1306 // used to remember the last one we saw
1307 // we'll be comparing entries to see if we need to add
1308 // modifiers, like "1984a"
1309 map<docstring, BibTeXInfo>::iterator last = bimap_.end();
1311 vector<docstring>::const_iterator it = cited_entries_.begin();
1312 vector<docstring>::const_iterator const en = cited_entries_.end();
1313 for (; it != en; ++it) {
1314 map<docstring, BibTeXInfo>::iterator const biit = bimap_.find(*it);
1315 // this shouldn't happen, but...
1316 if (biit == bimap_.end())
1317 // ...fail gracefully, anyway.
1319 BibTeXInfo & entry = biit->second;
1321 docstring const num = convert<docstring>(++keynumber);
1322 entry.setCiteNumber(num);
1324 // The first test here is checking whether this is the first
1325 // time through the loop. If so, then we do not have anything
1326 // with which to compare.
1327 if (last != bimap_.end()
1328 && entry.getAuthorOrEditorList() == last->second.getAuthorOrEditorList()
1329 // we access the year via getYear() so as to get it from the xref,
1330 // if we need to do so
1331 && getYear(entry.key()) == getYear(last->second.key())) {
1332 if (modifier == 0) {
1333 // so the last one should have been 'a'
1334 last->second.setModifier('a');
1336 } else if (modifier == 'z')
1343 entry.setModifier(modifier);
1344 // remember the last one
1349 it = cited_entries_.begin();
1350 for (; it != en; ++it) {
1351 map<docstring, BibTeXInfo>::iterator const biit = bimap_.find(*it);
1352 // this shouldn't happen, but...
1353 if (biit == bimap_.end())
1354 // ...fail gracefully, anyway.
1356 BibTeXInfo & entry = biit->second;
1358 entry.label(entry.citeNumber());
1360 docstring const auth = entry.getAuthorOrEditorList(&buf, false);
1361 // we do it this way so as to access the xref, if necessary
1362 // note that this also gives us the modifier
1363 docstring const year = getYear(*it, buf, true);
1364 if (!auth.empty() && !year.empty())
1365 entry.label(auth + ' ' + year);
1367 entry.label(entry.key());
1373 //////////////////////////////////////////////////////////////////////
1377 //////////////////////////////////////////////////////////////////////
1380 CitationStyle citationStyleFromString(string const & command,
1381 BufferParams const & params)
1384 if (command.empty())
1387 string const alias = params.getCiteAlias(command);
1388 string cmd = alias.empty() ? command : alias;
1389 if (isUpperCase(command[0])) {
1390 cs.forceUpperCase = true;
1391 cmd[0] = lowercase(cmd[0]);
1394 size_t const n = command.size() - 1;
1395 if (command[n] == '*') {
1396 cs.hasStarredVersion = true;
1397 if (suffixIs(cmd, '*'))
1398 cmd = cmd.substr(0, cmd.size() - 1);
1406 string citationStyleToString(const CitationStyle & cs, bool const latex)
1408 string cmd = latex ? cs.cmd : cs.name;
1409 if (cs.forceUpperCase)
1410 cmd[0] = uppercase(cmd[0]);
1411 if (cs.hasStarredVersion)