Skip to content

Commit b099926

Browse files
committed
Regex: hide implementation details
1 parent 508e940 commit b099926

File tree

8 files changed

+301
-314
lines changed

8 files changed

+301
-314
lines changed

Makefile

Lines changed: 127 additions & 127 deletions
Large diffs are not rendered by default.

cli/cmdlineparser.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <iostream>
5252
#include <iterator>
5353
#include <list>
54+
#include <memory>
5455
#include <set>
5556
#include <sstream>
5657
#include <unordered_set>
@@ -1260,9 +1261,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
12601261
return Result::Fail;
12611262
}
12621263

1263-
Regex regex;
1264-
const std::string regex_err = regex.compile(rule.pattern);
1265-
if (!regex_err.empty()) {
1264+
std::string regex_err;
1265+
auto regex = Regex::create(rule.pattern, regex_err);
1266+
if (!regex) {
12661267
mLogger.printError("failed to compile rule pattern '" + rule.pattern + "' (" + regex_err + ").");
12671268
return Result::Fail;
12681269
}
@@ -1344,11 +1345,13 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
13441345
return Result::Fail;
13451346
}
13461347

1347-
const std::string regex_err = rule.regex.compile(rule.pattern);
1348-
if (!regex_err.empty()) {
1348+
std::string regex_err;
1349+
auto regex = Regex::create(rule.pattern, regex_err);
1350+
if (!regex) {
13491351
mLogger.printError("unable to load rule-file '" + ruleFile + "' - pattern '" + rule.pattern + "' failed to compile (" + regex_err + ").");
13501352
return Result::Fail;
13511353
}
1354+
rule.regex = std::move(regex);
13521355

13531356
if (rule.severity == Severity::none) {
13541357
mLogger.printError("unable to load rule-file '" + ruleFile + "' - a rule has an invalid severity.");

lib/cppcheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,7 @@ void CppCheck::executeRules(const std::string &tokenlist, const TokenList &list)
14811481
mErrorLogger.reportErr(errmsg);
14821482
};
14831483

1484-
const std::string err = rule.regex.match(str, f);
1484+
const std::string err = rule.regex->match(str, f);
14851485
if (!err.empty()) {
14861486
const ErrorMessage errmsg(std::list<ErrorMessage::FileLocation>(),
14871487
emptyString,

lib/regex.cpp

Lines changed: 79 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -156,115 +156,105 @@ namespace {
156156
}
157157
return "unknown PCRE error " + std::to_string(pcreExecRet);
158158
}
159-
}
160-
161-
class Regex::Data
162-
{
163-
public:
164-
explicit Data(std::string pattern)
165-
: mPattern(std::move(pattern))
166-
{}
167159

168-
~Data()
160+
class PcreRegex : public Regex
169161
{
170-
if (mExtra) {
171-
pcre_free(mExtra);
172-
mExtra = nullptr;
173-
}
174-
if (mRe) {
175-
pcre_free(mRe);
176-
mRe = nullptr;
162+
public:
163+
explicit PcreRegex(std::string pattern)
164+
: mPattern(std::move(pattern))
165+
{}
166+
167+
~PcreRegex() override
168+
{
169+
if (mExtra) {
170+
pcre_free(mExtra);
171+
mExtra = nullptr;
172+
}
173+
if (mRe) {
174+
pcre_free(mRe);
175+
mRe = nullptr;
176+
}
177177
}
178-
}
179178

180-
std::string compile();
181-
std::string match(const std::string& str, const MatchFn& match) const;
179+
std::string compile();
180+
std::string match(const std::string& str, const MatchFn& match) const override;
182181

183-
private:
184-
std::string mPattern;
185-
pcre* mRe{};
186-
pcre_extra* mExtra{};
187-
};
182+
private:
183+
std::string mPattern;
184+
pcre* mRe{};
185+
pcre_extra* mExtra{};
186+
};
188187

189-
std::string Regex::Data::compile()
190-
{
191-
if (mRe)
192-
return "pcre_compile failed: regular expression has already been compiled";
188+
std::string PcreRegex::compile()
189+
{
190+
if (mRe)
191+
return "pcre_compile failed: regular expression has already been compiled";
193192

194-
const char *pcreCompileErrorStr = nullptr;
195-
int erroffset = 0;
196-
pcre * const re = pcre_compile(mPattern.c_str(),0,&pcreCompileErrorStr,&erroffset,nullptr);
197-
if (!re) {
198-
if (pcreCompileErrorStr)
199-
return "pcre_compile failed: " + std::string(pcreCompileErrorStr);
200-
return "pcre_compile failed: unknown error";
201-
}
193+
const char *pcreCompileErrorStr = nullptr;
194+
int erroffset = 0;
195+
pcre * const re = pcre_compile(mPattern.c_str(),0,&pcreCompileErrorStr,&erroffset,nullptr);
196+
if (!re) {
197+
if (pcreCompileErrorStr)
198+
return "pcre_compile failed: " + std::string(pcreCompileErrorStr);
199+
return "pcre_compile failed: unknown error";
200+
}
202201

203-
// Optimize the regex, but only if PCRE_CONFIG_JIT is available
202+
// Optimize the regex, but only if PCRE_CONFIG_JIT is available
204203
#ifdef PCRE_CONFIG_JIT
205-
const char *pcreStudyErrorStr = nullptr;
206-
pcre_extra * const pcreExtra = pcre_study(re, PCRE_STUDY_JIT_COMPILE, &pcreStudyErrorStr);
207-
// pcre_study() returns NULL for both errors and when it can not optimize the regex.
208-
// The last argument is how one checks for errors.
209-
// It is NULL if everything works, and points to an error string otherwise.
210-
if (pcreStudyErrorStr) {
211-
// pcre_compile() worked, but pcre_study() returned an error. Free the resources allocated by pcre_compile().
212-
pcre_free(re);
213-
return "pcre_study failed: " + std::string(pcreStudyErrorStr);
214-
}
215-
mExtra = pcreExtra;
204+
const char *pcreStudyErrorStr = nullptr;
205+
pcre_extra * const pcreExtra = pcre_study(re, PCRE_STUDY_JIT_COMPILE, &pcreStudyErrorStr);
206+
// pcre_study() returns NULL for both errors and when it can not optimize the regex.
207+
// The last argument is how one checks for errors.
208+
// It is NULL if everything works, and points to an error string otherwise.
209+
if (pcreStudyErrorStr) {
210+
// pcre_compile() worked, but pcre_study() returned an error. Free the resources allocated by pcre_compile().
211+
pcre_free(re);
212+
return "pcre_study failed: " + std::string(pcreStudyErrorStr);
213+
}
214+
mExtra = pcreExtra;
216215
#endif
217216

218-
mRe = re;
217+
mRe = re;
219218

220-
return "";
221-
}
222-
223-
std::string Regex::Data::match(const std::string& str, const MatchFn& match) const
224-
{
225-
if (!mRe)
226-
return "pcre_exec failed: regular expression has not been compiled yet";
227-
228-
int pos = 0;
229-
int ovector[30]= {0};
230-
while (pos < static_cast<int>(str.size())) {
231-
const int pcreExecRet = pcre_exec(mRe, mExtra, str.c_str(), static_cast<int>(str.size()), pos, 0, ovector, 30);
232-
if (pcreExecRet == PCRE_ERROR_NOMATCH)
233-
return "";
234-
if (pcreExecRet < 0) {
235-
return std::string("pcre_exec failed (pos: " + std::to_string(pos) + "): ") + pcreErrorCodeToString(pcreExecRet);
236-
}
237-
const auto pos1 = static_cast<unsigned int>(ovector[0]);
238-
const auto pos2 = static_cast<unsigned int>(ovector[1]);
219+
return "";
220+
}
239221

240-
match(pos1, pos2);
222+
std::string PcreRegex::match(const std::string& str, const MatchFn& match) const
223+
{
224+
if (!mRe)
225+
return "pcre_exec failed: regular expression has not been compiled yet";
241226

242-
// jump to the end of the match for the next pcre_exec
243-
pos = static_cast<int>(pos2);
244-
}
227+
int pos = 0;
228+
int ovector[30]= {0};
229+
while (pos < static_cast<int>(str.size())) {
230+
const int pcreExecRet = pcre_exec(mRe, mExtra, str.c_str(), static_cast<int>(str.size()), pos, 0, ovector, 30);
231+
if (pcreExecRet == PCRE_ERROR_NOMATCH)
232+
return "";
233+
if (pcreExecRet < 0) {
234+
return std::string("pcre_exec failed (pos: " + std::to_string(pos) + "): ") + pcreErrorCodeToString(pcreExecRet);
235+
}
236+
const auto pos1 = static_cast<unsigned int>(ovector[0]);
237+
const auto pos2 = static_cast<unsigned int>(ovector[1]);
245238

246-
return "";
247-
}
239+
match(pos1, pos2);
248240

249-
std::string Regex::compile(std::string pattern)
250-
{
251-
if (mData)
252-
return "regular expression has already been compiled";
241+
// jump to the end of the match for the next pcre_exec
242+
pos = static_cast<int>(pos2);
243+
}
253244

254-
auto* data = new Data(std::move(pattern));
255-
auto res = data->compile();
256-
if (res.empty())
257-
mData.reset(data);
258-
else
259-
delete data;
260-
return res;
245+
return "";
246+
}
261247
}
262248

263-
std::string Regex::match(const std::string& str, const MatchFn& match) const
249+
std::shared_ptr<Regex> Regex::create(std::string pattern, std::string& err)
264250
{
265-
if (!mData)
266-
return "regular expression hat not been compiled yet";
267-
return mData->match(str, match);
251+
auto* regex = new PcreRegex(std::move(pattern));
252+
err = regex->compile();
253+
if (!err.empty()) {
254+
delete regex;
255+
return nullptr;
256+
}
257+
return std::shared_ptr<Regex>(regex);
268258
}
269259

270260
#endif // HAVE_RULES

lib/regex.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,12 @@
3232
class CPPCHECKLIB Regex
3333
{
3434
public:
35-
std::string compile(std::string pattern);
35+
virtual ~Regex() = default;
3636

3737
using MatchFn = std::function<void (int start, int end)>;
38-
std::string match(const std::string& str, const MatchFn& match)const;
38+
virtual std::string match(const std::string& str, const MatchFn& matchFn) const = 0;
3939

40-
private:
41-
class Data;
42-
std::shared_ptr<Data> mData;
40+
static std::shared_ptr<Regex> create(std::string pattern, std::string& err);
4341
};
4442

4543
#endif // HAVE_RULES

lib/settings.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@
4545
#endif
4646

4747
#ifdef HAVE_RULES
48-
#include "regex.h"
48+
#include <memory>
49+
50+
class Regex;
4951
#endif
5052

5153
struct Suppressions;
@@ -342,7 +344,7 @@ class CPPCHECKLIB WARN_UNUSED Settings {
342344
std::string id = "rule"; // default id
343345
std::string summary;
344346
Severity severity = Severity::style; // default severity
345-
Regex regex;
347+
std::shared_ptr<Regex> regex;
346348
};
347349

348350
/**

0 commit comments

Comments
 (0)