1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/tools/pcre/pcrecpp.cc Tue Jul 28 17:51:34 2009 -0400
1.3 @@ -0,0 +1,893 @@
1.4 +// Copyright (c) 2005, Google Inc.
1.5 +// All rights reserved.
1.6 +//
1.7 +// Redistribution and use in source and binary forms, with or without
1.8 +// modification, are permitted provided that the following conditions are
1.9 +// met:
1.10 +//
1.11 +// * Redistributions of source code must retain the above copyright
1.12 +// notice, this list of conditions and the following disclaimer.
1.13 +// * Redistributions in binary form must reproduce the above
1.14 +// copyright notice, this list of conditions and the following disclaimer
1.15 +// in the documentation and/or other materials provided with the
1.16 +// distribution.
1.17 +// * Neither the name of Google Inc. nor the names of its
1.18 +// contributors may be used to endorse or promote products derived from
1.19 +// this software without specific prior written permission.
1.20 +//
1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.32 +//
1.33 +// Author: Sanjay Ghemawat
1.34 +
1.35 +#ifdef HAVE_CONFIG_H
1.36 +#include "config.h"
1.37 +#endif
1.38 +
1.39 +#include <stdlib.h>
1.40 +#include <stdio.h>
1.41 +#include <ctype.h>
1.42 +#include <limits.h> /* for SHRT_MIN, USHRT_MAX, etc */
1.43 +#include <assert.h>
1.44 +#include <errno.h>
1.45 +#include <string>
1.46 +#include <algorithm>
1.47 +
1.48 +#include "pcrecpp_internal.h"
1.49 +#include "pcre.h"
1.50 +#include "pcrecpp.h"
1.51 +#include "pcre_stringpiece.h"
1.52 +
1.53 +
1.54 +namespace pcrecpp {
1.55 +
1.56 +// Maximum number of args we can set
1.57 +static const int kMaxArgs = 16;
1.58 +static const int kVecSize = (1 + kMaxArgs) * 3; // results + PCRE workspace
1.59 +
1.60 +// Special object that stands-in for no argument
1.61 +Arg RE::no_arg((void*)NULL);
1.62 +
1.63 +// This is for ABI compatibility with old versions of pcre (pre-7.6),
1.64 +// which defined a global no_arg variable instead of putting it in the
1.65 +// RE class. This works on GCC >= 3, at least. It definitely works
1.66 +// for ELF, but may not for other object formats (Mach-O, for
1.67 +// instance, does not support aliases.) We could probably have a more
1.68 +// inclusive test if we ever needed it. (Note that not only the
1.69 +// __attribute__ syntax, but also __USER_LABEL_PREFIX__, are
1.70 +// gnu-specific.)
1.71 +#if defined(__GNUC__) && __GNUC__ >= 3 && defined(__ELF__)
1.72 +# define ULP_AS_STRING(x) ULP_AS_STRING_INTERNAL(x)
1.73 +# define ULP_AS_STRING_INTERNAL(x) #x
1.74 +# define USER_LABEL_PREFIX_STR ULP_AS_STRING(__USER_LABEL_PREFIX__)
1.75 +extern Arg no_arg
1.76 + __attribute__((alias(USER_LABEL_PREFIX_STR "_ZN7pcrecpp2RE6no_argE")));
1.77 +#endif
1.78 +
1.79 +// If a regular expression has no error, its error_ field points here
1.80 +static const string empty_string;
1.81 +
1.82 +// If the user doesn't ask for any options, we just use this one
1.83 +static RE_Options default_options;
1.84 +
1.85 +void RE::Init(const string& pat, const RE_Options* options) {
1.86 + pattern_ = pat;
1.87 + if (options == NULL) {
1.88 + options_ = default_options;
1.89 + } else {
1.90 + options_ = *options;
1.91 + }
1.92 + error_ = &empty_string;
1.93 + re_full_ = NULL;
1.94 + re_partial_ = NULL;
1.95 +
1.96 + re_partial_ = Compile(UNANCHORED);
1.97 + if (re_partial_ != NULL) {
1.98 + re_full_ = Compile(ANCHOR_BOTH);
1.99 + }
1.100 +}
1.101 +
1.102 +void RE::Cleanup() {
1.103 + if (re_full_ != NULL) (*pcre_free)(re_full_);
1.104 + if (re_partial_ != NULL) (*pcre_free)(re_partial_);
1.105 + if (error_ != &empty_string) delete error_;
1.106 +}
1.107 +
1.108 +
1.109 +RE::~RE() {
1.110 + Cleanup();
1.111 +}
1.112 +
1.113 +
1.114 +pcre* RE::Compile(Anchor anchor) {
1.115 + // First, convert RE_Options into pcre options
1.116 + int pcre_options = 0;
1.117 + pcre_options = options_.all_options();
1.118 +
1.119 + // Special treatment for anchoring. This is needed because at
1.120 + // runtime pcre only provides an option for anchoring at the
1.121 + // beginning of a string (unless you use offset).
1.122 + //
1.123 + // There are three types of anchoring we want:
1.124 + // UNANCHORED Compile the original pattern, and use
1.125 + // a pcre unanchored match.
1.126 + // ANCHOR_START Compile the original pattern, and use
1.127 + // a pcre anchored match.
1.128 + // ANCHOR_BOTH Tack a "\z" to the end of the original pattern
1.129 + // and use a pcre anchored match.
1.130 +
1.131 + const char* compile_error;
1.132 + int eoffset;
1.133 + pcre* re;
1.134 + if (anchor != ANCHOR_BOTH) {
1.135 + re = pcre_compile(pattern_.c_str(), pcre_options,
1.136 + &compile_error, &eoffset, NULL);
1.137 + } else {
1.138 + // Tack a '\z' at the end of RE. Parenthesize it first so that
1.139 + // the '\z' applies to all top-level alternatives in the regexp.
1.140 + string wrapped = "(?:"; // A non-counting grouping operator
1.141 + wrapped += pattern_;
1.142 + wrapped += ")\\z";
1.143 + re = pcre_compile(wrapped.c_str(), pcre_options,
1.144 + &compile_error, &eoffset, NULL);
1.145 + }
1.146 + if (re == NULL) {
1.147 + if (error_ == &empty_string) error_ = new string(compile_error);
1.148 + }
1.149 + return re;
1.150 +}
1.151 +
1.152 +/***** Matching interfaces *****/
1.153 +
1.154 +bool RE::FullMatch(const StringPiece& text,
1.155 + const Arg& ptr1,
1.156 + const Arg& ptr2,
1.157 + const Arg& ptr3,
1.158 + const Arg& ptr4,
1.159 + const Arg& ptr5,
1.160 + const Arg& ptr6,
1.161 + const Arg& ptr7,
1.162 + const Arg& ptr8,
1.163 + const Arg& ptr9,
1.164 + const Arg& ptr10,
1.165 + const Arg& ptr11,
1.166 + const Arg& ptr12,
1.167 + const Arg& ptr13,
1.168 + const Arg& ptr14,
1.169 + const Arg& ptr15,
1.170 + const Arg& ptr16) const {
1.171 + const Arg* args[kMaxArgs];
1.172 + int n = 0;
1.173 + if (&ptr1 == &no_arg) goto done; args[n++] = &ptr1;
1.174 + if (&ptr2 == &no_arg) goto done; args[n++] = &ptr2;
1.175 + if (&ptr3 == &no_arg) goto done; args[n++] = &ptr3;
1.176 + if (&ptr4 == &no_arg) goto done; args[n++] = &ptr4;
1.177 + if (&ptr5 == &no_arg) goto done; args[n++] = &ptr5;
1.178 + if (&ptr6 == &no_arg) goto done; args[n++] = &ptr6;
1.179 + if (&ptr7 == &no_arg) goto done; args[n++] = &ptr7;
1.180 + if (&ptr8 == &no_arg) goto done; args[n++] = &ptr8;
1.181 + if (&ptr9 == &no_arg) goto done; args[n++] = &ptr9;
1.182 + if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10;
1.183 + if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11;
1.184 + if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12;
1.185 + if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13;
1.186 + if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14;
1.187 + if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15;
1.188 + if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16;
1.189 + done:
1.190 +
1.191 + int consumed;
1.192 + int vec[kVecSize];
1.193 + return DoMatchImpl(text, ANCHOR_BOTH, &consumed, args, n, vec, kVecSize);
1.194 +}
1.195 +
1.196 +bool RE::PartialMatch(const StringPiece& text,
1.197 + const Arg& ptr1,
1.198 + const Arg& ptr2,
1.199 + const Arg& ptr3,
1.200 + const Arg& ptr4,
1.201 + const Arg& ptr5,
1.202 + const Arg& ptr6,
1.203 + const Arg& ptr7,
1.204 + const Arg& ptr8,
1.205 + const Arg& ptr9,
1.206 + const Arg& ptr10,
1.207 + const Arg& ptr11,
1.208 + const Arg& ptr12,
1.209 + const Arg& ptr13,
1.210 + const Arg& ptr14,
1.211 + const Arg& ptr15,
1.212 + const Arg& ptr16) const {
1.213 + const Arg* args[kMaxArgs];
1.214 + int n = 0;
1.215 + if (&ptr1 == &no_arg) goto done; args[n++] = &ptr1;
1.216 + if (&ptr2 == &no_arg) goto done; args[n++] = &ptr2;
1.217 + if (&ptr3 == &no_arg) goto done; args[n++] = &ptr3;
1.218 + if (&ptr4 == &no_arg) goto done; args[n++] = &ptr4;
1.219 + if (&ptr5 == &no_arg) goto done; args[n++] = &ptr5;
1.220 + if (&ptr6 == &no_arg) goto done; args[n++] = &ptr6;
1.221 + if (&ptr7 == &no_arg) goto done; args[n++] = &ptr7;
1.222 + if (&ptr8 == &no_arg) goto done; args[n++] = &ptr8;
1.223 + if (&ptr9 == &no_arg) goto done; args[n++] = &ptr9;
1.224 + if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10;
1.225 + if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11;
1.226 + if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12;
1.227 + if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13;
1.228 + if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14;
1.229 + if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15;
1.230 + if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16;
1.231 + done:
1.232 +
1.233 + int consumed;
1.234 + int vec[kVecSize];
1.235 + return DoMatchImpl(text, UNANCHORED, &consumed, args, n, vec, kVecSize);
1.236 +}
1.237 +
1.238 +bool RE::Consume(StringPiece* input,
1.239 + const Arg& ptr1,
1.240 + const Arg& ptr2,
1.241 + const Arg& ptr3,
1.242 + const Arg& ptr4,
1.243 + const Arg& ptr5,
1.244 + const Arg& ptr6,
1.245 + const Arg& ptr7,
1.246 + const Arg& ptr8,
1.247 + const Arg& ptr9,
1.248 + const Arg& ptr10,
1.249 + const Arg& ptr11,
1.250 + const Arg& ptr12,
1.251 + const Arg& ptr13,
1.252 + const Arg& ptr14,
1.253 + const Arg& ptr15,
1.254 + const Arg& ptr16) const {
1.255 + const Arg* args[kMaxArgs];
1.256 + int n = 0;
1.257 + if (&ptr1 == &no_arg) goto done; args[n++] = &ptr1;
1.258 + if (&ptr2 == &no_arg) goto done; args[n++] = &ptr2;
1.259 + if (&ptr3 == &no_arg) goto done; args[n++] = &ptr3;
1.260 + if (&ptr4 == &no_arg) goto done; args[n++] = &ptr4;
1.261 + if (&ptr5 == &no_arg) goto done; args[n++] = &ptr5;
1.262 + if (&ptr6 == &no_arg) goto done; args[n++] = &ptr6;
1.263 + if (&ptr7 == &no_arg) goto done; args[n++] = &ptr7;
1.264 + if (&ptr8 == &no_arg) goto done; args[n++] = &ptr8;
1.265 + if (&ptr9 == &no_arg) goto done; args[n++] = &ptr9;
1.266 + if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10;
1.267 + if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11;
1.268 + if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12;
1.269 + if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13;
1.270 + if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14;
1.271 + if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15;
1.272 + if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16;
1.273 + done:
1.274 +
1.275 + int consumed;
1.276 + int vec[kVecSize];
1.277 + if (DoMatchImpl(*input, ANCHOR_START, &consumed,
1.278 + args, n, vec, kVecSize)) {
1.279 + input->remove_prefix(consumed);
1.280 + return true;
1.281 + } else {
1.282 + return false;
1.283 + }
1.284 +}
1.285 +
1.286 +bool RE::FindAndConsume(StringPiece* input,
1.287 + const Arg& ptr1,
1.288 + const Arg& ptr2,
1.289 + const Arg& ptr3,
1.290 + const Arg& ptr4,
1.291 + const Arg& ptr5,
1.292 + const Arg& ptr6,
1.293 + const Arg& ptr7,
1.294 + const Arg& ptr8,
1.295 + const Arg& ptr9,
1.296 + const Arg& ptr10,
1.297 + const Arg& ptr11,
1.298 + const Arg& ptr12,
1.299 + const Arg& ptr13,
1.300 + const Arg& ptr14,
1.301 + const Arg& ptr15,
1.302 + const Arg& ptr16) const {
1.303 + const Arg* args[kMaxArgs];
1.304 + int n = 0;
1.305 + if (&ptr1 == &no_arg) goto done; args[n++] = &ptr1;
1.306 + if (&ptr2 == &no_arg) goto done; args[n++] = &ptr2;
1.307 + if (&ptr3 == &no_arg) goto done; args[n++] = &ptr3;
1.308 + if (&ptr4 == &no_arg) goto done; args[n++] = &ptr4;
1.309 + if (&ptr5 == &no_arg) goto done; args[n++] = &ptr5;
1.310 + if (&ptr6 == &no_arg) goto done; args[n++] = &ptr6;
1.311 + if (&ptr7 == &no_arg) goto done; args[n++] = &ptr7;
1.312 + if (&ptr8 == &no_arg) goto done; args[n++] = &ptr8;
1.313 + if (&ptr9 == &no_arg) goto done; args[n++] = &ptr9;
1.314 + if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10;
1.315 + if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11;
1.316 + if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12;
1.317 + if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13;
1.318 + if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14;
1.319 + if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15;
1.320 + if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16;
1.321 + done:
1.322 +
1.323 + int consumed;
1.324 + int vec[kVecSize];
1.325 + if (DoMatchImpl(*input, UNANCHORED, &consumed,
1.326 + args, n, vec, kVecSize)) {
1.327 + input->remove_prefix(consumed);
1.328 + return true;
1.329 + } else {
1.330 + return false;
1.331 + }
1.332 +}
1.333 +
1.334 +bool RE::Replace(const StringPiece& rewrite,
1.335 + string *str) const {
1.336 + int vec[kVecSize];
1.337 + int matches = TryMatch(*str, 0, UNANCHORED, vec, kVecSize);
1.338 + if (matches == 0)
1.339 + return false;
1.340 +
1.341 + string s;
1.342 + if (!Rewrite(&s, rewrite, *str, vec, matches))
1.343 + return false;
1.344 +
1.345 + assert(vec[0] >= 0);
1.346 + assert(vec[1] >= 0);
1.347 + str->replace(vec[0], vec[1] - vec[0], s);
1.348 + return true;
1.349 +}
1.350 +
1.351 +// Returns PCRE_NEWLINE_CRLF, PCRE_NEWLINE_CR, or PCRE_NEWLINE_LF.
1.352 +// Note that PCRE_NEWLINE_CRLF is defined to be P_N_CR | P_N_LF.
1.353 +// Modified by PH to add PCRE_NEWLINE_ANY and PCRE_NEWLINE_ANYCRLF.
1.354 +
1.355 +static int NewlineMode(int pcre_options) {
1.356 + // TODO: if we can make it threadsafe, cache this var
1.357 + int newline_mode = 0;
1.358 + /* if (newline_mode) return newline_mode; */ // do this once it's cached
1.359 + if (pcre_options & (PCRE_NEWLINE_CRLF|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|
1.360 + PCRE_NEWLINE_ANY|PCRE_NEWLINE_ANYCRLF)) {
1.361 + newline_mode = (pcre_options &
1.362 + (PCRE_NEWLINE_CRLF|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|
1.363 + PCRE_NEWLINE_ANY|PCRE_NEWLINE_ANYCRLF));
1.364 + } else {
1.365 + int newline;
1.366 + pcre_config(PCRE_CONFIG_NEWLINE, &newline);
1.367 + if (newline == 10)
1.368 + newline_mode = PCRE_NEWLINE_LF;
1.369 + else if (newline == 13)
1.370 + newline_mode = PCRE_NEWLINE_CR;
1.371 + else if (newline == 3338)
1.372 + newline_mode = PCRE_NEWLINE_CRLF;
1.373 + else if (newline == -1)
1.374 + newline_mode = PCRE_NEWLINE_ANY;
1.375 + else if (newline == -2)
1.376 + newline_mode = PCRE_NEWLINE_ANYCRLF;
1.377 + else
1.378 + assert(NULL == "Unexpected return value from pcre_config(NEWLINE)");
1.379 + }
1.380 + return newline_mode;
1.381 +}
1.382 +
1.383 +int RE::GlobalReplace(const StringPiece& rewrite,
1.384 + string *str) const {
1.385 + int count = 0;
1.386 + int vec[kVecSize];
1.387 + string out;
1.388 + int start = 0;
1.389 + int lastend = -1;
1.390 +
1.391 + while (start <= static_cast<int>(str->length())) {
1.392 + int matches = TryMatch(*str, start, UNANCHORED, vec, kVecSize);
1.393 + if (matches <= 0)
1.394 + break;
1.395 + int matchstart = vec[0], matchend = vec[1];
1.396 + assert(matchstart >= start);
1.397 + assert(matchend >= matchstart);
1.398 + if (matchstart == matchend && matchstart == lastend) {
1.399 + // advance one character if we matched an empty string at the same
1.400 + // place as the last match occurred
1.401 + matchend = start + 1;
1.402 + // If the current char is CR and we're in CRLF mode, skip LF too.
1.403 + // Note it's better to call pcre_fullinfo() than to examine
1.404 + // all_options(), since options_ could have changed bewteen
1.405 + // compile-time and now, but this is simpler and safe enough.
1.406 + // Modified by PH to add ANY and ANYCRLF.
1.407 + if (start+1 < static_cast<int>(str->length()) &&
1.408 + (*str)[start] == '\r' && (*str)[start+1] == '\n' &&
1.409 + (NewlineMode(options_.all_options()) == PCRE_NEWLINE_CRLF ||
1.410 + NewlineMode(options_.all_options()) == PCRE_NEWLINE_ANY ||
1.411 + NewlineMode(options_.all_options()) == PCRE_NEWLINE_ANYCRLF)
1.412 + ) {
1.413 + matchend++;
1.414 + }
1.415 + // We also need to advance more than one char if we're in utf8 mode.
1.416 +#ifdef SUPPORT_UTF8
1.417 + if (options_.utf8()) {
1.418 + while (matchend < static_cast<int>(str->length()) &&
1.419 + ((*str)[matchend] & 0xc0) == 0x80)
1.420 + matchend++;
1.421 + }
1.422 +#endif
1.423 + if (matchend <= static_cast<int>(str->length()))
1.424 + out.append(*str, start, matchend - start);
1.425 + start = matchend;
1.426 + } else {
1.427 + out.append(*str, start, matchstart - start);
1.428 + Rewrite(&out, rewrite, *str, vec, matches);
1.429 + start = matchend;
1.430 + lastend = matchend;
1.431 + count++;
1.432 + }
1.433 + }
1.434 +
1.435 + if (count == 0)
1.436 + return 0;
1.437 +
1.438 + if (start < static_cast<int>(str->length()))
1.439 + out.append(*str, start, str->length() - start);
1.440 + swap(out, *str);
1.441 + return count;
1.442 +}
1.443 +
1.444 +bool RE::Extract(const StringPiece& rewrite,
1.445 + const StringPiece& text,
1.446 + string *out) const {
1.447 + int vec[kVecSize];
1.448 + int matches = TryMatch(text, 0, UNANCHORED, vec, kVecSize);
1.449 + if (matches == 0)
1.450 + return false;
1.451 + out->erase();
1.452 + return Rewrite(out, rewrite, text, vec, matches);
1.453 +}
1.454 +
1.455 +/*static*/ string RE::QuoteMeta(const StringPiece& unquoted) {
1.456 + string result;
1.457 +
1.458 + // Escape any ascii character not in [A-Za-z_0-9].
1.459 + //
1.460 + // Note that it's legal to escape a character even if it has no
1.461 + // special meaning in a regular expression -- so this function does
1.462 + // that. (This also makes it identical to the perl function of the
1.463 + // same name; see `perldoc -f quotemeta`.) The one exception is
1.464 + // escaping NUL: rather than doing backslash + NUL, like perl does,
1.465 + // we do '\0', because pcre itself doesn't take embedded NUL chars.
1.466 + for (int ii = 0; ii < unquoted.size(); ++ii) {
1.467 + // Note that using 'isalnum' here raises the benchmark time from
1.468 + // 32ns to 58ns:
1.469 + if (unquoted[ii] == '\0') {
1.470 + result += "\\0";
1.471 + } else if ((unquoted[ii] < 'a' || unquoted[ii] > 'z') &&
1.472 + (unquoted[ii] < 'A' || unquoted[ii] > 'Z') &&
1.473 + (unquoted[ii] < '0' || unquoted[ii] > '9') &&
1.474 + unquoted[ii] != '_' &&
1.475 + // If this is the part of a UTF8 or Latin1 character, we need
1.476 + // to copy this byte without escaping. Experimentally this is
1.477 + // what works correctly with the regexp library.
1.478 + !(unquoted[ii] & 128)) {
1.479 + result += '\\';
1.480 + result += unquoted[ii];
1.481 + } else {
1.482 + result += unquoted[ii];
1.483 + }
1.484 + }
1.485 +
1.486 + return result;
1.487 +}
1.488 +
1.489 +/***** Actual matching and rewriting code *****/
1.490 +
1.491 +int RE::TryMatch(const StringPiece& text,
1.492 + int startpos,
1.493 + Anchor anchor,
1.494 + int *vec,
1.495 + int vecsize) const {
1.496 + pcre* re = (anchor == ANCHOR_BOTH) ? re_full_ : re_partial_;
1.497 + if (re == NULL) {
1.498 + //fprintf(stderr, "Matching against invalid re: %s\n", error_->c_str());
1.499 + return 0;
1.500 + }
1.501 +
1.502 + pcre_extra extra = { 0, 0, 0, 0, 0, 0 };
1.503 + if (options_.match_limit() > 0) {
1.504 + extra.flags |= PCRE_EXTRA_MATCH_LIMIT;
1.505 + extra.match_limit = options_.match_limit();
1.506 + }
1.507 + if (options_.match_limit_recursion() > 0) {
1.508 + extra.flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
1.509 + extra.match_limit_recursion = options_.match_limit_recursion();
1.510 + }
1.511 + int rc = pcre_exec(re, // The regular expression object
1.512 + &extra,
1.513 + (text.data() == NULL) ? "" : text.data(),
1.514 + text.size(),
1.515 + startpos,
1.516 + (anchor == UNANCHORED) ? 0 : PCRE_ANCHORED,
1.517 + vec,
1.518 + vecsize);
1.519 +
1.520 + // Handle errors
1.521 + if (rc == PCRE_ERROR_NOMATCH) {
1.522 + return 0;
1.523 + } else if (rc < 0) {
1.524 + //fprintf(stderr, "Unexpected return code: %d when matching '%s'\n",
1.525 + // re, pattern_.c_str());
1.526 + return 0;
1.527 + } else if (rc == 0) {
1.528 + // pcre_exec() returns 0 as a special case when the number of
1.529 + // capturing subpatterns exceeds the size of the vector.
1.530 + // When this happens, there is a match and the output vector
1.531 + // is filled, but we miss out on the positions of the extra subpatterns.
1.532 + rc = vecsize / 2;
1.533 + }
1.534 +
1.535 + return rc;
1.536 +}
1.537 +
1.538 +bool RE::DoMatchImpl(const StringPiece& text,
1.539 + Anchor anchor,
1.540 + int* consumed,
1.541 + const Arg* const* args,
1.542 + int n,
1.543 + int* vec,
1.544 + int vecsize) const {
1.545 + assert((1 + n) * 3 <= vecsize); // results + PCRE workspace
1.546 + int matches = TryMatch(text, 0, anchor, vec, vecsize);
1.547 + assert(matches >= 0); // TryMatch never returns negatives
1.548 + if (matches == 0)
1.549 + return false;
1.550 +
1.551 + *consumed = vec[1];
1.552 +
1.553 + if (n == 0 || args == NULL) {
1.554 + // We are not interested in results
1.555 + return true;
1.556 + }
1.557 +
1.558 + if (NumberOfCapturingGroups() < n) {
1.559 + // RE has fewer capturing groups than number of arg pointers passed in
1.560 + return false;
1.561 + }
1.562 +
1.563 + // If we got here, we must have matched the whole pattern.
1.564 + // We do not need (can not do) any more checks on the value of 'matches' here
1.565 + // -- see the comment for TryMatch.
1.566 + for (int i = 0; i < n; i++) {
1.567 + const int start = vec[2*(i+1)];
1.568 + const int limit = vec[2*(i+1)+1];
1.569 + if (!args[i]->Parse(text.data() + start, limit-start)) {
1.570 + // TODO: Should we indicate what the error was?
1.571 + return false;
1.572 + }
1.573 + }
1.574 +
1.575 + return true;
1.576 +}
1.577 +
1.578 +bool RE::DoMatch(const StringPiece& text,
1.579 + Anchor anchor,
1.580 + int* consumed,
1.581 + const Arg* const args[],
1.582 + int n) const {
1.583 + assert(n >= 0);
1.584 + size_t const vecsize = (1 + n) * 3; // results + PCRE workspace
1.585 + // (as for kVecSize)
1.586 + int space[21]; // use stack allocation for small vecsize (common case)
1.587 + int* vec = vecsize <= 21 ? space : new int[vecsize];
1.588 + bool retval = DoMatchImpl(text, anchor, consumed, args, n, vec, vecsize);
1.589 + if (vec != space) delete [] vec;
1.590 + return retval;
1.591 +}
1.592 +
1.593 +bool RE::Rewrite(string *out, const StringPiece &rewrite,
1.594 + const StringPiece &text, int *vec, int veclen) const {
1.595 + for (const char *s = rewrite.data(), *end = s + rewrite.size();
1.596 + s < end; s++) {
1.597 + int c = *s;
1.598 + if (c == '\\') {
1.599 + c = *++s;
1.600 + if (isdigit(c)) {
1.601 + int n = (c - '0');
1.602 + if (n >= veclen) {
1.603 + //fprintf(stderr, requested group %d in regexp %.*s\n",
1.604 + // n, rewrite.size(), rewrite.data());
1.605 + return false;
1.606 + }
1.607 + int start = vec[2 * n];
1.608 + if (start >= 0)
1.609 + out->append(text.data() + start, vec[2 * n + 1] - start);
1.610 + } else if (c == '\\') {
1.611 + *out += '\\';
1.612 + } else {
1.613 + //fprintf(stderr, "invalid rewrite pattern: %.*s\n",
1.614 + // rewrite.size(), rewrite.data());
1.615 + return false;
1.616 + }
1.617 + } else {
1.618 + *out += c;
1.619 + }
1.620 + }
1.621 + return true;
1.622 +}
1.623 +
1.624 +// Return the number of capturing subpatterns, or -1 if the
1.625 +// regexp wasn't valid on construction.
1.626 +int RE::NumberOfCapturingGroups() const {
1.627 + if (re_partial_ == NULL) return -1;
1.628 +
1.629 + int result;
1.630 + int pcre_retval = pcre_fullinfo(re_partial_, // The regular expression object
1.631 + NULL, // We did not study the pattern
1.632 + PCRE_INFO_CAPTURECOUNT,
1.633 + &result);
1.634 + assert(pcre_retval == 0);
1.635 + return result;
1.636 +}
1.637 +
1.638 +/***** Parsers for various types *****/
1.639 +
1.640 +bool Arg::parse_null(const char* str, int n, void* dest) {
1.641 + // We fail if somebody asked us to store into a non-NULL void* pointer
1.642 + return (dest == NULL);
1.643 +}
1.644 +
1.645 +bool Arg::parse_string(const char* str, int n, void* dest) {
1.646 + if (dest == NULL) return true;
1.647 + reinterpret_cast<string*>(dest)->assign(str, n);
1.648 + return true;
1.649 +}
1.650 +
1.651 +bool Arg::parse_stringpiece(const char* str, int n, void* dest) {
1.652 + if (dest == NULL) return true;
1.653 + reinterpret_cast<StringPiece*>(dest)->set(str, n);
1.654 + return true;
1.655 +}
1.656 +
1.657 +bool Arg::parse_char(const char* str, int n, void* dest) {
1.658 + if (n != 1) return false;
1.659 + if (dest == NULL) return true;
1.660 + *(reinterpret_cast<char*>(dest)) = str[0];
1.661 + return true;
1.662 +}
1.663 +
1.664 +bool Arg::parse_uchar(const char* str, int n, void* dest) {
1.665 + if (n != 1) return false;
1.666 + if (dest == NULL) return true;
1.667 + *(reinterpret_cast<unsigned char*>(dest)) = str[0];
1.668 + return true;
1.669 +}
1.670 +
1.671 +// Largest number spec that we are willing to parse
1.672 +static const int kMaxNumberLength = 32;
1.673 +
1.674 +// REQUIRES "buf" must have length at least kMaxNumberLength+1
1.675 +// REQUIRES "n > 0"
1.676 +// Copies "str" into "buf" and null-terminates if necessary.
1.677 +// Returns one of:
1.678 +// a. "str" if no termination is needed
1.679 +// b. "buf" if the string was copied and null-terminated
1.680 +// c. "" if the input was invalid and has no hope of being parsed
1.681 +static const char* TerminateNumber(char* buf, const char* str, int n) {
1.682 + if ((n > 0) && isspace(*str)) {
1.683 + // We are less forgiving than the strtoxxx() routines and do not
1.684 + // allow leading spaces.
1.685 + return "";
1.686 + }
1.687 +
1.688 + // See if the character right after the input text may potentially
1.689 + // look like a digit.
1.690 + if (isdigit(str[n]) ||
1.691 + ((str[n] >= 'a') && (str[n] <= 'f')) ||
1.692 + ((str[n] >= 'A') && (str[n] <= 'F'))) {
1.693 + if (n > kMaxNumberLength) return ""; // Input too big to be a valid number
1.694 + memcpy(buf, str, n);
1.695 + buf[n] = '\0';
1.696 + return buf;
1.697 + } else {
1.698 + // We can parse right out of the supplied string, so return it.
1.699 + return str;
1.700 + }
1.701 +}
1.702 +
1.703 +bool Arg::parse_long_radix(const char* str,
1.704 + int n,
1.705 + void* dest,
1.706 + int radix) {
1.707 + if (n == 0) return false;
1.708 + char buf[kMaxNumberLength+1];
1.709 + str = TerminateNumber(buf, str, n);
1.710 + char* end;
1.711 + errno = 0;
1.712 + long r = strtol(str, &end, radix);
1.713 + if (end != str + n) return false; // Leftover junk
1.714 + if (errno) return false;
1.715 + if (dest == NULL) return true;
1.716 + *(reinterpret_cast<long*>(dest)) = r;
1.717 + return true;
1.718 +}
1.719 +
1.720 +bool Arg::parse_ulong_radix(const char* str,
1.721 + int n,
1.722 + void* dest,
1.723 + int radix) {
1.724 + if (n == 0) return false;
1.725 + char buf[kMaxNumberLength+1];
1.726 + str = TerminateNumber(buf, str, n);
1.727 + if (str[0] == '-') return false; // strtoul() on a negative number?!
1.728 + char* end;
1.729 + errno = 0;
1.730 + unsigned long r = strtoul(str, &end, radix);
1.731 + if (end != str + n) return false; // Leftover junk
1.732 + if (errno) return false;
1.733 + if (dest == NULL) return true;
1.734 + *(reinterpret_cast<unsigned long*>(dest)) = r;
1.735 + return true;
1.736 +}
1.737 +
1.738 +bool Arg::parse_short_radix(const char* str,
1.739 + int n,
1.740 + void* dest,
1.741 + int radix) {
1.742 + long r;
1.743 + if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse
1.744 + if (r < SHRT_MIN || r > SHRT_MAX) return false; // Out of range
1.745 + if (dest == NULL) return true;
1.746 + *(reinterpret_cast<short*>(dest)) = static_cast<short>(r);
1.747 + return true;
1.748 +}
1.749 +
1.750 +bool Arg::parse_ushort_radix(const char* str,
1.751 + int n,
1.752 + void* dest,
1.753 + int radix) {
1.754 + unsigned long r;
1.755 + if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse
1.756 + if (r > USHRT_MAX) return false; // Out of range
1.757 + if (dest == NULL) return true;
1.758 + *(reinterpret_cast<unsigned short*>(dest)) = static_cast<unsigned short>(r);
1.759 + return true;
1.760 +}
1.761 +
1.762 +bool Arg::parse_int_radix(const char* str,
1.763 + int n,
1.764 + void* dest,
1.765 + int radix) {
1.766 + long r;
1.767 + if (!parse_long_radix(str, n, &r, radix)) return false; // Could not parse
1.768 + if (r < INT_MIN || r > INT_MAX) return false; // Out of range
1.769 + if (dest == NULL) return true;
1.770 + *(reinterpret_cast<int*>(dest)) = r;
1.771 + return true;
1.772 +}
1.773 +
1.774 +bool Arg::parse_uint_radix(const char* str,
1.775 + int n,
1.776 + void* dest,
1.777 + int radix) {
1.778 + unsigned long r;
1.779 + if (!parse_ulong_radix(str, n, &r, radix)) return false; // Could not parse
1.780 + if (r > UINT_MAX) return false; // Out of range
1.781 + if (dest == NULL) return true;
1.782 + *(reinterpret_cast<unsigned int*>(dest)) = r;
1.783 + return true;
1.784 +}
1.785 +
1.786 +bool Arg::parse_longlong_radix(const char* str,
1.787 + int n,
1.788 + void* dest,
1.789 + int radix) {
1.790 +#ifndef HAVE_LONG_LONG
1.791 + return false;
1.792 +#else
1.793 + if (n == 0) return false;
1.794 + char buf[kMaxNumberLength+1];
1.795 + str = TerminateNumber(buf, str, n);
1.796 + char* end;
1.797 + errno = 0;
1.798 +#if defined HAVE_STRTOQ
1.799 + long long r = strtoq(str, &end, radix);
1.800 +#elif defined HAVE_STRTOLL
1.801 + long long r = strtoll(str, &end, radix);
1.802 +#elif defined HAVE__STRTOI64
1.803 + long long r = _strtoi64(str, &end, radix);
1.804 +#else
1.805 +#error parse_longlong_radix: cannot convert input to a long-long
1.806 +#endif
1.807 + if (end != str + n) return false; // Leftover junk
1.808 + if (errno) return false;
1.809 + if (dest == NULL) return true;
1.810 + *(reinterpret_cast<long long*>(dest)) = r;
1.811 + return true;
1.812 +#endif /* HAVE_LONG_LONG */
1.813 +}
1.814 +
1.815 +bool Arg::parse_ulonglong_radix(const char* str,
1.816 + int n,
1.817 + void* dest,
1.818 + int radix) {
1.819 +#ifndef HAVE_UNSIGNED_LONG_LONG
1.820 + return false;
1.821 +#else
1.822 + if (n == 0) return false;
1.823 + char buf[kMaxNumberLength+1];
1.824 + str = TerminateNumber(buf, str, n);
1.825 + if (str[0] == '-') return false; // strtoull() on a negative number?!
1.826 + char* end;
1.827 + errno = 0;
1.828 +#if defined HAVE_STRTOQ
1.829 + unsigned long long r = strtouq(str, &end, radix);
1.830 +#elif defined HAVE_STRTOLL
1.831 + unsigned long long r = strtoull(str, &end, radix);
1.832 +#elif defined HAVE__STRTOI64
1.833 + unsigned long long r = _strtoui64(str, &end, radix);
1.834 +#else
1.835 +#error parse_ulonglong_radix: cannot convert input to a long-long
1.836 +#endif
1.837 + if (end != str + n) return false; // Leftover junk
1.838 + if (errno) return false;
1.839 + if (dest == NULL) return true;
1.840 + *(reinterpret_cast<unsigned long long*>(dest)) = r;
1.841 + return true;
1.842 +#endif /* HAVE_UNSIGNED_LONG_LONG */
1.843 +}
1.844 +
1.845 +bool Arg::parse_double(const char* str, int n, void* dest) {
1.846 + if (n == 0) return false;
1.847 + static const int kMaxLength = 200;
1.848 + char buf[kMaxLength];
1.849 + if (n >= kMaxLength) return false;
1.850 + memcpy(buf, str, n);
1.851 + buf[n] = '\0';
1.852 + errno = 0;
1.853 + char* end;
1.854 + double r = strtod(buf, &end);
1.855 + if (end != buf + n) return false; // Leftover junk
1.856 + if (errno) return false;
1.857 + if (dest == NULL) return true;
1.858 + *(reinterpret_cast<double*>(dest)) = r;
1.859 + return true;
1.860 +}
1.861 +
1.862 +bool Arg::parse_float(const char* str, int n, void* dest) {
1.863 + double r;
1.864 + if (!parse_double(str, n, &r)) return false;
1.865 + if (dest == NULL) return true;
1.866 + *(reinterpret_cast<float*>(dest)) = static_cast<float>(r);
1.867 + return true;
1.868 +}
1.869 +
1.870 +
1.871 +#define DEFINE_INTEGER_PARSERS(name) \
1.872 + bool Arg::parse_##name(const char* str, int n, void* dest) { \
1.873 + return parse_##name##_radix(str, n, dest, 10); \
1.874 + } \
1.875 + bool Arg::parse_##name##_hex(const char* str, int n, void* dest) { \
1.876 + return parse_##name##_radix(str, n, dest, 16); \
1.877 + } \
1.878 + bool Arg::parse_##name##_octal(const char* str, int n, void* dest) { \
1.879 + return parse_##name##_radix(str, n, dest, 8); \
1.880 + } \
1.881 + bool Arg::parse_##name##_cradix(const char* str, int n, void* dest) { \
1.882 + return parse_##name##_radix(str, n, dest, 0); \
1.883 + }
1.884 +
1.885 +DEFINE_INTEGER_PARSERS(short) /* */
1.886 +DEFINE_INTEGER_PARSERS(ushort) /* */
1.887 +DEFINE_INTEGER_PARSERS(int) /* Don't use semicolons after these */
1.888 +DEFINE_INTEGER_PARSERS(uint) /* statements because they can cause */
1.889 +DEFINE_INTEGER_PARSERS(long) /* compiler warnings if the checking */
1.890 +DEFINE_INTEGER_PARSERS(ulong) /* level is turned up high enough. */
1.891 +DEFINE_INTEGER_PARSERS(longlong) /* */
1.892 +DEFINE_INTEGER_PARSERS(ulonglong) /* */
1.893 +
1.894 +#undef DEFINE_INTEGER_PARSERS
1.895 +
1.896 +} // namespace pcrecpp