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 * Full author contact details are available in file CREDITS.
15 #include "BiblioInfo.h"
17 #include "BufferParams.h"
18 #include "buffer_funcs.h"
19 #include "InsetIterator.h"
20 #include "Paragraph.h"
22 #include "insets/Inset.h"
23 #include "insets/InsetBibitem.h"
24 #include "insets/InsetBibtex.h"
25 #include "insets/InsetInclude.h"
27 #include "support/docstream.h"
28 #include "support/gettext.h"
29 #include "support/lassert.h"
30 #include "support/lstrings.h"
32 #include "boost/regex.hpp"
35 using namespace lyx::support;
40 //////////////////////////////////////////////////////////////////////
44 //////////////////////////////////////////////////////////////////////
46 BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type)
47 : is_bibtex_(true), bib_key_(key), entry_type_(type)
51 bool BibTeXInfo::hasField(docstring const & field) const
53 return count(field) == 1;
57 docstring const & BibTeXInfo::operator[](docstring const & field) const
59 BibTeXInfo::const_iterator it = find(field);
62 static docstring const empty_value = docstring();
67 docstring const & BibTeXInfo::operator[](string const & field) const
69 return operator[](from_ascii(field));
73 docstring familyName(docstring const & name)
79 docstring fname = name;
81 // possible authorname combinations are:
82 // "Surname, FirstName"
84 // "FirstName Surname"
86 docstring::size_type idx = fname.find(',');
87 if (idx != docstring::npos)
88 return ltrim(fname.substr(0, idx));
89 idx = fname.rfind('.');
90 if (idx != docstring::npos && idx + 1 < fname.size())
91 fname = ltrim(fname.substr(idx + 1));
92 // test if we have a LaTeX Space in front
94 return fname.substr(2);
98 docstring const BibTeXInfo::getAbbreviatedAuthor() const
101 docstring const opt = trim(operator[]("label"));
106 split(opt, authors, '(');
110 docstring author = operator[]("author");
111 if (author.empty()) {
112 author = operator[]("editor");
117 // OK, we've got some names. Let's format them.
118 // Try to split the author list on " and "
119 vector<docstring> const authors =
120 getVectorFromString(author, from_ascii(" and "));
122 if (authors.size() == 2)
123 return bformat(_("%1$s and %2$s"),
124 familyName(authors[0]), familyName(authors[1]));
126 if (authors.size() > 2)
127 return bformat(_("%1$s et al."), familyName(authors[0]));
129 return familyName(authors[0]);
133 docstring const BibTeXInfo::getYear() const
136 docstring const opt = trim(operator[]("label"));
141 docstring const tmp = split(opt, authors, '(');
143 split(tmp, year, ')');
147 docstring year = operator[]("year");
154 docstring const BibTeXInfo::getInfo() const
157 BibTeXInfo::const_iterator it = find(from_ascii("ref"));
162 // This could be made a lot better using the entryType
163 // field to customize the output based upon entry type.
165 // Search for all possible "required" fields
166 docstring author = operator[]("author");
168 author = operator[]("editor");
170 docstring year = operator[]("year");
171 docstring title = operator[]("title");
172 docstring docLoc = operator[]("pages");
173 if (docLoc.empty()) {
174 docLoc = operator[]("chapter");
176 docLoc = from_ascii("Ch. ") + docLoc;
178 docLoc = from_ascii("pp. ") + docLoc;
181 docstring media = operator[]("journal");
183 media = operator[]("publisher");
185 media = operator[]("school");
187 media = operator[]("institution");
190 docstring volume = operator[]("volume");
192 odocstringstream result;
194 result << author << ", ";
198 result << ", " << media;
200 result << ", " << year;
202 result << ", " << docLoc;
204 docstring const result_str = rtrim(result.str());
205 if (!result_str.empty())
208 // This should never happen (or at least be very unusual!)
213 //////////////////////////////////////////////////////////////////////
217 //////////////////////////////////////////////////////////////////////
220 // A functor for use with sort, leading to case insensitive sorting
221 class compareNoCase: public binary_function<docstring, docstring, bool>
224 bool operator()(docstring const & s1, docstring const & s2) const {
225 return compare_no_case(s1, s2) < 0;
231 vector<docstring> const BiblioInfo::getKeys() const
233 vector<docstring> bibkeys;
234 BiblioInfo::const_iterator it = begin();
235 for (; it != end(); ++it)
236 bibkeys.push_back(it->first);
237 sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
242 vector<docstring> const BiblioInfo::getFields() const
244 vector<docstring> bibfields;
245 set<docstring>::const_iterator it = field_names_.begin();
246 set<docstring>::const_iterator end = field_names_.end();
247 for (; it != end; ++it)
248 bibfields.push_back(*it);
249 sort(bibfields.begin(), bibfields.end());
254 vector<docstring> const BiblioInfo::getEntries() const
256 vector<docstring> bibentries;
257 set<docstring>::const_iterator it = entry_types_.begin();
258 set<docstring>::const_iterator end = entry_types_.end();
259 for (; it != end; ++it)
260 bibentries.push_back(*it);
261 sort(bibentries.begin(), bibentries.end());
266 docstring const BiblioInfo::getAbbreviatedAuthor(docstring const & key) const
268 BiblioInfo::const_iterator it = find(key);
271 BibTeXInfo const & data = it->second;
272 return data.getAbbreviatedAuthor();
276 docstring const BiblioInfo::getYear(docstring const & key) const
278 BiblioInfo::const_iterator it = find(key);
281 BibTeXInfo const & data = it->second;
282 return data.getYear();
286 docstring const BiblioInfo::getInfo(docstring const & key) const
288 BiblioInfo::const_iterator it = find(key);
291 BibTeXInfo const & data = it->second;
292 return data.getInfo();
296 vector<docstring> const BiblioInfo::getCiteStrings(
297 docstring const & key, Buffer const & buf) const
299 CiteEngine const engine = buf.params().citeEngine();
300 if (engine == ENGINE_BASIC || engine == ENGINE_NATBIB_NUMERICAL)
301 return getNumericalStrings(key, buf);
303 return getAuthorYearStrings(key, buf);
307 vector<docstring> const BiblioInfo::getNumericalStrings(
308 docstring const & key, Buffer const & buf) const
311 return vector<docstring>();
313 docstring const author = getAbbreviatedAuthor(key);
314 docstring const year = getYear(key);
315 if (author.empty() || year.empty())
316 return vector<docstring>();
318 vector<CiteStyle> const & styles = citeStyles(buf.params().citeEngine());
320 vector<docstring> vec(styles.size());
321 for (size_t i = 0; i != vec.size(); ++i) {
327 str = from_ascii("[#ID]");
331 str = _("Add to bibliography only.");
335 str = author + " [#ID]";
339 str = author + " #ID";
343 str = from_ascii("#ID");
355 str = '(' + year + ')';
366 vector<docstring> const BiblioInfo::getAuthorYearStrings(
367 docstring const & key, Buffer const & buf) const
370 return vector<docstring>();
372 docstring const author = getAbbreviatedAuthor(key);
373 docstring const year = getYear(key);
374 if (author.empty() || year.empty())
375 return vector<docstring>();
377 vector<CiteStyle> const & styles = citeStyles(buf.params().citeEngine());
379 vector<docstring> vec(styles.size());
380 for (size_t i = 0; i != vec.size(); ++i) {
385 // jurabib only: Author/Annotator
386 // (i.e. the "before" field, 2nd opt arg)
387 str = author + "/<" + _("before") + '>';
391 str = _("Add to bibliography only.");
395 str = author + " (" + year + ')';
399 str = '(' + author + ", " + year + ')';
403 str = author + ' ' + year ;
407 str = author + ", " + year ;
419 str = '(' + year + ')';
428 void BiblioInfo::mergeBiblioInfo(BiblioInfo const & info)
430 bimap_.insert(info.begin(), info.end());
434 //////////////////////////////////////////////////////////////////////
438 //////////////////////////////////////////////////////////////////////
443 char const * const citeCommands[] = {
444 "cite", "citet", "citep", "citealt", "citealp",
445 "citeauthor", "citeyear", "citeyearpar", "nocite" };
447 unsigned int const nCiteCommands =
448 sizeof(citeCommands) / sizeof(char *);
450 CiteStyle const citeStylesArray[] = {
451 CITE, CITET, CITEP, CITEALT, CITEALP,
452 CITEAUTHOR, CITEYEAR, CITEYEARPAR, NOCITE };
454 unsigned int const nCiteStyles =
455 sizeof(citeStylesArray) / sizeof(CiteStyle);
457 CiteStyle const citeStylesFull[] = {
458 CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR };
460 unsigned int const nCiteStylesFull =
461 sizeof(citeStylesFull) / sizeof(CiteStyle);
463 CiteStyle const citeStylesUCase[] = {
464 CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR };
466 unsigned int const nCiteStylesUCase =
467 sizeof(citeStylesUCase) / sizeof(CiteStyle);
472 CitationStyle citationStyleFromString(string const & command)
478 string cmd = command;
480 s.forceUpperCase = true;
484 size_t const n = cmd.size() - 1;
485 if (cmd != "cite" && cmd[n] == '*') {
487 cmd = cmd.substr(0, n);
490 char const * const * const last = citeCommands + nCiteCommands;
491 char const * const * const ptr = find(citeCommands, last, cmd);
494 size_t idx = ptr - citeCommands;
495 s.style = citeStylesArray[idx];
501 string citationStyleToString(const CitationStyle & s)
503 string cite = citeCommands[s.style];
505 CiteStyle const * last = citeStylesFull + nCiteStylesFull;
506 if (find(citeStylesFull, last, s.style) != last)
510 if (s.forceUpperCase) {
511 CiteStyle const * last = citeStylesUCase + nCiteStylesUCase;
512 if (find(citeStylesUCase, last, s.style) != last)
519 vector<CiteStyle> citeStyles(CiteEngine engine)
521 unsigned int nStyles = 0;
522 unsigned int start = 0;
529 case ENGINE_NATBIB_AUTHORYEAR:
530 case ENGINE_NATBIB_NUMERICAL:
531 nStyles = nCiteStyles - 1;
535 nStyles = nCiteStyles;
540 vector<CiteStyle> styles(nStyles);
543 for (; i != styles.size(); ++i, ++j)
544 styles[i] = citeStylesArray[j];