]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/controllers/biblio.C
Add a buffer_path arg to InsetGraphicsMailer's params2string, string2params.
[lyx.git] / src / frontends / controllers / biblio.C
index 564f474fb959f9ca70e8fd13a2e055bcb4ae3701..e689b2213d51d18e43eaca556807f34349f5e17d 100644 (file)
 
 #include <config.h>
 
-#ifdef __GNUG__
-#pragma implementation
-#endif
-
-#include "LString.h"
 #include "biblio.h"
+
+#include "Lsstream.h"
 #include "gettext.h" // for _()
 #include "helper_funcs.h"
+#include "Lsstream.h"
+#include "LString.h"
+
 #include "support/lstrings.h"
 #include "support/LAssert.h"
 
 
 #include <algorithm>
 
-using std::find;
-using std::min;
-using std::vector;
-
-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<string>::const_iterator
-simpleSearch(InfoMap const & theMap,
-            vector<string> const & keys,
-            string const & expr,
-            vector<string>::const_iterator start,
-            Direction dir,
-            bool caseSensitive)
-{
-       string tmp = expr;
-       if (!caseSensitive)
-               tmp = lowercase(tmp);
-
-       vector<string> searchwords = getVectorFromString(tmp, " ");
-
-       // Loop over all keys from start...
-       for (vector<string>::const_iterator it = start;
-            // End condition is direction-dependent.
-            (dir == FORWARD) ? (it<keys.end()) : (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<string>::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<string>::const_iterator
-regexSearch(InfoMap const & theMap,
-           vector<string> const & keys,
-           string const & expr,
-           vector<string>::const_iterator start,
-           Direction dir)
-{
-       boost::regex reg(STRCONV(expr));
-
-       for (vector<string>::const_iterator it = start;
-            // End condition is direction-dependent.
-            (dir == FORWARD) ? (it < keys.end()) : (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 (boost::regex_match(STRCONV(data), reg)) {
-                       return it;
-               }
-       }
-
-       return keys.end();
-}
+using namespace lyx::support;
 
+using std::vector;
 
-} // namespace anon
 
+namespace biblio {
 
 string const familyName(string const & name)
 {
@@ -152,10 +43,10 @@ string const familyName(string const & name)
        // "Surname, F."
        // "FirstName Surname"
        // "F. Surname"
-       string::size_type idx = fname.find(",");
+       string::size_type idx = fname.find(',');
        if (idx != string::npos)
                return ltrim(fname.substr(0, idx));
-       idx = fname.rfind(".");
+       idx = fname.rfind('.');
        if (idx != string::npos)
                fname = ltrim(fname.substr(idx + 1));
        // test if we have a LaTeX Space in front
@@ -168,7 +59,7 @@ string const familyName(string const & name)
 
 string const getAbbreviatedAuthor(InfoMap const & map, string const & key)
 {
-       lyx::Assert(!map.empty());
+       Assert(!map.empty());
 
        InfoMap::const_iterator it = map.find(key);
        if (it == map.end())
@@ -192,6 +83,7 @@ string const getAbbreviatedAuthor(InfoMap const & map, string const & key)
        }
 
        string author = parseBibTeX(data, "author");
+
        if (author.empty())
                author = parseBibTeX(data, "editor");
 
@@ -206,19 +98,20 @@ string const getAbbreviatedAuthor(InfoMap const & map, string const & key)
        if (authors.empty())
                return author;
 
-       author = familyName(authors[0]);
        if (authors.size() == 2)
-               author += _(" and ") + familyName(authors[1]);
-       else if (authors.size() > 2)
-               author += _(" et al.");
+               return bformat(_("%1$s and %2$s"),
+                       familyName(authors[0]), familyName(authors[1]));
 
-       return author;
+       if (authors.size() > 2)
+               return bformat(_("%1$s et al."), familyName(authors[0]));
+
+       return familyName(authors[0]);
 }
 
 
 string const getYear(InfoMap const & map, string const & key)
 {
-       lyx::Assert(!map.empty());
+       Assert(!map.empty());
 
        InfoMap::const_iterator it = map.find(key);
        if (it == map.end())
@@ -262,7 +155,7 @@ struct compareNoCase: public std::binary_function<string, string, bool>
                return compare_ascii_no_case(s1, s2) < 0;
        }
 };
+
 } // namespace anon
 
 
@@ -282,7 +175,7 @@ vector<string> const getKeys(InfoMap const & map)
 
 string const getInfo(InfoMap const & map, string const & key)
 {
-       lyx::Assert(!map.empty());
+       Assert(!map.empty());
 
        InfoMap::const_iterator it = map.find(key);
        if (it == map.end())
@@ -348,10 +241,66 @@ string const getInfo(InfoMap const & map, string const & key)
 }
 
 
+namespace {
+
+// Escape special chars.
+// All characters are literals except: '.|*?+(){}[]^$\'
+// These characters are literals when preceded by a "\", which is done here
+string const escape_special_chars(string const & expr)
+{
+       // Search for all chars '.|*?+(){}[^$]\'
+       // Note that '[' and '\' must be escaped.
+       // This is a limitation of boost::regex, but all other chars in BREs
+       // are assumed literal.
+       boost::RegEx reg("[].|*?+(){}^$\\[\\\\]");
+
+       // $& is a perl-like expression that expands to all of the current match
+       // The '$' must be prefixed with the escape character '\' for
+       // boost to treat it as a literal.
+       // Thus, to prefix a matched expression with '\', we use:
+       return STRCONV(reg.Merge(STRCONV(expr), "\\\\$&"));
+}
+
+
+// A functor for use with std::find_if, used to ascertain whether a
+// data entry matches the required regex_
+struct RegexMatch
+{
+       // re and icase are used to construct an instance of boost::RegEx.
+       // if icase is true, then matching is insensitive to case
+       RegexMatch(InfoMap const & m, string const & re, bool icase)
+               : map_(m), regex_(STRCONV(re), icase) {}
+
+       bool operator()(string const & key) {
+               if (!validRE())
+                       return false;
+
+               // the data searched is the key + its associated BibTeX/biblio
+               // fields
+               string data = key;
+               InfoMap::const_iterator info = map_.find(key);
+               if (info != map_.end())
+                       data += ' ' + info->second;
+
+               // Attempts to find a match for the current RE
+               // somewhere in data.
+               return regex_.Search(STRCONV(data));
+       }
+
+       bool validRE() const { return regex_.error_code() == 0; }
+
+private:
+       InfoMap const map_;
+       boost::RegEx regex_;
+};
+
+} // namespace anon
+
+
 vector<string>::const_iterator
 searchKeys(InfoMap const & theMap,
           vector<string> const & keys,
-          string const & expr,
+          string const & search_expr,
           vector<string>::const_iterator start,
           Search type,
           Direction dir,
@@ -361,15 +310,34 @@ searchKeys(InfoMap const & theMap,
        if (start < keys.begin() || start >= keys.end())
                return keys.end();
 
-       string search_expr = trim(expr);
-       if (search_expr.empty())
+       string expr = trim(search_expr);
+       if (expr.empty())
                return keys.end();
 
        if (type == SIMPLE)
-               return simpleSearch(theMap, keys, search_expr, start, dir,
-                                   caseSensitive);
+               // We must escape special chars in the search_expr so that
+               // it is treated as a simple string by boost::regex.
+               expr = escape_special_chars(expr);
+
+       // Build the functor that will be passed to find_if.
+       RegexMatch const match(theMap, expr, !caseSensitive);
+       if (!match.validRE())
+               return keys.end();
 
-       return regexSearch(theMap, keys, search_expr, start, dir);
+       // Search the vector of 'keys' from 'start' for one that matches the
+       // predicate 'match'. Searching can be forward or backward from start.
+       if (dir == FORWARD)
+               return std::find_if(start, keys.end(), match);
+
+       vector<string>::const_reverse_iterator rit(start);
+       vector<string>::const_reverse_iterator rend = keys.rend();
+       rit = std::find_if(rit, rend, match);
+
+       if (rit == rend)
+               return keys.end();
+       // This is correct and always safe.
+       // (See Meyer's Effective STL, Item 28.)
+       return (++rit).base();
 }
 
 
@@ -397,7 +365,7 @@ string const parseBibTeX(string data, string const & findkey)
                // with a space
                if (!dummy.empty()) {
                        if (!contains(dummy, "="))
-                               data_ += (' ' + dummy);
+                               data_ += ' ' + dummy;
                        else
                                data_ += dummy;
                }
@@ -439,7 +407,7 @@ string const parseBibTeX(string data, string const & findkey)
        keyvalue = dummy;
        dummy = token(data, ',', Entries++);
        while (!contains(dummy, '=') && !dummy.empty()) {
-               keyvalue += (',' + dummy);
+               keyvalue += ',' + dummy;
                dummy = token(data, ',', Entries++);
        }
 
@@ -503,6 +471,39 @@ string const parseBibTeX(string data, string const & findkey)
 }
 
 
+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);
+
+} // namespace anon
+
+
 CitationStyle const getCitationStyle(string const & command)
 {
        if (command.empty()) return CitationStyle();
@@ -539,7 +540,7 @@ string const getCiteCommand(CiteStyle command, bool full, bool forceUCase)
        if (full) {
                CiteStyle const * last = citeStylesFull + nCiteStylesFull;
                if (std::find(citeStylesFull, last, command) != last)
-                       cite += "*";
+                       cite += '*';
        }
 
        if (forceUCase) {
@@ -617,7 +618,7 @@ getNumericalStrings(string const & key,
                        break;
 
                case CITEYEARPAR:
-                       str = "(" + year + ")";
+                       str = '(' + year + ')';
                        break;
                }
 
@@ -648,15 +649,15 @@ getAuthorYearStrings(string const & key,
                switch (styles[i]) {
                case CITE:
                case CITET:
-                       str = author + " (" + year + ")";
+                       str = author + " (" + year + ')';
                        break;
 
                case CITEP:
-                       str = "(" + author + ", " + year + ")";
+                       str = '(' + author + ", " + year + ')';
                        break;
 
                case CITEALT:
-                       str = author + " " + year ;
+                       str = author + ' ' + year ;
                        break;
 
                case CITEALP:
@@ -672,7 +673,7 @@ getAuthorYearStrings(string const & key,
                        break;
 
                case CITEYEARPAR:
-                       str = "(" + year + ")";
+                       str = '(' + year + ')';
                        break;
                }