* \author Herbert Voß
* \author Richard Heck
* \author Julien Rioux
+ * \author Jürgen Spitzmüller
*
* Full author contact details are available in file CREDITS.
*/
#include "support/regex.h"
#include "support/textutils.h"
+#include <map>
#include <set>
using namespace std;
namespace {
-// gets the "family name" from an author-type string
-docstring familyName(docstring const & name)
+// gets the "prename" and "family name" from an author-type string
+pair<docstring, docstring> nameParts(docstring const & name)
{
if (name.empty())
- return docstring();
+ return make_pair(docstring(), docstring());
// first we look for a comma, and take the last name to be everything
// preceding the right-most one, so that we also get the "jr" part.
- docstring::size_type idx = name.rfind(',');
- if (idx != docstring::npos)
- return ltrim(name.substr(0, idx));
+ vector<docstring> pieces = getVectorFromString(name);
+ if (pieces.size() > 1)
+ // whether we have a jr. part or not, it's always
+ // the first and last item (reversed)
+ return make_pair(pieces.back(), pieces.front());
// OK, so now we want to look for the last name. We're going to
// include the "von" part. This isn't perfect.
// Split on spaces, to get various tokens.
- vector<docstring> pieces = getVectorFromString(name, from_ascii(" "));
+ pieces = getVectorFromString(name, from_ascii(" "));
// If we only get two, assume the last one is the last name
if (pieces.size() <= 2)
- return pieces.back();
+ return make_pair(pieces.front(), pieces.back());
- // Now we look for the first token that begins with a lower case letter.
+ // Now we look for the first token that begins with
+ // a lower case letter or an opening group {.
+ docstring prename;
vector<docstring>::const_iterator it = pieces.begin();
vector<docstring>::const_iterator en = pieces.end();
+ bool first = true;
for (; it != en; ++it) {
if ((*it).empty())
continue;
char_type const c = (*it)[0];
- if (isLower(c))
+ if (isLower(c) || c == '{')
break;
+ if (!first)
+ prename += " ";
+ else
+ first = false;
+ prename += *it;
}
- if (it == en) // we never found a "von"
- return pieces.back();
+ if (it == en) // we never found a "von" or group
+ return make_pair(prename, pieces.back());
- // reconstruct what we need to return
- docstring retval;
- bool first = true;
+ // reconstruct the family name
+ docstring surname;
+ first = true;
for (; it != en; ++it) {
if (!first)
- retval += " ";
+ surname += " ";
else
first = false;
- retval += *it;
+ surname += *it;
}
- return retval;
+ return make_pair(prename, surname);
+}
+
+
+docstring constructName(docstring const & name, string const scheme)
+{
+ // re-constructs a name from name parts according
+ // to a given scheme
+ docstring const prename = nameParts(name).first;
+ docstring const surname = nameParts(name).second;
+ docstring result = from_ascii(scheme);
+ result = subst(result, from_ascii("%prename%"), prename);
+ result = subst(result, from_ascii("%surname%"), surname);
+ return result;
+}
+
+
+bool multipleAuthors(docstring const author)
+{
+ vector<docstring> const authors =
+ getVectorFromString(author, from_ascii(" and "));
+ return authors.size() > 1;
}
{}
-docstring const BibTeXInfo::getAuthorList(
- Buffer const * buf, bool full, bool forceshort) const
+docstring const BibTeXInfo::getAuthorOrEditorList(Buffer const * buf,
+ bool full, bool forceshort) const
+{
+ docstring author = operator[]("author");
+ if (author.empty())
+ author = operator[]("editor");
+
+ return getAuthorList(buf, author, full, forceshort);
+}
+
+
+docstring const BibTeXInfo::getAuthorList(Buffer const * buf, docstring author,
+ bool full, bool forceshort, bool allnames,
+ bool beginning) const
{
// Maxnames treshold depend on engine
size_t maxnames = buf ?
return authors;
}
- docstring author = operator[]("author");
- if (author.empty()) {
- author = operator[]("editor");
- if (author.empty())
- return author;
- }
+ if (author.empty())
+ return author;
// FIXME Move this to a separate routine that can
// be called from elsewhere.
string const pairnamesep =
buf ? buf->params().documentClass().getCiteMacro(engine_type, "_pairnamesep")
: " and ";
+ string firstnameform =
+ buf ? buf->params().documentClass().getCiteMacro(engine_type, "!firstnameform")
+ : "%surname%, %prename%";
+ if (!beginning)
+ firstnameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!firstbynameform")
+ : "%prename% %surname%";
+ string othernameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!othernameform")
+ : "%surname%, %prename%";
+ if (!beginning)
+ othernameform = buf ? buf->params().documentClass().getCiteMacro(engine_type, "!otherbynameform")
+ : "%prename% %surname%";
// Shorten the list (with et al.) if forceshort is set
// and the list can actually be shorten, else if maxcitenames
retval += buf ? buf->B_(lastnamesep) : from_ascii(lastnamesep);
} else if (i > 0)
retval += buf ? buf->B_(namesep) : from_ascii(namesep);
- retval += familyName(*it);
+ if (allnames)
+ retval += (i == 0) ? constructName(*it, firstnameform)
+ : constructName(*it, othernameform);
+ else
+ retval += nameParts(*it).second;
+ }
+ if (shorten) {
+ if (allnames)
+ retval = constructName(authors[0], firstnameform) + (buf ? buf->B_(etal) : from_ascii(etal));
+ else
+ retval = nameParts(authors[0]).second + (buf ? buf->B_(etal) : from_ascii(etal));
}
- if (shorten)
- retval = familyName(authors[0]) + (buf ? buf->B_(etal) : from_ascii(etal));
return convertLaTeXCommands(retval);
}
static int const max_passes = 5000;
// the use of overly large keys can lead to performance problems, due
// to eventual attempts to convert LaTeX macros to unicode. See bug
- // #8944. This is perhaps not the best solution, but it will have to
- // do for now.
- static size_t const max_keysize = 128;
+ // #8944. By default, the size is limited to 128 (in CiteItem), but
+ // for specific purposes (such as XHTML export), it needs to be enlarged
+ // This is perhaps not the best solution, but it will have to do for now.
+ size_t const max_keysize = ci.max_key_size;
odocstringstream ret; // return value
string key;
bool scanning_key = false;
getValueForKey(optkey, buf, ci, xrefs);
if (optkey == "next" && next)
ret << ifpart; // without expansion
- else if (!val.empty()) {
+ else if (optkey == "second" && second) {
+ int newcounter = 0;
+ ret << expandFormat(ifpart, xrefs, newcounter, buf,
+ ci, next);
+ } else if (!val.empty()) {
int newcounter = 0;
ret << expandFormat(ifpart, xrefs, newcounter, buf,
ci, next);
// FIXME: dialog, textbefore and textafter have nothing to do with this
if (key == "dialog" && ci.context == CiteItem::Dialog)
ret = from_ascii("x"); // any non-empty string will do
+ else if (key == "export" && ci.context == CiteItem::Export)
+ ret = from_ascii("x"); // any non-empty string will do
else if (key == "ifstar" && ci.Starred)
ret = from_ascii("x"); // any non-empty string will do
+ else if (key == "ifqualified" && ci.isQualified)
+ ret = from_ascii("x"); // any non-empty string will do
else if (key == "entrytype")
ret = entry_type_;
+ else if (prefixIs(key, "ifentrytype:")
+ && from_ascii(key.substr(12)) == entry_type_)
+ ret = from_ascii("x"); // any non-empty string will do
else if (key == "key")
ret = bib_key_;
else if (key == "label")
ret = modifier_;
else if (key == "numericallabel")
ret = cite_number_;
- else if (key == "abbrvauthor") {
- // Special key to provide abbreviated author names,
+ else if (prefixIs(key, "ifmultiple:")) {
+ // Return whether we have multiple authors
+ docstring const kind = operator[](from_ascii(key.substr(11)));
+ if (multipleAuthors(kind))
+ ret = from_ascii("x"); // any non-empty string will do
+ }
+ else if (prefixIs(key, "abbrvnames:")) {
+ // Special key to provide abbreviated name list,
+ // with respect to maxcitenames. Suitable for Bibliography
+ // beginnings.
+ docstring const kind = operator[](from_ascii(key.substr(11)));
+ ret = getAuthorList(&buf, kind, false, false, true);
+ if (ci.forceUpperCase && isLowerCase(ret[0]))
+ ret[0] = uppercase(ret[0]);
+ } else if (prefixIs(key, "fullnames:")) {
+ // Return a full name list. Suitable for Bibliography
+ // beginnings.
+ docstring const kind = operator[](from_ascii(key.substr(10)));
+ ret = getAuthorList(&buf, kind, true, false, true);
+ if (ci.forceUpperCase && isLowerCase(ret[0]))
+ ret[0] = uppercase(ret[0]);
+ } else if (prefixIs(key, "forceabbrvnames:")) {
+ // Special key to provide abbreviated name lists,
+ // irrespective of maxcitenames. Suitable for Bibliography
+ // beginnings.
+ docstring const kind = operator[](from_ascii(key.substr(15)));
+ ret = getAuthorList(&buf, kind, false, true, true);
+ if (ci.forceUpperCase && isLowerCase(ret[0]))
+ ret[0] = uppercase(ret[0]);
+ } else if (prefixIs(key, "abbrvbynames:")) {
+ // Special key to provide abbreviated name list,
+ // with respect to maxcitenames. Suitable for further names inside a
+ // bibliography item // (such as "ed. by ...")
+ docstring const kind = operator[](from_ascii(key.substr(11)));
+ ret = getAuthorList(&buf, kind, false, false, true, false);
+ if (ci.forceUpperCase && isLowerCase(ret[0]))
+ ret[0] = uppercase(ret[0]);
+ } else if (prefixIs(key, "fullbynames:")) {
+ // Return a full name list. Suitable for further names inside a
+ // bibliography item // (such as "ed. by ...")
+ docstring const kind = operator[](from_ascii(key.substr(10)));
+ ret = getAuthorList(&buf, kind, true, false, true, false);
+ if (ci.forceUpperCase && isLowerCase(ret[0]))
+ ret[0] = uppercase(ret[0]);
+ } else if (prefixIs(key, "forceabbrvbynames:")) {
+ // Special key to provide abbreviated name lists,
+ // irrespective of maxcitenames. Suitable for further names inside a
+ // bibliography item // (such as "ed. by ...")
+ docstring const kind = operator[](from_ascii(key.substr(15)));
+ ret = getAuthorList(&buf, kind, false, true, true, false);
+ if (ci.forceUpperCase && isLowerCase(ret[0]))
+ ret[0] = uppercase(ret[0]);
+ } else if (key == "abbrvciteauthor") {
+ // Special key to provide abbreviated author or
+ // editor names (suitable for citation labels),
// with respect to maxcitenames.
- ret = getAuthorList(&buf, false, false);
+ ret = getAuthorOrEditorList(&buf, false, false);
if (ci.forceUpperCase && isLowerCase(ret[0]))
ret[0] = uppercase(ret[0]);
- } else if (key == "fullauthor") {
- // Return a full author list
- ret = getAuthorList(&buf, true, false);
+ } else if (key == "fullciteauthor") {
+ // Return a full author or editor list (for citation labels)
+ ret = getAuthorOrEditorList(&buf, true, false);
if (ci.forceUpperCase && isLowerCase(ret[0]))
ret[0] = uppercase(ret[0]);
- } else if (key == "forceabbrvauthor") {
- // Special key to provide abbreviated author names,
+ } else if (key == "forceabbrvciteauthor") {
+ // Special key to provide abbreviated author or
+ // editor names (suitable for citation labels),
// irrespective of maxcitenames.
- ret = getAuthorList(&buf, false, true);
+ ret = getAuthorOrEditorList(&buf, false, true);
if (ci.forceUpperCase && isLowerCase(ret[0]))
ret[0] = uppercase(ret[0]);
} else if (key == "bibentry") {
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_)));
+ from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_), false));
int counter = 0;
ret = expandFormat(format, xrefs, counter, buf, ci, false, false);
} else if (key == "textbefore")
ret = ci.textBefore;
else if (key == "textafter")
ret = ci.textAfter;
+ else if (key == "curpretext")
+ ret = ci.getPretexts()[bib_key_];
+ else if (key == "curposttext")
+ ret = ci.getPosttexts()[bib_key_];
else if (key == "year")
ret = getYear();
}
}
-docstring const BiblioInfo::getAuthorList(docstring const & key, Buffer const & buf) const
+docstring const BiblioInfo::getAuthorOrEditorList(docstring const & key, Buffer const & buf) const
{
BiblioInfo::const_iterator it = find(key);
if (it == end())
return docstring();
BibTeXInfo const & data = it->second;
- return data.getAuthorList(&buf, false);
+ return data.getAuthorOrEditorList(&buf, false);
}
CiteEngineType const engine_type = buf.params().citeEngineType();
DocumentClass const & dc = buf.params().documentClass();
- docstring const & format = from_utf8(dc.getCiteFormat(engine_type, style, "cite"));
+ docstring const & format = from_utf8(dc.getCiteFormat(engine_type, style, false, "cite"));
docstring ret = format;
vector<docstring>::const_iterator key = keys.begin();
vector<docstring>::const_iterator ken = keys.end();
- for (; key != ken; ++key) {
+ for (int i = 0; key != ken; ++key, ++i) {
BiblioInfo::const_iterator it = find(*key);
BibTeXInfo empty_data;
empty_data.key(*key);
// used in xhtml to sort a list of BibTeXInfo objects
bool lSorter(BibTeXInfo const * lhs, BibTeXInfo const * rhs)
{
- docstring const lauth = lhs->getAuthorList();
- docstring const rauth = rhs->getAuthorList();
+ docstring const lauth = lhs->getAuthorOrEditorList();
+ docstring const rauth = rhs->getAuthorOrEditorList();
docstring const lyear = lhs->getYear();
docstring const ryear = rhs->getYear();
docstring const ltitl = lhs->operator[]("title");
// the first test.
// coverity[FORWARD_NULL]
if (it != cited_entries_.begin()
- && entry.getAuthorList() == last->second.getAuthorList()
+ && entry.getAuthorOrEditorList() == last->second.getAuthorOrEditorList()
// we access the year via getYear() so as to get it from the xref,
// if we need to do so
&& getYear(entry.key()) == getYear(last->second.key())) {
if (numbers) {
entry.label(entry.citeNumber());
} else {
- docstring const auth = entry.getAuthorList(&buf, false);
+ 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);