# # # patch "ChangeLog" # from [1b1b7c07088e736bb647b6e730e5461973158d8a] # to [46322c5ce6d7212ac4d983b7e3ebf934077625e8] # # patch "lua.cc" # from [6e59fe049bc11b83e177f02d9bf5620335c80488] # to [584d32c9ad2fd3358d18116d195af8b308c1d469] # # patch "luaext_globish.cc" # from [506249a961f0209231535ac1c696bda6442d22da] # to [91142495a024ecca88d1e5caaf06259e047c2d07] # # patch "pcrewrap.cc" # from [4dc70cfb7a55e24b3fd86a0324487f645e25db2c] # to [5e175ccccd98a56490c4479e634b4547a52eb9e5] # # patch "pcrewrap.hh" # from [701afe7a88a0cbb36c0b38afb6a03050f22f89b4] # to [5b3070b3642cc669273a7347bf6feb938f465215] # # patch "po/POTFILES.in" # from [76d2c8a470bc2f234c0b239155b20dbc29f59fdf] # to [3642b5fb461f3a18033922e4e72ac081613ea8f3] # ============================================================ --- ChangeLog 1b1b7c07088e736bb647b6e730e5461973158d8a +++ ChangeLog 46322c5ce6d7212ac4d983b7e3ebf934077625e8 @@ -1,5 +1,19 @@ 2006-12-27 Zack Weinberg + * pcrewrap.hh (pcre::compile_error, pcre::match_error): Simplify. + Constructor now takes an i18n_format const &. + (pcre::study_error, pcre::fullinfo_error): Delete. + * pcrewrap.cc (pcre_compile_error, pcre_study_error, pcre_match_error): + New functions. + (compile, get_capturecount, match): Use them. + (compile_error_message, compile_error::compile_error) + (match_error::match_error, fullinfo_error::fullinfo_error): Delete. + + * lua.cc (regex.search): Simplify error handling. + * luaext_globish.cc (globish.match): Likewise. + * po/POTFILES.in: Add pcrewrap.cc. + +2006-12-27 Zack Weinberg * pcrewrap.cc, pcrewrap.hh: Change "const T" to "T const" throughout. 2006-12-27 Zack Weinberg ============================================================ --- lua.cc 6e59fe049bc11b83e177f02d9bf5620335c80488 +++ lua.cc 584d32c9ad2fd3358d18116d195af8b308c1d469 @@ -550,10 +550,10 @@ LUAEXT(search, regex) bool result = false; try { result = pcre::regex(re).match(str); - } catch (pcre::compile_error e) { - return luaL_error(L, (string("error parsing regex: ") + e.what()).c_str()); - } catch (pcre::match_error e) { - return luaL_error(L, (string("error during match: ") + e.what()).c_str()); + } catch (pcre::compile_error & e) { + return luaL_error(L, e.what()); + } catch (pcre::match_error & e) { + return luaL_error(L, e.what()); } lua_pushboolean(L, result); return 1; ============================================================ --- luaext_globish.cc 506249a961f0209231535ac1c696bda6442d22da +++ luaext_globish.cc 91142495a024ecca88d1e5caaf06259e047c2d07 @@ -18,10 +18,10 @@ LUAEXT(match, globish) result = globish_matcher(r, n)(s); } catch (informative_failure & e) { return luaL_error(L, e.what()); - } catch (pcre::compile_error e) { - return luaL_error(L, (string("error parsing regex: ") + e.what()).c_str()); - } catch (pcre::match_error e) { - return luaL_error(L, (string("error during match: ") + e.what()).c_str()); + } catch (pcre::compile_error & e) { + return luaL_error(L, e.what()); + } catch (pcre::match_error & e) { + return luaL_error(L, e.what()); } catch (...) { return luaL_error(L, "Unknown error."); } ============================================================ --- pcrewrap.cc 4dc70cfb7a55e24b3fd86a0324487f645e25db2c +++ pcrewrap.cc 5e175ccccd98a56490c4479e634b4547a52eb9e5 @@ -1,4 +1,5 @@ #include "pcrewrap.hh" +#include #define pcre pcre_t #include "pcre.h" @@ -7,6 +8,11 @@ using std::runtime_error; using std::string; using std::runtime_error; +static void pcre_compile_error(char const * err, int erroff, + char const * pattern) NORETURN; +static void pcre_study_error(char const * err) NORETURN; +static void pcre_match_error(int errcode, string const & subject) NORETURN; + inline unsigned int flags_to_internal(pcre::flags f) { @@ -40,11 +46,11 @@ compile(const char * pattern, pcre::flag pcre_t const * basedat = pcre_compile(pattern, flags_to_internal(options), &err, &erroff, 0); if (!basedat) - throw pcre::compile_error(err, erroff, pattern); + pcre_compile_error(err, erroff, pattern); pcre_extra const * extradat = pcre_study(basedat, 0, &err); if (err) - throw pcre::study_error(err); + pcre_study_error(err); return std::make_pair(static_cast(basedat), static_cast(extradat)); @@ -57,8 +63,7 @@ get_capturecount(void const * bd) int err = pcre_fullinfo(static_cast(bd), 0, PCRE_INFO_CAPTURECOUNT, static_cast(&cc)); - if (err < 0) - throw pcre::fullinfo_error(err); + I(err == 0); return cc; } @@ -120,11 +125,12 @@ namespace pcre if (ovec[i] == -1 && ovec[i+1] == -1) result.push_back(capture(string::const_iterator(0), string::const_iterator(0))); - else if (ovec[i] == -1 || ovec[i+1] == -1) - throw match_error(PCRE_ERROR_INTERNAL); // should never happen else - result.push_back(capture(subject.begin() + ovec[i], - subject.begin() + ovec[i+1])); + { + I(ovec[i] != -1 && ovec[i+1] != -1); + result.push_back(capture(subject.begin() + ovec[i], + subject.begin() + ovec[i+1])); + } } for (unsigned int i = rc; i < capturecount + 1; i++) result.push_back(capture(string::const_iterator(0), @@ -141,7 +147,7 @@ namespace pcre return false; } else - throw match_error(rc); + pcre_match_error(rc, subject); } // This overload is for when you don't care about captures, only @@ -164,34 +170,142 @@ namespace pcre else if (rc == PCRE_ERROR_NOMATCH) return false; else - throw match_error(rc); + pcre_match_error(rc, subject); } +} // namespace pcre - // error handling. +// These functions produce properly translated diagnostics from PCRE +// internal errors. +static void +pcre_compile_error(char const *err, int erroff, char const * pattern) +{ + using std::strcmp; + // Special case out-of-memory ... + if (!strcmp(err, "failed to get memory")) + throw std::bad_alloc(); - static string - compile_error_message(char const * err, int offset, char const * pattern) - { - return (F("parse error at char %d in pattern '%s': %s") - % offset % pattern % err).str(); - } + // ... and all errors that represent program bugs. + I(strcmp(err, "erroffset passed as NULL")); + I(strcmp(err, "unknown option bit(s) set")); + I(strcmp(err, "this version of PCRE is not compiled with PCRE_UTF8 support")); + I(strcmp(err, "internal error: code overflow")); + I(strcmp(err, "internal error: unexpected repeat")); + I(strcmp(err, "spare error")); + I(strcmp(err, "invalid UTF-8 string")); + I(strcmp(err, "no error")); // because we should never get here with that - compile_error::compile_error(char const * err, int offset, - char const * pattern) - : std::runtime_error(compile_error_message(err, offset, pattern)) - {} + // PCRE fails to distinguish between errors at no position and errors at + // character offset 0 in the pattern, so in practice we give the + // position-ful variant for all errors, but I'm leaving the == -1 check + // here in case PCRE gets fixed. + if (erroff == -1) + throw pcre::compile_error(F("Error in regex \"%s\": %s") + % pattern % gettext(err)); + else + throw pcre::compile_error(F("Error at character %d of regex \"%s\": %s") + % (erroff + 1) % pattern % gettext(err)); +} - match_error::match_error(int code) - : std::runtime_error((F("Error during matching, code %d") % code).str()) - {} +static void +pcre_study_error(char const * err) +{ + // If the error is not out-of-memory, it's a bug. + I(!std::strcmp(err, "failed to get memory")); + throw std::bad_alloc(); +} - fullinfo_error::fullinfo_error(int code) - : std::runtime_error((F("Error getting capture count, code %d") % code) - .str()) - {} +static void +pcre_match_error(int errcode, string const & subject) +{ + // This one actually has error codes! Almost all of which indicate bugs + // in monotone. + switch(errcode) + { + case PCRE_ERROR_NOMEMORY: + throw std::bad_alloc(); -} // namespace pcre + case PCRE_ERROR_MATCHLIMIT: + throw pcre::match_error(F("backtrack limit exceeded, matching \"%s\"") + % subject); + + case PCRE_ERROR_RECURSIONLIMIT: + throw pcre::match_error(F("recursion limit exceeded, matching \"%s\"") + % subject); + default: + global_sanity.invariant_failure((FL("pcre_match returned %d") % errcode) + .str().c_str(), __FILE__, __LINE__); + } +} +#ifdef XGETTEXT +// This is a copy of the error message table from pcre_compile.c, with +// N_() applied to all the strings that the user will actually see. +static char const * const error_texts[] = { + "no error", + N_("\\ at end of pattern"), + N_("\\c at end of pattern"), + N_("unrecognized character follows \\"), + N_("numbers out of order in {} quantifier"), + /* 5 */ + N_("number too big in {} quantifier"), + N_("missing terminating ] for character class"), + N_("invalid escape sequence in character class"), + N_("range out of order in character class"), + N_("nothing to repeat"), + /* 10 */ + N_("operand of unlimited repeat could match the empty string"), + "internal error: unexpected repeat", + N_("unrecognized character after (?"), + N_("POSIX named classes are supported only within a class"), + N_("missing )"), + /* 15 */ + N_("reference to non-existent subpattern"), + "erroffset passed as NULL", + "unknown option bit(s) set", + N_("missing ) after comment"), + N_("parentheses nested too deeply"), + /* 20 */ + N_("regular expression too large"), + "failed to get memory", // std::bad_alloc + N_("unmatched parentheses"), + "internal error: code overflow", + N_("unrecognized character after (?<"), + /* 25 */ + N_("lookbehind assertion is not fixed length"), + N_("malformed number or name after (?("), + N_("conditional group contains more than two branches"), + N_("assertion expected after (?("), + N_("(?R or (?digits must be followed by )"), + /* 30 */ + N_("unknown POSIX class name"), + N_("POSIX collating elements are not supported"), + "this version of PCRE is not compiled with PCRE_UTF8 support", + "spare error", + N_("character value in \\x{...} sequence is too large"), + /* 35 */ + N_("invalid condition (?(0)"), + N_("\\C not allowed in lookbehind assertion"), + N_("PCRE does not support \\L, \\l, \\N, \\U, or \\u"), + N_("number after (?C is > 255"), + N_("closing ) for (?C expected"), + /* 40 */ + N_("recursive call could loop indefinitely"), + N_("unrecognized character after (?P"), + N_("syntax error after (?P"), + N_("two named subpatterns have the same name"), + "invalid UTF-8 string", + /* 45 */ + N_("support for \\P, \\p, and \\X has not been compiled"), + N_("malformed \\P or \\p sequence"), + N_("unknown property name after \\P or \\p"), + N_("subpattern name is too long (maximum 32 characters)"), + N_("too many named subpatterns (maximum 10,000)"), + /* 50 */ + N_("repeated subpattern is too long"), + N_("octal value is greater than \\377 (not in UTF-8 mode)"), +}; +#endif + // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- pcrewrap.hh 701afe7a88a0cbb36c0b38afb6a03050f22f89b4 +++ pcrewrap.hh 5b3070b3642cc669273a7347bf6feb938f465215 @@ -124,26 +124,15 @@ namespace pcre // exceptions thrown for errors from PCRE APIs struct compile_error : public std::runtime_error { - explicit compile_error(char const * error, int offset, - char const * pattern); + explicit compile_error(i18n_format const & e) + : runtime_error(e.str().c_str()) {} virtual ~compile_error() throw() {} }; - struct study_error : public std::runtime_error - { - explicit study_error(char const * error) : runtime_error(error) {}; - virtual ~study_error() throw() {} - }; - - struct fullinfo_error : public std::runtime_error - { - explicit fullinfo_error(int code); - virtual ~fullinfo_error() throw() {} - }; - struct match_error : public std::runtime_error { - explicit match_error(int code); + explicit match_error(i18n_format const & e) + : runtime_error(e.str().c_str()) {} virtual ~match_error() throw() {} }; ============================================================ --- po/POTFILES.in 76d2c8a470bc2f234c0b239155b20dbc29f59fdf +++ po/POTFILES.in 3642b5fb461f3a18033922e4e72ac081613ea8f3 @@ -57,6 +57,7 @@ packet.hh options_list.hh packet.cc packet.hh +pcrewrap.cc platform.hh quick_alloc.hh randomfile.hh