diff --git a/simplecpp.cpp b/simplecpp.cpp index 9c35d03..6cebd90 100755 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -3293,6 +3292,40 @@ static std::string getTimeDefine(const struct tm *timep) return std::string("\"").append(buf).append("\""); } +// Reuse some code from https://compressionratings.com/d_archiver_template.html +// SPDX-License-Identifier: CC0-1.0 +class simplecpp::Mask : public std::string { +public: + explicit Mask(const std::string &s) : std::string(s), i(false) { + if (size_t len = length()) { + while (at(--len) != front()) { + switch (at(len)) { + case 'i': + i = true; + break; + default: + break; + } + } + resize(len); + if (len) + erase(0, 1); + } + } + bool match(const char *s) const { + return (i ? fnmatch : fnmatch)(ustr(c_str()), ustr(s)) == 0; + } +private: + typedef const unsigned char *ustr; + static int identity(int x) { return x; } + template + static int fnmatch(ustr m, ustr s) { + if (*m == '*') for (++m; *s; ++s) if (!fnmatch(m, s)) return 0; + return (!*s || !(normalize(*s) == normalize(*m) || *m == '?')) ? *m | *s : fnmatch(++m, ++s); + } + bool i; // whether to ignore character case +}; + void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenList &rawtokens, std::vector &files, std::map &filedata, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list *macroUsage, std::list *ifCond) { #ifdef SIMPLECPP_WINDOWS @@ -3386,11 +3419,11 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL // Support an odd #pragma once usage to prevent unwanted inclusions from happening even once // Example: // #ifdef CPPCHECK - // # pragma once "^boost/" - // # pragma once "^google/protobuf/" - // # pragma once "\.pb\.h$" + // # pragma once "boost/*" + // # pragma once "google/protobuf/*" + // # pragma once "*.pb.h" // #endif - std::map pragmaOddOnce; + std::set pragmaOddOnce; includetokenstack.push(rawtokens.cfront()); for (std::list::const_iterator it = dui.includes.begin(); it != dui.includes.end(); ++it) { @@ -3518,7 +3551,10 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL const bool systemheader = (inctok->str()[0] == '<'); const std::string header(realFilename(inctok->str().substr(1U, inctok->str().size() - 2U))); - if (std::find_if(pragmaOddOnce.begin(), pragmaOddOnce.end(), [&header](auto r) { return std::regex_search(header, r.second); }) != pragmaOddOnce.end()) { + bool ignore = false; + for (std::set::iterator it = pragmaOddOnce.begin(); it != pragmaOddOnce.end() && !ignore; ++it) + ignore = it->match(header.c_str()); + if (ignore) { rawtok = gotoNextLine(rawtok); continue; } @@ -3722,26 +3758,13 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL macros.erase(tok->str()); } } else if (ifstates.top() == True && rawtok->str() == PRAGMA && rawtok->next && rawtok->next->str() == ONCE && sameline(rawtok,rawtok->next)) { - std::string regex; + std::string mask; for (const Token *inctok = rawtok->next; sameline(rawtok, inctok = inctok->next); ) { if (!inctok->comment) - regex += inctok->str(); - } - if (!regex.empty()) { - std::regex_constants::syntax_option_type options = std::regex_constants::ECMAScript; - while (regex.back() != regex.front()) { - switch (regex.back()) { - case 'i': - options |= std::regex_constants::icase; - break; - default: - break; - } - regex.pop_back(); - } - if (size_t const len = regex.length() - 1) { - pragmaOddOnce[regex] = std::regex(regex.c_str() + 1, len - 1, options); - } + mask += inctok->str(); + } + if (!mask.empty()) { + pragmaOddOnce.insert(Mask(mask)); } else { pragmaOnce.insert(rawtok->location.file()); } diff --git a/simplecpp.h b/simplecpp.h index f5c6959..7e60897 100755 --- a/simplecpp.h +++ b/simplecpp.h @@ -47,6 +47,7 @@ namespace simplecpp { typedef std::string TokenString; class Macro; + class Mask; /** * Location in source code diff --git a/test.cpp b/test.cpp index 08fa682..2c01ebc 100644 --- a/test.cpp +++ b/test.cpp @@ -18,6 +18,7 @@ #define STRINGIZE_(x) #x #define STRINGIZE(x) STRINGIZE_(x) +#define CODE(x) #x "\n" static int numberOfFailedAssertions = 0; @@ -1839,18 +1840,17 @@ static void missingHeader3() static void missingHeader4() { - const char code[] = R"_( - #pragma once "^boost/" - #pragma once "^google/protobuf/" - #pragma once "\.pb\.h$" - #pragma once "^inc/"i - #include "boost/config/workaround.hpp" - #include "google/protobuf/stubs/port.h" - #include "proto/message.pb.h" - #include "inc/lowercase.h" - #include "Inc/MixedCase.h" - #include "INC/UPPERCASE.H" - )_"; // none of the given files are included + const char code[] = CODE(#pragma once "boost/*") + CODE(#pragma once "google/protobuf/*") + CODE(#pragma once "*.pb.h") + CODE(#pragma once "inc/*" i) + CODE(#include "boost/config/workaround.hpp") + CODE(#include "google/protobuf/stubs/port.h") + CODE(#include "proto/message.pb.h") + CODE(#include "inc/lowercase.h") + CODE(#include "Inc/MixedCase.h") + CODE(#include "INC/UPPERCASE.H"); + // none of the given files are included simplecpp::OutputList outputList; ASSERT_EQUALS("", preprocess(code, &outputList)); ASSERT_EQUALS("", toString(outputList));