This commit is contained in:
Jean-Francois Dockes
2018-10-12 12:06:21 +02:00
151 changed files with 10323 additions and 3194 deletions
+1
View File
@@ -415,6 +415,7 @@ int ConfSimple::i_set(const std::string& nm, const std::string& value,
// During the initial construction, just append:
CONFDEB("ConfSimple::i_set: init true: append\n");
m_order.push_back(ConfLine(ConfLine::CFL_VAR, nm));
m_order.back().m_value = value;
return 1;
}
+1
View File
@@ -71,6 +71,7 @@ public:
enum Kind {CFL_COMMENT, CFL_SK, CFL_VAR, CFL_VARCOMMENT};
Kind m_kind;
std::string m_data;
std::string m_value;
std::string m_aux;
ConfLine(Kind k, const std::string& d, std::string a = std::string())
: m_kind(k), m_data(d), m_aux(a) {
+16 -378
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2004 J.F.Dockes
/* Copyright (C) 2004-2018 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -14,7 +14,6 @@
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef TEST_EXECMD
#ifdef BUILDING_RECOLL
#include "autoconfig.h"
#else
@@ -74,6 +73,7 @@ public:
ExecCmdProvide *m_provide{0};
bool m_killRequest{false};
int m_timeoutMs{1000};
int m_killTimeoutMs{2000};
int m_rlimit_as_mbytes{0};
string m_stderrFile;
// Pipe for data going to the command
@@ -122,6 +122,10 @@ void ExecCmd::setTimeout(int mS)
m->m_timeoutMs = mS;
}
}
void ExecCmd::setKillTimeout(int mS)
{
m->m_killTimeoutMs = mS;
}
void ExecCmd::setStderr(const std::string& stderrFile)
{
m->m_stderrFile = stderrFile;
@@ -276,17 +280,23 @@ public:
", SIGTERM)\n");
int ret = killpg(grp, SIGTERM);
if (ret == 0) {
for (int i = 0; i < 3; i++) {
msleep(i == 0 ? 5 : (i == 1 ? 100 : 2000));
int ms_slept{0};
for (int i = 0; ; i++) {
int tosleep = i == 0 ? 5 : (i == 1 ? 100 : 1000);
msleep(tosleep);
ms_slept += tosleep;
int status;
(void)waitpid(m_parent->m_pid, &status, WNOHANG);
if (kill(m_parent->m_pid, 0) != 0) {
break;
}
if (i == 2) {
LOGDEB("ExecCmd: killpg(" << (grp) << ", SIGKILL)\n");
// killtimeout == -1 -> never KILL
if (m_parent->m_killTimeoutMs >= 0 &&
ms_slept >= m_parent->m_killTimeoutMs) {
LOGDEB("ExecCmd: killpg(" << grp << ", SIGKILL)\n");
killpg(grp, SIGKILL);
(void)waitpid(m_parent->m_pid, &status, WNOHANG);
break;
}
}
} else {
@@ -1144,375 +1154,3 @@ void ReExec::reexec()
argv[i] = 0;
execvp(m_argv[0].c_str(), (char *const*)argv);
}
////////////////////////////////////////////////////////////////////
#else // TEST
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include "log.h"
#include "execmd.h"
#ifdef BUILDING_RECOLL
#include "smallut.h"
#include "cancelcheck.h"
#endif
using namespace std;
#ifdef BUILDING_RECOLL
// Testing the rclexecm protocol outside of recoll. Here we use the
// rcldoc.py filter, you can try with rclaudio too, adjust the file arg
// accordingly
bool exercise_mhexecm(const string& cmdstr, const string& mimetype,
vector<string>& files)
{
ExecCmd cmd;
vector<string> myparams;
if (cmd.startExec(cmdstr, myparams, 1, 1) < 0) {
cerr << "startExec " << cmdstr << " failed. Missing command?\n";
return false;
}
for (vector<string>::const_iterator it = files.begin();
it != files.end(); it++) {
// Build request message
ostringstream obuf;
obuf << "Filename: " << (*it).length() << "\n" << (*it);
obuf << "Mimetype: " << mimetype.length() << "\n" << mimetype;
// Bogus parameter should be skipped by filter
obuf << "BogusParam: " << string("bogus").length() << "\n" << "bogus";
obuf << "\n";
cerr << "SENDING: [" << obuf.str() << "]\n";
// Send it
if (cmd.send(obuf.str()) < 0) {
// The real code calls zapchild here, but we don't need it as
// this will be handled by ~ExecCmd
//cmd.zapChild();
cerr << "send error\n";
return false;
}
// Read answer
for (int loop = 0;; loop++) {
string name, data;
// Code from mh_execm.cpp: readDataElement
string ibuf;
// Read name and length
if (cmd.getline(ibuf) <= 0) {
cerr << "getline error\n";
return false;
}
// Empty line (end of message)
if (!ibuf.compare("\n")) {
cerr << "Got empty line\n";
name.clear();
break;
}
// Filters will sometimes abort before entering the real
// protocol, ie if a module can't be loaded. Check the
// special filter error first word:
if (ibuf.find("RECFILTERROR ") == 0) {
cerr << "Got RECFILTERROR\n";
return false;
}
// We're expecting something like Name: len\n
vector<string> tokens;
stringToTokens(ibuf, tokens);
if (tokens.size() != 2) {
cerr << "bad line in filter output: [" << ibuf << "]\n";
return false;
}
vector<string>::iterator it = tokens.begin();
name = *it++;
string& slen = *it;
int len;
if (sscanf(slen.c_str(), "%d", &len) != 1) {
cerr << "bad line in filter output (no len): [" <<
ibuf << "]\n";
return false;
}
// Read element data
data.erase();
if (len > 0 && cmd.receive(data, len) != len) {
cerr << "MHExecMultiple: expected " << len <<
" bytes of data, got " << data.length() << endl;
return false;
}
// Empty element: end of message
if (name.empty()) {
break;
}
cerr << "Got name: [" << name << "] data [" << data << "]\n";
}
}
return true;
}
#endif
static char *thisprog;
static char usage [] =
"trexecmd [-c -r -i -o] cmd [arg1 arg2 ...]\n"
" -c : test cancellation (ie: trexecmd -c sleep 1000)\n"
" -r : run reexec. Must be separate option.\n"
" -i : command takes input\n"
" -o : command produces output\n"
" If -i is set, we send /etc/group contents to whatever command is run\n"
" If -o is set, we print whatever comes out\n"
"trexecmd -m <filter> <mimetype> <file> [file ...]: test execm:\n"
" <filter> should be the path to an execm filter\n"
" <mimetype> the type of the file parameters\n"
"trexecmd -w cmd : do the 'which' thing\n"
"trexecmd -l cmd test getline\n"
;
static void Usage(void)
{
fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
exit(1);
}
static int op_flags;
#define OPT_MOINS 0x1
#define OPT_i 0x4
#define OPT_w 0x8
#define OPT_c 0x10
#define OPT_r 0x20
#define OPT_m 0x40
#define OPT_o 0x80
#define OPT_l 0x100
// Data sink for data coming out of the command. We also use it to set
// a cancellation after a moment.
class MEAdv : public ExecCmdAdvise {
public:
void newData(int cnt) {
if (op_flags & OPT_c) {
#ifdef BUILDING_RECOLL
static int callcnt;
if (callcnt++ == 10) {
// Just sets the cancellation flag
CancelCheck::instance().setCancel();
// Would be called from somewhere else and throws an
// exception. We call it here for simplicity
CancelCheck::instance().checkCancel();
}
#endif
}
cerr << "newData(" << cnt << ")" << endl;
}
};
// Data provider, used if the -i flag is set
class MEPv : public ExecCmdProvide {
public:
FILE *m_fp;
string *m_input;
MEPv(string *i)
: m_input(i) {
m_fp = fopen("/etc/group", "r");
}
~MEPv() {
if (m_fp) {
fclose(m_fp);
}
}
void newData() {
char line[1024];
if (m_fp && fgets(line, 1024, m_fp)) {
m_input->assign((const char *)line);
} else {
m_input->erase();
}
}
};
ReExec reexec;
int main(int argc, char *argv[])
{
reexec.init(argc, argv);
if (0) {
// Disabled: For testing reexec arg handling
vector<string> newargs;
newargs.push_back("newarg");
newargs.push_back("newarg1");
newargs.push_back("newarg2");
newargs.push_back("newarg3");
newargs.push_back("newarg4");
reexec.insertArgs(newargs, 2);
}
thisprog = argv[0];
argc--;
argv++;
while (argc > 0 && **argv == '-') {
(*argv)++;
if (!(**argv))
/* Cas du "adb - core" */
{
Usage();
}
while (**argv)
switch (*(*argv)++) {
case 'c':
op_flags |= OPT_c;
break;
case 'r':
op_flags |= OPT_r;
break;
case 'w':
op_flags |= OPT_w;
break;
#ifdef BUILDING_RECOLL
case 'm':
op_flags |= OPT_m;
break;
#endif
case 'i':
op_flags |= OPT_i;
break;
case 'l':
op_flags |= OPT_l;
break;
case 'o':
op_flags |= OPT_o;
break;
default:
Usage();
break;
}
argc--;
argv++;
}
if (argc < 1) {
Usage();
}
string arg1 = *argv++;
argc--;
vector<string> l;
while (argc > 0) {
l.push_back(*argv++);
argc--;
}
#ifdef BUILDING_RECOLL
DebugLog::getdbl()->setloglevel(DEBDEB1);
DebugLog::setfilename("stderr");
#endif
signal(SIGPIPE, SIG_IGN);
if (op_flags & OPT_r) {
// Test reexec. Normally only once, next time we fall through
// because we remove the -r option (only works if it was isolated, not like -rc
chdir("/");
argv[0] = strdup("");
sleep(1);
cerr << "Calling reexec\n";
// We remove the -r arg from list, otherwise we are going to
// loop (which you can try by commenting out the following
// line)
reexec.removeArg("-r");
reexec.reexec();
}
if (op_flags & OPT_w) {
// Test "which" method
string path;
if (ExecCmd::which(arg1, path)) {
cout << path << endl;
return 0;
}
return 1;
#ifdef BUILDING_RECOLL
} else if (op_flags & OPT_m) {
if (l.size() < 2) {
Usage();
}
string mimetype = l[0];
l.erase(l.begin());
return exercise_mhexecm(arg1, mimetype, l) ? 0 : 1;
#endif
} else if (op_flags & OPT_l) {
ExecCmd mexec;
if (mexec.startExec(arg1, l, false, true) < 0) {
cerr << "Startexec failed\n";
exit(1);
}
string output;
int ret = mexec.getline(output, 2);
cerr << "Got ret " << ret << " output " << output << endl;
cerr << "Waiting\n";
int status = mexec.wait();
cerr << "Got status " << status << endl;
exit(status);
} else {
// Default: execute command line arguments
ExecCmd mexec;
// Set callback to be called whenever there is new data
// available and at a periodic interval, to check for
// cancellation
MEAdv adv;
mexec.setAdvise(&adv);
mexec.setTimeout(5);
// Stderr output goes there
mexec.setStderr("/tmp/trexecStderr");
// A few environment variables. Check with trexecmd env
mexec.putenv("TESTVARIABLE1=TESTVALUE1");
mexec.putenv("TESTVARIABLE2=TESTVALUE2");
mexec.putenv("TESTVARIABLE3=TESTVALUE3");
string input, output;
MEPv pv(&input);
string *ip = 0;
if (op_flags & OPT_i) {
ip = &input;
mexec.setProvide(&pv);
}
string *op = 0;
if (op_flags & OPT_o) {
op = &output;
}
int status = -1;
try {
status = mexec.doexec(arg1, l, ip, op);
} catch (...) {
cerr << "CANCELLED" << endl;
}
fprintf(stderr, "Status: 0x%x\n", status);
if (op_flags & OPT_o) {
cout << output;
}
exit(status >> 8);
}
}
#endif // TEST
+12 -1
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2004 J.F.Dockes
/* Copyright (C) 2004-2018 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -117,6 +117,17 @@ public:
*/
void setStderr(const std::string& stderrFile);
/**
* Set kill wait timeout. This is the maximum time we'll wait for
* the command after sending a SIGTERM, before sending a SIGKILL.
* @param mS the maximum number of mS to wait. Note that values
* below 1000 mS make no sense as the program will sleep for
* longer time before retrying the waitpid(). Use -1 for
* forever (bad idea), 0 for absolutely no pity.
*/
void setKillTimeout(int mS);
/**
* Execute command.
*
-20
View File
@@ -26,20 +26,6 @@
using std::string;
// Debug only
#ifdef PATHHASH_HEX
static void md5hexprint(const unsigned char hash[16], string &out)
{
out.erase();
out.reserve(33);
static const char hex[]="0123456789abcdef";
for (int i = 0; i < 16; i++) {
out.append(1, hex[hash[i] >> 4]);
out.append(1, hex[hash[i] & 0x0f]);
}
}
#endif
// Size of the hashed result (base64 of 16 bytes of md5, minus 2 pad chars)
#define HASHLEN 22
@@ -66,12 +52,6 @@ void pathHash(const std::string &path, std::string &phash, unsigned int maxlen)
path.length() - (maxlen - HASHLEN));
MD5Final(chash, &ctx);
#ifdef PATHHASH_HEX
string hex;
md5hexprint(chash, hex);
printf("hex [%s]\n", hex.c_str());
#endif
// Encode it to ascii. This shouldn't be strictly necessary as
// xapian terms can be binary
string hash;
+15
View File
@@ -34,6 +34,8 @@
#ifndef _LOG_H_X_INCLUDED_
#define _LOG_H_X_INCLUDED_
#include <string.h>
#include <fstream>
#include <iostream>
#include <string>
@@ -191,4 +193,17 @@ private:
#endif
#define LOGFATAL LOGFAT
#if (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
#define LOGSYSERR(who, what, arg) { \
char buf[200]; buf[0] = 0; strerror_r(errno, buf, 200); \
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
": " << buf << std::endl); \
}
#else
#define LOGSYSERR(who, what, arg) { \
char buf[200]; buf[0] = 0; \
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
": " << strerror_r(errno, buf, 200) << std::endl); \
}
#endif
#endif /* _LOG_H_X_INCLUDED_ */
+10 -3
View File
@@ -72,10 +72,11 @@ using namespace std;
static const int one = 1;
static const int zero = 0;
#ifndef LOGSYSERR
#define LOGSYSERR(who, call, spar) \
LOGERR(who << ": " << call << "(" << spar << ") errno " << \
errno << " (" << strerror(errno) << ")\n")
#endif
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
#endif
@@ -700,7 +701,10 @@ void NetconData::cancelReceive()
{
if (m_wkfds[1] >= 0) {
LOGDEB2("NetconData::cancelReceive: writing to " << m_wkfds[1] << endl);
::write(m_wkfds[1], "!", 1);
// We can't do a thing about the ::write return value, the
// following nonsense is for cancelling warnings
int ret = ::write(m_wkfds[1], "!", 1);
ret = ret;
}
}
@@ -749,7 +753,10 @@ int NetconData::receive(char *buf, int cnt, int timeo)
if (cancellable && FD_ISSET(m_wkfds[0], &rd)) {
char b[100];
read(m_wkfds[0], b, 100);
// We can't do a thing about the return value, the
// following nonsense is for cancelling warnings
int ret = ::read(m_wkfds[0], b, 100);
ret = ret;
return Cancelled;
}
+91
View File
@@ -52,6 +52,7 @@
#include <stack>
#include <set>
#include <vector>
#include <regex>
#include "pathut.h"
#include "smallut.h"
@@ -761,6 +762,96 @@ bool urlisfileurl(const string& url)
return url.find("file://") == 0;
}
static std::regex
re_uriparse("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?",
std::regex::extended);
ParsedUri::ParsedUri(std::string uri)
{
std::smatch mr;
parsed = regex_match(uri, mr, re_uriparse);
if (!parsed)
return;
// cf http://www.ietf.org/rfc/rfc2396.txt
// scheme = $2
// authority = $4
// path = $5
// query = $7
// fragment = $9
if (mr[2].matched) {
scheme = mr[2].str();
}
if (mr[4].matched) {
string auth = mr[4].str();
// user:pass@host, user@host
string::size_type at = auth.find_first_of('@');
if (at != string::npos) {
host = auth.substr(at+1);
string::size_type colon = auth.find_first_of(':');
if (colon != string::npos && colon < at) {
user = auth.substr(0, colon);
pass = auth.substr(colon+1, at-colon-1);
} else {
user = auth.substr(0, at);
}
} else {
host.swap(auth);
}
string::size_type pc = host.find_first_of(':');
if (pc != string::npos) {
port = host.substr(pc+1);
host = host.substr(0, pc);
}
}
if (mr[5].matched) {
path = mr[5].str();
}
if (mr[7].matched) {
query = mr[7].str();
string::size_type pos=0, amp, eq;
string nm, val;
for (;;) {
nm.clear();
val.clear();
amp = query.find_first_of('&', pos);
//cerr << "pos " << pos << " amp " << amp << endl;
if (amp > pos && amp != string::npos) {
eq = query.find_first_of('=', pos);
if (eq > amp || eq == string::npos) {
nm = query.substr(pos, amp-pos);
} else {
nm = query.substr(pos, eq-pos);
val = query.substr(eq+1, amp-eq-1);
}
pos = amp + 1;
} else if (amp == string::npos) {
if (pos < query.size()-1) {
eq = query.find_first_of('=', pos);
if (eq == string::npos) {
nm = query.substr(pos);
} else {
nm = query.substr(pos, eq-pos);
val = query.substr(eq+1);
}
}
pos = query.size()-1;
} else {
pos++;
}
if (!nm.empty()) {
parsedquery.push_back(pair<string,string>(nm, val));
}
if (pos >= query.size()-1) {
break;
}
}
}
if (mr[9].matched) {
fragment = mr[9].str();
}
}
bool readdir(const string& dir, string& reason, set<string>& entries)
{
struct stat st;
+16
View File
@@ -120,6 +120,22 @@ extern bool path_isdesc(const std::string& top, const std::string& sub);
/// Turn absolute path into file:// url
extern std::string path_pathtofileurl(const std::string& path);
/// URI parser, loosely from rfc2396.txt
class ParsedUri {
public:
ParsedUri(std::string uri);
bool parsed{false};
std::string scheme;
std::string user;
std::string pass;
std::string host;
std::string port;
std::string path;
std::string query;
std::vector<std::pair<std::string,std::string>> parsedquery;
std::string fragment;
};
#ifdef _WIN32
/// Convert \ separators to /
void path_slashize(std::string& s);
+49 -3
View File
@@ -43,6 +43,7 @@
#include "wipedir.h"
#include "transcode.h"
#include "md5ut.h"
#include "log.h"
using namespace std;
@@ -281,8 +282,51 @@ bool maketmpdir(string& tdir, string& reason)
return true;
}
TempFileInternal::TempFileInternal(const string& suffix)
: m_noremove(false)
class TempFile::Internal {
public:
Internal(const std::string& suffix);
~Internal();
friend class TempFile;
private:
std::string m_filename;
std::string m_reason;
bool m_noremove{false};
};
TempFile::TempFile(const string& suffix)
: m(new Internal(suffix))
{
}
TempFile::TempFile()
{
m = std::shared_ptr<Internal>();
}
const char *TempFile::filename() const
{
return m ? m->m_filename.c_str() : "";
}
const std::string& TempFile::getreason() const
{
static string fatal{"fatal error"};
return m ? m->m_reason : fatal;
}
void TempFile::setnoremove(bool onoff)
{
if (m)
m->m_noremove = onoff;
}
bool TempFile::ok() const
{
return m ? !m->m_filename.empty() : false;
}
TempFile::Internal::Internal(const string& suffix)
{
// Because we need a specific suffix, can't use mkstemp
// well. There is a race condition between name computation and
@@ -322,7 +366,7 @@ TempFileInternal::TempFileInternal(const string& suffix)
}
}
TempFileInternal::~TempFileInternal()
TempFile::Internal::~Internal()
{
if (!m_filename.empty() && !m_noremove) {
unlink(m_filename.c_str());
@@ -335,11 +379,13 @@ TempDir::TempDir()
m_dirname.erase();
return;
}
LOGDEB("TempDir::TempDir: -> " << m_dirname << endl);
}
TempDir::~TempDir()
{
if (!m_dirname.empty()) {
LOGDEB("TempDir::~TempDir: erasing " << m_dirname << endl);
(void)wipedir(m_dirname, true, true);
m_dirname.erase();
}
+9 -20
View File
@@ -48,30 +48,19 @@ extern const std::string& tmplocation();
extern bool maketmpdir(std::string& tdir, std::string& reason);
/// Temporary file class
class TempFileInternal {
class TempFile {
public:
TempFileInternal(const std::string& suffix);
~TempFileInternal();
const char *filename() {
return m_filename.c_str();
}
const std::string& getreason() {
return m_reason;
}
void setnoremove(bool onoff) {
m_noremove = onoff;
}
bool ok() {
return !m_filename.empty();
}
TempFile(const std::string& suffix);
TempFile();
const char *filename() const;
const std::string& getreason() const;
void setnoremove(bool onoff);
bool ok() const;
class Internal;
private:
std::string m_filename;
std::string m_reason;
bool m_noremove;
std::shared_ptr<Internal> m;
};
typedef std::shared_ptr<TempFileInternal> TempFile;
/// Temporary directory class. Recursively deleted by destructor.
class TempDir {
public:
-70
View File
@@ -1,70 +0,0 @@
#ifndef _REFCNTR_H_
#define _REFCNTR_H_
/* Copyright (C) 2014 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// See Stroustrup C++ 3rd ed, p. 783
// This is only used if std::shared_ptr is not available
template <class X> class RefCntr {
X *rep;
int *pcount;
public:
RefCntr()
: rep(0), pcount(0)
{}
explicit RefCntr(X *pp)
: rep(pp), pcount(new int(1))
{}
RefCntr(const RefCntr &r)
: rep(r.rep), pcount(r.pcount)
{
if (pcount)
(*pcount)++;
}
RefCntr& operator=(const RefCntr& r)
{
if (rep == r.rep)
return *this;
if (pcount && --(*pcount) == 0) {
delete rep;
delete pcount;
}
rep = r.rep;
pcount = r.pcount;
if (pcount)
(*pcount)++;
return *this;
}
void reset() {
if (pcount && --(*pcount) == 0) {
delete rep;
delete pcount;
}
rep = 0;
pcount = 0;
}
~RefCntr()
{
reset();
}
X *operator->() {return rep;}
X *get() const {return rep;}
int use_count() const {return pcount ? *pcount : 0;}
operator bool() const {return rep != 0;}
};
#endif /*_REFCNTR_H_ */
+11 -61
View File
@@ -16,14 +16,10 @@
*/
#include "autoconfig.h"
#include "strmatcher.h"
#include <stdio.h>
#include <sys/types.h>
#ifdef _WIN32
#include <regex>
#else
#include <regex.h>
#endif
#include <fnmatch.h>
#include <string>
@@ -31,19 +27,19 @@
#include "cstr.h"
#include "log.h"
#include "pathut.h"
#include "strmatcher.h"
using namespace std;
bool StrWildMatcher::match(const string& val) const
{
LOGDEB2("StrWildMatcher::match: [" << (m_sexp) << "] against [" << (val) << "]\n" );
LOGDEB2("StrWildMatcher::match ["<< m_sexp<< "] against [" << val << "]\n");
int ret = fnmatch(m_sexp.c_str(), val.c_str(), FNM_NOESCAPE);
switch (ret) {
case 0: return true;
case FNM_NOMATCH: return false;
default:
LOGINFO("StrWildMatcher::match:err: e [" << (m_sexp) << "] s [" << (val) << "] (" << (url_encode(val)) << ") ret " << (ret) << "\n" );
LOGINFO("StrWildMatcher::match:err: e [" << m_sexp << "] s [" << val
<< "] (" << url_encode(val) << ") ret " << ret << "\n");
return false;
}
}
@@ -54,68 +50,22 @@ string::size_type StrWildMatcher::baseprefixlen() const
}
StrRegexpMatcher::StrRegexpMatcher(const string& exp)
: StrMatcher(exp), m_compiled(0), m_errcode(0)
: StrMatcher(exp),
m_re(exp, SimpleRegexp::SRE_NOSUB)
{
setExp(exp);
}
bool StrRegexpMatcher::setExp(const string& exp)
{
if (m_compiled) {
#ifdef _WIN32
delete (regex*)m_compiled;
#else
regfree((regex_t*)m_compiled);
delete (regex_t*)m_compiled;
#endif
}
m_compiled = 0;
#ifdef _WIN32
try {
m_compiled = new regex(exp, std::regex_constants::nosubs |
std::regex_constants::extended);
} catch (...) {
m_reason = string("StrRegexpMatcher:regcomp failed for ")
+ exp + string("syntax error ?");
return false;
}
#else
m_compiled = new regex_t;
if ((m_errcode =
regcomp((regex_t*)m_compiled, exp.c_str(), REG_EXTENDED|REG_NOSUB))) {
char errbuf[200];
regerror(m_errcode, (regex_t*)m_compiled, errbuf, 199);
m_reason = string("StrRegexpMatcher:regcomp failed for ")
+ exp + string(errbuf);
return false;
}
#endif
m_sexp = exp;
return true;
}
StrRegexpMatcher::~StrRegexpMatcher()
{
if (m_compiled) {
#ifdef _WIN32
delete (regex *)m_compiled;
#else
regfree((regex_t*)m_compiled);
delete (regex_t*)m_compiled;
#endif
}
m_re = SimpleRegexp(exp, SimpleRegexp::SRE_NOSUB);
return m_re.ok();
}
bool StrRegexpMatcher::match(const string& val) const
{
if (m_errcode)
if (!m_re.ok())
return false;
#ifdef _WIN32
return regex_match(val, *((regex *)m_compiled));
#else
return regexec((regex_t*)m_compiled, val.c_str(), 0, 0, 0) != REG_NOMATCH;
#endif
return m_re(val);
}
string::size_type StrRegexpMatcher::baseprefixlen() const
@@ -125,6 +75,6 @@ string::size_type StrRegexpMatcher::baseprefixlen() const
bool StrRegexpMatcher::ok() const
{
return !m_errcode;
return m_re.ok();
}
+15 -31
View File
@@ -18,6 +18,7 @@
#define _STRMATCHER_H_INCLUDED_
#include <string>
#include "smallut.h"
// Encapsulating simple wildcard/regexp string matching.
@@ -25,28 +26,22 @@
class StrMatcher {
public:
StrMatcher(const std::string& exp)
: m_sexp(exp)
{
}
: m_sexp(exp) {}
virtual ~StrMatcher() {};
virtual bool match(const std::string &val) const = 0;
virtual std::string::size_type baseprefixlen() const = 0;
virtual bool setExp(const std::string& newexp)
{
virtual bool setExp(const std::string& newexp) {
m_sexp = newexp;
return true;
}
virtual bool ok() const
{
virtual bool ok() const {
return true;
}
virtual const std::string& exp()
{
virtual const std::string& exp() const {
return m_sexp;
}
virtual StrMatcher *clone() = 0;
const string& getreason()
{
virtual StrMatcher *clone() const = 0;
const std::string& getreason() const {
return m_reason;
}
protected:
@@ -57,16 +52,11 @@ protected:
class StrWildMatcher : public StrMatcher {
public:
StrWildMatcher(const std::string& exp)
: StrMatcher(exp)
{
}
virtual ~StrWildMatcher()
{
}
: StrMatcher(exp) {}
virtual ~StrWildMatcher() {}
virtual bool match(const std::string& val) const;
virtual std::string::size_type baseprefixlen() const;
virtual StrWildMatcher *clone()
{
virtual StrWildMatcher *clone() const {
return new StrWildMatcher(m_sexp);
}
};
@@ -74,22 +64,16 @@ public:
class StrRegexpMatcher : public StrMatcher {
public:
StrRegexpMatcher(const std::string& exp);
virtual bool setExp(const std::string& newexp);
virtual ~StrRegexpMatcher();
virtual bool setExp(const std::string& newexp) override;
virtual ~StrRegexpMatcher() {};
virtual bool match(const std::string& val) const;
virtual std::string::size_type baseprefixlen() const;
virtual bool ok() const;
virtual StrRegexpMatcher *clone()
{
virtual bool ok() const override;
virtual StrRegexpMatcher *clone() const {
return new StrRegexpMatcher(m_sexp);
}
const string& getreason()
{
return m_reason;
}
private:
void *m_compiled;
bool m_errcode;
SimpleRegexp m_re;
};
#endif /* _STRMATCHER_H_INCLUDED_ */