X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FBiblioInfo.cpp;h=1464e7088e0aa636835871f7c1f7d64e5e33f93e;hb=b198a36a363bb6a084407d476942d68ef5fb5e86;hp=8d5bfe5f7206ea68f6b0a85a8409429bc79ef051;hpb=d9edf32b67ba0256aeacfe6100790576e0fe90b5;p=lyx.git diff --git a/src/BiblioInfo.cpp b/src/BiblioInfo.cpp index 8d5bfe5f72..1464e7088e 100644 --- a/src/BiblioInfo.cpp +++ b/src/BiblioInfo.cpp @@ -5,7 +5,7 @@ * * \author Angus Leeming * \author Herbert Voß - * \author Richard Heck + * \author Richard Kimberly Heck * \author Julien Rioux * \author Jürgen Spitzmüller * @@ -15,28 +15,27 @@ #include #include "BiblioInfo.h" + #include "Buffer.h" #include "BufferParams.h" -#include "buffer_funcs.h" #include "Citation.h" #include "Encoding.h" -#include "InsetIterator.h" #include "Language.h" -#include "output_xhtml.h" -#include "Paragraph.h" #include "TextClass.h" #include "TocBackend.h" +#include "xml.h" #include "support/convert.h" #include "support/debug.h" #include "support/docstream.h" +#include "support/FileName.h" #include "support/gettext.h" #include "support/lassert.h" #include "support/lstrings.h" -#include "support/regex.h" #include "support/textutils.h" #include +#include #include using namespace std; @@ -278,8 +277,14 @@ vector const getAuthors(docstring const & author) // in author names, but can happen (consider cases such as "C \& A Corp."). docstring iname = subst(author, from_ascii("&"), from_ascii("$$amp!")); // Then, we temporarily make all " and " strings to ampersands in order - // to handle them later on a per-char level. - iname = subst(iname, from_ascii(" and "), from_ascii(" & ")); + // to handle them later on a per-char level. Note that arbitrary casing + // ("And", "AND", "aNd", ...) is allowed in bibtex (#10465). + static regex const and_reg("(.* )([aA][nN][dD])( .*)"); + smatch sub; + string res = to_utf8(iname); + while (regex_match(res, sub, and_reg)) + res = sub.str(1) + "&" + sub.str(3); + iname = from_utf8(res); // Now we traverse through the string and replace the "&" by the proper // output in- and outside groups docstring name; @@ -384,8 +389,8 @@ docstring convertLaTeXCommands(docstring const & str) // {\v a} to \v{a} (see #9340). // FIXME: This is a sort of mini-tex2lyx. // Use the real tex2lyx instead! - static lyx::regex const tma_reg("^\\{\\\\[bcCdfGhHkrtuUv]\\s\\w\\}"); - if (lyx::regex_search(to_utf8(val), tma_reg)) { + static regex const tma_reg("^\\{\\\\[bcCdfGhHkrtuUv]\\s\\w\\}"); + if (regex_search(to_utf8(val), tma_reg)) { val = val.substr(1); val.replace(2, 1, from_ascii("{")); continue; @@ -412,8 +417,8 @@ docstring convertLaTeXCommands(docstring const & str) // look for that and change it, if necessary. // FIXME: This is a sort of mini-tex2lyx. // Use the real tex2lyx instead! - static lyx::regex const reg("^\\\\\\W\\w"); - if (lyx::regex_search(to_utf8(val), reg)) { + static regex const reg("^\\\\\\W\\w"); + if (regex_search(to_utf8(val), reg)) { val.insert(3, from_ascii("}")); val.insert(2, from_ascii("{")); } @@ -488,8 +493,8 @@ docstring processRichtext(docstring const & str, bool richtext) ////////////////////////////////////////////////////////////////////// BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type) - : is_bibtex_(true), bib_key_(key), num_bib_key_(0), entry_type_(type), info_(), - modifier_(0) + : is_bibtex_(true), bib_key_(key), num_bib_key_(0), entry_type_(type), + info_(), format_(), modifier_(0) {} @@ -651,6 +656,75 @@ docstring const BibTeXInfo::getYear() const } +void BibTeXInfo::getLocators(docstring & doi, docstring & url, docstring & file) const +{ + if (is_bibtex_) { + // get "doi" entry from citation record + doi = operator[]("doi"); + if (!doi.empty() && !prefixIs(doi,from_ascii("http"))) + doi = "https://doi.org/" + doi; + // get "url" entry from citation record + url = operator[]("url"); + // get "file" entry from citation record + file = operator[]("file"); + + // Jabref case, field has a format: + // Description:Location:Filetype;Description:Location:Filetype... + // We will grab only first pdf + if (!file.empty()) { + docstring ret, filedest, tmp; + ret = split(file, tmp, ':'); + tmp = split(ret, filedest, ':'); + //TODO howto deal with relative directories? + FileName f(to_utf8(filedest)); + if (f.exists()) + file = "file:///" + filedest; + } + + // kbibtex case, format: + // file1.pdf;file2.pdf + // We will grab only first pdf + docstring kfile; + if (file.empty()) + kfile = operator[]("localfile"); + if (!kfile.empty()) { + docstring filedest, tmp; + tmp = split(kfile, filedest, ';'); + //TODO howto deal with relative directories? + FileName f(to_utf8(filedest)); + if (f.exists()) + file = "file:///" + filedest; + } + + if (!url.empty()) + return; + + // try biblatex specific fields, see its manual + // 3.13.7 "Electronic Publishing Informationl" + docstring eprinttype = operator[]("eprinttype"); + docstring eprint = operator[]("eprint"); + if (eprint.empty()) + return; + + if (eprinttype == "arxiv") + url = "https://arxiv.org/abs/" + eprint; + if (eprinttype == "jstor") + url = "https://www.jstor.org/stable/" + eprint; + if (eprinttype == "pubmed") + url = "http://www.ncbi.nlm.nih.gov/pubmed/" + eprint; + if (eprinttype == "hdl") + url = "https://hdl.handle.net/" + eprint; + if (eprinttype == "googlebooks") + url = "http://books.google.com/books?id=" + eprint; + + return; + } + + // Here can be handled the bibliography environment. All one could do + // here is let LyX scan the entry for URL or HRef insets. +} + + namespace { docstring parseOptions(docstring const & format, string & optkey, @@ -927,12 +1001,27 @@ docstring BibTeXInfo::expandFormat(docstring const & format, docstring const & BibTeXInfo::getInfo(BibTeXInfoList const & xrefs, - Buffer const & buf, CiteItem const & ci) const + Buffer const & buf, CiteItem const & ci, docstring const & format_in) const { bool const richtext = ci.richtext; - if (!richtext && !info_.empty()) + CiteEngineType const engine_type = buf.params().citeEngineType(); + DocumentClass const & dc = buf.params().documentClass(); + docstring const & format = format_in.empty()? + from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_))) + : format_in; + + if (format != format_) { + // clear caches since format changed + info_.clear(); + info_richtext_.clear(); + format_ = format; + } + + if (!richtext && !info_.empty()) { + info_ = convertLaTeXCommands(processRichtext(info_, false)); return info_; + } if (richtext && !info_richtext_.empty()) return info_richtext_; @@ -942,10 +1031,6 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfoList const & xrefs, return info_; } - CiteEngineType const engine_type = buf.params().citeEngineType(); - DocumentClass const & dc = buf.params().documentClass(); - docstring const & format = - from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_))); int counter = 0; info_ = expandFormat(format, xrefs, counter, buf, ci, false, false); @@ -965,7 +1050,7 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfoList const & xrefs, } -docstring const BibTeXInfo::getLabel(BibTeXInfoList const xrefs, +docstring const BibTeXInfo::getLabel(BibTeXInfoList const & xrefs, Buffer const & buf, docstring const & format, CiteItem const & ci, bool next, bool second) const { @@ -1013,11 +1098,10 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf, docstring ret = operator[](key); if (ret.empty() && !xrefs.empty()) { - vector::const_iterator it = xrefs.begin(); - vector::const_iterator en = xrefs.end(); - for (; it != en; ++it) { - if (*it && !(**it)[key].empty()) { - ret = (**it)[key]; + // xr is a (reference to a) BibTeXInfo const * + for (auto const & xr : xrefs) { + if (xr && !(*xr)[key].empty()) { + ret = (*xr)[key]; break; } } @@ -1160,7 +1244,7 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf, } if (cleanit) - ret = html::cleanAttr(ret); + ret = xml::cleanAttr(ret); // make sure it is not too big support::truncateWithEllipsis(ret, maxsize); @@ -1177,13 +1261,9 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf, namespace { // A functor for use with sort, leading to case insensitive sorting -class compareNoCase: public binary_function -{ -public: - bool operator()(docstring const & s1, docstring const & s2) const { - return compare_no_case(s1, s2) < 0; - } -}; +bool compareNoCase(const docstring & a, const docstring & b) { + return compare_no_case(a, b) < 0; +} } // namespace @@ -1210,10 +1290,7 @@ vector const BiblioInfo::getXRefs(BibTeXInfo const & data, bool const // XData field can consist of a comma-separated list of keys vector const xdatakeys = getVectorFromString(data["xdata"]); if (!xdatakeys.empty()) { - vector::const_iterator xit = xdatakeys.begin(); - vector::const_iterator xen = xdatakeys.end(); - for (; xit != xen; ++xit) { - docstring const xdatakey = *xit; + for (auto const & xdatakey : xdatakeys) { result.push_back(xdatakey); BiblioInfo::const_iterator it = find(xdatakey); if (it != end()) { @@ -1231,10 +1308,9 @@ vector const BiblioInfo::getXRefs(BibTeXInfo const & data, bool const vector const BiblioInfo::getKeys() const { vector bibkeys; - BiblioInfo::const_iterator it = begin(); - for (; it != end(); ++it) - bibkeys.push_back(it->first); - sort(bibkeys.begin(), bibkeys.end(), compareNoCase()); + for (auto const & bi : *this) + bibkeys.push_back(bi.first); + sort(bibkeys.begin(), bibkeys.end(), &compareNoCase); return bibkeys; } @@ -1242,10 +1318,8 @@ vector const BiblioInfo::getKeys() const vector const BiblioInfo::getFields() const { vector bibfields; - set::const_iterator it = field_names_.begin(); - set::const_iterator end = field_names_.end(); - for (; it != end; ++it) - bibfields.push_back(*it); + for (auto const & fn : field_names_) + bibfields.push_back(fn); sort(bibfields.begin(), bibfields.end()); return bibfields; } @@ -1254,10 +1328,8 @@ vector const BiblioInfo::getFields() const vector const BiblioInfo::getEntries() const { vector bibentries; - set::const_iterator it = entry_types_.begin(); - set::const_iterator end = entry_types_.end(); - for (; it != end; ++it) - bibentries.push_back(*it); + for (auto const & et : entry_types_) + bibentries.push_back(et); sort(bibentries.begin(), bibentries.end()); return bibentries; } @@ -1282,6 +1354,15 @@ docstring const BiblioInfo::getCiteNumber(docstring const & key) const return data.citeNumber(); } +void BiblioInfo::getLocators(docstring const & key, docstring & doi, docstring & url, docstring & file) const +{ + BiblioInfo::const_iterator it = find(key); + if (it == end()) + return; + BibTeXInfo const & data = it->second; + data.getLocators(doi,url,file); +} + docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) const { @@ -1323,11 +1404,11 @@ docstring const BiblioInfo::getYear(docstring const & key, Buffer const & buf, b docstring const BiblioInfo::getInfo(docstring const & key, - Buffer const & buf, CiteItem const & ci) const + Buffer const & buf, CiteItem const & ci, docstring const & format) const { BiblioInfo::const_iterator it = find(key); if (it == end()) - return docstring(_("Bibliography entry not found!")); + return _("Bibliography entry not found!"); BibTeXInfo const & data = it->second; BibTeXInfoList xrefptrs; for (docstring const & xref : getXRefs(data)) { @@ -1335,7 +1416,7 @@ docstring const BiblioInfo::getInfo(docstring const & key, if (xrefit != end()) xrefptrs.push_back(&(xrefit->second)); } - return data.getInfo(xrefptrs, buf, ci); + return data.getInfo(xrefptrs, buf, ci, format); } @@ -1367,7 +1448,7 @@ docstring const BiblioInfo::getLabel(vector keys, for (int i = 0; key != ken; ++key, ++i) { handled_keys.push_back(*key); int n = 0; - for (auto const k : handled_keys) { + for (auto const & k : handled_keys) { if (k == *key) ++n; } @@ -1458,13 +1539,11 @@ void BiblioInfo::collectCitedEntries(Buffer const & buf) // FIXME We may want to collect these differently, in the first case, // so that we might have them in order of appearance. set citekeys; - shared_ptr toc = buf.tocBackend().toc("citation"); - Toc::const_iterator it = toc->begin(); - Toc::const_iterator const en = toc->end(); - for (; it != en; ++it) { - if (it->str().empty()) + Toc const & toc = *buf.tocBackend().toc("citation"); + for (auto const & t : toc) { + if (t.str().empty()) continue; - vector const keys = getVectorFromString(it->str()); + vector const keys = getVectorFromString(t.str()); citekeys.insert(keys.begin(), keys.end()); } if (citekeys.empty()) @@ -1474,10 +1553,8 @@ void BiblioInfo::collectCitedEntries(Buffer const & buf) // We will now convert it to a list of the BibTeXInfo objects used in // this document... vector bi; - set::const_iterator cit = citekeys.begin(); - set::const_iterator const cen = citekeys.end(); - for (; cit != cen; ++cit) { - BiblioInfo::const_iterator const bt = find(*cit); + for (auto const & ck : citekeys) { + BiblioInfo::const_iterator const bt = find(ck); if (bt == end() || !bt->second.isBibTeX()) continue; bi.push_back(&(bt->second)); @@ -1486,10 +1563,9 @@ void BiblioInfo::collectCitedEntries(Buffer const & buf) sort(bi.begin(), bi.end(), lSorter); // Now we can write the sorted keys - vector::const_iterator bit = bi.begin(); - vector::const_iterator ben = bi.end(); - for (; bit != ben; ++bit) - cited_entries_.push_back((*bit)->key()); + // b is a BibTeXInfo const * + for (auto const & b : bi) + cited_entries_.push_back(b->key()); } @@ -1506,10 +1582,9 @@ void BiblioInfo::makeCitationLabels(Buffer const & buf) // modifiers, like "1984a" map::iterator last = bimap_.end(); - vector::const_iterator it = cited_entries_.begin(); - vector::const_iterator const en = cited_entries_.end(); - for (; it != en; ++it) { - map::iterator const biit = bimap_.find(*it); + // add letters to years + for (auto const & ce : cited_entries_) { + map::iterator const biit = bimap_.find(ce); // this shouldn't happen, but... if (biit == bimap_.end()) // ...fail gracefully, anyway. @@ -1544,9 +1619,8 @@ void BiblioInfo::makeCitationLabels(Buffer const & buf) } } // Set the labels - it = cited_entries_.begin(); - for (; it != en; ++it) { - map::iterator const biit = bimap_.find(*it); + for (auto const & ce : cited_entries_) { + map::iterator const biit = bimap_.find(ce); // this shouldn't happen, but... if (biit == bimap_.end()) // ...fail gracefully, anyway. @@ -1558,7 +1632,7 @@ void BiblioInfo::makeCitationLabels(Buffer const & buf) docstring const auth = entry.getAuthorOrEditorList(&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); + docstring const year = getYear(ce, buf, true); if (!auth.empty() && !year.empty()) entry.label(auth + ' ' + year); else @@ -1611,4 +1685,79 @@ string citationStyleToString(const CitationStyle & cs, bool const latex) return cmd; } + +docstring authorsToDocBookAuthorGroup(docstring const & authorsString, XMLStream & xs, Buffer const & buf) +{ + // This function closely mimics getAuthorList, but produces DocBook instead of text. + // It has been greatly simplified, as the complete list of authors is always produced. No separators are required, + // as the output has a database-like shape. + // constructName has also been merged within, as it becomes really simple and leads to no copy-paste. + + if (authorsString.empty()) { + return docstring(); + } + + // Split the input list of authors into individual authors. + vector const authors = getAuthors(authorsString); + + // Retrieve the "et al." variation. + string const etal = buf.params().documentClass().getCiteMacro(buf.params().citeEngineType(), "_etal"); + + // Output the list of authors. + xs << xml::StartTag("authorgroup"); + xs << xml::CR(); + + auto it = authors.cbegin(); + auto en = authors.cend(); + for (size_t i = 0; it != en; ++it, ++i) { + xs << xml::StartTag("author"); + xs << xml::CR(); + xs << xml::StartTag("personname"); + xs << xml::CR(); + docstring name = *it; + + // All authors go in a . If more structure is known, use it; otherwise (just "et al."), print it as such. + if (name == "others") { + xs << buf.B_(etal); + } else { + name_parts parts = nameParts(name); + if (! parts.prefix.empty()) { + xs << xml::StartTag("honorific"); + xs << parts.prefix; + xs << xml::EndTag("honorific"); + xs << xml::CR(); + } + if (! parts.prename.empty()) { + xs << xml::StartTag("firstname"); + xs << parts.prename; + xs << xml::EndTag("firstname"); + xs << xml::CR(); + } + if (! parts.surname.empty()) { + xs << xml::StartTag("surname"); + xs << parts.surname; + xs << xml::EndTag("surname"); + xs << xml::CR(); + } + if (! parts.suffix.empty()) { + xs << xml::StartTag("othername", "role=\"suffix\""); + xs << parts.suffix; + xs << xml::EndTag("othername"); + xs << xml::CR(); + } + } + + xs << xml::EndTag("personname"); + xs << xml::CR(); + xs << xml::EndTag("author"); + xs << xml::CR(); + + // Could add an affiliation after , but not stored in BibTeX. + } + xs << xml::EndTag("authorgroup"); + xs << xml::CR(); + + return docstring(); +} + } // namespace lyx