]> git.lyx.org Git - lyx.git/blobdiff - src/BiblioInfo.cpp
Force local language switch in IPA insets
[lyx.git] / src / BiblioInfo.cpp
index d306c87e5f149cfb254327fb3748f2a71aac1c89..243f78c59f6595fb7d24ac0cede957e04e2db87c 100644 (file)
@@ -255,7 +255,8 @@ BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type)
 {}
 
 
-docstring const BibTeXInfo::getAbbreviatedAuthor(bool jurabib_style) const
+docstring const BibTeXInfo::getAbbreviatedAuthor(
+    Buffer const * buf, bool jurabib_style) const
 {
        if (!is_bibtex_) {
                docstring const opt = label();
@@ -296,37 +297,45 @@ docstring const BibTeXInfo::getAbbreviatedAuthor(bool jurabib_style) const
 
        docstring retval = familyName(authors[0]);
 
-       if (authors.size() == 2 && authors[1] != "others")
-               retval = bformat(from_ascii("%1$s and %2$s"),
-                       familyName(authors[0]), familyName(authors[1]));
-
-       if (authors.size() >= 2)
-               retval = bformat(from_ascii("%1$s et al."),
-                       familyName(authors[0]));
+       if (authors.size() == 2 && authors[1] != "others") {
+               docstring const dformat = buf ? 
+                       buf->B_("%1$s and %2$s") : from_ascii("%1$s and %2$s");
+               retval = bformat(dformat, familyName(authors[0]), familyName(authors[1]));
+       } else if (authors.size() >= 2) {
+               // we get here either if the author list is longer than two names
+               // or if the second 'name' is "others". we do the same thing either
+               // way.
+               docstring const dformat = buf ? 
+                       buf->B_("%1$s et al.") : from_ascii("%1$s et al.");
+               retval = bformat(dformat, familyName(authors[0]));
+       }
 
        return convertLaTeXCommands(retval);
 }
 
 
-docstring const BibTeXInfo::getAbbreviatedAuthor(Buffer const & buf, bool jurabib_style) const
-{
-       docstring const author = getAbbreviatedAuthor(jurabib_style);
-       if (!is_bibtex_)
-               return author;
-       vector<docstring> const authors = getVectorFromString(author, from_ascii(" and "));
-       if (authors.size() == 2)
-               return bformat(buf.B_("%1$s and %2$s"), authors[0], authors[1]);
-       docstring::size_type const idx = author.rfind(from_ascii(" et al."));
-       if (idx != docstring::npos)
-               return bformat(buf.B_("%1$s et al."), author.substr(0, idx));
-       return author;
-}
-
-
 docstring const BibTeXInfo::getYear() const
 {
-       if (is_bibtex_)
-               return operator[]("year");
+       if (is_bibtex_) {
+               // first try legacy year field
+               docstring year = operator[]("year");
+               if (!year.empty())
+                       return year;
+               // now try biblatex's date field
+               year = operator[]("date");
+               // Format is [-]YYYY-MM-DD*/[-]YYYY-MM-DD*
+               // We only want the years.
+               static regex const yreg("[-]?([\\d]{4}).*");
+               static regex const ereg(".*/[-]?([\\d]{4}).*");
+               smatch sm;
+               string const date = to_utf8(year);
+               regex_match(date, sm, yreg);
+               year = from_ascii(sm[1]);
+               // check for an endyear
+               if (regex_match(date, sm, ereg))
+                       year += char_type(0x2013) + from_ascii(sm[1]);
+               return year;
+       }
 
        docstring const opt = label();
        if (opt.empty())
@@ -343,14 +352,6 @@ docstring const BibTeXInfo::getYear() const
 }
 
 
-docstring const BibTeXInfo::getXRef() const
-{
-       if (!is_bibtex_)
-               return docstring();
-       return operator[]("crossref");
-}
-
-
 namespace {
 
 docstring parseOptions(docstring const & format, string & optkey,
@@ -476,7 +477,7 @@ I can tell, but it still feels like a hack. Fixing this would require quite a
 bit of work, however.
 */
 docstring BibTeXInfo::expandFormat(docstring const & format,
-               BibTeXInfo const * const xref, int & counter, Buffer const & buf,
+               BibTeXInfoList const xrefs, int & counter, Buffer const & buf,
                docstring before, docstring after, docstring dialog, bool next) const
 {
        // incorrect use of macros could put us in an infinite loop
@@ -525,7 +526,7 @@ docstring BibTeXInfo::expandFormat(docstring const & format,
                                        ret << trans;
                                } else {
                                        docstring const val =
-                                               getValueForKey(key, buf, before, after, dialog, xref, max_keysize);
+                                               getValueForKey(key, buf, before, after, dialog, xrefs, max_keysize);
                                        if (!scanning_rich)
                                                ret << from_ascii("{!<span class=\"bib-" + key + "\">!}");
                                        ret << val;
@@ -556,16 +557,16 @@ docstring BibTeXInfo::expandFormat(docstring const & format,
                                                return _("ERROR!");
                                        fmt = newfmt;
                                        docstring const val =
-                                               getValueForKey(optkey, buf, before, after, dialog, xref);
+                                               getValueForKey(optkey, buf, before, after, dialog, xrefs);
                                        if (optkey == "next" && next)
                                                ret << ifpart; // without expansion
                                        else if (!val.empty()) {
                                                int newcounter = 0;
-                                               ret << expandFormat(ifpart, xref, newcounter, buf,
+                                               ret << expandFormat(ifpart, xrefs, newcounter, buf,
                                                        before, after, dialog, next);
                                        } else if (!elsepart.empty()) {
                                                int newcounter = 0;
-                                               ret << expandFormat(elsepart, xref, newcounter, buf,
+                                               ret << expandFormat(elsepart, xrefs, newcounter, buf,
                                                        before, after, dialog, next);
                                        }
                                        // fmt will have been shortened for us already
@@ -614,7 +615,7 @@ docstring BibTeXInfo::expandFormat(docstring const & format,
 }
 
 
-docstring const & BibTeXInfo::getInfo(BibTeXInfo const * const xref,
+docstring const & BibTeXInfo::getInfo(BibTeXInfoList const xrefs,
        Buffer const & buf, bool richtext) const
 {
        if (!richtext && !info_.empty())
@@ -633,7 +634,7 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfo const * const xref,
        docstring const & format =
                from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_)));
        int counter = 0;
-       info_ = expandFormat(format, xref, counter, buf,
+       info_ = expandFormat(format, xrefs, counter, buf,
                docstring(), docstring(), docstring(), false);
 
        if (info_.empty()) {
@@ -651,7 +652,7 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfo const * const xref,
 }
 
 
-docstring const BibTeXInfo::getLabel(BibTeXInfo const * const xref,
+docstring const BibTeXInfo::getLabel(BibTeXInfoList const xrefs,
        Buffer const & buf, docstring const & format, bool richtext,
        docstring const & before, docstring const & after, 
        docstring const & dialog, bool next) const
@@ -659,7 +660,7 @@ docstring const BibTeXInfo::getLabel(BibTeXInfo const * const xref,
        docstring loclabel;
 
        int counter = 0;
-       loclabel = expandFormat(format, xref, counter, buf,
+       loclabel = expandFormat(format, xrefs, counter, buf,
                before, after, dialog, next);
 
        if (!loclabel.empty() && !next) {
@@ -689,7 +690,7 @@ docstring const & BibTeXInfo::operator[](string const & field) const
 
 docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
        docstring const & before, docstring const & after, docstring const & dialog,
-       BibTeXInfo const * const xref, size_t maxsize) const
+       BibTeXInfoList const xrefs, size_t maxsize) const
 {
        // anything less is pointless
        LASSERT(maxsize >= 16, maxsize = 16);
@@ -701,8 +702,16 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
        }
 
        docstring ret = operator[](key);
-       if (ret.empty() && xref)
-               ret = (*xref)[key];
+       if (ret.empty() && !xrefs.empty()) {
+               vector<BibTeXInfo const *>::const_iterator it = xrefs.begin();
+               vector<BibTeXInfo const *>::const_iterator en = xrefs.end();
+               for (; it != en; ++it) {
+                       if (*it && !(**it)[key].empty()) {
+                               ret = (**it)[key];
+                               break;
+                       }
+               }
+       }
        if (ret.empty()) {
                // some special keys
                // FIXME: dialog, textbefore and textafter have nothing to do with this
@@ -720,12 +729,12 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
                        ret = cite_number_;
                else if (key == "abbrvauthor")
                        // Special key to provide abbreviated author names.
-                       ret = getAbbreviatedAuthor(buf, false);
+                       ret = getAbbreviatedAuthor(&buf, false);
                else if (key == "shortauthor")
                        // When shortauthor is not defined, jurabib automatically
                        // provides jurabib-style abbreviated author names. We do
                        // this as well.
-                       ret = getAbbreviatedAuthor(buf, true);
+                       ret = getAbbreviatedAuthor(&buf, true);
                else if (key == "shorttitle") {
                        // When shorttitle is not defined, jurabib uses for `article'
                        // and `periodical' entries the form `journal volume [year]'
@@ -742,7 +751,7 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
                        docstring const & format =
                                from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_)));
                        int counter = 0;
-                       ret = expandFormat(format, xref, counter, buf,
+                       ret = expandFormat(format, xrefs, counter, buf,
                                docstring(), docstring(), docstring(), false);
                } else if (key == "textbefore")
                        ret = before;
@@ -756,8 +765,7 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf,
                ret = html::cleanAttr(ret);
 
        // make sure it is not too big
-       if (ret.size() > maxsize)
-               ret = ret.substr(0, maxsize - 3) + from_ascii("...");
+       support::truncateWithEllipsis(ret, maxsize);
        return ret;
 }
 
@@ -782,6 +790,46 @@ public:
 } // namespace anon
 
 
+vector<docstring> const BiblioInfo::getXRefs(BibTeXInfo const & data, bool const nested) const
+{
+       vector<docstring> result;
+       if (!data.isBibTeX())
+               return result;
+       // Legacy crossref field. This is not nestable.
+       if (!nested && !data["crossref"].empty()) {
+               docstring const xrefkey = data["crossref"];
+               result.push_back(xrefkey);
+               // However, check for nested xdatas
+               BiblioInfo::const_iterator it = find(xrefkey);
+               if (it != end()) {
+                       BibTeXInfo const & xref = it->second;
+                       vector<docstring> const nxdata = getXRefs(xref, true);
+                       if (!nxdata.empty())
+                               result.insert(result.end(), nxdata.begin(), nxdata.end());
+               }
+       }
+       // Biblatex's xdata field. Infinitely nestable.
+       // XData field can consist of a comma-separated list of keys
+       vector<docstring> const xdatakeys = getVectorFromString(data["xdata"]);
+       if (!xdatakeys.empty()) {
+               vector<docstring>::const_iterator xit = xdatakeys.begin();
+               vector<docstring>::const_iterator xen = xdatakeys.end();
+               for (; xit != xen; ++xit) {
+                       docstring const xdatakey = *xit;
+                       result.push_back(xdatakey);
+                       BiblioInfo::const_iterator it = find(xdatakey);
+                       if (it != end()) {
+                               BibTeXInfo const & xdata = it->second;
+                               vector<docstring> const nxdata = getXRefs(xdata, true);
+                               if (!nxdata.empty())
+                                       result.insert(result.end(), nxdata.begin(), nxdata.end());
+                       }
+               }
+       }
+       return result;
+}
+
+
 vector<docstring> const BiblioInfo::getKeys() const
 {
        vector<docstring> bibkeys;
@@ -823,7 +871,7 @@ docstring const BiblioInfo::getAbbreviatedAuthor(docstring const & key, Buffer c
        if (it == end())
                return docstring();
        BibTeXInfo const & data = it->second;
-       return data.getAbbreviatedAuthor(buf, false);
+       return data.getAbbreviatedAuthor(&buf, false);
 }
 
 
@@ -845,17 +893,23 @@ docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) co
        BibTeXInfo const & data = it->second;
        docstring year = data.getYear();
        if (year.empty()) {
-               // let's try the crossref
-               docstring const xref = data.getXRef();
-               if (xref.empty())
+               // let's try the crossrefs
+               vector<docstring> const xrefs = getXRefs(data);
+               if (xrefs.empty())
                        // no luck
                        return docstring();
-               BiblioInfo::const_iterator const xrefit = find(xref);
-               if (xrefit == end())
-                       // no luck again
-                       return docstring();
-               BibTeXInfo const & xref_data = xrefit->second;
-               year = xref_data.getYear();
+               vector<docstring>::const_iterator it = xrefs.begin();
+               vector<docstring>::const_iterator en = xrefs.end();
+               for (; it != en; ++it) {
+                       BiblioInfo::const_iterator const xrefit = find(*it);
+                       if (xrefit == end())
+                               continue;
+                       BibTeXInfo const & xref_data = xrefit->second;
+                       year = xref_data.getYear();
+                       if (!year.empty())
+                               // success!
+                               break;
+               }
        }
        if (use_modifier && data.modifier() != 0)
                year += data.modifier();
@@ -879,14 +933,18 @@ docstring const BiblioInfo::getInfo(docstring const & key,
        if (it == end())
                return docstring(_("Bibliography entry not found!"));
        BibTeXInfo const & data = it->second;
-       BibTeXInfo const * xrefptr = 0;
-       docstring const xref = data.getXRef();
-       if (!xref.empty()) {
-               BiblioInfo::const_iterator const xrefit = find(xref);
-               if (xrefit != end())
-                       xrefptr = &(xrefit->second);
+       BibTeXInfoList xrefptrs;
+       vector<docstring> const xrefs = getXRefs(data);
+       if (!xrefs.empty()) {
+               vector<docstring>::const_iterator it = xrefs.begin();
+               vector<docstring>::const_iterator en = xrefs.end();
+               for (; it != en; ++it) {
+                       BiblioInfo::const_iterator const xrefit = find(*it);
+                       if (xrefit != end())
+                               xrefptrs.push_back(&(xrefit->second));
+               }
        }
-       return data.getInfo(xrefptr, buf, richtext);
+       return data.getInfo(xrefptrs, buf, richtext);
 }
 
 
@@ -914,28 +972,27 @@ docstring const BiblioInfo::getLabel(vector<docstring> keys,
                BibTeXInfo empty_data;
                empty_data.key(*key);
                BibTeXInfo & data = empty_data;
-               BibTeXInfo const * xrefptr = 0;
+               vector<BibTeXInfo const *> xrefptrs;
                if (it != end()) {
                        data = it->second;
-                       docstring const xref = data.getXRef();
-                       if (!xref.empty()) {
-                               BiblioInfo::const_iterator const xrefit = find(xref);
-                               if (xrefit != end())
-                                       xrefptr = &(xrefit->second);
+                       vector<docstring> const xrefs = getXRefs(data);
+                       if (!xrefs.empty()) {
+                               vector<docstring>::const_iterator it = xrefs.begin();
+                               vector<docstring>::const_iterator en = xrefs.end();
+                               for (; it != en; ++it) {
+                                       BiblioInfo::const_iterator const xrefit = find(*it);
+                                       if (xrefit != end())
+                                               xrefptrs.push_back(&(xrefit->second));
+                               }
                        }
                }
-               ret = data.getLabel(xrefptr, buf, ret, for_xhtml,
+               ret = data.getLabel(xrefptrs, buf, ret, for_xhtml,
                        before, after, dialog, key + 1 != ken);
        }
 
-       if (ret.size() > max_size) {
-               ret.resize(max_size - 3);
-               ret += "...";
-       } else if (too_many_keys) {
-               if (ret.size() > max_size - 3)
-                       ret.resize(max_size - 3);
-               ret += "...";
-       }
+       if (too_many_keys)
+               ret.push_back(0x2026);//HORIZONTAL ELLIPSIS
+       support::truncateWithEllipsis(ret, max_size);
        return ret;
 }
 
@@ -1066,6 +1123,11 @@ void BiblioInfo::makeCitationLabels(Buffer const & buf)
                        docstring const num = convert<docstring>(++keynumber);
                        entry.setCiteNumber(num);
                } else {
+                       // coverity complains about our derefercing the iterator last,
+                       // which was not initialized above. but it does get initialized
+                       // after the first time through the loop, which is the point of
+                       // the first test.
+                       // coverity[FORWARD_NULL]
                        if (it != cited_entries_.begin()
                            && entry.getAbbreviatedAuthor() == last->second.getAbbreviatedAuthor()
                            // we access the year via getYear() so as to get it from the xref,
@@ -1099,7 +1161,7 @@ void BiblioInfo::makeCitationLabels(Buffer const & buf)
                if (numbers) {
                        entry.label(entry.citeNumber());
                } else {
-                       docstring const auth = entry.getAbbreviatedAuthor(buf, false);
+                       docstring const auth = entry.getAbbreviatedAuthor(&buf, false);
                        // we do it this way so as to access the xref, if necessary
                        // note that this also gives us the modifier
                        docstring const year = getYear(*it, buf, true);
@@ -1146,7 +1208,7 @@ string citationStyleToString(const CitationStyle & cs)
 {
        string cmd = cs.cmd;
        if (cs.forceUpperCase)
-               cmd[0] = 'C';
+               cmd[0] = uppercase(cmd[0]);
        if (cs.fullAuthorList)
                cmd += '*';
        return cmd;