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/lassert.h"
28 #include "support/docstream.h"
29 #include "support/gettext.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::getValueForField(docstring
const & field
) const
59 BibTeXInfo::const_iterator it
= find(field
);
62 static docstring
const empty_value
= docstring();
67 docstring
const & BibTeXInfo::getValueForField(string
const & field
) const
69 return getValueForField(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);
99 docstring
const BibTeXInfo::getAbbreviatedAuthor() const
104 docstring author
= getValueForField("author");
106 if (author
.empty()) {
107 author
= getValueForField("editor");
112 // OK, we've got some names. Let's format them.
113 // Try to split the author list on " and "
114 vector
<docstring
> const authors
=
115 getVectorFromString(author
, from_ascii(" and "));
117 if (authors
.size() == 2)
118 return bformat(_("%1$s and %2$s"),
119 familyName(authors
[0]), familyName(authors
[1]));
121 if (authors
.size() > 2)
122 return bformat(_("%1$s et al."), familyName(authors
[0]));
124 return familyName(authors
[0]);
128 docstring
const BibTeXInfo::getYear() const
133 docstring year
= getValueForField("year");
140 docstring
const BibTeXInfo::getInfo() const
143 BibTeXInfo::const_iterator it
= find(from_ascii("ref"));
148 // This could be made a lot better using the entryType
149 // field to customize the output based upon entry type.
151 // Search for all possible "required" fields
152 docstring author
= getValueForField("author");
154 author
= getValueForField("editor");
156 docstring year
= getValueForField("year");
157 docstring title
= getValueForField("title");
158 docstring docLoc
= getValueForField("pages");
159 if (docLoc
.empty()) {
160 docLoc
= getValueForField("chapter");
162 docLoc
= from_ascii("Ch. ") + docLoc
;
164 docLoc
= from_ascii("pp. ") + docLoc
;
167 docstring media
= getValueForField("journal");
169 media
= getValueForField("publisher");
171 media
= getValueForField("school");
173 media
= getValueForField("institution");
176 docstring volume
= getValueForField("volume");
178 odocstringstream result
;
180 result
<< author
<< ", ";
184 result
<< ", " << media
;
186 result
<< ", " << year
;
188 result
<< ", " << docLoc
;
190 docstring
const result_str
= rtrim(result
.str());
191 if (!result_str
.empty())
194 // This should never happen (or at least be very unusual!)
199 //////////////////////////////////////////////////////////////////////
203 //////////////////////////////////////////////////////////////////////
206 // A functor for use with sort, leading to case insensitive sorting
207 class compareNoCase
: public binary_function
<docstring
, docstring
, bool>
210 bool operator()(docstring
const & s1
, docstring
const & s2
) const {
211 return compare_no_case(s1
, s2
) < 0;
217 vector
<docstring
> const BiblioInfo::getKeys() const
219 vector
<docstring
> bibkeys
;
220 BiblioInfo::const_iterator it
= begin();
221 for (; it
!= end(); ++it
)
222 bibkeys
.push_back(it
->first
);
223 sort(bibkeys
.begin(), bibkeys
.end(), compareNoCase());
228 vector
<docstring
> const BiblioInfo::getFields() const
230 vector
<docstring
> bibfields
;
231 set
<docstring
>::const_iterator it
= field_names_
.begin();
232 set
<docstring
>::const_iterator end
= field_names_
.end();
233 for (; it
!= end
; ++it
)
234 bibfields
.push_back(*it
);
235 sort(bibfields
.begin(), bibfields
.end());
240 vector
<docstring
> const BiblioInfo::getEntries() const
242 vector
<docstring
> bibentries
;
243 set
<docstring
>::const_iterator it
= entry_types_
.begin();
244 set
<docstring
>::const_iterator end
= entry_types_
.end();
245 for (; it
!= end
; ++it
)
246 bibentries
.push_back(*it
);
247 sort(bibentries
.begin(), bibentries
.end());
252 docstring
const BiblioInfo::getAbbreviatedAuthor(docstring
const & key
) const
254 BiblioInfo::const_iterator it
= find(key
);
257 BibTeXInfo
const & data
= it
->second
;
258 return data
.getAbbreviatedAuthor();
262 docstring
const BiblioInfo::getYear(docstring
const & key
) const
264 BiblioInfo::const_iterator it
= find(key
);
267 BibTeXInfo
const & data
= it
->second
;
268 return data
.getYear();
272 docstring
const BiblioInfo::getInfo(docstring
const & key
) const
274 BiblioInfo::const_iterator it
= find(key
);
277 BibTeXInfo
const & data
= it
->second
;
278 return data
.getInfo();
282 vector
<docstring
> const BiblioInfo::getCiteStrings(
283 docstring
const & key
, Buffer
const & buf
) const
285 CiteEngine
const engine
= buf
.params().citeEngine();
286 if (engine
== ENGINE_BASIC
|| engine
== ENGINE_NATBIB_NUMERICAL
)
287 return getNumericalStrings(key
, buf
);
289 return getAuthorYearStrings(key
, buf
);
293 vector
<docstring
> const BiblioInfo::getNumericalStrings(
294 docstring
const & key
, Buffer
const & buf
) const
297 return vector
<docstring
>();
299 docstring
const author
= getAbbreviatedAuthor(key
);
300 docstring
const year
= getYear(key
);
301 if (author
.empty() || year
.empty())
302 return vector
<docstring
>();
304 vector
<CiteStyle
> const & styles
= citeStyles(buf
.params().citeEngine());
306 vector
<docstring
> vec(styles
.size());
307 for (size_t i
= 0; i
!= vec
.size(); ++i
) {
313 str
= from_ascii("[#ID]");
317 str
= _("Add to bibliography only.");
321 str
= author
+ " [#ID]";
325 str
= author
+ " #ID";
329 str
= from_ascii("#ID");
341 str
= '(' + year
+ ')';
352 vector
<docstring
> const BiblioInfo::getAuthorYearStrings(
353 docstring
const & key
, Buffer
const & buf
) const
356 return vector
<docstring
>();
358 docstring
const author
= getAbbreviatedAuthor(key
);
359 docstring
const year
= getYear(key
);
360 if (author
.empty() || year
.empty())
361 return vector
<docstring
>();
363 vector
<CiteStyle
> const & styles
= citeStyles(buf
.params().citeEngine());
365 vector
<docstring
> vec(styles
.size());
366 for (size_t i
= 0; i
!= vec
.size(); ++i
) {
371 // jurabib only: Author/Annotator
372 // (i.e. the "before" field, 2nd opt arg)
373 str
= author
+ "/<" + _("before") + '>';
377 str
= _("Add to bibliography only.");
381 str
= author
+ " (" + year
+ ')';
385 str
= '(' + author
+ ", " + year
+ ')';
389 str
= author
+ ' ' + year
;
393 str
= author
+ ", " + year
;
405 str
= '(' + year
+ ')';
414 void BiblioInfo::mergeBiblioInfo(BiblioInfo
const & info
)
416 bimap_
.insert(info
.begin(), info
.end());
420 //////////////////////////////////////////////////////////////////////
424 //////////////////////////////////////////////////////////////////////
429 char const * const citeCommands
[] = {
430 "cite", "nocite", "citet", "citep", "citealt", "citealp",
431 "citeauthor", "citeyear", "citeyearpar" };
433 unsigned int const nCiteCommands
=
434 sizeof(citeCommands
) / sizeof(char *);
436 CiteStyle
const citeStylesArray
[] = {
437 CITE
, NOCITE
, CITET
, CITEP
, CITEALT
,
438 CITEALP
, CITEAUTHOR
, CITEYEAR
, CITEYEARPAR
};
440 unsigned int const nCiteStyles
=
441 sizeof(citeStylesArray
) / sizeof(CiteStyle
);
443 CiteStyle
const citeStylesFull
[] = {
444 CITET
, CITEP
, CITEALT
, CITEALP
, CITEAUTHOR
};
446 unsigned int const nCiteStylesFull
=
447 sizeof(citeStylesFull
) / sizeof(CiteStyle
);
449 CiteStyle
const citeStylesUCase
[] = {
450 CITET
, CITEP
, CITEALT
, CITEALP
, CITEAUTHOR
};
452 unsigned int const nCiteStylesUCase
=
453 sizeof(citeStylesUCase
) / sizeof(CiteStyle
);
458 CitationStyle
citationStyleFromString(string
const & command
)
464 string cmd
= command
;
466 s
.forceUpperCase
= true;
470 size_t const n
= cmd
.size() - 1;
471 if (cmd
!= "cite" && cmd
[n
] == '*') {
473 cmd
= cmd
.substr(0, n
);
476 char const * const * const last
= citeCommands
+ nCiteCommands
;
477 char const * const * const ptr
= find(citeCommands
, last
, cmd
);
480 size_t idx
= ptr
- citeCommands
;
481 s
.style
= citeStylesArray
[idx
];
487 string
citationStyleToString(const CitationStyle
& s
)
489 string cite
= citeCommands
[s
.style
];
491 CiteStyle
const * last
= citeStylesFull
+ nCiteStylesFull
;
492 if (find(citeStylesFull
, last
, s
.style
) != last
)
496 if (s
.forceUpperCase
) {
497 CiteStyle
const * last
= citeStylesUCase
+ nCiteStylesUCase
;
498 if (find(citeStylesUCase
, last
, s
.style
) != last
)
505 vector
<CiteStyle
> citeStyles(CiteEngine engine
)
507 unsigned int nStyles
= 0;
508 unsigned int start
= 0;
515 case ENGINE_NATBIB_AUTHORYEAR
:
516 case ENGINE_NATBIB_NUMERICAL
:
517 nStyles
= nCiteStyles
- 1;
521 nStyles
= nCiteStyles
;
526 vector
<CiteStyle
> styles(nStyles
);
529 for (; i
!= styles
.size(); ++i
, ++j
)
530 styles
[i
] = citeStylesArray
[j
];