diff --git a/include/exiv2/version.hpp b/include/exiv2/version.hpp index b9f88b63..ff93d7b0 100644 --- a/include/exiv2/version.hpp +++ b/include/exiv2/version.hpp @@ -37,11 +37,25 @@ // + standard includes #include #include -#if EXV_HAVE_REGEX -#include -typedef std::vector exv_grep_keys_t ; + +#define CPLUSPLUS11 201103L + +#if __cplusplus >= CPLUSPLUS11 +# include + typedef std::vector exv_grep_keys_t ; #else -typedef std::vector exv_grep_keys_t ; +# if EXV_HAVE_REGEX +# include + typedef std::vector exv_grep_keys_t ; +# else + struct Exiv2_grep_key_t { + Exiv2_grep_key_t(std::string pattern,bool bIgnoreCase) + :pattern_(pattern),bIgnoreCase_(bIgnoreCase) {} + std::string pattern_; + bool bIgnoreCase_; + }; + typedef std::vector exv_grep_keys_t ; +# endif #endif /*! diff --git a/src/actions.cpp b/src/actions.cpp index 20c0a5be..d6a29fa8 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -49,6 +49,7 @@ EXIV2_RCSID("@(#) $Id$") #include "preview.hpp" #include "futils.hpp" #include "i18n.h" // NLS support. +#include "version.hpp" // + standard includes #include @@ -581,10 +582,22 @@ namespace Action { for (Params::Greps::const_iterator g = Params::instance().greps_.begin(); !result && g != Params::instance().greps_.end(); ++g) { +#if __cplusplus >= CPLUSPLUS11 + std::smatch m; + result = std::regex_search(key,m, *g); +#else #if EXV_HAVE_REGEX result = regexec( &(*g), key.c_str(), 0, NULL, 0) == 0 ; #else - result = key.find(*g) != std::string::npos; + 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 #endif } return result ; diff --git a/src/exiv2.1 b/src/exiv2.1 index 02d8c8ad..0714663d 100644 --- a/src/exiv2.1 +++ b/src/exiv2.1 @@ -3,7 +3,7 @@ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) -.TH EXIV2 1 "Nov 23, 2015" +.TH EXIV2 1 "Dec 8, 2015" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: @@ -222,10 +222,11 @@ Show unknown tags (default is to suppress tags which don't have a name). Only keys which match the given key (grep). .br Multiple \fB\-g\fP options -can be used to grep info for several keys. This option uses the system -regular expression engine: see man 3 regex. Platforms which do not support +can be used to grep info for several keys. When the library is build with C++11, +keys are matched using std::regex::extended. When build without C++11, keys are +processed with the system regular expression engine: see man 3 regex. Platforms which do not support regex use key for a substring match. You can determine the availability of regex -using the command: exiv2 -v -V -g have_regex +using the command: exiv2 -v -V -g have_regex -g cplusplus. .nf exiv2 \-g Date \-pt R.jpg @@ -235,6 +236,8 @@ Exif.Photo.DateTimeDigitized Ascii 20 2011:09:18 16:25:48 .fi -g (--grep) is only applied to keys. It is not generally applied to all output such as the default -ps report. + +The key may finish with the optional modifier /i to indicated case insensitive. .TP .B \-K \fIkey\fP Only report data for given key. diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 9878f5c1..22f72dd1 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -415,15 +415,30 @@ 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) +{ + 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 ; +} + 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 __cplusplus >= CPLUSPLUS11 + greps_.push_back( std::regex(pattern, bIgnoreCase ? std::regex::icase|std::regex::extended : std::regex::extended) ); +#else #if EXV_HAVE_REGEX // 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, optarg.c_str(), REG_NOSUB); + int errcode = regcomp( pRegex, pattern.c_str(), bIgnoreCase ? REG_NOSUB|REG_ICASE : REG_NOSUB); // there was an error compiling the regexp if( errcode ) { @@ -441,7 +456,8 @@ int Params::evalGrep( const std::string& optarg) result=1; } #else - greps_.push_back(optarg); + greps_.push_back(Exiv2_grep_key_t(pattern,bIgnoreCase)); +#endif #endif return result; } // Params::evalGrep @@ -846,50 +862,50 @@ typedef std::map long_t; int Params::getopt(int argc, char* const Argv[]) { - char** argv = new char* [argc+1]; - argv[argc] = NULL; - long_t longs; - - longs["--adjust" ] = "-a"; - longs["--binary" ] = "-b"; - longs["--comment" ] = "-c"; - longs["--delete" ] = "-d"; - longs["--days" ] = "-D"; - longs["--force" ] = "-f"; - longs["--Force" ] = "-F"; - longs["--grep" ] = "-g"; - longs["--help" ] = "-h"; - longs["--insert" ] = "-i"; - longs["--keep" ] = "-k"; - longs["--key" ] = "-K"; - longs["--location" ] = "-l"; - longs["--modify" ] = "-m"; - longs["--Modify" ] = "-M"; - longs["--encode" ] = "-n"; - longs["--months" ] = "-O"; - longs["--print" ] = "-p"; - longs["--Print" ] = "-P"; - longs["--quiet" ] = "-q"; - longs["--log" ] = "-Q"; - longs["--rename" ] = "-r"; - longs["--suffix" ] = "-S"; - longs["--timestamp"] = "-t"; - longs["--Timestamp"] = "-T"; - longs["--unknown" ] = "-u"; - longs["--verbose" ] = "-v"; - longs["--Version" ] = "-V"; - longs["--version" ] = "-V"; - longs["--years" ] = "-Y"; - - for ( int i = 0 ; i < argc ; i++ ) { - std::string* arg = new std::string(Argv[i]); - if (longs.find(*arg) != longs.end() ) { - argv[i] = ::strdup(longs[*arg].c_str()); - } else { - argv[i] = ::strdup(Argv[i]); - } - delete arg; - } + char** argv = new char* [argc+1]; + argv[argc] = NULL; + long_t longs; + + longs["--adjust" ] = "-a"; + longs["--binary" ] = "-b"; + longs["--comment" ] = "-c"; + longs["--delete" ] = "-d"; + longs["--days" ] = "-D"; + longs["--force" ] = "-f"; + longs["--Force" ] = "-F"; + longs["--grep" ] = "-g"; + longs["--help" ] = "-h"; + longs["--insert" ] = "-i"; + longs["--keep" ] = "-k"; + longs["--key" ] = "-K"; + longs["--location" ] = "-l"; + longs["--modify" ] = "-m"; + longs["--Modify" ] = "-M"; + longs["--encode" ] = "-n"; + longs["--months" ] = "-O"; + longs["--print" ] = "-p"; + longs["--Print" ] = "-P"; + longs["--quiet" ] = "-q"; + longs["--log" ] = "-Q"; + longs["--rename" ] = "-r"; + longs["--suffix" ] = "-S"; + longs["--timestamp"] = "-t"; + longs["--Timestamp"] = "-T"; + longs["--unknown" ] = "-u"; + longs["--verbose" ] = "-v"; + longs["--Version" ] = "-V"; + longs["--version" ] = "-V"; + longs["--years" ] = "-Y"; + + for ( int i = 0 ; i < argc ; i++ ) { + std::string* arg = new std::string(Argv[i]); + if (longs.find(*arg) != longs.end() ) { + argv[i] = ::strdup(longs[*arg].c_str()); + } else { + argv[i] = ::strdup(Argv[i]); + } + delete arg; + } int rc = Util::Getopt::getopt(argc, argv, optstring_); // Further consistency checks @@ -958,8 +974,8 @@ int Params::getopt(int argc, char* const Argv[]) rc = 1; } - // cleanup the argument vector - for ( int i = 0 ; i < argc ; i++ ) ::free((void*)argv[i]); + // cleanup the argument vector + for ( int i = 0 ; i < argc ; i++ ) ::free((void*)argv[i]); delete [] argv; return rc; diff --git a/src/version.cpp b/src/version.cpp index 55fb2e6f..4d499a8c 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -172,18 +172,32 @@ namespace Exiv2 { }; #endif -static bool shouldOutput(const exv_grep_keys_t& greps,const char* name,const std::string& value) +static bool shouldOutput(const exv_grep_keys_t& greps,const char* key,const std::string& value) { bool bPrint = greps.empty(); for( exv_grep_keys_t::const_iterator g = greps.begin(); !bPrint && g != greps.end() ; ++g ) { +#if __cplusplus >= CPLUSPLUS11 + std::smatch m; + bPrint = std::regex_search(std::string(key),m,*g) || std::regex_search(value,m,*g); +#else #if EXV_HAVE_REGEX - bPrint = ( 0 == regexec( &(*g), name , 0, NULL, 0) + bPrint = ( 0 == regexec( &(*g), key , 0, NULL, 0) || 0 == regexec( &(*g), value.c_str(), 0, NULL, 0) ); #else - bPrint = std::string(name).find(*g) != std::string::npos || value.find(*g) != std::string::npos; + std::string Pattern(g->pattern_); + std::string Key(key); + 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 #endif } return bPrint; @@ -504,6 +518,8 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const exv_grep_keys_t& keys) output(os,keys,"bits" , bits ); output(os,keys,"dll" , dll ); output(os,keys,"debug" , debug ); + output(os,keys,"cplusplus" , __cplusplus); + output(os,keys,"cplusplus11" , __cplusplus >= CPLUSPLUS11 ); output(os,keys,"version" , __VERSION__); output(os,keys,"date" , __DATE__ ); output(os,keys,"time" , __TIME__ ); diff --git a/test/bugfixes-test.sh b/test/bugfixes-test.sh index bd11b8b9..b799a305 100755 --- a/test/bugfixes-test.sh +++ b/test/bugfixes-test.sh @@ -332,6 +332,13 @@ source ./functions.source diff $diffargs $num-before.txt $num-after.txt > $num.txt diff $diffargs $num.txt $diffname + num=1024 + filename=exiv2-bug$num.exv + printf "$num " >&3 + echo '------>' Bug $num '<-------' >&2 + copyTestFile $filename + runTest exiv2 -pa --grep gpsl/i $filename + num=1026 filename=exiv2-bug$num.jpg printf "$num " >&3 @@ -430,7 +437,7 @@ source ./functions.source copyTestFile $filename runTest exiv2 -pv -g Lens $filename runTest exiv2 -pa -g Lens $filename - + num=1137 filename=exiv2-bug$num.jpg printf "$num " >&3 @@ -440,7 +447,7 @@ source ./functions.source runTest exiv2 -pa $filename runTest exiv2 -PkV --grep GPSL http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg | runTest exiv2 -m- $filename runTest exiv2 -pa $filename - + ) 3>&1 > $results 2>&1 diff --git a/test/data/bugfixes-test.out b/test/data/bugfixes-test.out index 12149dc0..e9ab4e85 100644 Binary files a/test/data/bugfixes-test.out and b/test/data/bugfixes-test.out differ diff --git a/test/data/exiv2-bug1024.exv b/test/data/exiv2-bug1024.exv new file mode 100644 index 00000000..6d0edb24 Binary files /dev/null and b/test/data/exiv2-bug1024.exv differ