Skip to content

Commit

Permalink
Rework the feature to comply with C++03
Browse files Browse the repository at this point in the history
  • Loading branch information
datadiode committed Sep 28, 2024
1 parent 38f26e2 commit 90a17cc
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 36 deletions.
71 changes: 47 additions & 24 deletions simplecpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include <limits>
#include <list>
#include <map>
#include <regex>
#include <set>
#include <sstream>
#include <stack>
Expand Down Expand Up @@ -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) != at(0)) {
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<std::tolower> : fnmatch<identity>)(ustr(c_str()), ustr(s)) == 0;
}
private:
typedef const unsigned char *ustr;
static int identity(int x) { return x; }
template<int(*normalize)(int)>
static int fnmatch(ustr m, ustr s) {
if (*m == '*') for (++m; *s; ++s) if (!fnmatch<normalize>(m, s)) return 0;
return (!*s || !(normalize(*s) == normalize(*m) || *m == '?')) ? *m | *s : fnmatch<normalize>(++m, ++s);
}
bool i; // whether to ignore character case
};

void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenList &rawtokens, std::vector<std::string> &files, std::map<std::string, simplecpp::TokenList *> &filedata, const simplecpp::DUI &dui, simplecpp::OutputList *outputList, std::list<simplecpp::MacroUsage> *macroUsage, std::list<simplecpp::IfCond> *ifCond)
{
#ifdef SIMPLECPP_WINDOWS
Expand Down Expand Up @@ -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<std::string, std::regex> pragmaOddOnce;
std::set<Mask> pragmaOddOnce;

includetokenstack.push(rawtokens.cfront());
for (std::list<std::string>::const_iterator it = dui.includes.begin(); it != dui.includes.end(); ++it) {
Expand Down Expand Up @@ -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<Mask>::iterator it = pragmaOddOnce.begin(); it != pragmaOddOnce.end() && !ignore; ++it)
ignore = it->match(header.c_str());
if (ignore) {
rawtok = gotoNextLine(rawtok);
continue;
}
Expand Down Expand Up @@ -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());
}
Expand Down
1 change: 1 addition & 0 deletions simplecpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace simplecpp {

typedef std::string TokenString;
class Macro;
class Mask;

/**
* Location in source code
Expand Down
24 changes: 12 additions & 12 deletions test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#define STRINGIZE_(x) #x
#define STRINGIZE(x) STRINGIZE_(x)
#define CODE(x) #x "\n"

static int numberOfFailedAssertions = 0;

Expand Down Expand Up @@ -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));
Expand Down

0 comments on commit 90a17cc

Please sign in to comment.