3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
11 * Full author contact details are available in file CREDITS.
16 #include "BiblioInfo.h"
18 #include "BufferParams.h"
19 #include "buffer_funcs.h"
22 #include "InsetIterator.h"
24 #include "output_xhtml.h"
25 #include "Paragraph.h"
26 #include "TextClass.h"
27 #include "TocBackend.h"
29 #include "support/convert.h"
30 #include "support/debug.h"
31 #include "support/docstream.h"
32 #include "support/gettext.h"
33 #include "support/lassert.h"
34 #include "support/lstrings.h"
35 #include "support/regex.h"
36 #include "support/textutils.h"
41 using namespace lyx::support;
48 // gets the "family name" from an author-type string
49 docstring familyName(docstring const & name)
54 // first we look for a comma, and take the last name to be everything
55 // preceding the right-most one, so that we also get the "jr" part.
56 docstring::size_type idx = name.rfind(',');
57 if (idx != docstring::npos)
58 return ltrim(name.substr(0, idx));
60 // OK, so now we want to look for the last name. We're going to
61 // include the "von" part. This isn't perfect.
62 // Split on spaces, to get various tokens.
63 vector<docstring> pieces = getVectorFromString(name, from_ascii(" "));
64 // If we only get two, assume the last one is the last name
65 if (pieces.size() <= 2)
68 // Now we look for the first token that begins with a lower case letter.
69 vector<docstring>::const_iterator it = pieces.begin();
70 vector<docstring>::const_iterator en = pieces.end();
71 for (; it != en; ++it) {
74 char_type const c = (*it)[0];
79 if (it == en) // we never found a "von"
82 // reconstruct what we need to return
85 for (; it != en; ++it) {
96 // converts a string containing LaTeX commands into unicode
98 docstring convertLaTeXCommands(docstring const & str)
103 bool scanning_cmd = false;
104 bool scanning_math = false;
105 bool escaped = false; // used to catch \$, etc.
106 while (!val.empty()) {
107 char_type const ch = val[0];
109 // if we're scanning math, we output everything until we
110 // find an unescaped $, at which point we break out.
117 scanning_math = false;
123 // if we're scanning a command name, then we just
124 // discard characters until we hit something that
127 if (isAlphaASCII(ch)) {
132 // so we're done with this command.
133 // now we fall through and check this character.
134 scanning_cmd = false;
137 // was the last character a \? If so, then this is something like:
138 // \\ or \$, so we'll just output it. That's probably not always right...
140 // exception: output \, as THIN SPACE
142 ret.push_back(0x2009);
153 scanning_math = true;
157 // we just ignore braces
158 if (ch == '{' || ch == '}') {
163 // we're going to check things that look like commands, so if
164 // this doesn't, just output it.
171 // ok, could be a command of some sort
172 // let's see if it corresponds to some unicode
173 // unicodesymbols has things in the form: \"{u},
174 // whereas we may see things like: \"u. So we'll
175 // look for that and change it, if necessary.
176 // FIXME: This is a sort of mini-tex2lyx.
177 // Use the real tex2lyx instead!
178 static lyx::regex const reg("^\\\\\\W\\w");
179 if (lyx::regex_search(to_utf8(val), reg)) {
180 val.insert(3, from_ascii("}"));
181 val.insert(2, from_ascii("{"));
185 docstring const cnvtd = Encodings::fromLaTeXCommand(val,
186 Encodings::TEXT_CMD, termination, rem);
187 if (!cnvtd.empty()) {
188 // it did, so we'll take that bit and proceed with what's left
193 // it's a command of some sort
202 // Escape '<' and '>' and remove richtext markers (e.g. {!this is richtext!}) from a string.
203 docstring processRichtext(docstring const & str, bool richtext)
208 bool scanning_rich = false;
209 while (!val.empty()) {
210 char_type const ch = val[0];
211 if (ch == '{' && val.size() > 1 && val[1] == '!') {
212 // beginning of rich text
213 scanning_rich = true;
217 if (scanning_rich && ch == '!' && val.size() > 1 && val[1] == '}') {
219 scanning_rich = false;
227 // we need to escape '<' and '>'
235 } else if (!scanning_rich /* && !richtext */)
237 // else the character is discarded, which will happen only if
238 // richtext == false and we are scanning rich text
247 //////////////////////////////////////////////////////////////////////
251 //////////////////////////////////////////////////////////////////////
253 BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type)
254 : is_bibtex_(true), bib_key_(key), entry_type_(type), info_(),
259 docstring const BibTeXInfo::getAuthorList(
260 Buffer const * buf, bool full, bool forceshort) const
262 // Maxnames treshold depend on engine
263 size_t maxnames = buf ?
264 buf->params().documentClass().max_citenames() : 2;
267 docstring const opt = label();
272 docstring const remainder = trim(split(opt, authors, '('));
273 if (remainder.empty())
274 // in this case, we didn't find a "(",
275 // so we don't have author (year)
280 docstring author = operator[]("author");
281 if (author.empty()) {
282 author = operator[]("editor");
287 // FIXME Move this to a separate routine that can
288 // be called from elsewhere.
290 // OK, we've got some names. Let's format them.
291 // Try to split the author list on " and "
292 vector<docstring> const authors =
293 getVectorFromString(author, from_ascii(" and "));
295 if (jurabib_style && (authors.size() == 2 || authors.size() == 3)) {
296 docstring shortauthor = familyName(authors[0])
297 + "/" + familyName(authors[1]);
298 if (authors.size() == 3)
299 shortauthor += "/" + familyName(authors[2]);
300 return convertLaTeXCommands(shortauthor);
304 CiteEngineType const engine_type = buf ? buf->params().citeEngineType()
305 : ENGINE_TYPE_DEFAULT;
307 // These are defined in the styles
309 buf ? buf->params().documentClass().getCiteMacro(engine_type, "_etal")
311 string const namesep =
312 buf ? buf->params().documentClass().getCiteMacro(engine_type, "_namesep")
314 string const lastnamesep =
315 buf ? buf->params().documentClass().getCiteMacro(engine_type, "_lastnamesep")
317 string const pairnamesep =
318 buf ? buf->params().documentClass().getCiteMacro(engine_type, "_pairnamesep")
321 // Shorten the list (with et al.) if forceshort is set
322 // and the list can actually be shorten, else if maxcitenames
323 // is passed and full is not set.
324 bool shorten = forceshort && authors.size() > 1;
325 vector<docstring>::const_iterator it = authors.begin();
326 vector<docstring>::const_iterator en = authors.end();
327 for (size_t i = 0; it != en; ++it, ++i) {
328 if (i >= maxnames && !full) {
332 if (*it == "others") {
333 retval += buf ? buf->B_(etal) : from_ascii(etal);
336 if (i > 0 && i == authors.size() - 1) {
337 if (authors.size() == 2)
338 retval += buf ? buf->B_(pairnamesep) : from_ascii(pairnamesep);
340 retval += buf ? buf->B_(lastnamesep) : from_ascii(lastnamesep);
342 retval += buf ? buf->B_(namesep) : from_ascii(namesep);
343 retval += familyName(*it);
346 retval = familyName(authors[0]) + (buf ? buf->B_(etal) : from_ascii(etal));
348 return convertLaTeXCommands(retval);
352 docstring const BibTeXInfo::getYear() const
355 // first try legacy year field
356 docstring year = operator[]("year");
359 // now try biblatex's date field
360 year = operator[]("date");
361 // Format is [-]YYYY-MM-DD*/[-]YYYY-MM-DD*
362 // We only want the years.
363 static regex const yreg("[-]?([\\d]{4}).*");
364 static regex const ereg(".*/[-]?([\\d]{4}).*");
366 string const date = to_utf8(year);
367 regex_match(date, sm, yreg);
368 year = from_ascii(sm[1]);
369 // check for an endyear
370 if (regex_match(date, sm, ereg))
371 year += char_type(0x2013) + from_ascii(sm[1]);
375 docstring const opt = label();
380 docstring tmp = split(opt, authors, '(');
382 // we don't have author (year)
385 tmp = split(tmp, year, ')');
392 docstring parseOptions(docstring const & format, string & optkey,
393 docstring & ifpart, docstring & elsepart);
395 // Calls parseOptions to deal with an embedded option, such as:
396 // {%number%[[, no.~%number%]]}
397 // which must appear at the start of format. ifelsepart gets the
398 // whole of the option, and we return what's left after the option.
399 // we return format if there is an error.
400 docstring parseEmbeddedOption(docstring const & format, docstring & ifelsepart)
402 LASSERT(format[0] == '{' && format[1] == '%', return format);
406 docstring const rest = parseOptions(format, optkey, ifpart, elsepart);
407 if (format == rest) { // parse error
408 LYXERR0("ERROR! Couldn't parse `" << format <<"'.");
411 LASSERT(rest.size() <= format.size(),
412 { ifelsepart = docstring(); return format; });
413 ifelsepart = format.substr(0, format.size() - rest.size());
418 // Gets a "clause" from a format string, where the clause is
419 // delimited by '[[' and ']]'. Returns what is left after the
420 // clause is removed, and returns format if there is an error.
421 docstring getClause(docstring const & format, docstring & clause)
423 docstring fmt = format;
426 // we'll remove characters from the front of fmt as we
428 while (!fmt.empty()) {
429 if (fmt[0] == ']' && fmt.size() > 1 && fmt[1] == ']') {
434 // check for an embedded option
435 if (fmt[0] == '{' && fmt.size() > 1 && fmt[1] == '%') {
437 docstring const rest = parseEmbeddedOption(fmt, part);
439 LYXERR0("ERROR! Couldn't parse embedded option in `" << format <<"'.");
444 } else { // it's just a normal character
453 // parse an options string, which must appear at the start of the
454 // format parameter. puts the parsed bits in optkey, ifpart, and
455 // elsepart and returns what's left after the option is removed.
456 // if there's an error, it returns format itself.
457 docstring parseOptions(docstring const & format, string & optkey,
458 docstring & ifpart, docstring & elsepart)
460 LASSERT(format[0] == '{' && format[1] == '%', return format);
462 docstring fmt = format.substr(2);
463 size_t pos = fmt.find('%'); // end of key
464 if (pos == string::npos) {
465 LYXERR0("Error parsing `" << format <<"'. Can't find end of key.");
468 optkey = to_utf8(fmt.substr(0, pos));
469 fmt = fmt.substr(pos + 1);
470 // [[format]] should be next
471 if (fmt[0] != '[' || fmt[1] != '[') {
472 LYXERR0("Error parsing `" << format <<"'. Can't find '[[' after key.");
476 docstring curfmt = fmt;
477 fmt = getClause(curfmt, ifpart);
479 LYXERR0("Error parsing `" << format <<"'. Couldn't get if clause.");
483 if (fmt[0] == '}') // we're done, no else clause
484 return fmt.substr(1);
486 // else part should follow
487 if (fmt[0] != '[' || fmt[1] != '[') {
488 LYXERR0("Error parsing `" << format <<"'. Can't find else clause.");
493 fmt = getClause(curfmt, elsepart);
495 if (fmt == curfmt || fmt[0] != '}') {
496 LYXERR0("Error parsing `" << format <<"'. Can't find end of option.");
499 return fmt.substr(1);
506 Bug #9131 revealed an oddity in how we are generating citation information
507 when more than one key is given. We end up building a longer and longer format
508 string as we go, which we then have to re-parse, over and over and over again,
509 rather than generating the information for the individual keys and then putting
510 all of that together. We do that to deal with the way separators work, from what
511 I can tell, but it still feels like a hack. Fixing this would require quite a
512 bit of work, however.
514 docstring BibTeXInfo::expandFormat(docstring const & format,
515 BibTeXInfoList const xrefs, int & counter, Buffer const & buf,
516 CiteItem const & ci, bool next, bool second) const
518 // incorrect use of macros could put us in an infinite loop
519 static int const max_passes = 5000;
520 // the use of overly large keys can lead to performance problems, due
521 // to eventual attempts to convert LaTeX macros to unicode. See bug
522 // #8944. This is perhaps not the best solution, but it will have to
524 static size_t const max_keysize = 128;
525 odocstringstream ret; // return value
527 bool scanning_key = false;
528 bool scanning_rich = false;
530 CiteEngineType const engine_type = buf.params().citeEngineType();
531 docstring fmt = format;
532 // we'll remove characters from the front of fmt as we
534 while (!fmt.empty()) {
535 if (counter > max_passes) {
536 LYXERR0("Recursion limit reached while parsing `"
541 char_type thischar = fmt[0];
542 if (thischar == '%') {
543 // beginning or end of key
546 scanning_key = false;
547 // so we replace the key with its value, which may be empty
551 buf.params().documentClass().getCiteMacro(engine_type, key);
552 fmt = from_utf8(val) + fmt.substr(1);
555 } else if (key[0] == '_') {
556 // a translatable bit
558 buf.params().documentClass().getCiteMacro(engine_type, key);
559 docstring const trans =
560 translateIfPossible(from_utf8(val), buf.params().language->code());
563 docstring const val =
564 getValueForKey(key, buf, ci, xrefs, max_keysize);
566 ret << from_ascii("{!<span class=\"bib-" + key + "\">!}");
569 ret << from_ascii("{!</span>!}");
577 else if (thischar == '{') {
578 // beginning of option?
580 LYXERR0("ERROR: Found `{' when scanning key in `" << format << "'.");
583 if (fmt.size() > 1) {
585 // it is the beginning of an optional format
589 docstring const newfmt =
590 parseOptions(fmt, optkey, ifpart, elsepart);
591 if (newfmt == fmt) // parse error
594 docstring const val =
595 getValueForKey(optkey, buf, ci, xrefs);
596 if (optkey == "next" && next)
597 ret << ifpart; // without expansion
598 else if (!val.empty()) {
600 ret << expandFormat(ifpart, xrefs, newcounter, buf,
602 } else if (!elsepart.empty()) {
604 ret << expandFormat(elsepart, xrefs, newcounter, buf,
607 // fmt will have been shortened for us already
611 // beginning of rich text
612 scanning_rich = true;
614 ret << from_ascii("{!");
618 // we are here if '{' was not followed by % or !.
619 // So it's just a character.
622 else if (scanning_rich && thischar == '!'
623 && fmt.size() > 1 && fmt[1] == '}') {
625 scanning_rich = false;
627 ret << from_ascii("!}");
630 else if (scanning_key)
631 key += char(thischar);
635 } catch (EncodingException & /* e */) {
636 LYXERR0("Uncodable character '" << docstring(1, thischar) << " in citation label!");
642 LYXERR0("Never found end of key in `" << format << "'!");
646 LYXERR0("Never found end of rich text in `" << format << "'!");
653 docstring const & BibTeXInfo::getInfo(BibTeXInfoList const xrefs,
654 Buffer const & buf, CiteItem const & ci) const
656 bool const richtext = ci.richtext;
658 if (!richtext && !info_.empty())
660 if (richtext && !info_richtext_.empty())
661 return info_richtext_;
664 BibTeXInfo::const_iterator it = find(from_ascii("ref"));
669 CiteEngineType const engine_type = buf.params().citeEngineType();
670 DocumentClass const & dc = buf.params().documentClass();
671 docstring const & format =
672 from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_)));
674 info_ = expandFormat(format, xrefs, counter, buf,
678 // this probably shouldn't happen
683 info_richtext_ = convertLaTeXCommands(processRichtext(info_, true));
684 return info_richtext_;
687 info_ = convertLaTeXCommands(processRichtext(info_, false));
692 docstring const BibTeXInfo::getLabel(BibTeXInfoList const xrefs,
693 Buffer const & buf, docstring const & format,
694 CiteItem const & ci, bool next, bool second) const
699 loclabel = expandFormat(format, xrefs, counter, buf, ci, next, second);
701 if (!loclabel.empty() && !next) {
702 loclabel = processRichtext(loclabel, ci.richtext);
703 loclabel = convertLaTeXCommands(loclabel);
710 docstring const & BibTeXInfo::operator[](docstring const & field) const
712 BibTeXInfo::const_iterator it = find(field);
715 static docstring const empty_value = docstring();
720 docstring const & BibTeXInfo::operator[](string const & field) const
722 return operator[](from_ascii(field));
726 docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
727 CiteItem const & ci, BibTeXInfoList const xrefs, size_t maxsize) const
729 // anything less is pointless
730 LASSERT(maxsize >= 16, maxsize = 16);
732 bool cleanit = false;
733 if (prefixIs(oldkey, "clean:")) {
734 key = oldkey.substr(6);
738 docstring ret = operator[](key);
739 if (ret.empty() && !xrefs.empty()) {
740 vector<BibTeXInfo const *>::const_iterator it = xrefs.begin();
741 vector<BibTeXInfo const *>::const_iterator en = xrefs.end();
742 for (; it != en; ++it) {
743 if (*it && !(**it)[key].empty()) {
751 // FIXME: dialog, textbefore and textafter have nothing to do with this
752 if (key == "dialog" && ci.context == CiteItem::Dialog)
753 ret = from_ascii("x"); // any non-empty string will do
754 else if (key == "ifstar" && ci.Starred)
755 ret = from_ascii("x"); // any non-empty string will do
756 else if (key == "entrytype")
758 else if (key == "key")
760 else if (key == "label")
762 else if (key == "modifier" && modifier_ != 0)
764 else if (key == "numericallabel")
766 else if (key == "shortauthor")
767 // When shortauthor is not defined, jurabib automatically
768 // provides jurabib-style abbreviated author names. We do
770 ret = getAbbreviatedAuthor(&buf, true);
771 else if (key == "shorttitle") {
772 // When shorttitle is not defined, jurabib uses for `article'
773 // and `periodical' entries the form `journal volume [year]'
774 // and for other types of entries it uses the `title' field.
775 if (entry_type_ == "article" || entry_type_ == "periodical")
776 ret = operator[]("journal") + " " + operator[]("volume")
777 + " [" + operator[]("year") + "]";
779 ret = operator[]("title");
780 else if (key == "abbrvauthor") {
781 // Special key to provide abbreviated author names,
782 // with respect to maxcitenames.
783 ret = getAuthorList(&buf, false, false);
784 if (ci.forceUpperCase && isLowerCase(ret[0]))
785 ret[0] = uppercase(ret[0]);
786 } else if (key == "fullauthor") {
787 // Return a full author list
788 ret = getAuthorList(&buf, true, false);
789 if (ci.forceUpperCase && isLowerCase(ret[0]))
790 ret[0] = uppercase(ret[0]);
791 } else if (key == "forceabbrvauthor") {
792 // Special key to provide abbreviated author names,
793 // irrespective of maxcitenames.
794 ret = getAuthorList(&buf, false, true);
795 if (ci.forceUpperCase && isLowerCase(ret[0]))
796 ret[0] = uppercase(ret[0]);
797 } else if (key == "bibentry") {
798 // Special key to provide the full bibliography entry: see getInfo()
799 CiteEngineType const engine_type = buf.params().citeEngineType();
800 DocumentClass const & dc = buf.params().documentClass();
801 docstring const & format =
802 from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_)));
804 ret = expandFormat(format, xrefs, counter, buf, ci, false, false);
805 } else if (key == "textbefore")
807 else if (key == "textafter")
809 else if (key == "year")
814 ret = html::cleanAttr(ret);
816 // make sure it is not too big
817 support::truncateWithEllipsis(ret, maxsize);
822 //////////////////////////////////////////////////////////////////////
826 //////////////////////////////////////////////////////////////////////
830 // A functor for use with sort, leading to case insensitive sorting
831 class compareNoCase: public binary_function<docstring, docstring, bool>
834 bool operator()(docstring const & s1, docstring const & s2) const {
835 return compare_no_case(s1, s2) < 0;
842 vector<docstring> const BiblioInfo::getXRefs(BibTeXInfo const & data, bool const nested) const
844 vector<docstring> result;
845 if (!data.isBibTeX())
847 // Legacy crossref field. This is not nestable.
848 if (!nested && !data["crossref"].empty()) {
849 docstring const xrefkey = data["crossref"];
850 result.push_back(xrefkey);
851 // However, check for nested xdatas
852 BiblioInfo::const_iterator it = find(xrefkey);
854 BibTeXInfo const & xref = it->second;
855 vector<docstring> const nxdata = getXRefs(xref, true);
857 result.insert(result.end(), nxdata.begin(), nxdata.end());
860 // Biblatex's xdata field. Infinitely nestable.
861 // XData field can consist of a comma-separated list of keys
862 vector<docstring> const xdatakeys = getVectorFromString(data["xdata"]);
863 if (!xdatakeys.empty()) {
864 vector<docstring>::const_iterator xit = xdatakeys.begin();
865 vector<docstring>::const_iterator xen = xdatakeys.end();
866 for (; xit != xen; ++xit) {
867 docstring const xdatakey = *xit;
868 result.push_back(xdatakey);
869 BiblioInfo::const_iterator it = find(xdatakey);
871 BibTeXInfo const & xdata = it->second;
872 vector<docstring> const nxdata = getXRefs(xdata, true);
874 result.insert(result.end(), nxdata.begin(), nxdata.end());
882 vector<docstring> const BiblioInfo::getKeys() const
884 vector<docstring> bibkeys;
885 BiblioInfo::const_iterator it = begin();
886 for (; it != end(); ++it)
887 bibkeys.push_back(it->first);
888 sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
893 vector<docstring> const BiblioInfo::getFields() const
895 vector<docstring> bibfields;
896 set<docstring>::const_iterator it = field_names_.begin();
897 set<docstring>::const_iterator end = field_names_.end();
898 for (; it != end; ++it)
899 bibfields.push_back(*it);
900 sort(bibfields.begin(), bibfields.end());
905 vector<docstring> const BiblioInfo::getEntries() const
907 vector<docstring> bibentries;
908 set<docstring>::const_iterator it = entry_types_.begin();
909 set<docstring>::const_iterator end = entry_types_.end();
910 for (; it != end; ++it)
911 bibentries.push_back(*it);
912 sort(bibentries.begin(), bibentries.end());
917 docstring const BiblioInfo::getAuthorList(docstring const & key, Buffer const & buf) const
919 BiblioInfo::const_iterator it = find(key);
922 BibTeXInfo const & data = it->second;
923 return data.getAuthorList(&buf, false);
927 docstring const BiblioInfo::getCiteNumber(docstring const & key) const
929 BiblioInfo::const_iterator it = find(key);
932 BibTeXInfo const & data = it->second;
933 return data.citeNumber();
937 docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) const
939 BiblioInfo::const_iterator it = find(key);
942 BibTeXInfo const & data = it->second;
943 docstring year = data.getYear();
945 // let's try the crossrefs
946 vector<docstring> const xrefs = getXRefs(data);
950 vector<docstring>::const_iterator it = xrefs.begin();
951 vector<docstring>::const_iterator en = xrefs.end();
952 for (; it != en; ++it) {
953 BiblioInfo::const_iterator const xrefit = find(*it);
956 BibTeXInfo const & xref_data = xrefit->second;
957 year = xref_data.getYear();
963 if (use_modifier && data.modifier() != 0)
964 year += data.modifier();
969 docstring const BiblioInfo::getYear(docstring const & key, Buffer const & buf, bool use_modifier) const
971 docstring const year = getYear(key, use_modifier);
973 return buf.B_("No year");
978 docstring const BiblioInfo::getInfo(docstring const & key,
979 Buffer const & buf, CiteItem const & ci) const
981 BiblioInfo::const_iterator it = find(key);
983 return docstring(_("Bibliography entry not found!"));
984 BibTeXInfo const & data = it->second;
985 BibTeXInfoList xrefptrs;
986 vector<docstring> const xrefs = getXRefs(data);
987 if (!xrefs.empty()) {
988 vector<docstring>::const_iterator it = xrefs.begin();
989 vector<docstring>::const_iterator en = xrefs.end();
990 for (; it != en; ++it) {
991 BiblioInfo::const_iterator const xrefit = find(*it);
993 xrefptrs.push_back(&(xrefit->second));
996 return data.getInfo(xrefptrs, buf, ci);
1000 docstring const BiblioInfo::getLabel(vector<docstring> keys,
1001 Buffer const & buf, string const & style, CiteItem const & ci) const
1003 size_t max_size = ci.max_size;
1004 // shorter makes no sense
1005 LASSERT(max_size >= 16, max_size = 16);
1007 // we can't display more than 10 of these, anyway
1008 bool const too_many_keys = keys.size() > 10;
1012 CiteEngineType const engine_type = buf.params().citeEngineType();
1013 DocumentClass const & dc = buf.params().documentClass();
1014 docstring const & format = from_utf8(dc.getCiteFormat(engine_type, style, "cite"));
1015 docstring ret = format;
1016 vector<docstring>::const_iterator key = keys.begin();
1017 vector<docstring>::const_iterator ken = keys.end();
1018 for (; key != ken; ++key) {
1019 BiblioInfo::const_iterator it = find(*key);
1020 BibTeXInfo empty_data;
1021 empty_data.key(*key);
1022 BibTeXInfo & data = empty_data;
1023 vector<BibTeXInfo const *> xrefptrs;
1026 vector<docstring> const xrefs = getXRefs(data);
1027 if (!xrefs.empty()) {
1028 vector<docstring>::const_iterator it = xrefs.begin();
1029 vector<docstring>::const_iterator en = xrefs.end();
1030 for (; it != en; ++it) {
1031 BiblioInfo::const_iterator const xrefit = find(*it);
1032 if (xrefit != end())
1033 xrefptrs.push_back(&(xrefit->second));
1037 ret = data.getLabel(xrefptrs, buf, ret, ci, key + 1 != ken, i == 1);
1041 ret.push_back(0x2026);//HORIZONTAL ELLIPSIS
1042 support::truncateWithEllipsis(ret, max_size);
1047 bool BiblioInfo::isBibtex(docstring const & key) const
1050 split(key, key1, ',');
1051 BiblioInfo::const_iterator it = find(key1);
1054 return it->second.isBibTeX();
1058 vector<docstring> const BiblioInfo::getCiteStrings(
1059 vector<docstring> const & keys, vector<CitationStyle> const & styles,
1060 Buffer const & buf, CiteItem const & ci) const
1063 return vector<docstring>();
1066 vector<docstring> vec(styles.size());
1067 for (size_t i = 0; i != vec.size(); ++i) {
1068 style = styles[i].name;
1069 vec[i] = getLabel(keys, buf, style, ci);
1076 void BiblioInfo::mergeBiblioInfo(BiblioInfo const & info)
1078 bimap_.insert(info.begin(), info.end());
1079 field_names_.insert(info.field_names_.begin(), info.field_names_.end());
1080 entry_types_.insert(info.entry_types_.begin(), info.entry_types_.end());
1086 // used in xhtml to sort a list of BibTeXInfo objects
1087 bool lSorter(BibTeXInfo const * lhs, BibTeXInfo const * rhs)
1089 docstring const lauth = lhs->getAuthorList();
1090 docstring const rauth = rhs->getAuthorList();
1091 docstring const lyear = lhs->getYear();
1092 docstring const ryear = rhs->getYear();
1093 docstring const ltitl = lhs->operator[]("title");
1094 docstring const rtitl = rhs->operator[]("title");
1095 return (lauth < rauth)
1096 || (lauth == rauth && lyear < ryear)
1097 || (lauth == rauth && lyear == ryear && ltitl < rtitl);
1103 void BiblioInfo::collectCitedEntries(Buffer const & buf)
1105 cited_entries_.clear();
1106 // We are going to collect all the citation keys used in the document,
1107 // getting them from the TOC.
1108 // FIXME We may want to collect these differently, in the first case,
1109 // so that we might have them in order of appearance.
1110 set<docstring> citekeys;
1111 shared_ptr<Toc const> toc = buf.tocBackend().toc("citation");
1112 Toc::const_iterator it = toc->begin();
1113 Toc::const_iterator const en = toc->end();
1114 for (; it != en; ++it) {
1115 if (it->str().empty())
1117 vector<docstring> const keys = getVectorFromString(it->str());
1118 citekeys.insert(keys.begin(), keys.end());
1120 if (citekeys.empty())
1123 // We have a set of the keys used in this document.
1124 // We will now convert it to a list of the BibTeXInfo objects used in
1126 vector<BibTeXInfo const *> bi;
1127 set<docstring>::const_iterator cit = citekeys.begin();
1128 set<docstring>::const_iterator const cen = citekeys.end();
1129 for (; cit != cen; ++cit) {
1130 BiblioInfo::const_iterator const bt = find(*cit);
1131 if (bt == end() || !bt->second.isBibTeX())
1133 bi.push_back(&(bt->second));
1136 sort(bi.begin(), bi.end(), lSorter);
1138 // Now we can write the sorted keys
1139 vector<BibTeXInfo const *>::const_iterator bit = bi.begin();
1140 vector<BibTeXInfo const *>::const_iterator ben = bi.end();
1141 for (; bit != ben; ++bit)
1142 cited_entries_.push_back((*bit)->key());
1146 void BiblioInfo::makeCitationLabels(Buffer const & buf)
1148 collectCitedEntries(buf);
1149 CiteEngineType const engine_type = buf.params().citeEngineType();
1150 bool const numbers = (engine_type & ENGINE_TYPE_NUMERICAL);
1154 // used to remember the last one we saw
1155 // we'll be comparing entries to see if we need to add
1156 // modifiers, like "1984a"
1157 map<docstring, BibTeXInfo>::iterator last;
1159 vector<docstring>::const_iterator it = cited_entries_.begin();
1160 vector<docstring>::const_iterator const en = cited_entries_.end();
1161 for (; it != en; ++it) {
1162 map<docstring, BibTeXInfo>::iterator const biit = bimap_.find(*it);
1163 // this shouldn't happen, but...
1164 if (biit == bimap_.end())
1165 // ...fail gracefully, anyway.
1167 BibTeXInfo & entry = biit->second;
1169 docstring const num = convert<docstring>(++keynumber);
1170 entry.setCiteNumber(num);
1172 // coverity complains about our derefercing the iterator last,
1173 // which was not initialized above. but it does get initialized
1174 // after the first time through the loop, which is the point of
1176 // coverity[FORWARD_NULL]
1177 if (it != cited_entries_.begin()
1178 && entry.getAuthorList() == last->second.getAuthorList()
1179 // we access the year via getYear() so as to get it from the xref,
1180 // if we need to do so
1181 && getYear(entry.key()) == getYear(last->second.key())) {
1182 if (modifier == 0) {
1183 // so the last one should have been 'a'
1184 last->second.setModifier('a');
1186 } else if (modifier == 'z')
1193 entry.setModifier(modifier);
1194 // remember the last one
1199 it = cited_entries_.begin();
1200 for (; it != en; ++it) {
1201 map<docstring, BibTeXInfo>::iterator const biit = bimap_.find(*it);
1202 // this shouldn't happen, but...
1203 if (biit == bimap_.end())
1204 // ...fail gracefully, anyway.
1206 BibTeXInfo & entry = biit->second;
1208 entry.label(entry.citeNumber());
1210 docstring const auth = entry.getAuthorList(&buf, false);
1211 // we do it this way so as to access the xref, if necessary
1212 // note that this also gives us the modifier
1213 docstring const year = getYear(*it, buf, true);
1214 if (!auth.empty() && !year.empty())
1215 entry.label(auth + ' ' + year);
1217 entry.label(entry.key());
1223 //////////////////////////////////////////////////////////////////////
1227 //////////////////////////////////////////////////////////////////////
1230 CitationStyle citationStyleFromString(string const & command,
1231 BufferParams const & params)
1234 if (command.empty())
1237 string const alias = params.getCiteAlias(command);
1238 string cmd = alias.empty() ? command : alias;
1239 if (isUpperCase(command[0])) {
1240 cs.forceUpperCase = true;
1241 cmd[0] = lowercase(cmd[0]);
1244 size_t const n = command.size() - 1;
1245 if (command[n] == '*') {
1246 cs.hasStarredVersion = true;
1247 if (suffixIs(cmd, '*'))
1248 cmd = cmd.substr(0, cmd.size() - 1);
1256 string citationStyleToString(const CitationStyle & cs, bool const latex)
1258 string cmd = latex ? cs.cmd : cs.name;
1259 if (cs.forceUpperCase)
1260 cmd[0] = uppercase(cmd[0]);
1261 if (cs.hasStarredVersion)