|
29 | 29 |
|
30 | 30 | namespace shellanything |
31 | 31 | { |
32 | | - typedef std::vector<WildcardResult> WildcardResultList; |
| 32 | + static const size_t INVALID_WILDCARD_POSITION = (size_t)-1; |
| 33 | + |
| 34 | + size_t GetNextWildcardPosition(const size_t * wildcard_positions, size_t num_wildcards, size_t current) |
| 35 | + { |
| 36 | + for(size_t i=0; i<num_wildcards; i++) |
| 37 | + { |
| 38 | + const size_t & pos = wildcard_positions[i]; |
| 39 | + if (pos == current) |
| 40 | + { |
| 41 | + if (i+1 < num_wildcards) |
| 42 | + { |
| 43 | + return wildcard_positions[i+1]; |
| 44 | + } |
| 45 | + return INVALID_WILDCARD_POSITION; //requested wildcard is the last one |
| 46 | + } |
| 47 | + } |
| 48 | + return INVALID_WILDCARD_POSITION; //wildcard position not found |
| 49 | + } |
33 | 50 |
|
34 | 51 | bool IsWildcard(char c) |
35 | 52 | { |
@@ -136,224 +153,178 @@ namespace shellanything |
136 | 153 | return true; |
137 | 154 | } |
138 | 155 |
|
139 | | - bool WildcardSolve(const char * pattern, const char * value, WildcardResultList * presults) |
| 156 | + bool WildcardSolve( const char * pattern, |
| 157 | + const char * value, |
| 158 | + const size_t * wildcard_positions, |
| 159 | + size_t num_wildcards, |
| 160 | + const int iIndexWild, |
| 161 | + const int iIndexValue, |
| 162 | + WildcardList & matches) |
140 | 163 | { |
141 | | - size_t pattern_length = strlen(pattern); |
142 | | - size_t value_length = strlen(value); |
143 | | - |
144 | | - // If the pattern is empty, the value must also be empty to match. |
145 | | - if (pattern_length == 0) |
| 164 | + int indexWild = iIndexWild; |
| 165 | + int indexValue = iIndexValue; |
| 166 | + int wildLen = (int)std::string(pattern).size(); |
| 167 | + int valueLen = (int)std::string(value).size(); |
| 168 | + |
| 169 | + //while wildcard and value not fully solved |
| 170 | + while (indexWild < wildLen || indexValue < valueLen) |
146 | 171 | { |
147 | | - // If not, then there is not match. |
148 | | - if (value_length == 0) |
| 172 | + const char & cWild = pattern[indexWild]; |
| 173 | + const char & cValue = value[indexValue]; |
| 174 | + if ( !IsWildcard(cWild) ) |
149 | 175 | { |
150 | | - //if (presults) |
151 | | - //{ |
152 | | - // WildcardResult r = {0}; |
153 | | - // r.valid = true; |
154 | | - // r.pattern_offset = 0; |
155 | | - // r.value = value; |
156 | | - // r.value_length = 0; |
157 | | - // presults->push_back(r); |
158 | | - //} |
159 | | - return true; |
160 | | - } |
161 | | - return false; |
162 | | - } |
| 176 | + if (cWild != cValue) |
| 177 | + return false; //characters don't match! |
163 | 178 |
|
164 | | - // If the value is empty, the pattern must be '*' (or a '*' sequence) to match |
165 | | - if (value_length == 0) |
166 | | - { |
167 | | - if (!IsStarSequence(&pattern[0])) |
168 | | - return false; |
169 | | - |
170 | | - // We have a match. |
171 | | - if (presults) |
172 | | - { |
173 | | - WildcardResult r = {0}; |
174 | | - r.valid = true; |
175 | | - r.pattern_offset = 0; |
176 | | - r.value = value; |
177 | | - r.value_length = 0; |
178 | | - presults->push_back(r); |
| 179 | + //next char |
| 180 | + indexWild++; |
| 181 | + indexValue++; |
179 | 182 | } |
180 | | - |
181 | | - return true; |
182 | | - } |
183 | | - |
184 | | - // At this point, both pattern and value are not empty |
185 | | - |
186 | | - size_t value_offset = 0; |
187 | | - for(size_t pattern_offset = 0; pattern_offset < pattern_length; pattern_offset++) |
188 | | - { |
189 | | - const char & pattern_char = pattern[pattern_offset]; |
190 | | - const char & value_char = value[value_offset]; |
191 | | - |
192 | | - // If we reached a '*' sequence, move forward to the last '*' character of the sequence |
193 | | - while(pattern[pattern_offset] == '*' && (pattern_offset+1 < pattern_length) && pattern[pattern_offset+1] == '*') |
| 183 | + else |
194 | 184 | { |
195 | | - pattern_offset++; |
196 | | - } |
197 | | - |
198 | | - size_t remaining_pattern_length = pattern_length - pattern_offset; |
199 | | - size_t remaining_value_length = value_length - value_offset; |
| 185 | + //cWild is wildcard |
| 186 | + if (cWild == '?') |
| 187 | + { |
| 188 | + //save wildcard resolve information |
| 189 | + WILDCARD w; |
| 190 | + w.character = cWild; |
| 191 | + w.index = indexWild; |
| 192 | + w.value = cValue; |
| 193 | + matches.push_back(w); |
| 194 | + |
| 195 | + //next char |
| 196 | + indexWild++; |
| 197 | + indexValue++; |
| 198 | + } |
| 199 | + else if (cWild == '*') |
| 200 | + { |
| 201 | + //if wildcard character * is the last one |
| 202 | + if (indexWild+1 >= wildLen) |
| 203 | + { |
| 204 | + //automatically match the end of the string |
200 | 205 |
|
201 | | - // If we reached the end of both strings, we are done searching |
202 | | - if (remaining_pattern_length == 0 && remaining_value_length == 0) |
203 | | - return true; |
| 206 | + //save wildcard resolve information |
| 207 | + WILDCARD w; |
| 208 | + w.character = cWild; |
| 209 | + w.index = indexWild; |
| 210 | + w.value = &cValue; |
| 211 | + matches.push_back(w); |
204 | 212 |
|
205 | | - // If the pattern is '*', and the next pattern character is valid, and the value is empty, then we won't be able to match. |
206 | | - // (because there is a next non-wildcard character in the pattern) |
207 | | - if (pattern_char == '*' && |
208 | | - (pattern_offset+1 < pattern_length) && // pattern has more characters |
209 | | - pattern[pattern_offset+1] != '\0' && // next pattern character is valid) |
210 | | - remaining_value_length == 0) // value is empty |
211 | | - { |
212 | | - return false; |
213 | | - } |
| 213 | + // If we reached a '*' sequence, move forward to the last '*' character of the sequence |
| 214 | + while(pattern[indexWild] == '*' && (indexWild+1 < wildLen) && pattern[indexWild+1] == '*') |
| 215 | + { |
| 216 | + indexWild++; |
| 217 | + } |
214 | 218 |
|
215 | | - if (pattern_char == '?') |
216 | | - { |
217 | | - // In order to match, the '?' must match the current value character |
218 | | - if (value_char == '\0') |
219 | | - return false; // We reached the end of the value string |
| 219 | + //next char |
| 220 | + indexWild++; |
| 221 | + indexValue += (int)w.value.size(); |
| 222 | + } |
| 223 | + else |
| 224 | + { |
| 225 | + //wildcard character * is not the last one |
220 | 226 |
|
221 | | - // We matched this wildcard character |
222 | | - // Save this wildcard expansion |
223 | | - if (presults) |
224 | | - { |
225 | | - WildcardResult r = {0}; |
226 | | - r.valid = true; |
227 | | - r.pattern_offset = pattern_offset; |
228 | | - r.value = &value[value_offset]; |
229 | | - r.value_length = 1; |
230 | | - presults->push_back(r); |
231 | | - } |
| 227 | + //compute all possibilities that can fit in * and then use recursion to check if it can be resolved |
| 228 | + //compute the possibilities in the from the longest to the shortest ("") for optimizing the replacement string |
| 229 | + //since all wildcard caracters must be mapped, do not compute possibilities beyond the next wildcard character |
232 | 230 |
|
233 | | - // Advance both offsets and keep on looking |
234 | | - value_offset++; |
235 | | - } |
236 | | - else if (pattern_char == value_char) |
237 | | - { |
238 | | - // Advance both offsets and keep on looking |
239 | | - value_offset++; |
240 | | - } |
241 | | - else if (pattern_char == '*') |
242 | | - { |
243 | | - // Found a '*' character or sequence. |
244 | | - // From this point, there are 2 possibilities. |
| 231 | + //compute next character |
| 232 | + const char & nextWild = (&cWild)[1]; |
245 | 233 |
|
246 | | - WildcardResultList tmp; |
247 | | - WildcardResultList * sub_results = NULL; |
248 | | - if (presults) |
249 | | - sub_results = &tmp; |
| 234 | + int nextWildcardPosition = (int)GetNextWildcardPosition(wildcard_positions, num_wildcards, indexWild); |
250 | 235 |
|
251 | | - // 1) The '*' replaces the next value character. |
252 | | - bool match = WildcardSolve(&pattern[pattern_offset], &value[value_offset+1], sub_results); |
253 | | - if (match) |
254 | | - { |
255 | | - // Add the sub results to our results |
256 | | - if (presults) |
257 | | - { |
258 | | - for(size_t i=0; i<sub_results->size(); i++) |
| 236 | + //compute fixed characters between this wildcard and the last one (of the end of the file) |
| 237 | + //ie: fgh in abc*fgh?j or abc*fgh |
| 238 | + std::string fixedCharacters = &nextWild; |
| 239 | + if (nextWildcardPosition != -1) |
259 | 240 | { |
260 | | - WildcardResult & r = (*sub_results)[i]; |
261 | | - r.pattern_offset += pattern_offset; |
262 | | - presults->push_back(r); |
| 241 | + //there is at least another wildcard character after this one |
| 242 | + fixedCharacters = &nextWild; |
| 243 | + size_t size = nextWildcardPosition - indexWild; |
| 244 | + fixedCharacters.resize(size); |
263 | 245 | } |
264 | | - sub_results->clear(); |
265 | | - } |
266 | 246 |
|
267 | | - return true; |
268 | | - } |
| 247 | + //compute maximum length of replacementString |
| 248 | + int remainingCharactersInValue = valueLen-indexValue; |
| 249 | + int replacementStringMaxLength = remainingCharactersInValue-(int)fixedCharacters.size(); |
269 | 250 |
|
270 | | - // 2) The '*' does not replaces the next value character. |
271 | | - match = WildcardSolve(&pattern[pattern_offset+1], &value[value_offset], sub_results); |
272 | | - if (match) |
273 | | - { |
274 | | - // Add the sub results to our results |
275 | | - if (presults) |
276 | | - { |
277 | | - for(size_t i=0; i<sub_results->size(); i++) |
| 251 | + //compute all possibilities that can fit in * with a length in [0,replacementStringMaxLength] |
| 252 | + for(int length=replacementStringMaxLength; length>=0; length--) |
278 | 253 | { |
279 | | - WildcardResult & r = (*sub_results)[i]; |
280 | | - r.pattern_offset += pattern_offset+1; |
281 | | - presults->push_back(r); |
| 254 | + //assuming replacement string is the right one |
| 255 | + |
| 256 | + std::string replacementString = &cValue; |
| 257 | + replacementString.resize(length); |
| 258 | + |
| 259 | + WildcardList tmpList = matches; |
| 260 | + |
| 261 | + //save wildcard resolve information |
| 262 | + WILDCARD w; |
| 263 | + w.character = cWild; |
| 264 | + w.index = indexWild; |
| 265 | + w.value = replacementString; |
| 266 | + tmpList.push_back(w); |
| 267 | + |
| 268 | + //next char |
| 269 | + int tmpIndexWild = indexWild+1; |
| 270 | + int tmpIndexValue = indexValue + (int)w.value.size(); |
| 271 | + |
| 272 | + //execute recursive call |
| 273 | + bool solved = WildcardSolve(pattern, value, wildcard_positions, num_wildcards, tmpIndexWild, tmpIndexValue, tmpList); |
| 274 | + if (solved) |
| 275 | + { |
| 276 | + //solved! |
| 277 | + //refresh matches |
| 278 | + matches = tmpList; |
| 279 | + return true; |
| 280 | + } |
282 | 281 | } |
283 | | - sub_results->clear(); |
284 | | - } |
285 | 282 |
|
286 | | - return true; |
| 283 | + //all possibilities were checked |
| 284 | + //unable to solve * wildcard |
| 285 | + return false; |
| 286 | + } |
287 | 287 | } |
288 | | - |
289 | | - // We recurse on all possibilities. No match found. |
290 | | - return false; |
291 | | - } |
292 | | - else |
293 | | - { |
294 | | - // Characters from pattern and value does not match |
295 | | - return false; |
296 | 288 | } |
297 | 289 | } |
298 | 290 |
|
299 | | - // We reached the end of the pattern, the value must be empty too to match |
300 | | - if (value[value_offset] != '\0') |
301 | | - return false; |
302 | | - |
303 | | - //// The remaining of the value is the expansion of the last wildcard character |
304 | | - //if (presults) |
305 | | - //{ |
306 | | - // WildcardResult r = {0}; |
307 | | - // r.valid = true; |
308 | | - // r.pattern_offset = 0; |
309 | | - // r.value = value; |
310 | | - // r.value_length = 0; |
311 | | - // presults->push_back(r); |
312 | | - //} |
313 | | - |
314 | | - return true; |
| 291 | + if (indexWild == wildLen && indexValue == valueLen) |
| 292 | + return true; //solved |
| 293 | + if ((indexWild == wildLen && indexValue < valueLen) || |
| 294 | + (indexWild == wildLen && indexValue < valueLen) ) |
| 295 | + return false; //reached the end of wildcard or the end of value |
| 296 | + return false; //??? |
315 | 297 | } |
316 | 298 |
|
317 | | - bool WildcardSolve(const char * pattern, const char * value, WildcardResult * results_array, size_t results_size) |
| 299 | + bool WildcardSolve(const char * pattern, const char * value, WildcardList & matches) |
318 | 300 | { |
319 | | - size_t results_array_count = results_size / sizeof(WildcardResult); |
320 | | - bool has_array = (results_array != NULL && results_array_count > 0); |
321 | | - if (has_array) |
322 | | - memset(results_array, 0, results_size); |
323 | | - |
324 | 301 | if (pattern == NULL || value == NULL) |
325 | 302 | return false; |
326 | 303 |
|
| 304 | + matches.clear(); |
| 305 | + |
327 | 306 | // Force the pattern to its simplest form |
328 | 307 | std::string simplified_pattern = pattern; |
329 | 308 | WildcardSimplify(simplified_pattern); |
330 | 309 |
|
331 | | - // Create a results list if required |
332 | | - WildcardResultList results; |
333 | | - WildcardResultList * presults = NULL; |
334 | | - if (has_array) |
335 | | - presults = &results; |
| 310 | + // Find all wildcard character positions |
| 311 | + size_t num_wildcards = FindWildcardCharacters(simplified_pattern.c_str(), NULL, 0); |
| 312 | + |
| 313 | + // If no wildcard character found, the strings must be equal |
| 314 | + if (num_wildcards == 0) |
| 315 | + return (std::string(pattern) == std::string(value)); |
336 | 316 |
|
337 | | - // Search for a possible match |
338 | | - bool match = WildcardSolve(simplified_pattern.c_str(), value, presults); |
339 | | - if (!match) |
340 | | - return false; |
| 317 | + // Allocate memory for all wildcard positions |
| 318 | + size_t * wildcard_positions = new size_t[num_wildcards]; |
| 319 | + FindWildcardCharacters(simplified_pattern.c_str(), wildcard_positions, num_wildcards); |
341 | 320 |
|
342 | | - if (has_array) |
343 | | - { |
344 | | - // The pattern and value matches |
345 | | - // Copy the results list into results_array |
346 | | - #define MIN(a,b) ((a) < (b) ? (a) : (b)) |
347 | | - size_t count = MIN(results.size(), results_array_count); |
348 | | - #undef MIN |
349 | | - for(size_t i=0; i<count; i++) |
350 | | - { |
351 | | - const WildcardResult & result = results[i]; |
352 | | - results_array[i] = result; |
353 | | - } |
354 | | - } |
| 321 | + //solve wildcards |
| 322 | + bool solved = WildcardSolve(simplified_pattern.c_str(), value, wildcard_positions, num_wildcards, 0, 0, matches); |
355 | 323 |
|
356 | | - return true; |
| 324 | + delete[] wildcard_positions; |
| 325 | + wildcard_positions = NULL; |
| 326 | + |
| 327 | + return solved; |
357 | 328 | } |
358 | 329 |
|
359 | 330 | } //namespace shellanything |
0 commit comments