From d82980b563c9f29f595f6e50d80ac27ff79866a2 Mon Sep 17 00:00:00 2001 From: Christoph Hasse Date: Fri, 16 Jul 2021 21:47:11 +0200 Subject: [PATCH] refactor: replace old linux regex.h with regex from STL. --- include/exiv2/version.hpp | 30 ++--------------- src/actions.cpp | 22 ++++--------- src/exiv2.cpp | 69 +++++++++++---------------------------- src/exiv2app.hpp | 4 +-- src/version.cpp | 33 ++++--------------- 5 files changed, 34 insertions(+), 124 deletions(-) diff --git a/include/exiv2/version.hpp b/include/exiv2/version.hpp index d83e2596..24514067 100644 --- a/include/exiv2/version.hpp +++ b/include/exiv2/version.hpp @@ -27,35 +27,9 @@ // included header files // + standard includes #include +#include +using exv_grep_keys_t = std::vector; -#if defined(EXV_HAVE_REGEX_H) -# include - /*! - @brief exv_grep_keys_t is a vector of keys to match to strings - */ - typedef std::vector exv_grep_keys_t ; -# else - /*! - @brief exv_grep_key_t is a simple string and the ignore flag - */ - struct Exiv2_grep_key_t { - /*! - @brief Exiv2_grep_key_t constructor - */ - Exiv2_grep_key_t(std::string pattern,bool bIgnoreCase) - :pattern_(pattern),bIgnoreCase_(bIgnoreCase) {} - - //! simple string to match - std::string pattern_; - - //! should we ignore cast in the match? - bool bIgnoreCase_; - }; - /*! - @brief exv_grep_keys_t is a vector of keys to match to strings - */ - typedef std::vector exv_grep_keys_t ; -#endif /*! @brief Make an integer version number for comparison from a major, minor and diff --git a/src/actions.cpp b/src/actions.cpp index 0fc36290..16071a35 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -483,24 +483,14 @@ namespace Action { bool Print::grepTag(const std::string& key) { - bool result=Params::instance().greps_.empty(); - for (auto&& g : Params::instance().greps_) { - if (result) + bool result = Params::instance().greps_.empty(); + for (auto const& g : Params::instance().greps_) { + result = std::regex_search(key, g); + if (result) { break; -#if defined(EXV_HAVE_REGEX_H) - result = regexec(&g, key.c_str(), 0, nullptr, 0) == 0; -#else - std::string Pattern(g.pattern_); - std::string Key(key); - if (g.bIgnoreCase_) { - // https://notfaq.wordpress.com/2007/08/04/cc-convert-string-to-upperlower-case/ - std::transform(Pattern.begin(), Pattern.end(),Pattern.begin(), ::tolower); - std::transform(Key.begin() , Key.end() ,Key.begin() , ::tolower); - } - result = Key.find(Pattern) != std::string::npos; -#endif + } } - return result ; + return result; } bool Print::keyTag(const std::string& key) diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 5c165533..c07c8ec6 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -37,9 +37,7 @@ #include #include -#if defined(EXV_HAVE_REGEX_H) -#include -#endif +#include #if defined(_MSC_VER) #include @@ -204,14 +202,6 @@ Params& Params::instance() return *instance_; } -Params::~Params() { -#if defined(EXV_HAVE_REGEX_H) - for (auto&& grep : instance().greps_) { - regfree(&grep); - } -#endif -} - void Params::cleanup() { delete instance_; @@ -448,48 +438,27 @@ int Params::setLogLevel(const std::string& optArg) return rc; } // Params::setLogLevel -// http://stackoverflow.com/questions/874134/find-if-string-ends-with-another-string-in-c -static inline bool ends_with(std::string const & value, std::string const & ending,std::string& stub) +int Params::evalGrep(const std::string& optArg) { - if (ending.size() > value.size()) return false; - bool bResult = std::equal(ending.rbegin(), ending.rend(), value.rbegin()); - stub = bResult ? value.substr(0,value.length() - ending.length()) : value; - return bResult ; -} + // check that string ends in "/i" + bool bIgnoreCase = optArg.size() > 2 && optArg.back() == 'i' && optArg[optArg.size() - 2] == '/'; + auto pattern = bIgnoreCase ? optArg.substr(0, optArg.size() - 2) : optArg; -int Params::evalGrep( const std::string& optArg) -{ - int result=0; - std::string pattern; - std::string ignoreCase("/i"); - bool bIgnoreCase = ends_with(optArg,ignoreCase,pattern); -#if defined(EXV_HAVE_REGEX_H) - // try to compile a reg-exp from the input argument and store it in the vector - const size_t i = greps_.size(); - greps_.resize(i + 1); - regex_t *pRegex = &greps_[i]; - int errcode = regcomp( pRegex, pattern.c_str(), bIgnoreCase ? REG_NOSUB|REG_ICASE : REG_NOSUB); - - // there was an error compiling the regexp - if( errcode ) { - size_t length = regerror(errcode, pRegex, nullptr, 0); - auto buffer = new char[length]; - regerror (errcode, pRegex, buffer, length); - std::cerr << progname() - << ": " << _("Option") << " -g: " - << _("Invalid regexp") << " \"" << optArg << "\": " << buffer << "\n"; - - // free the memory and drop the regexp - delete[] buffer; - regfree( pRegex); - greps_.resize(i); - result=1; + try { + // use grep syntax, optimize for faster matching, treat all sub expressions as unnamed + auto flags = std::regex::grep | std::regex::optimize | std::regex::nosubs; + flags = bIgnoreCase ? flags | std::regex::icase : flags; + // try and emplace regex into vector + // might throw if invalid pattern + greps_.emplace_back(pattern, flags); + } catch (std::regex_error const& e) { + // there was an error compiling the regexp + std::cerr << progname() << ": " << _("Option") << " -g: " << _("Invalid regexp") << " \"" << optArg << "\n"; + return 1; } -#else - greps_.push_back(Exiv2_grep_key_t(pattern,bIgnoreCase)); -#endif - return result; -} // Params::evalGrep + + return 0; +} // Params::evalGrep int Params::evalKey( const std::string& optArg) { diff --git a/src/exiv2app.hpp b/src/exiv2app.hpp index 82fdf131..bc1f8566 100644 --- a/src/exiv2app.hpp +++ b/src/exiv2app.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef EXV_HAVE_UNISTD_H #include @@ -297,9 +298,6 @@ private: yodAdjust_[yodDay] = emptyYodAdjust_[yodDay]; } - //! Destructor, frees any allocated regexes in greps_ - ~Params() override; - //! @name Helpers //@{ int setLogLevel(const std::string& optarg); diff --git a/src/version.cpp b/src/version.cpp index 5ec8a89c..16bdf359 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -42,6 +42,7 @@ #include #include #include +#include // #1147 #ifndef WIN32 @@ -115,21 +116,11 @@ namespace Exiv2 { static bool shouldOutput(const exv_grep_keys_t& greps,const char* key,const std::string& value) { bool bPrint = greps.empty(); - for (auto g = greps.begin(); !bPrint && g != greps.end(); ++g) { - std::string Key(key); -#if defined(EXV_HAVE_REGEX_H) - bPrint = (0 == regexec(&(*g), key, 0, nullptr, 0) || 0 == regexec(&(*g), value.c_str(), 0, nullptr, 0)); -#else - std::string Pattern(g->pattern_); - std::string Value(value); - if ( g->bIgnoreCase_ ) { - // https://notfaq.wordpress.com/2007/08/04/cc-convert-string-to-upperlower-case/ - std::transform(Pattern.begin(), Pattern.end(),Pattern.begin(), ::tolower); - std::transform(Key.begin() , Key.end() ,Key.begin() , ::tolower); - std::transform(Value.begin() , Value.end() ,Value.begin() , ::tolower); - } - bPrint = Key.find(Pattern) != std::string::npos || Value.find(Pattern) != std::string::npos; -#endif + for (auto const& g : greps) { + bPrint = std::regex_search(key, g) || std::regex_search(value, g); + if (bPrint) { + break; + } } return bPrint; } @@ -323,8 +314,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) int have_iconv =0; int have_memory =0; int have_lstat =0; - int have_regex =0; - int have_regex_h =0; int have_stdbool =0; int have_stdint =0; int have_stdlib =0; @@ -378,14 +367,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) have_lstat=1; #endif -#ifdef EXV_HAVE_REGEX - have_regex=1; -#endif - -#ifdef EXV_HAVE_REGEX_H - have_regex_h=1; -#endif - #ifdef EXV_HAVE_STDBOOL_H have_stdbool=1; #endif @@ -517,8 +498,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) output(os,keys,"have_iconv" ,have_iconv ); output(os,keys,"have_memory" ,have_memory ); output(os,keys,"have_lstat" ,have_lstat ); - output(os,keys,"have_regex" ,have_regex ); - output(os,keys,"have_regex_h" ,have_regex_h ); output(os,keys,"have_stdbool" ,have_stdbool ); output(os,keys,"have_stdint" ,have_stdint ); output(os,keys,"have_stdlib" ,have_stdlib );