* \author Angus Leeming <a.leeming@ic.ac.uk>
*/
+#include <config.h>
+
#include <vector>
#include <algorithm>
#pragma implementation
#endif
-#include <config.h>
-
-/*
-#include "buffer.h"
-#include "Dialogs.h"
-#include "LyXView.h"
-*/
#include "LString.h"
#include "biblio.h"
+#include "gettext.h" // for _()
#include "helper_funcs.h"
#include "support/lstrings.h"
#include "support/LAssert.h"
using std::find;
using std::min;
-using std::pair;
using std::vector;
using std::sort;
namespace biblio
{
+namespace {
-// A functor for use with std::sort, leading to case insensitive sorting
-struct compareNoCase: public std::binary_function<string, string, bool>
-{
- bool operator()(string const & s1, string const & s2) const {
- return compare_no_case(s1, s2) < 0;
- }
-};
-
-vector<string> const getKeys(InfoMap const & map)
-{
- vector<string> bibkeys;
+using namespace biblio;
+
+char const * const citeCommands[] = {
+ "cite", "citet", "citep", "citealt", "citealp", "citeauthor",
+ "citeyear", "citeyearpar" };
- typedef std::map<string, string>::value_type InfoMapValue;
+unsigned int const nCiteCommands =
+ sizeof(citeCommands) / sizeof(char *);
- for (InfoMap::const_iterator it = map.begin(); it != map.end(); ++it) {
- bibkeys.push_back(it->first);
- }
+CiteStyle const citeStyles[] = {
+ CITE, CITET, CITEP, CITEALT, CITEALP,
+ CITEAUTHOR, CITEYEAR, CITEYEARPAR };
- sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
- return bibkeys;
-}
+unsigned int const nCiteStyles =
+ sizeof(citeStyles) / sizeof(CiteStyle);
+CiteStyle const citeStylesFull[] = {
+ CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR };
-string const getInfo(InfoMap const & map, string const & key)
-{
- Assert(!map.empty());
+unsigned int const nCiteStylesFull =
+ sizeof(citeStylesFull) / sizeof(CiteStyle);
- string result;
+CiteStyle const citeStylesUCase[] = {
+ CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR };
- InfoMap::const_iterator it = map.find(key);
- if (it != map.end()) {
- // Search for all possible "required" keys
- string author = parseBibTeX(it->second, "author");
- if (author.empty())
- author = parseBibTeX(it->second, "editor");
-
- string year = parseBibTeX(it->second, "year");
- string title = parseBibTeX(it->second, "title");
- string booktitle = parseBibTeX(it->second, "booktitle");
- string chapter = parseBibTeX(it->second, "chapter");
- string pages = parseBibTeX(it->second, "pages");
-
- string media = parseBibTeX(it->second, "journal");
- if (media.empty())
- media = parseBibTeX(it->second, "publisher");
- if (media.empty())
- media = parseBibTeX(it->second, "school");
- if (media.empty())
- media = parseBibTeX(it->second, "institution");
-
- result = author;
- if (!year.empty())
- result += ", " + year;
- if (!title.empty())
- result += ", " + title;
- if (!booktitle.empty())
- result += ", in " + booktitle;
- if (!chapter.empty())
- result += ", Ch. " + chapter;
- if (!media.empty())
- result += ", " + media;
- if (!pages.empty())
- result += ", pp. " + pages;
-
- if (result.empty()) // not a BibTeX record
- result = it->second;
- }
-
- return result;
-}
+unsigned int const nCiteStylesUCase =
+ sizeof(citeStylesUCase) / sizeof(CiteStyle);
-vector<string>::const_iterator
-searchKeys(InfoMap const & theMap,
- vector<string> const & keys,
- string const & expr,
- vector<string>::const_iterator start,
- Search type,
- Direction dir,
- bool caseSensitive)
-{
- // Preliminary checks
- if(start < keys.begin() || start >= keys.end())
- return keys.end();
-
- string search_expr = frontStrip(strip(expr));
- if (search_expr.empty())
- return keys.end();
-
- if (type == SIMPLE)
- return simpleSearch(theMap, keys, search_expr, start, dir,
- caseSensitive);
-
- return regexSearch(theMap, keys, search_expr, start, dir);
-}
-
-
+// The functions doing the dirty work for the search.
vector<string>::const_iterator
simpleSearch(InfoMap const & theMap,
vector<string> const & keys,
(dir == FORWARD) ? (++it) : (--it)) {
string data = (*it);
- biblio::InfoMap::const_iterator info = theMap.find(*it);
+ InfoMap::const_iterator info = theMap.find(*it);
if (info != theMap.end())
data += " " + info->second;
if (!caseSensitive)
return keys.end();
}
-
+
vector<string>::const_iterator
regexSearch(InfoMap const & theMap,
vector<string> const & keys,
(dir == FORWARD) ? (++it) : (--it)) {
string data = (*it);
- biblio::InfoMap::const_iterator info = theMap.find(*it);
+ InfoMap::const_iterator info = theMap.find(*it);
if (info != theMap.end())
data += " " + info->second;
return keys.end();
}
+string const familyName(string const & name)
+{
+ // Very simple parser
+ string fname = name;
+
+ string::size_type idx = fname.rfind(".");
+ if (idx != string::npos)
+ fname = frontStrip(fname.substr(idx+1));
+
+ return fname;
+}
+
+
+string const getAbbreviatedAuthor(InfoMap const & map, string const & key)
+{
+ lyx::Assert(!map.empty());
+
+ InfoMap::const_iterator it = map.find(key);
+
+ string author;
+ if (it != map.end()) {
+ author = parseBibTeX(it->second, "author");
+ if (author.empty())
+ author = parseBibTeX(it->second, "editor");
+
+ vector<string> authors = getVectorFromString(author, "and");
+
+ if (!authors.empty()) {
+ author.erase();
+
+ for (vector<string>::iterator it = authors.begin();
+ it != authors.end(); ++it) {
+ *it = familyName(strip(*it));
+ }
+
+ author = authors[0];
+ if (authors.size() == 2)
+ author += _(" and ") + authors[1];
+ else if (authors.size() > 2)
+ author += _(" et al.");
+ }
+ }
+
+ if (author.empty())
+ author = _("Caesar et al.");
+
+ return author;
+}
+
+
+string const getYear(InfoMap const & map, string const & key)
+{
+ lyx::Assert(!map.empty());
+
+ InfoMap::const_iterator it = map.find(key);
+
+ string year;
+
+ if (it != map.end())
+ year = parseBibTeX(it->second, "year");
+
+ if (year.empty())
+ year = "50BC";
+
+ return year;
+}
+
+} // namespace anon
+
+
+
+
+
+
+
+// A functor for use with std::sort, leading to case insensitive sorting
+struct compareNoCase: public std::binary_function<string, string, bool>
+{
+ bool operator()(string const & s1, string const & s2) const {
+ return compare_no_case(s1, s2) < 0;
+ }
+};
+
+vector<string> const getKeys(InfoMap const & map)
+{
+ vector<string> bibkeys;
+
+ for (InfoMap::const_iterator it = map.begin(); it != map.end(); ++it) {
+ bibkeys.push_back(it->first);
+ }
+
+ sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
+ return bibkeys;
+}
+
+
+string const getInfo(InfoMap const & map, string const & key)
+{
+ lyx::Assert(!map.empty());
+
+ InfoMap::const_iterator it = map.find(key);
+ if (it == map.end()) return string();
+
+ // Search for all possible "required" keys
+ string author = parseBibTeX(it->second, "author");
+ if (author.empty())
+ author = parseBibTeX(it->second, "editor");
+
+ string year = parseBibTeX(it->second, "year");
+ string title = parseBibTeX(it->second, "title");
+ string booktitle = parseBibTeX(it->second, "booktitle");
+ string chapter = parseBibTeX(it->second, "chapter");
+ string number = parseBibTeX(it->second, "number");
+ string volume = parseBibTeX(it->second, "volume");
+ string pages = parseBibTeX(it->second, "pages");
+
+ string media = parseBibTeX(it->second, "journal");
+ if (media.empty())
+ media = parseBibTeX(it->second, "publisher");
+ if (media.empty())
+ media = parseBibTeX(it->second, "school");
+ if (media.empty())
+ media = parseBibTeX(it->second, "institution");
+
+ ostringstream result;
+ result << author;
+ if (!title.empty())
+ result << ", " << title;
+ if (!booktitle.empty())
+ result << ", in " << booktitle;
+ if (!chapter.empty())
+ result << ", Ch. " << chapter;
+ if (!media.empty())
+ result << ", " << media;
+ if (!volume.empty())
+ result << ", vol. " << volume;
+ if (!number.empty())
+ result << ", no. " << number;
+ if (!pages.empty())
+ result << ", pp. " << pages;
+ if (!year.empty())
+ result << ", " << year;
+
+ if (result.str().empty()) // not a BibTeX record
+ result << it->second;
+
+ return result.str().c_str();
+}
+
+
+vector<string>::const_iterator
+searchKeys(InfoMap const & theMap,
+ vector<string> const & keys,
+ string const & expr,
+ vector<string>::const_iterator start,
+ Search type,
+ Direction dir,
+ bool caseSensitive)
+{
+ // Preliminary checks
+ if(start < keys.begin() || start >= keys.end())
+ return keys.end();
+
+ string search_expr = frontStrip(strip(expr));
+ if (search_expr.empty())
+ return keys.end();
+
+ if (type == SIMPLE)
+ return simpleSearch(theMap, keys, search_expr, start, dir,
+ caseSensitive);
+
+ return regexSearch(theMap, keys, search_expr, start, dir);
+}
+
+
string const parseBibTeX(string data, string const & findkey)
{
string keyvalue;
}
-} // namespace biblio
+CitationStyle const getCitationStyle(string const & command)
+{
+ if (command.empty()) return CitationStyle();
+
+ CitationStyle cs;
+ string cmd = command;
+
+ if (cmd[0] == 'C') {
+ cs.forceUCase = true;
+ cmd[0] = 'c';
+ }
+
+ size_t n = cmd.size()-1;
+ if (cmd[n] == '*') {
+ cs.full = true;
+ cmd = cmd.substr(0,n);
+ }
+
+ char const * const * const last = citeCommands + nCiteCommands;
+ char const * const * const ptr = std::find(citeCommands, last, cmd);
+
+ if (ptr != last) {
+ size_t idx = ptr - citeCommands;
+ cs.style = citeStyles[idx];
+ }
+
+ return cs;
+}
+
+
+string const getCiteCommand(CiteStyle command, bool full, bool forceUCase)
+{
+ string cite = citeCommands[command];
+ if (full) {
+ CiteStyle const * last = citeStylesFull + nCiteStylesFull;
+ if (std::find(citeStylesFull, last, command) != last)
+ cite += "*";
+ }
+
+ if (forceUCase) {
+ CiteStyle const * last = citeStylesUCase + nCiteStylesUCase;
+ if (std::find(citeStylesUCase, last, command) != last)
+ cite[0] = 'C';
+ }
+
+ return cite;
+}
+
+
+vector<CiteStyle> const getCiteStyles(bool usingNatbib)
+{
+ unsigned int nStyles = 1;
+ unsigned int start = 0;
+ if (usingNatbib) {
+ nStyles = nCiteStyles - 1;
+ start = 1;
+ }
+
+ vector<CiteStyle> styles(nStyles);
+
+ vector<CiteStyle>::size_type i = 0;
+ int j = start;
+ for (; i != styles.size(); ++i, ++j) {
+ styles[i] = citeStyles[j];
+ }
+
+ return styles;
+}
+
+vector<string> const
+getNumericalStrings(string const & key,
+ InfoMap const & map, vector<CiteStyle> const & styles)
+{
+ if (map.empty()) {
+ vector<string> vec(1);
+ vec[0] = _("No database");
+ return vec;
+ }
+
+ vector<string> vec(styles.size());
+
+ string const author = getAbbreviatedAuthor(map, key);
+ string const year = getYear(map, key);
+
+ for (vector<string>::size_type i = 0; i != vec.size(); ++i) {
+ string str;
+
+ switch (styles[i]) {
+ case CITE:
+ case CITEP:
+ str = "[#ID]";
+ break;
+
+ case CITET:
+ str = author + " [#ID]";
+ break;
+
+ case CITEALT:
+ str = author + " #ID";
+ break;
+
+ case CITEALP:
+ str = "#ID";
+ break;
+
+ case CITEAUTHOR:
+ str = author;
+ break;
+
+ case CITEYEAR:
+ str = year;
+ break;
+
+ case CITEYEARPAR:
+ str = "(" + year + ")";
+ break;
+ }
+
+ vec[i] = str;
+ }
+
+ return vec;
+}
+
+
+vector<string> const
+getAuthorYearStrings(string const & key,
+ InfoMap const & map, vector<CiteStyle> const & styles)
+{
+ if (map.empty()) {
+ vector<string> vec(1);
+ vec[0] = _("No database");
+ return vec;
+ }
+
+ vector<string> vec(styles.size());
+
+ string const author = getAbbreviatedAuthor(map, key);
+ string const year = getYear(map, key);
+
+ for (vector<string>::size_type i = 0; i != vec.size(); ++i) {
+ string str;
+
+ switch (styles[i]) {
+ case CITET:
+ str = author + " (" + year + ")";
+ break;
+
+ case CITE:
+ case CITEP:
+ str = "(" + author + ", " + year + ")";
+ break;
+
+ case CITEALT:
+ str = author + " " + year ;
+ break;
+
+ case CITEALP:
+ str = author + ", " + year ;
+ break;
+
+ case CITEAUTHOR:
+ str = author;
+ break;
+
+ case CITEYEAR:
+ str = year;
+ break;
+
+ case CITEYEARPAR:
+ str = "(" + year + ")";
+ break;
+ }
+
+ vec[i] = str;
+ }
+
+ return vec;
+}
+
+} // namespace biblio