OLD | NEW |
1 // Copyright 2003-2009 Google Inc. All rights reserved. | 1 // Copyright 2003-2009 Google Inc. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // This is a variant of PCRE's pcrecpp.cc, originally written at Google. | 5 // This is a variant of PCRE's pcrecpp.cc, originally written at Google. |
6 // The main changes are the addition of the HitLimit method and | 6 // The main changes are the addition of the HitLimit method and |
7 // compilation as PCRE in namespace re2. | 7 // compilation as PCRE in namespace re2. |
8 | 8 |
9 #include <errno.h> | 9 #include <errno.h> |
10 #include <limits> | |
11 #include "util/util.h" | 10 #include "util/util.h" |
12 #include "util/flags.h" | 11 #include "util/flags.h" |
13 #include "util/pcre.h" | 12 #include "util/pcre.h" |
14 | 13 |
| 14 #ifdef WIN32 |
| 15 #define strtoll _strtoi64 |
| 16 #define strtoull _strtoui64 |
| 17 #endif |
| 18 |
15 #define PCREPORT(level) LOG(level) | 19 #define PCREPORT(level) LOG(level) |
16 | 20 |
17 // Default PCRE limits. | 21 // Default PCRE limits. |
18 // Defaults chosen to allow a plausible amount of CPU and | 22 // Defaults chosen to allow a plausible amount of CPU and |
19 // not exceed main thread stacks. Note that other threads | 23 // not exceed main thread stacks. Note that other threads |
20 // often have smaller stacks, and therefore tightening | 24 // often have smaller stacks, and therefore tightening |
21 // regexp_stack_limit may frequently be necessary. | 25 // regexp_stack_limit may frequently be necessary. |
22 DEFINE_int32(regexp_stack_limit, 256<<10, "default PCRE stack limit (bytes)"); | 26 DEFINE_int32(regexp_stack_limit, 256<<10, "default PCRE stack limit (bytes)"); |
23 DEFINE_int32(regexp_match_limit, 1000000, | 27 DEFINE_int32(regexp_match_limit, 1000000, |
24 "default PCRE match limit (function calls)"); | 28 "default PCRE match limit (function calls)"); |
25 | 29 |
26 #ifndef USEPCRE | |
27 | |
28 // Fake just enough of the PCRE API to allow this file to build. :) | |
29 | |
30 struct pcre_extra { | |
31 int flags; | |
32 int match_limit; | |
33 int match_limit_recursion; | |
34 }; | |
35 | |
36 #define PCRE_EXTRA_MATCH_LIMIT 0 | |
37 #define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0 | |
38 #define PCRE_ANCHORED 0 | |
39 #define PCRE_NOTEMPTY 0 | |
40 #define PCRE_ERROR_NOMATCH 1 | |
41 #define PCRE_ERROR_MATCHLIMIT 2 | |
42 #define PCRE_ERROR_RECURSIONLIMIT 3 | |
43 #define PCRE_INFO_CAPTURECOUNT 0 | |
44 | |
45 void pcre_free(void*) { | |
46 } | |
47 | |
48 pcre* pcre_compile(const char*, int, const char**, int*, const unsigned char*) { | |
49 return NULL; | |
50 } | |
51 | |
52 int pcre_exec(const pcre*, const pcre_extra*, const char*, int, int, int, int*,
int) { | |
53 return 0; | |
54 } | |
55 | |
56 int pcre_fullinfo(const pcre*, const pcre_extra*, int, void*) { | |
57 return 0; | |
58 } | |
59 | |
60 #endif | |
61 | |
62 namespace re2 { | 30 namespace re2 { |
63 | 31 |
64 // Maximum number of args we can set | 32 // Maximum number of args we can set |
65 static const int kMaxArgs = 16; | 33 static const int kMaxArgs = 16; |
66 static const int kVecSize = (1 + kMaxArgs) * 3; // results + PCRE workspace | 34 static const int kVecSize = (1 + kMaxArgs) * 3; // results + PCRE workspace |
67 | 35 |
68 // Approximate size of a recursive invocation of PCRE's | 36 // Approximate size of a recursive invocation of PCRE's |
69 // internal "match()" frame. This varies depending on the | 37 // internal "match()" frame. This varies depending on the |
70 // compiler and architecture, of course, so the constant is | 38 // compiler and architecture, of course, so the constant is |
71 // just a conservative estimate. To find the exact number, | 39 // just a conservative estimate. To find the exact number, |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 // beginning of a string. | 111 // beginning of a string. |
144 // | 112 // |
145 // There are three types of anchoring we want: | 113 // There are three types of anchoring we want: |
146 // UNANCHORED Compile the original pattern, and use | 114 // UNANCHORED Compile the original pattern, and use |
147 // a pcre unanchored match. | 115 // a pcre unanchored match. |
148 // ANCHOR_START Compile the original pattern, and use | 116 // ANCHOR_START Compile the original pattern, and use |
149 // a pcre anchored match. | 117 // a pcre anchored match. |
150 // ANCHOR_BOTH Tack a "\z" to the end of the original pattern | 118 // ANCHOR_BOTH Tack a "\z" to the end of the original pattern |
151 // and use a pcre anchored match. | 119 // and use a pcre anchored match. |
152 | 120 |
153 const char* error = ""; | 121 const char* error; |
154 int eoffset; | 122 int eoffset; |
155 pcre* re; | 123 pcre* re; |
156 if (anchor != ANCHOR_BOTH) { | 124 if (anchor != ANCHOR_BOTH) { |
157 re = pcre_compile(pattern_.c_str(), | 125 re = pcre_compile(pattern_.c_str(), |
158 (options_ & EnabledCompileOptions), | 126 (options_ & EnabledCompileOptions), |
159 &error, &eoffset, NULL); | 127 &error, &eoffset, NULL); |
160 } else { | 128 } else { |
161 // Tack a '\z' at the end of PCRE. Parenthesize it first so that | 129 // Tack a '\z' at the end of PCRE. Parenthesize it first so that |
162 // the '\z' applies to all top-level alternatives in the regexp. | 130 // the '\z' applies to all top-level alternatives in the regexp. |
163 string wrapped = "(?:"; // A non-counting grouping operator | 131 string wrapped = "(?:"; // A non-counting grouping operator |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 if (&a9 == &no_more_args) goto done; args[n++] = &a9; | 176 if (&a9 == &no_more_args) goto done; args[n++] = &a9; |
209 if (&a10 == &no_more_args) goto done; args[n++] = &a10; | 177 if (&a10 == &no_more_args) goto done; args[n++] = &a10; |
210 if (&a11 == &no_more_args) goto done; args[n++] = &a11; | 178 if (&a11 == &no_more_args) goto done; args[n++] = &a11; |
211 if (&a12 == &no_more_args) goto done; args[n++] = &a12; | 179 if (&a12 == &no_more_args) goto done; args[n++] = &a12; |
212 if (&a13 == &no_more_args) goto done; args[n++] = &a13; | 180 if (&a13 == &no_more_args) goto done; args[n++] = &a13; |
213 if (&a14 == &no_more_args) goto done; args[n++] = &a14; | 181 if (&a14 == &no_more_args) goto done; args[n++] = &a14; |
214 if (&a15 == &no_more_args) goto done; args[n++] = &a15; | 182 if (&a15 == &no_more_args) goto done; args[n++] = &a15; |
215 done: | 183 done: |
216 | 184 |
217 int consumed; | 185 int consumed; |
218 int vec[kVecSize] = {}; | 186 int vec[kVecSize]; |
219 return re.DoMatchImpl(text, ANCHOR_BOTH, &consumed, args, n, vec, kVecSize); | 187 return re.DoMatchImpl(text, ANCHOR_BOTH, &consumed, args, n, vec, kVecSize); |
220 } | 188 } |
221 | 189 |
222 bool PCRE::PartialMatchFunctor::operator ()(const StringPiece& text, | 190 bool PCRE::PartialMatchFunctor::operator ()(const StringPiece& text, |
223 const PCRE& re, | 191 const PCRE& re, |
224 const Arg& a0, | 192 const Arg& a0, |
225 const Arg& a1, | 193 const Arg& a1, |
226 const Arg& a2, | 194 const Arg& a2, |
227 const Arg& a3, | 195 const Arg& a3, |
228 const Arg& a4, | 196 const Arg& a4, |
(...skipping 22 matching lines...) Expand all Loading... |
251 if (&a9 == &no_more_args) goto done; args[n++] = &a9; | 219 if (&a9 == &no_more_args) goto done; args[n++] = &a9; |
252 if (&a10 == &no_more_args) goto done; args[n++] = &a10; | 220 if (&a10 == &no_more_args) goto done; args[n++] = &a10; |
253 if (&a11 == &no_more_args) goto done; args[n++] = &a11; | 221 if (&a11 == &no_more_args) goto done; args[n++] = &a11; |
254 if (&a12 == &no_more_args) goto done; args[n++] = &a12; | 222 if (&a12 == &no_more_args) goto done; args[n++] = &a12; |
255 if (&a13 == &no_more_args) goto done; args[n++] = &a13; | 223 if (&a13 == &no_more_args) goto done; args[n++] = &a13; |
256 if (&a14 == &no_more_args) goto done; args[n++] = &a14; | 224 if (&a14 == &no_more_args) goto done; args[n++] = &a14; |
257 if (&a15 == &no_more_args) goto done; args[n++] = &a15; | 225 if (&a15 == &no_more_args) goto done; args[n++] = &a15; |
258 done: | 226 done: |
259 | 227 |
260 int consumed; | 228 int consumed; |
261 int vec[kVecSize] = {}; | 229 int vec[kVecSize]; |
262 return re.DoMatchImpl(text, UNANCHORED, &consumed, args, n, vec, kVecSize); | 230 return re.DoMatchImpl(text, UNANCHORED, &consumed, args, n, vec, kVecSize); |
263 } | 231 } |
264 | 232 |
265 bool PCRE::ConsumeFunctor::operator ()(StringPiece* input, | 233 bool PCRE::ConsumeFunctor::operator ()(StringPiece* input, |
266 const PCRE& pattern, | 234 const PCRE& pattern, |
267 const Arg& a0, | 235 const Arg& a0, |
268 const Arg& a1, | 236 const Arg& a1, |
269 const Arg& a2, | 237 const Arg& a2, |
270 const Arg& a3, | 238 const Arg& a3, |
271 const Arg& a4, | 239 const Arg& a4, |
(...skipping 22 matching lines...) Expand all Loading... |
294 if (&a9 == &no_more_args) goto done; args[n++] = &a9; | 262 if (&a9 == &no_more_args) goto done; args[n++] = &a9; |
295 if (&a10 == &no_more_args) goto done; args[n++] = &a10; | 263 if (&a10 == &no_more_args) goto done; args[n++] = &a10; |
296 if (&a11 == &no_more_args) goto done; args[n++] = &a11; | 264 if (&a11 == &no_more_args) goto done; args[n++] = &a11; |
297 if (&a12 == &no_more_args) goto done; args[n++] = &a12; | 265 if (&a12 == &no_more_args) goto done; args[n++] = &a12; |
298 if (&a13 == &no_more_args) goto done; args[n++] = &a13; | 266 if (&a13 == &no_more_args) goto done; args[n++] = &a13; |
299 if (&a14 == &no_more_args) goto done; args[n++] = &a14; | 267 if (&a14 == &no_more_args) goto done; args[n++] = &a14; |
300 if (&a15 == &no_more_args) goto done; args[n++] = &a15; | 268 if (&a15 == &no_more_args) goto done; args[n++] = &a15; |
301 done: | 269 done: |
302 | 270 |
303 int consumed; | 271 int consumed; |
304 int vec[kVecSize] = {}; | 272 int vec[kVecSize]; |
305 if (pattern.DoMatchImpl(*input, ANCHOR_START, &consumed, | 273 if (pattern.DoMatchImpl(*input, ANCHOR_START, &consumed, |
306 args, n, vec, kVecSize)) { | 274 args, n, vec, kVecSize)) { |
307 input->remove_prefix(consumed); | 275 input->remove_prefix(consumed); |
308 return true; | 276 return true; |
309 } else { | 277 } else { |
310 return false; | 278 return false; |
311 } | 279 } |
312 } | 280 } |
313 | 281 |
314 bool PCRE::FindAndConsumeFunctor::operator ()(StringPiece* input, | 282 bool PCRE::FindAndConsumeFunctor::operator ()(StringPiece* input, |
(...skipping 28 matching lines...) Expand all Loading... |
343 if (&a9 == &no_more_args) goto done; args[n++] = &a9; | 311 if (&a9 == &no_more_args) goto done; args[n++] = &a9; |
344 if (&a10 == &no_more_args) goto done; args[n++] = &a10; | 312 if (&a10 == &no_more_args) goto done; args[n++] = &a10; |
345 if (&a11 == &no_more_args) goto done; args[n++] = &a11; | 313 if (&a11 == &no_more_args) goto done; args[n++] = &a11; |
346 if (&a12 == &no_more_args) goto done; args[n++] = &a12; | 314 if (&a12 == &no_more_args) goto done; args[n++] = &a12; |
347 if (&a13 == &no_more_args) goto done; args[n++] = &a13; | 315 if (&a13 == &no_more_args) goto done; args[n++] = &a13; |
348 if (&a14 == &no_more_args) goto done; args[n++] = &a14; | 316 if (&a14 == &no_more_args) goto done; args[n++] = &a14; |
349 if (&a15 == &no_more_args) goto done; args[n++] = &a15; | 317 if (&a15 == &no_more_args) goto done; args[n++] = &a15; |
350 done: | 318 done: |
351 | 319 |
352 int consumed; | 320 int consumed; |
353 int vec[kVecSize] = {}; | 321 int vec[kVecSize]; |
354 if (pattern.DoMatchImpl(*input, UNANCHORED, &consumed, | 322 if (pattern.DoMatchImpl(*input, UNANCHORED, &consumed, |
355 args, n, vec, kVecSize)) { | 323 args, n, vec, kVecSize)) { |
356 input->remove_prefix(consumed); | 324 input->remove_prefix(consumed); |
357 return true; | 325 return true; |
358 } else { | 326 } else { |
359 return false; | 327 return false; |
360 } | 328 } |
361 } | 329 } |
362 | 330 |
363 bool PCRE::Replace(string *str, | 331 bool PCRE::Replace(string *str, |
364 const PCRE& pattern, | 332 const PCRE& pattern, |
365 const StringPiece& rewrite) { | 333 const StringPiece& rewrite) { |
366 int vec[kVecSize] = {}; | 334 int vec[kVecSize]; |
367 int matches = pattern.TryMatch(*str, 0, UNANCHORED, true, vec, kVecSize); | 335 int matches = pattern.TryMatch(*str, 0, UNANCHORED, true, vec, kVecSize); |
368 if (matches == 0) | 336 if (matches == 0) |
369 return false; | 337 return false; |
370 | 338 |
371 string s; | 339 string s; |
372 if (!pattern.Rewrite(&s, rewrite, *str, vec, matches)) | 340 if (!pattern.Rewrite(&s, rewrite, *str, vec, matches)) |
373 return false; | 341 return false; |
374 | 342 |
375 assert(vec[0] >= 0); | 343 assert(vec[0] >= 0); |
376 assert(vec[1] >= 0); | 344 assert(vec[1] >= 0); |
377 str->replace(vec[0], vec[1] - vec[0], s); | 345 str->replace(vec[0], vec[1] - vec[0], s); |
378 return true; | 346 return true; |
379 } | 347 } |
380 | 348 |
381 int PCRE::GlobalReplace(string *str, | 349 int PCRE::GlobalReplace(string *str, |
382 const PCRE& pattern, | 350 const PCRE& pattern, |
383 const StringPiece& rewrite) { | 351 const StringPiece& rewrite) { |
384 int count = 0; | 352 int count = 0; |
385 int vec[kVecSize] = {}; | 353 int vec[kVecSize]; |
386 string out; | 354 string out; |
387 int start = 0; | 355 int start = 0; |
388 bool last_match_was_empty_string = false; | 356 bool last_match_was_empty_string = false; |
389 | 357 |
390 while (start <= static_cast<int>(str->size())) { | 358 for (; start <= str->length();) { |
391 // If the previous match was for the empty string, we shouldn't | 359 // If the previous match was for the empty string, we shouldn't |
392 // just match again: we'll match in the same way and get an | 360 // just match again: we'll match in the same way and get an |
393 // infinite loop. Instead, we do the match in a special way: | 361 // infinite loop. Instead, we do the match in a special way: |
394 // anchored -- to force another try at the same position -- | 362 // anchored -- to force another try at the same position -- |
395 // and with a flag saying that this time, ignore empty matches. | 363 // and with a flag saying that this time, ignore empty matches. |
396 // If this special match returns, that means there's a non-empty | 364 // If this special match returns, that means there's a non-empty |
397 // match at this position as well, and we can continue. If not, | 365 // match at this position as well, and we can continue. If not, |
398 // we do what perl does, and just advance by one. | 366 // we do what perl does, and just advance by one. |
399 // Notice that perl prints '@@@' for this; | 367 // Notice that perl prints '@@@' for this; |
400 // perl -le '$_ = "aa"; s/b*|aa/@/g; print' | 368 // perl -le '$_ = "aa"; s/b*|aa/@/g; print' |
401 int matches; | 369 int matches; |
402 if (last_match_was_empty_string) { | 370 if (last_match_was_empty_string) { |
403 matches = pattern.TryMatch(*str, start, ANCHOR_START, false, | 371 matches = pattern.TryMatch(*str, start, ANCHOR_START, false, |
404 vec, kVecSize); | 372 vec, kVecSize); |
405 if (matches <= 0) { | 373 if (matches <= 0) { |
406 if (start < static_cast<int>(str->size())) | 374 if (start < str->length()) |
407 out.push_back((*str)[start]); | 375 out.push_back((*str)[start]); |
408 start++; | 376 start++; |
409 last_match_was_empty_string = false; | 377 last_match_was_empty_string = false; |
410 continue; | 378 continue; |
411 } | 379 } |
412 } else { | 380 } else { |
413 matches = pattern.TryMatch(*str, start, UNANCHORED, true, | 381 matches = pattern.TryMatch(*str, start, UNANCHORED, true, vec, kVecSize); |
414 vec, kVecSize); | |
415 if (matches <= 0) | 382 if (matches <= 0) |
416 break; | 383 break; |
417 } | 384 } |
418 int matchstart = vec[0], matchend = vec[1]; | 385 int matchstart = vec[0], matchend = vec[1]; |
419 assert(matchstart >= start); | 386 assert(matchstart >= start); |
420 assert(matchend >= matchstart); | 387 assert(matchend >= matchstart); |
421 | 388 |
422 out.append(*str, start, matchstart - start); | 389 out.append(*str, start, matchstart - start); |
423 pattern.Rewrite(&out, rewrite, *str, vec, matches); | 390 pattern.Rewrite(&out, rewrite, *str, vec, matches); |
424 start = matchend; | 391 start = matchend; |
425 count++; | 392 count++; |
426 last_match_was_empty_string = (matchstart == matchend); | 393 last_match_was_empty_string = (matchstart == matchend); |
427 } | 394 } |
428 | 395 |
429 if (count == 0) | 396 if (count == 0) |
430 return 0; | 397 return 0; |
431 | 398 |
432 if (start < static_cast<int>(str->size())) | 399 if (start < str->length()) |
433 out.append(*str, start, static_cast<int>(str->size()) - start); | 400 out.append(*str, start, str->length() - start); |
434 swap(out, *str); | 401 swap(out, *str); |
435 return count; | 402 return count; |
436 } | 403 } |
437 | 404 |
438 bool PCRE::Extract(const StringPiece &text, | 405 bool PCRE::Extract(const StringPiece &text, |
439 const PCRE& pattern, | 406 const PCRE& pattern, |
440 const StringPiece &rewrite, | 407 const StringPiece &rewrite, |
441 string *out) { | 408 string *out) { |
442 int vec[kVecSize] = {}; | 409 int vec[kVecSize]; |
443 int matches = pattern.TryMatch(text, 0, UNANCHORED, true, vec, kVecSize); | 410 int matches = pattern.TryMatch(text, 0, UNANCHORED, true, vec, kVecSize); |
444 if (matches == 0) | 411 if (matches == 0) |
445 return false; | 412 return false; |
446 out->clear(); | 413 out->clear(); |
447 return pattern.Rewrite(out, rewrite, text, vec, matches); | 414 return pattern.Rewrite(out, rewrite, text, vec, matches); |
448 } | 415 } |
449 | 416 |
450 string PCRE::QuoteMeta(const StringPiece& unquoted) { | 417 string PCRE::QuoteMeta(const StringPiece& unquoted) { |
451 string result; | 418 string result; |
452 result.reserve(unquoted.size() << 1); | 419 result.reserve(unquoted.size() << 1); |
(...skipping 25 matching lines...) Expand all Loading... |
478 } | 445 } |
479 result += unquoted[ii]; | 446 result += unquoted[ii]; |
480 } | 447 } |
481 | 448 |
482 return result; | 449 return result; |
483 } | 450 } |
484 | 451 |
485 /***** Actual matching and rewriting code *****/ | 452 /***** Actual matching and rewriting code *****/ |
486 | 453 |
487 bool PCRE::HitLimit() { | 454 bool PCRE::HitLimit() { |
488 return hit_limit_ != 0; | 455 return hit_limit_; |
489 } | 456 } |
490 | 457 |
491 void PCRE::ClearHitLimit() { | 458 void PCRE::ClearHitLimit() { |
492 hit_limit_ = 0; | 459 hit_limit_ = 0; |
493 } | 460 } |
494 | 461 |
495 int PCRE::TryMatch(const StringPiece& text, | 462 int PCRE::TryMatch(const StringPiece& text, |
496 int startpos, | 463 int startpos, |
497 Anchor anchor, | 464 Anchor anchor, |
498 bool empty_ok, | 465 bool empty_ok, |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
626 | 593 |
627 return true; | 594 return true; |
628 } | 595 } |
629 | 596 |
630 bool PCRE::DoMatch(const StringPiece& text, | 597 bool PCRE::DoMatch(const StringPiece& text, |
631 Anchor anchor, | 598 Anchor anchor, |
632 int* consumed, | 599 int* consumed, |
633 const Arg* const args[], | 600 const Arg* const args[], |
634 int n) const { | 601 int n) const { |
635 assert(n >= 0); | 602 assert(n >= 0); |
636 const int vecsize = (1 + n) * 3; // results + PCRE workspace | 603 size_t const vecsize = (1 + n) * 3; // results + PCRE workspace |
637 // (as for kVecSize) | 604 // (as for kVecSize) |
638 int* vec = new int[vecsize]; | 605 int *vec = new int[vecsize]; |
639 bool b = DoMatchImpl(text, anchor, consumed, args, n, vec, vecsize); | 606 bool b = DoMatchImpl(text, anchor, consumed, args, n, vec, vecsize); |
640 delete[] vec; | 607 delete[] vec; |
641 return b; | 608 return b; |
642 } | 609 } |
643 | 610 |
644 bool PCRE::Rewrite(string *out, const StringPiece &rewrite, | 611 bool PCRE::Rewrite(string *out, const StringPiece &rewrite, |
645 const StringPiece &text, int *vec, int veclen) const { | 612 const StringPiece &text, int *vec, int veclen) const { |
646 int number_of_capturing_groups = NumberOfCapturingGroups(); | 613 int number_of_capturing_groups = NumberOfCapturingGroups(); |
647 for (const char *s = rewrite.data(), *end = s + rewrite.size(); | 614 for (const char *s = rewrite.data(), *end = s + rewrite.size(); |
648 s < end; s++) { | 615 s < end; s++) { |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
834 } | 801 } |
835 | 802 |
836 bool PCRE::Arg::parse_short_radix(const char* str, | 803 bool PCRE::Arg::parse_short_radix(const char* str, |
837 int n, | 804 int n, |
838 void* dest, | 805 void* dest, |
839 int radix) { | 806 int radix) { |
840 long r; | 807 long r; |
841 if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse | 808 if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse |
842 if ((short)r != r) return false; // Out of range | 809 if ((short)r != r) return false; // Out of range |
843 if (dest == NULL) return true; | 810 if (dest == NULL) return true; |
844 *(reinterpret_cast<short*>(dest)) = (short)r; | 811 *(reinterpret_cast<short*>(dest)) = r; |
845 return true; | 812 return true; |
846 } | 813 } |
847 | 814 |
848 bool PCRE::Arg::parse_ushort_radix(const char* str, | 815 bool PCRE::Arg::parse_ushort_radix(const char* str, |
849 int n, | 816 int n, |
850 void* dest, | 817 void* dest, |
851 int radix) { | 818 int radix) { |
852 unsigned long r; | 819 unsigned long r; |
853 if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse | 820 if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse |
854 if ((ushort)r != r) return false; // Out of range | 821 if ((ushort)r != r) return false; // Out of range |
855 if (dest == NULL) return true; | 822 if (dest == NULL) return true; |
856 *(reinterpret_cast<unsigned short*>(dest)) = (ushort)r; | 823 *(reinterpret_cast<unsigned short*>(dest)) = r; |
857 return true; | 824 return true; |
858 } | 825 } |
859 | 826 |
860 bool PCRE::Arg::parse_int_radix(const char* str, | 827 bool PCRE::Arg::parse_int_radix(const char* str, |
861 int n, | 828 int n, |
862 void* dest, | 829 void* dest, |
863 int radix) { | 830 int radix) { |
864 long r; | 831 long r; |
865 if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse | 832 if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse |
866 if ((int)r != r) return false; // Out of range | 833 if ((int)r != r) return false; // Out of range |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
924 if (n == 0) return false; | 891 if (n == 0) return false; |
925 static const int kMaxLength = 200; | 892 static const int kMaxLength = 200; |
926 char buf[kMaxLength]; | 893 char buf[kMaxLength]; |
927 if (n >= kMaxLength) return false; | 894 if (n >= kMaxLength) return false; |
928 memcpy(buf, str, n); | 895 memcpy(buf, str, n); |
929 buf[n] = '\0'; | 896 buf[n] = '\0'; |
930 errno = 0; | 897 errno = 0; |
931 char* end; | 898 char* end; |
932 double r = strtod(buf, &end); | 899 double r = strtod(buf, &end); |
933 if (end != buf + n) { | 900 if (end != buf + n) { |
934 #ifdef _WIN32 | 901 #ifdef COMPILER_MSVC |
935 // Microsoft's strtod() doesn't handle inf and nan, so we have to | 902 // Microsoft's strtod() doesn't handle inf and nan, so we have to |
936 // handle it explicitly. Speed is not important here because this | 903 // handle it explicitly. Speed is not important here because this |
937 // code is only called in unit tests. | 904 // code is only called in unit tests. |
938 bool pos = true; | 905 bool pos = true; |
939 const char* i = buf; | 906 const char* i = buf; |
940 if ('-' == *i) { | 907 if ('-' == *i) { |
941 pos = false; | 908 pos = false; |
942 ++i; | 909 ++i; |
943 } else if ('+' == *i) { | 910 } else if ('+' == *i) { |
944 ++i; | 911 ++i; |
945 } | 912 } |
946 if (0 == stricmp(i, "inf") || 0 == stricmp(i, "infinity")) { | 913 if (0 == stricmp(i, "inf") || 0 == stricmp(i, "infinity")) { |
947 r = std::numeric_limits<double>::infinity(); | 914 r = numeric_limits<double>::infinity(); |
948 if (!pos) | 915 if (!pos) |
949 r = -r; | 916 r = -r; |
950 } else if (0 == stricmp(i, "nan")) { | 917 } else if (0 == stricmp(i, "nan")) { |
951 r = std::numeric_limits<double>::quiet_NaN(); | 918 r = numeric_limits<double>::quiet_NaN(); |
952 } else { | 919 } else { |
953 return false; | 920 return false; |
954 } | 921 } |
955 #else | 922 #else |
956 return false; // Leftover junk | 923 return false; // Leftover junk |
957 #endif | 924 #endif |
958 } | 925 } |
959 if (errno) return false; | 926 if (errno) return false; |
960 if (dest == NULL) return true; | 927 if (dest == NULL) return true; |
961 *(reinterpret_cast<double*>(dest)) = r; | 928 *(reinterpret_cast<double*>(dest)) = r; |
(...skipping 28 matching lines...) Expand all Loading... |
990 DEFINE_INTEGER_PARSERS(int); | 957 DEFINE_INTEGER_PARSERS(int); |
991 DEFINE_INTEGER_PARSERS(uint); | 958 DEFINE_INTEGER_PARSERS(uint); |
992 DEFINE_INTEGER_PARSERS(long); | 959 DEFINE_INTEGER_PARSERS(long); |
993 DEFINE_INTEGER_PARSERS(ulong); | 960 DEFINE_INTEGER_PARSERS(ulong); |
994 DEFINE_INTEGER_PARSERS(longlong); | 961 DEFINE_INTEGER_PARSERS(longlong); |
995 DEFINE_INTEGER_PARSERS(ulonglong); | 962 DEFINE_INTEGER_PARSERS(ulonglong); |
996 | 963 |
997 #undef DEFINE_INTEGER_PARSERS | 964 #undef DEFINE_INTEGER_PARSERS |
998 | 965 |
999 } // namespace re2 | 966 } // namespace re2 |
OLD | NEW |