Generates non-fatal failures and returns false if regex is invalid; otherwise returns true.
| 9296 | // Generates non-fatal failures and returns false if regex is invalid; |
| 9297 | // otherwise returns true. |
| 9298 | bool ValidateRegex(const char* regex) { |
| 9299 | if (regex == NULL) { |
| 9300 | // TODO(wan@google.com): fix the source file location in the |
| 9301 | // assertion failures to match where the regex is used in user |
| 9302 | // code. |
| 9303 | ADD_FAILURE() << "NULL is not a valid simple regular expression."; |
| 9304 | return false; |
| 9305 | } |
| 9306 | |
| 9307 | bool is_valid = true; |
| 9308 | |
| 9309 | // True iff ?, *, or + can follow the previous atom. |
| 9310 | bool prev_repeatable = false; |
| 9311 | for (int i = 0; regex[i]; i++) { |
| 9312 | if (regex[i] == '\\') { // An escape sequence |
| 9313 | i++; |
| 9314 | if (regex[i] == '\0') { |
| 9315 | ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) |
| 9316 | << "'\\' cannot appear at the end."; |
| 9317 | return false; |
| 9318 | } |
| 9319 | |
| 9320 | if (!IsValidEscape(regex[i])) { |
| 9321 | ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) |
| 9322 | << "invalid escape sequence \"\\" << regex[i] << "\"."; |
| 9323 | is_valid = false; |
| 9324 | } |
| 9325 | prev_repeatable = true; |
| 9326 | } else { // Not an escape sequence. |
| 9327 | const char ch = regex[i]; |
| 9328 | |
| 9329 | if (ch == '^' && i > 0) { |
| 9330 | ADD_FAILURE() << FormatRegexSyntaxError(regex, i) |
| 9331 | << "'^' can only appear at the beginning."; |
| 9332 | is_valid = false; |
| 9333 | } else if (ch == '$' && regex[i + 1] != '\0') { |
| 9334 | ADD_FAILURE() << FormatRegexSyntaxError(regex, i) |
| 9335 | << "'$' can only appear at the end."; |
| 9336 | is_valid = false; |
| 9337 | } else if (IsInSet(ch, "()[]{}|")) { |
| 9338 | ADD_FAILURE() << FormatRegexSyntaxError(regex, i) |
| 9339 | << "'" << ch << "' is unsupported."; |
| 9340 | is_valid = false; |
| 9341 | } else if (IsRepeat(ch) && !prev_repeatable) { |
| 9342 | ADD_FAILURE() << FormatRegexSyntaxError(regex, i) |
| 9343 | << "'" << ch << "' can only follow a repeatable token."; |
| 9344 | is_valid = false; |
| 9345 | } |
| 9346 | |
| 9347 | prev_repeatable = !IsInSet(ch, "^$?*+"); |
| 9348 | } |
| 9349 | } |
| 9350 | |
| 9351 | return is_valid; |
| 9352 | } |
| 9353 | |
| 9354 | // Matches a repeated regex atom followed by a valid simple regular |
| 9355 | // expression. The regex atom is defined as c if escaped is false, |
no test coverage detected