/src/cppcheck/oss-fuzz/build/utils.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Cppcheck - A tool for static C/C++ code analysis |
3 | | * Copyright (C) 2007-2024 Cppcheck team. |
4 | | * |
5 | | * This program is free software: you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation, either version 3 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | | */ |
18 | | |
19 | | #include "utils.h" |
20 | | |
21 | | #include <algorithm> |
22 | | #include <cctype> |
23 | | #include <cstring> |
24 | | #include <iterator> |
25 | | #include <stack> |
26 | | #include <utility> |
27 | | |
28 | | |
29 | | int caseInsensitiveStringCompare(const std::string &lhs, const std::string &rhs) |
30 | 0 | { |
31 | 0 | if (lhs.size() != rhs.size()) |
32 | 0 | return (lhs.size() < rhs.size()) ? -1 : 1; |
33 | 0 | for (unsigned int i = 0; i < lhs.size(); ++i) { |
34 | 0 | const int c1 = std::toupper(lhs[i]); |
35 | 0 | const int c2 = std::toupper(rhs[i]); |
36 | 0 | if (c1 != c2) |
37 | 0 | return (c1 < c2) ? -1 : 1; |
38 | 0 | } |
39 | 0 | return 0; |
40 | 0 | } |
41 | | |
42 | | bool isValidGlobPattern(const std::string& pattern) |
43 | 0 | { |
44 | 0 | for (auto i = pattern.cbegin(); i != pattern.cend(); ++i) { |
45 | 0 | if (*i == '*' || *i == '?') { |
46 | 0 | const auto j = i + 1; |
47 | 0 | if (j != pattern.cend() && (*j == '*' || *j == '?')) { |
48 | 0 | return false; |
49 | 0 | } |
50 | 0 | } |
51 | 0 | } |
52 | 0 | return true; |
53 | 0 | } |
54 | | |
55 | | bool matchglob(const std::string& pattern, const std::string& name) |
56 | 0 | { |
57 | 0 | const char* p = pattern.c_str(); |
58 | 0 | const char* n = name.c_str(); |
59 | 0 | std::stack<std::pair<const char*, const char*>, std::vector<std::pair<const char*, const char*>>> backtrack; |
60 | |
|
61 | 0 | for (;;) { |
62 | 0 | bool matching = true; |
63 | 0 | while (*p != '\0' && matching) { |
64 | 0 | switch (*p) { |
65 | 0 | case '*': |
66 | | // Step forward until we match the next character after * |
67 | 0 | while (*n != '\0' && *n != p[1]) { |
68 | 0 | n++; |
69 | 0 | } |
70 | 0 | if (*n != '\0') { |
71 | | // If this isn't the last possibility, save it for later |
72 | 0 | backtrack.emplace(p, n); |
73 | 0 | } |
74 | 0 | break; |
75 | 0 | case '?': |
76 | | // Any character matches unless we're at the end of the name |
77 | 0 | if (*n != '\0') { |
78 | 0 | n++; |
79 | 0 | } else { |
80 | 0 | matching = false; |
81 | 0 | } |
82 | 0 | break; |
83 | 0 | default: |
84 | | // Non-wildcard characters match literally |
85 | 0 | if (*n == *p) { |
86 | 0 | n++; |
87 | 0 | } else if (*n == '\\' && *p == '/') { |
88 | 0 | n++; |
89 | 0 | } else if (*n == '/' && *p == '\\') { |
90 | 0 | n++; |
91 | 0 | } else { |
92 | 0 | matching = false; |
93 | 0 | } |
94 | 0 | break; |
95 | 0 | } |
96 | 0 | p++; |
97 | 0 | } |
98 | | |
99 | | // If we haven't failed matching and we've reached the end of the name, then success |
100 | 0 | if (matching && *n == '\0') { |
101 | 0 | return true; |
102 | 0 | } |
103 | | |
104 | | // If there are no other paths to try, then fail |
105 | 0 | if (backtrack.empty()) { |
106 | 0 | return false; |
107 | 0 | } |
108 | | |
109 | | // Restore pointers from backtrack stack |
110 | 0 | p = backtrack.top().first; |
111 | 0 | n = backtrack.top().second; |
112 | 0 | backtrack.pop(); |
113 | | |
114 | | // Advance name pointer by one because the current position didn't work |
115 | 0 | n++; |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | 0 | bool matchglobs(const std::vector<std::string> &patterns, const std::string &name) { |
120 | 0 | return std::any_of(begin(patterns), end(patterns), [&name](const std::string &pattern) { |
121 | 0 | return matchglob(pattern, name); |
122 | 0 | }); |
123 | 0 | } |
124 | | |
125 | | void strTolower(std::string& str) |
126 | 60.8k | { |
127 | | // This wrapper exists because Sun's CC does not allow a static_cast |
128 | | // from extern "C" int(*)(int) to int(*)(int). |
129 | 243k | std::transform(str.cbegin(), str.cend(), str.begin(), [](int c) { |
130 | 243k | return std::tolower(c); |
131 | 243k | }); |
132 | 60.8k | } |
133 | | |
134 | | std::string trim(const std::string& s, const std::string& t) |
135 | 0 | { |
136 | 0 | const std::string::size_type beg = s.find_first_not_of(t); |
137 | 0 | if (beg == std::string::npos) |
138 | 0 | return ""; |
139 | 0 | const std::string::size_type end = s.find_last_not_of(t); |
140 | 0 | return s.substr(beg, end - beg + 1); |
141 | 0 | } |
142 | | |
143 | | void findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith) |
144 | 0 | { |
145 | 0 | std::string::size_type index = 0; |
146 | 0 | while ((index = source.find(searchFor, index)) != std::string::npos) { |
147 | 0 | source.replace(index, searchFor.length(), replaceWith); |
148 | 0 | index += replaceWith.length(); |
149 | 0 | } |
150 | 0 | } |
151 | | |
152 | 0 | std::string replaceEscapeSequences(const std::string &source) { |
153 | 0 | std::string result; |
154 | 0 | result.reserve(source.size()); |
155 | 0 | for (std::size_t i = 0; i < source.size(); ++i) { |
156 | 0 | if (source[i] != '\\' || i + 1 >= source.size()) |
157 | 0 | result += source[i]; |
158 | 0 | else { |
159 | 0 | ++i; |
160 | 0 | if (source[i] == 'n') { |
161 | 0 | result += '\n'; |
162 | 0 | } else if (source[i] == 'r') { |
163 | 0 | result += '\r'; |
164 | 0 | } else if (source[i] == 't') { |
165 | 0 | result += '\t'; |
166 | 0 | } else if (source[i] == 'x') { |
167 | 0 | std::string value = "0"; |
168 | 0 | if (i + 1 < source.size() && std::isxdigit(source[i+1])) |
169 | 0 | value += source[i++ + 1]; |
170 | 0 | if (i + 1 < source.size() && std::isxdigit(source[i+1])) |
171 | 0 | value += source[i++ + 1]; |
172 | 0 | result += static_cast<char>(std::stoi(value, nullptr, 16)); |
173 | 0 | } else if (source[i] == '0') { |
174 | 0 | std::string value = "0"; |
175 | 0 | if (i + 1 < source.size() && source[i+1] >= '0' && source[i+1] <= '7') |
176 | 0 | value += source[i++ + 1]; |
177 | 0 | if (i + 1 < source.size() && source[i+1] >= '0' && source[i+1] <= '7') |
178 | 0 | value += source[i++ + 1]; |
179 | 0 | result += static_cast<char>(std::stoi(value, nullptr, 8)); |
180 | 0 | } else { |
181 | 0 | result += source[i]; |
182 | 0 | } |
183 | 0 | } |
184 | 0 | } |
185 | 0 | return result; |
186 | 0 | } |
187 | | |
188 | | |
189 | | std::vector<std::string> splitString(const std::string& str, char sep) |
190 | 0 | { |
191 | 0 | std::vector<std::string> l; |
192 | |
|
193 | 0 | std::string::size_type pos1 = 0; |
194 | 0 | std::string::size_type pos2; |
195 | 0 | while (true) { |
196 | 0 | pos2 = str.find(sep, pos1); |
197 | 0 | l.push_back(str.substr(pos1, pos2 - pos1)); |
198 | 0 | if (pos2 == std::string::npos) |
199 | 0 | break; |
200 | 0 | pos1 = pos2 + 1; |
201 | 0 | } |
202 | 0 | return l; |
203 | 0 | } |