/* This file is part of * ====================================================== * * LyX, The Document Processor * * Copyright 2001 The LyX Team. * * ====================================================== * * \file biblio.C * \author Angus Leeming */ #include #include #include #ifdef __GNUG__ #pragma implementation #endif #include "LString.h" #include "biblio.h" #include "gettext.h" // for _() #include "helper_funcs.h" #include "support/lstrings.h" #include "support/LAssert.h" #include "support/LRegex.h" using std::find; using std::min; using std::vector; using std::sort; namespace biblio { namespace { using namespace biblio; char const * const citeCommands[] = { "cite", "citet", "citep", "citealt", "citealp", "citeauthor", "citeyear", "citeyearpar" }; unsigned int const nCiteCommands = sizeof(citeCommands) / sizeof(char *); CiteStyle const citeStyles[] = { CITE, CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR, CITEYEAR, CITEYEARPAR }; unsigned int const nCiteStyles = sizeof(citeStyles) / sizeof(CiteStyle); CiteStyle const citeStylesFull[] = { CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR }; unsigned int const nCiteStylesFull = sizeof(citeStylesFull) / sizeof(CiteStyle); CiteStyle const citeStylesUCase[] = { CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR }; unsigned int const nCiteStylesUCase = sizeof(citeStylesUCase) / sizeof(CiteStyle); // The functions doing the dirty work for the search. vector::const_iterator simpleSearch(InfoMap const & theMap, vector const & keys, string const & expr, vector::const_iterator start, Direction dir, bool caseSensitive) { string tmp = expr; if (!caseSensitive) tmp = lowercase(tmp); vector searchwords = getVectorFromString(tmp, " "); // Loop over all keys from start... for (vector::const_iterator it = start; // End condition is direction-dependent. (dir == FORWARD) ? (it=keys.begin()); // increment is direction-dependent. (dir == FORWARD) ? (++it) : (--it)) { string data = (*it); InfoMap::const_iterator info = theMap.find(*it); if (info != theMap.end()) data += " " + info->second; if (!caseSensitive) data = lowercase(data); bool found = true; // Loop over all search words... for (vector::const_iterator sit = searchwords.begin(); sit != searchwords.end(); ++sit) { if (data.find(*sit) == string::npos) { found = false; break; } } if (found) return it; } return keys.end(); } vector::const_iterator regexSearch(InfoMap const & theMap, vector const & keys, string const & expr, vector::const_iterator start, Direction dir) { LRegex reg(expr); for (vector::const_iterator it = start; // End condition is direction-dependent. (dir == FORWARD) ? (it=keys.begin()); // increment is direction-dependent. (dir == FORWARD) ? (++it) : (--it)) { string data = (*it); InfoMap::const_iterator info = theMap.find(*it); if (info != theMap.end()) data += " " + info->second; if (reg.exec(data).size() > 0) return it; } 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 authors = getVectorFromString(author, "and"); if (!authors.empty()) { author.erase(); for (vector::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 { bool operator()(string const & s1, string const & s2) const { return compare_no_case(s1, s2) < 0; } }; vector const getKeys(InfoMap const & map) { vector 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 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 (!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.str().empty()) // not a BibTeX record result << it->second; return result.str().c_str(); } vector::const_iterator searchKeys(InfoMap const & theMap, vector const & keys, string const & expr, vector::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; for (string::iterator it=data.begin(); it1) { string tmp = data.substr(keypos, data.length()-1); while (tmp.find('{') != string::npos && tmp.find('}') != string::npos && tmp.find('{') < tmp.find('}') && tmp.find('{') < tmp.find(enclosing)) { keypos += tmp.find('{')+1; tmp = data.substr(keypos, data.length()-1); keypos += tmp.find('}')+1; tmp = data.substr(keypos, data.length()-1); } if (tmp.find(enclosing)==string::npos) return keyvalue; else { keypos += tmp.find(enclosing); tmp = data.substr(keypos, data.length()-1); } value = data.substr(1, keypos-1); if (keypos+1 data.find(',')) keypos = data.find(','); value = data.substr(0, keypos); if (keypos+1 const getCiteStyles(bool usingNatbib) { unsigned int nStyles = 1; unsigned int start = 0; if (usingNatbib) { nStyles = nCiteStyles - 1; start = 1; } vector styles(nStyles); vector::size_type i = 0; int j = start; for (; i != styles.size(); ++i, ++j) { styles[i] = citeStyles[j]; } return styles; } vector const getNumericalStrings(string const & key, InfoMap const & map, vector const & styles) { if (map.empty()) { vector vec(1); vec[0] = _("No database"); return vec; } vector vec(styles.size()); string const author = getAbbreviatedAuthor(map, key); string const year = getYear(map, key); for (vector::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 const getAuthorYearStrings(string const & key, InfoMap const & map, vector const & styles) { if (map.empty()) { vector vec(1); vec[0] = _("No database"); return vec; } vector vec(styles.size()); string const author = getAbbreviatedAuthor(map, key); string const year = getYear(map, key); for (vector::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