diff --git a/src/frontends/controllers/ChangeLog b/src/frontends/controllers/ChangeLog index 796fb85b10..52500437a0 100644 --- a/src/frontends/controllers/ChangeLog +++ b/src/frontends/controllers/ChangeLog @@ -1,3 +1,9 @@ +2006-03-06 Lars Gullik Bjønnes + + * biblio.C (escape_special_chars): Update for boost::regex v4 + (RegexMatch): Update for bosot::regex v4 + (searchKeys): Handle exception if it occurs. + 2005-12-12 Jürgen Spitzmüller * ControlPrefs.[Ch]: new helper functions toPaperSize and diff --git a/src/frontends/controllers/biblio.C b/src/frontends/controllers/biblio.C index 32d4f8af36..0aa26f215b 100644 --- a/src/frontends/controllers/biblio.C +++ b/src/frontends/controllers/biblio.C @@ -370,24 +370,29 @@ namespace { // Escape special chars. // All characters are literals except: '.|*?+(){}[]^$\' // These characters are literals when preceded by a "\", which is done here +// @todo: This function should be moved to support, and then the test in tests +// should be moved there as well. 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("[].|*?+(){}^$\\[\\\\]"); + boost::regex reg("[].|*?+(){}^$\\[\\\\]"); - // $& is a perl-like expression that expands to all of the current match + // $& 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 reg.Merge(expr, "\\\\$&"); + return boost::regex_replace(expr, reg, "\\\\$&"); } // A functor for use with std::find_if, used to ascertain whether a // data entry matches the required regex_ +// @throws: boost::regex_error if the supplied regex pattern is not valid +// @todo: This function should be moved to support. class RegexMatch : public std::unary_function { public: @@ -397,9 +402,6 @@ public: : map_(m), regex_(re, icase) {} bool operator()(string const & key) const { - if (!validRE()) - return false; - // the data searched is the key + its associated BibTeX/biblio // fields string data = key; @@ -409,14 +411,11 @@ public: // Attempts to find a match for the current RE // somewhere in data. - return regex_.Search(data); + return boost::regex_search(data, regex_); } - - bool validRE() const { return regex_.error_code() == 0; } - private: InfoMap const map_; - mutable boost::RegEx regex_; + mutable boost::regex regex_; }; } // namespace anon @@ -442,27 +441,31 @@ searchKeys(InfoMap const & theMap, if (type == SIMPLE) // 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); + expr = escape_special_chars(expr); - // Build the functor that will be passed to find_if. - RegexMatch const match(theMap, expr, !caseSensitive); - if (!match.validRE()) + try { + // Build the functor that will be passed to find_if. + RegexMatch const match(theMap, expr, !caseSensitive); + + // 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::const_reverse_iterator rit(start); + vector::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(); + } + catch (boost::regex_error & regerr) { return keys.end(); - - // 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::const_reverse_iterator rit(start); - vector::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(); + } } diff --git a/src/frontends/controllers/tests/Makefile.am b/src/frontends/controllers/tests/Makefile.am new file mode 100644 index 0000000000..b028bf34a0 --- /dev/null +++ b/src/frontends/controllers/tests/Makefile.am @@ -0,0 +1,23 @@ +include $(top_srcdir)/config/common.am + +EXTRA_DIST = pch.h test_biblio + +BUILT_SOURCES = $(PCH_FILE) + +TESTS = \ + test_biblio + +check_PROGRAMS = \ + biblio + +AM_CPPFLAGS += $(BOOST_INCLUDES) + +biblio_LDADD = $(BOOST_REGEX) +biblio_SOURCES = \ + biblio.C \ + boost.C + +makeregfiles: ${check_PROGRAMS} + for all in ${check_PROGRAMS} ; do \ + ./$$all > ${srcdir}/regfiles/$$all ; \ + done diff --git a/src/frontends/controllers/tests/biblio.C b/src/frontends/controllers/tests/biblio.C new file mode 100755 index 0000000000..cc8fe11b3d --- /dev/null +++ b/src/frontends/controllers/tests/biblio.C @@ -0,0 +1,95 @@ +#include + +#include +#include + +#include + +using std::cout; +using std::endl; +using std::string; + +// Escape special chars. +// All characters are literals except: '.|*?+(){}[]^$\' +// These characters are literals when preceded by a "\", which is done here +// This function is unfortunately copied from ../biblio.C, so we should +// try to make sure to keep the two in sync. +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 boost::regex_replace(expr, reg, "\\\\$&"); +} + + +typedef std::map InfoMap; + +// A functor for use with std::find_if, used to ascertain whether a +// data entry matches the required regex_ +// This class is unfortunately copied from ../biblio.C, so we should +// try to make sure to keep the two in sync. +class RegexMatch : public std::unary_function +{ +public: + // 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_(re, icase) {} + + bool operator()(string const & key) const { + // 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 boost::regex_search(data, regex_); + } +private: + InfoMap const map_; + mutable boost::regex regex_; +}; + + +void test_escape_special_chars() +{ + cout << escape_special_chars("abcd") << endl; + cout << escape_special_chars("ab&cd") << endl; + cout << escape_special_chars(".|*?+(){}[]^$\"") << endl; + cout << escape_special_chars("..||**??++(()){{}}[[]]^^$$\\\\") << endl; +} + + +void test_RegexMatch() +{ + InfoMap im; + im["hello"] = "hei"; + + try { + RegexMatch rm(im, "h.*o", false); + + cout << rm("hello") << endl; + cout << rm("hei") << endl; + } + catch (boost::regex_error & regerr) { + cout << regerr.what() << endl; + } +} + + +int main() +{ + test_escape_special_chars(); + test_RegexMatch(); +} diff --git a/src/frontends/controllers/tests/boost.C b/src/frontends/controllers/tests/boost.C new file mode 100644 index 0000000000..443551a033 --- /dev/null +++ b/src/frontends/controllers/tests/boost.C @@ -0,0 +1,33 @@ +/** + * \file boost.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Lars Gullik Bjønnes + * + * Full author contact details are available in file CREDITS. + */ + +#include + +#include + +#include +#include + +namespace boost { + +void throw_exception(std::exception const & /*e*/) +{ + BOOST_ASSERT(false); +} + + +void assertion_failed(char const * /*expr*/, char const * /*function*/, + char const * /*file*/, long /*line*/) +{ + ::abort(); +} + + +} diff --git a/src/frontends/controllers/tests/pch.h b/src/frontends/controllers/tests/pch.h new file mode 100644 index 0000000000..6b2f9b7f64 --- /dev/null +++ b/src/frontends/controllers/tests/pch.h @@ -0,0 +1,64 @@ +// -*- C++ -*- +#include + +#include +#include +// #include // mult def symbols problem (_1,_2 etc) +#include +#include +#include +#include +#include +#include +#include + +#if BOOST_VERSION < 103301 +# include +#else +# include +#endif + +#include +#include + +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#include +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifndef _WIN32 +# include +# include +# ifdef HAVE_UNISTD_H +# include +# endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/frontends/controllers/tests/regfiles/biblio b/src/frontends/controllers/tests/regfiles/biblio new file mode 100644 index 0000000000..a3880d2434 --- /dev/null +++ b/src/frontends/controllers/tests/regfiles/biblio @@ -0,0 +1,6 @@ +abcd +ab&cd +\.\|\*\?\+\(\)\{\}\[\]\^\$" +\.\.\|\|\*\*\?\?\+\+\(\(\)\)\{\{\}\}\[\[\]\]\^\^\$\$\\\\ +1 +0 diff --git a/src/frontends/controllers/tests/test_biblio b/src/frontends/controllers/tests/test_biblio new file mode 100755 index 0000000000..2d8d54ec01 --- /dev/null +++ b/src/frontends/controllers/tests/test_biblio @@ -0,0 +1,7 @@ +#!/bin/bash + +regfile=`cat ${srcdir}/regfiles/biblio` +output=`./biblio` + +test "$regfile" = "$output" +exit $?