#1024. Support for C++11 #include <regex>. --grep keys may have an optional trailer /i to indicate to ignore case.

v0.27.3
Robin Mills 10 years ago
parent 8369445c6f
commit ab9ee2c6df

@ -37,11 +37,25 @@
// + standard includes // + standard includes
#include <string> #include <string>
#include <vector> #include <vector>
#if EXV_HAVE_REGEX
#include <regex.h> #define CPLUSPLUS11 201103L
typedef std::vector<regex_t> exv_grep_keys_t ;
#if __cplusplus >= CPLUSPLUS11
# include <regex>
typedef std::vector<std::regex> exv_grep_keys_t ;
#else #else
typedef std::vector<std::string> exv_grep_keys_t ; # if EXV_HAVE_REGEX
# include <regex.h>
typedef std::vector<regex_t> 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<Exiv2_grep_key_t> exv_grep_keys_t ;
# endif
#endif #endif
/*! /*!

@ -49,6 +49,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "preview.hpp" #include "preview.hpp"
#include "futils.hpp" #include "futils.hpp"
#include "i18n.h" // NLS support. #include "i18n.h" // NLS support.
#include "version.hpp"
// + standard includes // + standard includes
#include <string> #include <string>
@ -581,10 +582,22 @@ namespace Action {
for (Params::Greps::const_iterator g = Params::instance().greps_.begin(); for (Params::Greps::const_iterator g = Params::instance().greps_.begin();
!result && g != Params::instance().greps_.end(); ++g) !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 #if EXV_HAVE_REGEX
result = regexec( &(*g), key.c_str(), 0, NULL, 0) == 0 ; result = regexec( &(*g), key.c_str(), 0, NULL, 0) == 0 ;
#else #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 #endif
} }
return result ; return result ;

@ -3,7 +3,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" 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. .\" Please adjust this date whenever revising the manpage.
.\" .\"
.\" Some roff macros, for reference: .\" 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). Only keys which match the given key (grep).
.br .br
Multiple \fB\-g\fP options Multiple \fB\-g\fP options
can be used to grep info for several keys. This option uses the system can be used to grep info for several keys. When the library is build with C++11,
regular expression engine: see man 3 regex. Platforms which do not support 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 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 .nf
exiv2 \-g Date \-pt R.jpg exiv2 \-g Date \-pt R.jpg
@ -235,6 +236,8 @@ Exif.Photo.DateTimeDigitized Ascii 20 2011:09:18 16:25:48
.fi .fi
-g (--grep) is only applied to keys. It is not generally applied to all output such as the default -ps report. -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 .TP
.B \-K \fIkey\fP .B \-K \fIkey\fP
Only report data for given key. Only report data for given key.

@ -415,15 +415,30 @@ int Params::setLogLevel(const std::string& optarg)
return rc; return rc;
} // Params::setLogLevel } // 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 Params::evalGrep( const std::string& optarg)
{ {
int result=0; 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 #if EXV_HAVE_REGEX
// try to compile a reg-exp from the input argument and store it in the vector // try to compile a reg-exp from the input argument and store it in the vector
const size_t i = greps_.size(); const size_t i = greps_.size();
greps_.resize(i + 1); greps_.resize(i + 1);
regex_t *pRegex = &greps_[i]; 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 // there was an error compiling the regexp
if( errcode ) { if( errcode ) {
@ -441,7 +456,8 @@ int Params::evalGrep( const std::string& optarg)
result=1; result=1;
} }
#else #else
greps_.push_back(optarg); greps_.push_back(Exiv2_grep_key_t(pattern,bIgnoreCase));
#endif
#endif #endif
return result; return result;
} // Params::evalGrep } // Params::evalGrep
@ -846,50 +862,50 @@ typedef std::map<std::string,std::string> long_t;
int Params::getopt(int argc, char* const Argv[]) int Params::getopt(int argc, char* const Argv[])
{ {
char** argv = new char* [argc+1]; char** argv = new char* [argc+1];
argv[argc] = NULL; argv[argc] = NULL;
long_t longs; long_t longs;
longs["--adjust" ] = "-a"; longs["--adjust" ] = "-a";
longs["--binary" ] = "-b"; longs["--binary" ] = "-b";
longs["--comment" ] = "-c"; longs["--comment" ] = "-c";
longs["--delete" ] = "-d"; longs["--delete" ] = "-d";
longs["--days" ] = "-D"; longs["--days" ] = "-D";
longs["--force" ] = "-f"; longs["--force" ] = "-f";
longs["--Force" ] = "-F"; longs["--Force" ] = "-F";
longs["--grep" ] = "-g"; longs["--grep" ] = "-g";
longs["--help" ] = "-h"; longs["--help" ] = "-h";
longs["--insert" ] = "-i"; longs["--insert" ] = "-i";
longs["--keep" ] = "-k"; longs["--keep" ] = "-k";
longs["--key" ] = "-K"; longs["--key" ] = "-K";
longs["--location" ] = "-l"; longs["--location" ] = "-l";
longs["--modify" ] = "-m"; longs["--modify" ] = "-m";
longs["--Modify" ] = "-M"; longs["--Modify" ] = "-M";
longs["--encode" ] = "-n"; longs["--encode" ] = "-n";
longs["--months" ] = "-O"; longs["--months" ] = "-O";
longs["--print" ] = "-p"; longs["--print" ] = "-p";
longs["--Print" ] = "-P"; longs["--Print" ] = "-P";
longs["--quiet" ] = "-q"; longs["--quiet" ] = "-q";
longs["--log" ] = "-Q"; longs["--log" ] = "-Q";
longs["--rename" ] = "-r"; longs["--rename" ] = "-r";
longs["--suffix" ] = "-S"; longs["--suffix" ] = "-S";
longs["--timestamp"] = "-t"; longs["--timestamp"] = "-t";
longs["--Timestamp"] = "-T"; longs["--Timestamp"] = "-T";
longs["--unknown" ] = "-u"; longs["--unknown" ] = "-u";
longs["--verbose" ] = "-v"; longs["--verbose" ] = "-v";
longs["--Version" ] = "-V"; longs["--Version" ] = "-V";
longs["--version" ] = "-V"; longs["--version" ] = "-V";
longs["--years" ] = "-Y"; longs["--years" ] = "-Y";
for ( int i = 0 ; i < argc ; i++ ) { for ( int i = 0 ; i < argc ; i++ ) {
std::string* arg = new std::string(Argv[i]); std::string* arg = new std::string(Argv[i]);
if (longs.find(*arg) != longs.end() ) { if (longs.find(*arg) != longs.end() ) {
argv[i] = ::strdup(longs[*arg].c_str()); argv[i] = ::strdup(longs[*arg].c_str());
} else { } else {
argv[i] = ::strdup(Argv[i]); argv[i] = ::strdup(Argv[i]);
} }
delete arg; delete arg;
} }
int rc = Util::Getopt::getopt(argc, argv, optstring_); int rc = Util::Getopt::getopt(argc, argv, optstring_);
// Further consistency checks // Further consistency checks
@ -958,8 +974,8 @@ int Params::getopt(int argc, char* const Argv[])
rc = 1; rc = 1;
} }
// cleanup the argument vector // cleanup the argument vector
for ( int i = 0 ; i < argc ; i++ ) ::free((void*)argv[i]); for ( int i = 0 ; i < argc ; i++ ) ::free((void*)argv[i]);
delete [] argv; delete [] argv;
return rc; return rc;

@ -172,18 +172,32 @@ namespace Exiv2 {
}; };
#endif #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(); bool bPrint = greps.empty();
for( exv_grep_keys_t::const_iterator g = greps.begin(); for( exv_grep_keys_t::const_iterator g = greps.begin();
!bPrint && g != greps.end() ; ++g !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 #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) || 0 == regexec( &(*g), value.c_str(), 0, NULL, 0)
); );
#else #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 #endif
} }
return bPrint; 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,"bits" , bits );
output(os,keys,"dll" , dll ); output(os,keys,"dll" , dll );
output(os,keys,"debug" , debug ); output(os,keys,"debug" , debug );
output(os,keys,"cplusplus" , __cplusplus);
output(os,keys,"cplusplus11" , __cplusplus >= CPLUSPLUS11 );
output(os,keys,"version" , __VERSION__); output(os,keys,"version" , __VERSION__);
output(os,keys,"date" , __DATE__ ); output(os,keys,"date" , __DATE__ );
output(os,keys,"time" , __TIME__ ); output(os,keys,"time" , __TIME__ );

@ -332,6 +332,13 @@ source ./functions.source
diff $diffargs $num-before.txt $num-after.txt > $num.txt diff $diffargs $num-before.txt $num-after.txt > $num.txt
diff $diffargs $num.txt $diffname 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 num=1026
filename=exiv2-bug$num.jpg filename=exiv2-bug$num.jpg
printf "$num " >&3 printf "$num " >&3
@ -430,7 +437,7 @@ source ./functions.source
copyTestFile $filename copyTestFile $filename
runTest exiv2 -pv -g Lens $filename runTest exiv2 -pv -g Lens $filename
runTest exiv2 -pa -g Lens $filename runTest exiv2 -pa -g Lens $filename
num=1137 num=1137
filename=exiv2-bug$num.jpg filename=exiv2-bug$num.jpg
printf "$num " >&3 printf "$num " >&3
@ -440,7 +447,7 @@ source ./functions.source
runTest exiv2 -pa $filename 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 -PkV --grep GPSL http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg | runTest exiv2 -m- $filename
runTest exiv2 -pa $filename runTest exiv2 -pa $filename
) 3>&1 > $results 2>&1 ) 3>&1 > $results 2>&1

Binary file not shown.

Binary file not shown.
Loading…
Cancel
Save