darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 1 | /* This is JavaScriptCore's variant of the PCRE library. While this library |
| 2 | started out as a copy of PCRE, many of the features of PCRE have been |
| 3 | removed. This library now supports only the regular expression features |
| 4 | required by the JavaScript language specification, and has only the functions |
| 5 | needed by JavaScriptCore and the rest of WebKit. |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 6 | |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 7 | Originally written by Philip Hazel |
darin | ae790da | 2007-10-17 05:38:39 +0000 | [diff] [blame] | 8 | Copyright (c) 1997-2006 University of Cambridge |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 9 | Copyright (C) 2002, 2004, 2006, 2007 Apple Inc. All rights reserved. |
eric@webkit.org | 4cacbe4 | 2007-11-29 11:26:33 +0000 | [diff] [blame] | 10 | Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 11 | |
| 12 | ----------------------------------------------------------------------------- |
| 13 | Redistribution and use in source and binary forms, with or without |
| 14 | modification, are permitted provided that the following conditions are met: |
| 15 | |
| 16 | * Redistributions of source code must retain the above copyright notice, |
| 17 | this list of conditions and the following disclaimer. |
| 18 | |
| 19 | * Redistributions in binary form must reproduce the above copyright |
| 20 | notice, this list of conditions and the following disclaimer in the |
| 21 | documentation and/or other materials provided with the distribution. |
| 22 | |
| 23 | * Neither the name of the University of Cambridge nor the names of its |
| 24 | contributors may be used to endorse or promote products derived from |
| 25 | this software without specific prior written permission. |
| 26 | |
| 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 30 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| 31 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 32 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 33 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 34 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 35 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 36 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| 37 | POSSIBILITY OF SUCH DAMAGE. |
| 38 | ----------------------------------------------------------------------------- |
| 39 | */ |
| 40 | |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 41 | /* This module contains the external function jsRegExpExecute(), along with |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 42 | supporting internal functions that are not used by other modules. */ |
| 43 | |
darin@apple.com | 7f98487 | 2007-11-12 23:04:41 +0000 | [diff] [blame] | 44 | #include "config.h" |
| 45 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 46 | #include "pcre_internal.h" |
| 47 | |
mrowe@apple.com | 6be8941 | 2007-12-17 06:01:22 +0000 | [diff] [blame] | 48 | #include <string.h> |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 49 | #include <wtf/ASCIICType.h> |
| 50 | #include <wtf/FastMalloc.h> |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 51 | |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 52 | using namespace WTF; |
| 53 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 54 | /* Negative values for the firstchar and reqchar variables */ |
| 55 | |
| 56 | #define REQ_UNSET (-2) |
| 57 | #define REQ_NONE (-1) |
| 58 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 59 | /************************************************* |
| 60 | * Code parameters and static tables * |
| 61 | *************************************************/ |
| 62 | |
| 63 | /* Maximum number of items on the nested bracket stacks at compile time. This |
| 64 | applies to the nesting of all kinds of parentheses. It does not limit |
| 65 | un-nested, non-capturing parentheses. This number can be made bigger if |
| 66 | necessary - it is used to dimension one int and one unsigned char vector at |
| 67 | compile time. */ |
| 68 | |
| 69 | #define BRASTACK_SIZE 200 |
| 70 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 71 | /* Table for handling escaped characters in the range '0'-'z'. Positive returns |
| 72 | are simple data values; negative values are for special things like \d and so |
| 73 | on. Zero means further processing is needed (for things like \x), or the escape |
| 74 | is invalid. */ |
| 75 | |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 76 | static const short escapes[] = { |
darin | 74feca6 | 2007-07-19 21:10:40 +0000 | [diff] [blame] | 77 | 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ |
| 78 | 0, 0, ':', ';', '<', '=', '>', '?', /* 8 - ? */ |
| 79 | '@', 0, -ESC_B, 0, -ESC_D, 0, 0, 0, /* @ - G */ |
| 80 | 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ |
| 81 | 0, 0, 0, -ESC_S, 0, 0, 0, -ESC_W, /* P - W */ |
| 82 | 0, 0, 0, '[', '\\', ']', '^', '_', /* X - _ */ |
darin@apple.com | 7ecf0c3 | 2007-11-04 06:18:31 +0000 | [diff] [blame] | 83 | '`', 7, -ESC_b, 0, -ESC_d, 0, '\f', 0, /* ` - g */ |
| 84 | 0, 0, 0, 0, 0, 0, '\n', 0, /* h - o */ |
| 85 | 0, 0, '\r', -ESC_s, '\t', 0, '\v', -ESC_w, /* p - w */ |
darin | 74feca6 | 2007-07-19 21:10:40 +0000 | [diff] [blame] | 86 | 0, 0, 0 /* x - z */ |
| 87 | }; |
darin | ae790da | 2007-10-17 05:38:39 +0000 | [diff] [blame] | 88 | |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 89 | /* Error code numbers. They are given names so that they can more easily be |
| 90 | tracked. */ |
| 91 | |
eric@webkit.org | f2e7c2d | 2007-11-29 11:18:16 +0000 | [diff] [blame] | 92 | enum ErrorCode { |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 93 | ERR0, ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, |
| 94 | ERR10, ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17 |
eric@webkit.org | f2e7c2d | 2007-11-29 11:18:16 +0000 | [diff] [blame] | 95 | }; |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 96 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 97 | /* The texts of compile-time error messages. These are "char *" because they |
| 98 | are passed to the outside world. */ |
| 99 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 100 | static const char* errorText(ErrorCode code) |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 101 | { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 102 | static const char errorTexts[] = |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 103 | /* 1 */ |
| 104 | "\\ at end of pattern\0" |
| 105 | "\\c at end of pattern\0" |
| 106 | "character value in \\x{...} sequence is too large\0" |
| 107 | "numbers out of order in {} quantifier\0" |
| 108 | /* 5 */ |
| 109 | "number too big in {} quantifier\0" |
| 110 | "missing terminating ] for character class\0" |
| 111 | "internal error: code overflow\0" |
| 112 | "range out of order in character class\0" |
| 113 | "nothing to repeat\0" |
| 114 | /* 10 */ |
| 115 | "unmatched parentheses\0" |
| 116 | "internal error: unexpected repeat\0" |
| 117 | "unrecognized character after (?\0" |
| 118 | "failed to get memory\0" |
| 119 | "missing )\0" |
| 120 | /* 15 */ |
| 121 | "reference to non-existent subpattern\0" |
| 122 | "regular expression too large\0" |
| 123 | "parentheses nested too deeply" |
| 124 | ; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 125 | |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 126 | int i = code; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 127 | const char* text = errorTexts; |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 128 | while (i > 1) |
| 129 | i -= !*text++; |
| 130 | return text; |
| 131 | } |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 132 | |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 133 | /* Structure for passing "static" information around between the functions |
| 134 | doing the compiling. */ |
| 135 | |
| 136 | struct CompileData { |
| 137 | CompileData() { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 138 | topBackref = 0; |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 139 | backrefMap = 0; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 140 | reqVaryOpt = 0; |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 141 | needOuterBracket = false; |
darin@apple.com | f9c8dd5 | 2008-01-03 06:39:50 +0000 | [diff] [blame] | 142 | numCapturingBrackets = 0; |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 143 | } |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 144 | int topBackref; /* Maximum back reference */ |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 145 | unsigned backrefMap; /* Bitmap of low back refs */ |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 146 | int reqVaryOpt; /* "After variable item" flag for reqByte */ |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 147 | bool needOuterBracket; |
darin@apple.com | f9c8dd5 | 2008-01-03 06:39:50 +0000 | [diff] [blame] | 148 | int numCapturingBrackets; |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 149 | }; |
| 150 | |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 151 | /* Definitions to allow mutual recursion */ |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 152 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 153 | static bool compileBracket(int, int*, unsigned char**, const UChar**, const UChar*, ErrorCode*, int, int*, int*, CompileData&); |
| 154 | static bool bracketIsAnchored(const unsigned char* code); |
| 155 | static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap); |
| 156 | static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert); |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 157 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 158 | /************************************************* |
| 159 | * Handle escapes * |
| 160 | *************************************************/ |
| 161 | |
| 162 | /* This function is called when a \ has been encountered. It either returns a |
| 163 | positive value for a simple escape such as \n, or a negative value which |
| 164 | encodes one of the more complicated things such as \d. When UTF-8 is enabled, |
| 165 | a positive value greater than 255 may be returned. On entry, ptr is pointing at |
| 166 | the \. On exit, it is on the final character of the escape sequence. |
| 167 | |
| 168 | Arguments: |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 169 | ptrPtr points to the pattern position pointer |
| 170 | errorCodePtr points to the errorcode variable |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 171 | bracount number of previous extracting brackets |
| 172 | options the options bits |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 173 | isClass true if inside a character class |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 174 | |
| 175 | Returns: zero or positive => a data character |
| 176 | negative => a special escape sequence |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 177 | on error, errorPtr is set |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 178 | */ |
| 179 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 180 | static int checkEscape(const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int bracount, bool isClass) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 181 | { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 182 | const UChar* ptr = *ptrPtr + 1; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 183 | |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 184 | /* If backslash is at the end of the pattern, it's an error. */ |
| 185 | if (ptr == patternEnd) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 186 | *errorCodePtr = ERR1; |
| 187 | *ptrPtr = ptr; |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 188 | return 0; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 189 | } |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 190 | |
| 191 | int c = *ptr; |
| 192 | |
| 193 | /* Non-alphamerics are literals. For digits or letters, do an initial lookup in |
| 194 | a table. A non-zero result is something that can be returned immediately. |
| 195 | Otherwise further processing may be required. */ |
| 196 | |
| 197 | if (c < '0' || c > 'z') { /* Not alphameric */ |
darin@apple.com | 9be07b6 | 2007-12-17 01:26:54 +0000 | [diff] [blame] | 198 | } else if (int escapeValue = escapes[c - '0']) { |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 199 | c = escapeValue; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 200 | if (isClass) { |
darin@apple.com | 9be07b6 | 2007-12-17 01:26:54 +0000 | [diff] [blame] | 201 | if (-c == ESC_b) |
| 202 | c = '\b'; /* \b is backslash in a class */ |
| 203 | else if (-c == ESC_B) |
| 204 | c = 'B'; /* and \B is a capital B in a class (in browsers event though ECMAScript 15.10.2.19 says it raises an error) */ |
| 205 | } |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 206 | /* Escapes that need further processing, or are illegal. */ |
| 207 | |
darin@apple.com | 9be07b6 | 2007-12-17 01:26:54 +0000 | [diff] [blame] | 208 | } else { |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 209 | switch (c) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 210 | case '1': |
| 211 | case '2': |
| 212 | case '3': |
| 213 | case '4': |
| 214 | case '5': |
| 215 | case '6': |
| 216 | case '7': |
| 217 | case '8': |
| 218 | case '9': |
| 219 | /* Escape sequences starting with a non-zero digit are backreferences, |
| 220 | unless there are insufficient brackets, in which case they are octal |
| 221 | escape sequences. Those sequences end on the first non-octal character |
| 222 | or when we overflow 0-255, whichever comes first. */ |
| 223 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 224 | if (!isClass) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 225 | const UChar* oldptr = ptr; |
| 226 | c -= '0'; |
| 227 | while ((ptr + 1 < patternEnd) && isASCIIDigit(ptr[1]) && c <= bracount) |
| 228 | c = c * 10 + *(++ptr) - '0'; |
| 229 | if (c <= bracount) { |
| 230 | c = -(ESC_REF + c); |
| 231 | break; |
| 232 | } |
| 233 | ptr = oldptr; /* Put the pointer back and fall through */ |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 234 | } |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 235 | |
| 236 | /* Handle an octal number following \. If the first digit is 8 or 9, |
| 237 | this is not octal. */ |
| 238 | |
| 239 | if ((c = *ptr) >= '8') |
| 240 | break; |
| 241 | |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 242 | /* \0 always starts an octal number, but we may drop through to here with a |
| 243 | larger first octal digit. */ |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 244 | |
| 245 | case '0': { |
| 246 | c -= '0'; |
| 247 | int i; |
| 248 | for (i = 1; i <= 2; ++i) { |
| 249 | if (ptr + i >= patternEnd || ptr[i] < '0' || ptr[i] > '7') |
| 250 | break; |
| 251 | int cc = c * 8 + ptr[i] - '0'; |
| 252 | if (cc > 255) |
| 253 | break; |
| 254 | c = cc; |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 255 | } |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 256 | ptr += i - 1; |
| 257 | break; |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 258 | } |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 259 | |
| 260 | case 'x': { |
| 261 | c = 0; |
| 262 | int i; |
| 263 | for (i = 1; i <= 2; ++i) { |
| 264 | if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { |
| 265 | c = 'x'; |
| 266 | i = 1; |
| 267 | break; |
| 268 | } |
| 269 | int cc = ptr[i]; |
| 270 | if (cc >= 'a') |
| 271 | cc -= 32; /* Convert to upper case */ |
| 272 | c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 273 | } |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 274 | ptr += i - 1; |
| 275 | break; |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 276 | } |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 277 | |
| 278 | case 'u': { |
| 279 | c = 0; |
| 280 | int i; |
| 281 | for (i = 1; i <= 4; ++i) { |
| 282 | if (ptr + i >= patternEnd || !isASCIIHexDigit(ptr[i])) { |
| 283 | c = 'u'; |
| 284 | i = 1; |
| 285 | break; |
| 286 | } |
| 287 | int cc = ptr[i]; |
| 288 | if (cc >= 'a') |
| 289 | cc -= 32; /* Convert to upper case */ |
| 290 | c = c * 16 + cc - ((cc < 'A') ? '0' : ('A' - 10)); |
| 291 | } |
| 292 | ptr += i - 1; |
| 293 | break; |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 294 | } |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 295 | |
| 296 | case 'c': |
| 297 | if (++ptr == patternEnd) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 298 | *errorCodePtr = ERR2; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 299 | return 0; |
| 300 | } |
| 301 | c = *ptr; |
| 302 | |
| 303 | /* A letter is upper-cased; then the 0x40 bit is flipped. This coding |
| 304 | is ASCII-specific, but then the whole concept of \cx is ASCII-specific. */ |
| 305 | c = toASCIIUpper(c) ^ 0x40; |
| 306 | break; |
| 307 | } |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 308 | } |
| 309 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 310 | *ptrPtr = ptr; |
eric@webkit.org | 3029ab8 | 2007-11-29 11:17:32 +0000 | [diff] [blame] | 311 | return c; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 312 | } |
| 313 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 314 | /************************************************* |
| 315 | * Check for counted repeat * |
| 316 | *************************************************/ |
| 317 | |
| 318 | /* This function is called when a '{' is encountered in a place where it might |
| 319 | start a quantifier. It looks ahead to see if it really is a quantifier or not. |
| 320 | It is only a quantifier if it is one of the forms {ddd} {ddd,} or {ddd,ddd} |
| 321 | where the ddds are digits. |
| 322 | |
| 323 | Arguments: |
| 324 | p pointer to the first char after '{' |
| 325 | |
darin@apple.com | 7f98487 | 2007-11-12 23:04:41 +0000 | [diff] [blame] | 326 | Returns: true or false |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 327 | */ |
| 328 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 329 | static bool isCountedRepeat(const UChar* p, const UChar* patternEnd) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 330 | { |
eric@webkit.org | f2e7c2d | 2007-11-29 11:18:16 +0000 | [diff] [blame] | 331 | if (p >= patternEnd || !isASCIIDigit(*p)) |
| 332 | return false; |
ddkilzer | e171463 | 2007-01-02 05:13:00 +0000 | [diff] [blame] | 333 | p++; |
eric@webkit.org | f2e7c2d | 2007-11-29 11:18:16 +0000 | [diff] [blame] | 334 | while (p < patternEnd && isASCIIDigit(*p)) |
| 335 | p++; |
| 336 | if (p < patternEnd && *p == '}') |
| 337 | return true; |
| 338 | |
| 339 | if (p >= patternEnd || *p++ != ',') |
| 340 | return false; |
| 341 | if (p < patternEnd && *p == '}') |
| 342 | return true; |
| 343 | |
| 344 | if (p >= patternEnd || !isASCIIDigit(*p)) |
| 345 | return false; |
ddkilzer | e171463 | 2007-01-02 05:13:00 +0000 | [diff] [blame] | 346 | p++; |
eric@webkit.org | f2e7c2d | 2007-11-29 11:18:16 +0000 | [diff] [blame] | 347 | while (p < patternEnd && isASCIIDigit(*p)) |
| 348 | p++; |
| 349 | |
| 350 | return (p < patternEnd && *p == '}'); |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 351 | } |
| 352 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 353 | /************************************************* |
| 354 | * Read repeat counts * |
| 355 | *************************************************/ |
| 356 | |
| 357 | /* Read an item of the form {n,m} and return the values. This is called only |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 358 | after isCountedRepeat() has confirmed that a repeat-count quantifier exists, |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 359 | so the syntax is guaranteed to be correct, but we need to check the values. |
| 360 | |
| 361 | Arguments: |
| 362 | p pointer to first char after '{' |
| 363 | minp pointer to int for min |
| 364 | maxp pointer to int for max |
| 365 | returned as -1 if no max |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 366 | errorCodePtr points to error code variable |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 367 | |
| 368 | Returns: pointer to '}' on success; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 369 | current ptr on error, with errorCodePtr set non-zero |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 370 | */ |
| 371 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 372 | static const UChar* readRepeatCounts(const UChar* p, int* minp, int* maxp, ErrorCode* errorCodePtr) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 373 | { |
eric@webkit.org | 3c8d15cd | 2007-11-29 11:07:57 +0000 | [diff] [blame] | 374 | int min = 0; |
| 375 | int max = -1; |
| 376 | |
| 377 | /* Read the minimum value and do a paranoid check: a negative value indicates |
| 378 | an integer overflow. */ |
| 379 | |
| 380 | while (isASCIIDigit(*p)) |
| 381 | min = min * 10 + *p++ - '0'; |
| 382 | if (min < 0 || min > 65535) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 383 | *errorCodePtr = ERR5; |
eric@webkit.org | 3c8d15cd | 2007-11-29 11:07:57 +0000 | [diff] [blame] | 384 | return p; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 385 | } |
eric@webkit.org | 3c8d15cd | 2007-11-29 11:07:57 +0000 | [diff] [blame] | 386 | |
| 387 | /* Read the maximum value if there is one, and again do a paranoid on its size. |
| 388 | Also, max must not be less than min. */ |
| 389 | |
| 390 | if (*p == '}') |
| 391 | max = min; |
| 392 | else { |
| 393 | if (*(++p) != '}') { |
| 394 | max = 0; |
| 395 | while (isASCIIDigit(*p)) |
| 396 | max = max * 10 + *p++ - '0'; |
| 397 | if (max < 0 || max > 65535) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 398 | *errorCodePtr = ERR5; |
eric@webkit.org | 3c8d15cd | 2007-11-29 11:07:57 +0000 | [diff] [blame] | 399 | return p; |
| 400 | } |
| 401 | if (max < min) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 402 | *errorCodePtr = ERR4; |
eric@webkit.org | 3c8d15cd | 2007-11-29 11:07:57 +0000 | [diff] [blame] | 403 | return p; |
| 404 | } |
| 405 | } |
| 406 | } |
| 407 | |
| 408 | /* Fill in the required variables, and pass back the pointer to the terminating |
| 409 | '}'. */ |
| 410 | |
| 411 | *minp = min; |
| 412 | *maxp = max; |
| 413 | return p; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 414 | } |
| 415 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 416 | /************************************************* |
| 417 | * Find first significant op code * |
| 418 | *************************************************/ |
| 419 | |
| 420 | /* This is called by several functions that scan a compiled expression looking |
| 421 | for a fixed first character, or an anchoring op code etc. It skips over things |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 422 | that do not influence this. |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 423 | |
| 424 | Arguments: |
| 425 | code pointer to the start of the group |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 426 | Returns: pointer to the first significant opcode |
| 427 | */ |
| 428 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 429 | static const unsigned char* firstSignificantOpcode(const unsigned char* code) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 430 | { |
eric@webkit.org | d0cc3fd | 2007-11-29 11:18:59 +0000 | [diff] [blame] | 431 | while (*code == OP_BRANUMBER) |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 432 | code += 3; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 433 | return code; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 434 | } |
| 435 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 436 | static const unsigned char* firstSignificantOpcodeSkippingAssertions(const unsigned char* code) |
eric@webkit.org | d0cc3fd | 2007-11-29 11:18:59 +0000 | [diff] [blame] | 437 | { |
| 438 | while (true) { |
| 439 | switch (*code) { |
eric@webkit.org | 740cc73 | 2007-11-29 11:16:48 +0000 | [diff] [blame] | 440 | case OP_ASSERT_NOT: |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 441 | advanceToEndOfBracket(code); |
| 442 | code += 1 + LINK_SIZE; |
| 443 | break; |
eric@webkit.org | 740cc73 | 2007-11-29 11:16:48 +0000 | [diff] [blame] | 444 | case OP_WORD_BOUNDARY: |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 445 | case OP_NOT_WORD_BOUNDARY: |
| 446 | ++code; |
eric@webkit.org | 740cc73 | 2007-11-29 11:16:48 +0000 | [diff] [blame] | 447 | break; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 448 | case OP_BRANUMBER: |
| 449 | code += 3; |
eric@webkit.org | 740cc73 | 2007-11-29 11:16:48 +0000 | [diff] [blame] | 450 | break; |
eric@webkit.org | 740cc73 | 2007-11-29 11:16:48 +0000 | [diff] [blame] | 451 | default: |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 452 | return code; |
eric@webkit.org | 740cc73 | 2007-11-29 11:16:48 +0000 | [diff] [blame] | 453 | } |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 454 | } |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 455 | } |
| 456 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 457 | /************************************************* |
| 458 | * Get othercase range * |
| 459 | *************************************************/ |
| 460 | |
| 461 | /* This function is passed the start and end of a class range, in UTF-8 mode |
| 462 | with UCP support. It searches up the characters, looking for internal ranges of |
| 463 | characters in the "other" case. Each call returns the next one, updating the |
| 464 | start address. |
| 465 | |
| 466 | Arguments: |
| 467 | cptr points to starting character value; updated |
| 468 | d end value |
| 469 | ocptr where to put start of othercase range |
| 470 | odptr where to put end of othercase range |
| 471 | |
darin@apple.com | 7f98487 | 2007-11-12 23:04:41 +0000 | [diff] [blame] | 472 | Yield: true when range returned; false when no more |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 473 | */ |
| 474 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 475 | static bool getOthercaseRange(int* cptr, int d, int* ocptr, int* odptr) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 476 | { |
eric@webkit.org | 32f7c43 | 2007-11-29 11:12:11 +0000 | [diff] [blame] | 477 | int c, othercase = 0; |
eric@webkit.org | 5fa9832 | 2007-11-29 11:06:02 +0000 | [diff] [blame] | 478 | |
| 479 | for (c = *cptr; c <= d; c++) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 480 | if ((othercase = kjs_pcre_ucp_othercase(c)) >= 0) |
eric@webkit.org | 5fa9832 | 2007-11-29 11:06:02 +0000 | [diff] [blame] | 481 | break; |
| 482 | } |
| 483 | |
| 484 | if (c > d) |
| 485 | return false; |
| 486 | |
| 487 | *ocptr = othercase; |
eric@webkit.org | 32f7c43 | 2007-11-29 11:12:11 +0000 | [diff] [blame] | 488 | int next = othercase + 1; |
eric@webkit.org | 5fa9832 | 2007-11-29 11:06:02 +0000 | [diff] [blame] | 489 | |
| 490 | for (++c; c <= d; c++) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 491 | if (kjs_pcre_ucp_othercase(c) != next) |
eric@webkit.org | 5fa9832 | 2007-11-29 11:06:02 +0000 | [diff] [blame] | 492 | break; |
| 493 | next++; |
| 494 | } |
| 495 | |
| 496 | *odptr = next - 1; |
| 497 | *cptr = c; |
| 498 | |
| 499 | return true; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 500 | } |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 501 | |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 502 | /************************************************* |
| 503 | * Convert character value to UTF-8 * |
| 504 | *************************************************/ |
| 505 | |
| 506 | /* This function takes an integer value in the range 0 - 0x7fffffff |
| 507 | and encodes it as a UTF-8 character in 0 to 6 bytes. |
| 508 | |
| 509 | Arguments: |
| 510 | cvalue the character value |
| 511 | buffer pointer to buffer for result - at least 6 bytes long |
| 512 | |
| 513 | Returns: number of characters placed in the buffer |
| 514 | */ |
| 515 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 516 | static int encodeUTF8(int cvalue, unsigned char *buffer) |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 517 | { |
| 518 | int i; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 519 | for (i = 0; i < kjs_pcre_utf8_table1_size; i++) |
| 520 | if (cvalue <= kjs_pcre_utf8_table1[i]) |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 521 | break; |
| 522 | buffer += i; |
| 523 | for (int j = i; j > 0; j--) { |
| 524 | *buffer-- = 0x80 | (cvalue & 0x3f); |
| 525 | cvalue >>= 6; |
| 526 | } |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 527 | *buffer = kjs_pcre_utf8_table2[i] | cvalue; |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 528 | return i + 1; |
| 529 | } |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 530 | |
| 531 | /************************************************* |
| 532 | * Compile one branch * |
| 533 | *************************************************/ |
| 534 | |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 535 | /* Scan the pattern, compiling it into the code vector. |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 536 | |
| 537 | Arguments: |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 538 | options the option bits |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 539 | brackets points to number of extracting brackets used |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 540 | codePtr points to the pointer to the current code point |
| 541 | ptrPtr points to the current pattern pointer |
| 542 | errorCodePtr points to error code variable |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 543 | firstbyteptr set to initial literal character, or < 0 (REQ_UNSET, REQ_NONE) |
| 544 | reqbyteptr set to the last literal character required, else < 0 |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 545 | cd contains pointers to tables etc. |
| 546 | |
darin@apple.com | 7f98487 | 2007-11-12 23:04:41 +0000 | [diff] [blame] | 547 | Returns: true on success |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 548 | false, with *errorCodePtr set non-zero on error |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 549 | */ |
| 550 | |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 551 | static inline bool safelyCheckNextChar(const UChar* ptr, const UChar* patternEnd, UChar expected) |
| 552 | { |
| 553 | return ((ptr + 1 < patternEnd) && ptr[1] == expected); |
| 554 | } |
| 555 | |
eric@webkit.org | c8d4c7d | 2007-11-29 11:09:42 +0000 | [diff] [blame] | 556 | static bool |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 557 | compileBranch(int options, int* brackets, unsigned char** codePtr, |
| 558 | const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int *firstbyteptr, |
eric@webkit.org | 32f7c43 | 2007-11-29 11:12:11 +0000 | [diff] [blame] | 559 | int* reqbyteptr, CompileData& cd) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 560 | { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 561 | int repeatType, opType; |
| 562 | int repeatMin = 0, repeat_max = 0; /* To please picky compilers */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 563 | int bravalue = 0; |
| 564 | int reqvary, tempreqvary; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 565 | int c; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 566 | unsigned char* code = *codePtr; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 567 | unsigned char* tempcode; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 568 | bool didGroupSetFirstByte = false; |
| 569 | const UChar* ptr = *ptrPtr; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 570 | const UChar* tempptr; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 571 | unsigned char* previous = NULL; |
| 572 | unsigned char classbits[32]; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 573 | |
eric@webkit.org | c8d4c7d | 2007-11-29 11:09:42 +0000 | [diff] [blame] | 574 | bool class_utf8; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 575 | unsigned char* class_utf8data; |
| 576 | unsigned char utf8_char[6]; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 577 | |
| 578 | /* Initialize no first byte, no required byte. REQ_UNSET means "no char |
| 579 | matching encountered yet". It gets changed to REQ_NONE if we hit something that |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 580 | matches a non-fixed char first char; reqByte just remains unset if we never |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 581 | find one. |
| 582 | |
| 583 | When we hit a repeat whose minimum is zero, we may have to adjust these values |
| 584 | to take the zero repeat into account. This is implemented by setting them to |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 585 | zeroFirstByte and zeroReqByte when such a repeat is encountered. The individual |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 586 | item types that can be repeated set these backoff variables appropriately. */ |
| 587 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 588 | int firstByte = REQ_UNSET; |
| 589 | int reqByte = REQ_UNSET; |
| 590 | int zeroReqByte = REQ_UNSET; |
| 591 | int zeroFirstByte = REQ_UNSET; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 592 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 593 | /* The variable reqCaseOpt contains either the REQ_IGNORE_CASE value or zero, |
eric@webkit.org | 81716d8 | 2007-11-29 11:19:42 +0000 | [diff] [blame] | 594 | according to the current setting of the ignores-case flag. REQ_IGNORE_CASE is a bit |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 595 | value > 255. It is added into the firstByte or reqByte variables to record the |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 596 | case status of the value. This is used only for ASCII characters. */ |
| 597 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 598 | int reqCaseOpt = (options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 599 | |
| 600 | /* Switch on next character until the end of the branch */ |
| 601 | |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 602 | for (;; ptr++) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 603 | bool negateClass; |
| 604 | bool shouldFlipNegation; /* If a negative special such as \S is used, we should negate the whole class to properly support Unicode. */ |
| 605 | int classCharCount; |
| 606 | int classLastChar; |
| 607 | int skipBytes; |
| 608 | int subReqByte; |
| 609 | int subFirstByte; |
| 610 | int mcLength; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 611 | unsigned char mcbuffer[8]; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 612 | |
| 613 | /* Next byte in the pattern */ |
| 614 | |
| 615 | c = ptr < patternEnd ? *ptr : 0; |
| 616 | |
| 617 | /* Fill in length of a previous callout, except when the next thing is |
| 618 | a quantifier. */ |
| 619 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 620 | bool isQuantifier = c == '*' || c == '+' || c == '?' || (c == '{' && isCountedRepeat(ptr + 1, patternEnd)); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 621 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 622 | switch (c) { |
| 623 | /* The branch terminates at end of string, |, or ). */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 624 | |
| 625 | case 0: |
| 626 | if (ptr < patternEnd) |
| 627 | goto NORMAL_CHAR; |
| 628 | // End of string; fall through |
| 629 | case '|': |
| 630 | case ')': |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 631 | *firstbyteptr = firstByte; |
| 632 | *reqbyteptr = reqByte; |
| 633 | *codePtr = code; |
| 634 | *ptrPtr = ptr; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 635 | return true; |
| 636 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 637 | /* Handle single-character metacharacters. In multiline mode, ^ disables |
| 638 | the setting of any following char as a first character. */ |
eric@webkit.org | 7fbd893 | 2008-03-31 08:01:09 +0000 | [diff] [blame] | 639 | |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 640 | case '^': |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 641 | if (options & MatchAcrossMultipleLinesOption) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 642 | if (firstByte == REQ_UNSET) |
| 643 | firstByte = REQ_NONE; |
eric@webkit.org | 7fbd893 | 2008-03-31 08:01:09 +0000 | [diff] [blame] | 644 | *code++ = OP_BOL; |
| 645 | } else |
| 646 | *code++ = OP_CIRC; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 647 | previous = NULL; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 648 | break; |
eric@webkit.org | 7fbd893 | 2008-03-31 08:01:09 +0000 | [diff] [blame] | 649 | |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 650 | case '$': |
| 651 | previous = NULL; |
eric@webkit.org | 7fbd893 | 2008-03-31 08:01:09 +0000 | [diff] [blame] | 652 | if (options & MatchAcrossMultipleLinesOption) |
| 653 | *code++ = OP_EOL; |
| 654 | else |
| 655 | *code++ = OP_DOLL; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 656 | break; |
eric@webkit.org | 7fbd893 | 2008-03-31 08:01:09 +0000 | [diff] [blame] | 657 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 658 | /* There can never be a first char if '.' is first, whatever happens about |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 659 | repeats. The value of reqByte doesn't change either. */ |
eric@webkit.org | 7fbd893 | 2008-03-31 08:01:09 +0000 | [diff] [blame] | 660 | |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 661 | case '.': |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 662 | if (firstByte == REQ_UNSET) |
| 663 | firstByte = REQ_NONE; |
| 664 | zeroFirstByte = firstByte; |
| 665 | zeroReqByte = reqByte; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 666 | previous = code; |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 667 | *code++ = OP_NOT_NEWLINE; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 668 | break; |
| 669 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 670 | /* Character classes. If the included characters are all < 256, we build a |
| 671 | 32-byte bitmap of the permitted characters, except in the special case |
| 672 | where there is only one such character. For negated classes, we build the |
| 673 | map as usual, then invert it at the end. However, we use a different opcode |
| 674 | so that data characters > 255 can be handled correctly. |
| 675 | |
| 676 | If the class contains characters outside the 0-255 range, a different |
| 677 | opcode is compiled. It may optionally have a bit map for characters < 256, |
| 678 | but those above are are explicitly listed afterwards. A flag byte tells |
| 679 | whether the bitmap is present, and whether this is a negated class or not. |
| 680 | */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 681 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 682 | case '[': { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 683 | previous = code; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 684 | shouldFlipNegation = false; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 685 | |
| 686 | /* PCRE supports POSIX class stuff inside a class. Perl gives an error if |
| 687 | they are encountered at the top level, so we'll do that too. */ |
| 688 | |
| 689 | /* If the first character is '^', set the negation flag and skip it. */ |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 690 | |
aroben@apple.com | 9846753 | 2007-12-01 02:25:07 +0000 | [diff] [blame] | 691 | if (ptr + 1 >= patternEnd) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 692 | *errorCodePtr = ERR6; |
aroben@apple.com | 9846753 | 2007-12-01 02:25:07 +0000 | [diff] [blame] | 693 | return false; |
| 694 | } |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 695 | |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 696 | if (ptr[1] == '^') { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 697 | negateClass = true; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 698 | ++ptr; |
| 699 | } else |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 700 | negateClass = false; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 701 | |
| 702 | /* Keep a count of chars with values < 256 so that we can optimize the case |
| 703 | of just a single character (as long as it's < 256). For higher valued UTF-8 |
| 704 | characters, we don't yet do any optimization. */ |
| 705 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 706 | classCharCount = 0; |
| 707 | classLastChar = -1; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 708 | |
| 709 | class_utf8 = false; /* No chars >= 256 */ |
| 710 | class_utf8data = code + LINK_SIZE + 34; /* For UTF-8 items */ |
| 711 | |
| 712 | /* Initialize the 32-char bit map to all zeros. We have to build the |
| 713 | map in a temporary bit of store, in case the class contains only 1 |
| 714 | character (< 256), because in that case the compiled code doesn't use the |
| 715 | bit map. */ |
| 716 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 717 | memset(classbits, 0, 32 * sizeof(unsigned char)); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 718 | |
| 719 | /* Process characters until ] is reached. The first pass |
| 720 | through the regex checked the overall syntax, so we don't need to be very |
| 721 | strict here. At the start of the loop, c contains the first byte of the |
| 722 | character. */ |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 723 | |
| 724 | while ((++ptr < patternEnd) && (c = *ptr) != ']') { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 725 | /* Backslash may introduce a single character, or it may introduce one |
| 726 | of the specials, which just set a flag. Escaped items are checked for |
| 727 | validity in the pre-compiling pass. The sequence \b is a special case. |
| 728 | Inside a class (and only there) it is treated as backspace. Elsewhere |
| 729 | it marks a word boundary. Other escapes have preset maps ready to |
| 730 | or into the one we are building. We assume they have more than one |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 731 | character in them, so set classCharCount bigger than one. */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 732 | |
| 733 | if (c == '\\') { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 734 | c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 735 | if (c < 0) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 736 | classCharCount += 2; /* Greater than 1 is what matters */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 737 | switch (-c) { |
| 738 | case ESC_d: |
| 739 | for (c = 0; c < 32; c++) |
eric@webkit.org | 4c02335 | 2007-11-29 11:22:30 +0000 | [diff] [blame] | 740 | classbits[c] |= classBitmapForChar(c + cbit_digit); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 741 | continue; |
| 742 | |
| 743 | case ESC_D: |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 744 | shouldFlipNegation = true; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 745 | for (c = 0; c < 32; c++) |
eric@webkit.org | 4c02335 | 2007-11-29 11:22:30 +0000 | [diff] [blame] | 746 | classbits[c] |= ~classBitmapForChar(c + cbit_digit); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 747 | continue; |
| 748 | |
| 749 | case ESC_w: |
| 750 | for (c = 0; c < 32; c++) |
eric@webkit.org | 4c02335 | 2007-11-29 11:22:30 +0000 | [diff] [blame] | 751 | classbits[c] |= classBitmapForChar(c + cbit_word); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 752 | continue; |
| 753 | |
| 754 | case ESC_W: |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 755 | shouldFlipNegation = true; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 756 | for (c = 0; c < 32; c++) |
eric@webkit.org | 4c02335 | 2007-11-29 11:22:30 +0000 | [diff] [blame] | 757 | classbits[c] |= ~classBitmapForChar(c + cbit_word); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 758 | continue; |
| 759 | |
| 760 | case ESC_s: |
| 761 | for (c = 0; c < 32; c++) |
eric@webkit.org | 4c02335 | 2007-11-29 11:22:30 +0000 | [diff] [blame] | 762 | classbits[c] |= classBitmapForChar(c + cbit_space); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 763 | continue; |
| 764 | |
| 765 | case ESC_S: |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 766 | shouldFlipNegation = true; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 767 | for (c = 0; c < 32; c++) |
eric@webkit.org | 4c02335 | 2007-11-29 11:22:30 +0000 | [diff] [blame] | 768 | classbits[c] |= ~classBitmapForChar(c + cbit_space); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 769 | continue; |
| 770 | |
| 771 | /* Unrecognized escapes are faulted if PCRE is running in its |
| 772 | strict mode. By default, for compatibility with Perl, they are |
| 773 | treated as literals. */ |
| 774 | |
| 775 | default: |
| 776 | c = *ptr; /* The final character */ |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 777 | classCharCount -= 2; /* Undo the default count from above */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 778 | } |
| 779 | } |
| 780 | |
| 781 | /* Fall through if we have a single character (c >= 0). This may be |
| 782 | > 256 in UTF-8 mode. */ |
| 783 | |
| 784 | } /* End of backslash handling */ |
| 785 | |
| 786 | /* A single character may be followed by '-' to form a range. However, |
| 787 | Perl does not permit ']' to be the end of the range. A '-' character |
| 788 | here is treated as a literal. */ |
| 789 | |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 790 | if ((ptr + 2 < patternEnd) && ptr[1] == '-' && ptr[2] != ']') { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 791 | ptr += 2; |
| 792 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 793 | int d = *ptr; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 794 | |
| 795 | /* The second part of a range can be a single-character escape, but |
| 796 | not any of the other escapes. Perl 5.6 treats a hyphen as a literal |
| 797 | in such circumstances. */ |
| 798 | |
| 799 | if (d == '\\') { |
| 800 | const UChar* oldptr = ptr; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 801 | d = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, true); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 802 | |
darin@apple.com | 9be07b6 | 2007-12-17 01:26:54 +0000 | [diff] [blame] | 803 | /* \X is literal X; any other special means the '-' was literal */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 804 | if (d < 0) { |
darin@apple.com | 9be07b6 | 2007-12-17 01:26:54 +0000 | [diff] [blame] | 805 | ptr = oldptr - 2; |
| 806 | goto LONE_SINGLE_CHARACTER; /* A few lines below */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 807 | } |
| 808 | } |
| 809 | |
| 810 | /* The check that the two values are in the correct order happens in |
| 811 | the pre-pass. Optimize one-character ranges */ |
| 812 | |
| 813 | if (d == c) |
| 814 | goto LONE_SINGLE_CHARACTER; /* A few lines below */ |
| 815 | |
| 816 | /* In UTF-8 mode, if the upper limit is > 255, or > 127 for caseless |
| 817 | matching, we have to use an XCLASS with extra data items. Caseless |
| 818 | matching for characters > 127 is available only if UCP support is |
| 819 | available. */ |
| 820 | |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 821 | if ((d > 255 || ((options & IgnoreCaseOption) && d > 127))) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 822 | class_utf8 = true; |
| 823 | |
| 824 | /* With UCP support, we can find the other case equivalents of |
| 825 | the relevant characters. There may be several ranges. Optimize how |
| 826 | they fit with the basic range. */ |
| 827 | |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 828 | if (options & IgnoreCaseOption) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 829 | int occ, ocd; |
| 830 | int cc = c; |
| 831 | int origd = d; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 832 | while (getOthercaseRange(&cc, origd, &occ, &ocd)) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 833 | if (occ >= c && ocd <= d) |
| 834 | continue; /* Skip embedded ranges */ |
| 835 | |
| 836 | if (occ < c && ocd >= c - 1) /* Extend the basic range */ |
| 837 | { /* if there is overlap, */ |
| 838 | c = occ; /* noting that if occ < c */ |
| 839 | continue; /* we can't have ocd > d */ |
| 840 | } /* because a subrange is */ |
| 841 | if (ocd > d && occ <= d + 1) /* always shorter than */ |
| 842 | { /* the basic range. */ |
| 843 | d = ocd; |
| 844 | continue; |
| 845 | } |
| 846 | |
| 847 | if (occ == ocd) |
| 848 | *class_utf8data++ = XCL_SINGLE; |
| 849 | else { |
| 850 | *class_utf8data++ = XCL_RANGE; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 851 | class_utf8data += encodeUTF8(occ, class_utf8data); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 852 | } |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 853 | class_utf8data += encodeUTF8(ocd, class_utf8data); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 854 | } |
| 855 | } |
| 856 | |
| 857 | /* Now record the original range, possibly modified for UCP caseless |
| 858 | overlapping ranges. */ |
| 859 | |
| 860 | *class_utf8data++ = XCL_RANGE; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 861 | class_utf8data += encodeUTF8(c, class_utf8data); |
| 862 | class_utf8data += encodeUTF8(d, class_utf8data); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 863 | |
| 864 | /* With UCP support, we are done. Without UCP support, there is no |
| 865 | caseless matching for UTF-8 characters > 127; we can use the bit map |
| 866 | for the smaller ones. */ |
| 867 | |
| 868 | continue; /* With next character in the class */ |
| 869 | } |
| 870 | |
| 871 | /* We use the bit map for all cases when not in UTF-8 mode; else |
| 872 | ranges that lie entirely within 0-127 when there is UCP support; else |
| 873 | for partial ranges without UCP support. */ |
| 874 | |
| 875 | for (; c <= d; c++) { |
| 876 | classbits[c/8] |= (1 << (c&7)); |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 877 | if (options & IgnoreCaseOption) { |
eric@webkit.org | 4c02335 | 2007-11-29 11:22:30 +0000 | [diff] [blame] | 878 | int uc = flipCase(c); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 879 | classbits[uc/8] |= (1 << (uc&7)); |
| 880 | } |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 881 | classCharCount++; /* in case a one-char range */ |
| 882 | classLastChar = c; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 883 | } |
| 884 | |
| 885 | continue; /* Go get the next char in the class */ |
| 886 | } |
| 887 | |
| 888 | /* Handle a lone single character - we can get here for a normal |
| 889 | non-escape char, or after \ that introduces a single character or for an |
| 890 | apparent range that isn't. */ |
| 891 | |
| 892 | LONE_SINGLE_CHARACTER: |
| 893 | |
| 894 | /* Handle a character that cannot go in the bit map */ |
| 895 | |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 896 | if ((c > 255 || ((options & IgnoreCaseOption) && c > 127))) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 897 | class_utf8 = true; |
| 898 | *class_utf8data++ = XCL_SINGLE; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 899 | class_utf8data += encodeUTF8(c, class_utf8data); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 900 | |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 901 | if (options & IgnoreCaseOption) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 902 | int othercase; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 903 | if ((othercase = kjs_pcre_ucp_othercase(c)) >= 0) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 904 | *class_utf8data++ = XCL_SINGLE; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 905 | class_utf8data += encodeUTF8(othercase, class_utf8data); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 906 | } |
| 907 | } |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 908 | } else { |
| 909 | /* Handle a single-byte character */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 910 | classbits[c/8] |= (1 << (c&7)); |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 911 | if (options & IgnoreCaseOption) { |
eric@webkit.org | 4c02335 | 2007-11-29 11:22:30 +0000 | [diff] [blame] | 912 | c = flipCase(c); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 913 | classbits[c/8] |= (1 << (c&7)); |
| 914 | } |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 915 | classCharCount++; |
| 916 | classLastChar = c; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 917 | } |
| 918 | } |
| 919 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 920 | /* If classCharCount is 1, we saw precisely one character whose value is |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 921 | less than 256. In non-UTF-8 mode we can always optimize. In UTF-8 mode, we |
| 922 | can optimize the negative case only if there were no characters >= 128 |
| 923 | because OP_NOT and the related opcodes like OP_NOTSTAR operate on |
| 924 | single-bytes only. This is an historical hangover. Maybe one day we can |
| 925 | tidy these opcodes to handle multi-byte characters. |
| 926 | |
| 927 | The optimization throws away the bit map. We turn the item into a |
| 928 | 1-character OP_CHAR[NC] if it's positive, or OP_NOT if it's negative. Note |
| 929 | that OP_NOT does not support multibyte characters. In the positive case, it |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 930 | can cause firstByte to be set. Otherwise, there can be no first char if |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 931 | this item is first, whatever repeat count may follow. In the case of |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 932 | reqByte, save the previous value for reinstating. */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 933 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 934 | if (classCharCount == 1 && (!class_utf8 && (!negateClass || classLastChar < 128))) { |
| 935 | zeroReqByte = reqByte; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 936 | |
| 937 | /* The OP_NOT opcode works on one-byte characters only. */ |
| 938 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 939 | if (negateClass) { |
| 940 | if (firstByte == REQ_UNSET) |
| 941 | firstByte = REQ_NONE; |
| 942 | zeroFirstByte = firstByte; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 943 | *code++ = OP_NOT; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 944 | *code++ = classLastChar; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 945 | break; |
| 946 | } |
| 947 | |
| 948 | /* For a single, positive character, get the value into c, and |
| 949 | then we can handle this with the normal one-character code. */ |
| 950 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 951 | c = classLastChar; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 952 | goto NORMAL_CHAR; |
| 953 | } /* End of 1-char optimization */ |
| 954 | |
| 955 | /* The general case - not the one-char optimization. If this is the first |
| 956 | thing in the branch, there can be no first char setting, whatever the |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 957 | repeat count. Any reqByte setting must remain unchanged after any kind of |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 958 | repeat. */ |
| 959 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 960 | if (firstByte == REQ_UNSET) firstByte = REQ_NONE; |
| 961 | zeroFirstByte = firstByte; |
| 962 | zeroReqByte = reqByte; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 963 | |
| 964 | /* If there are characters with values > 255, we have to compile an |
| 965 | extended class, with its own opcode. If there are no characters < 256, |
| 966 | we can omit the bitmap. */ |
| 967 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 968 | if (class_utf8 && !shouldFlipNegation) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 969 | *class_utf8data++ = XCL_END; /* Marks the end of extra data */ |
| 970 | *code++ = OP_XCLASS; |
| 971 | code += LINK_SIZE; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 972 | *code = negateClass? XCL_NOT : 0; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 973 | |
| 974 | /* If the map is required, install it, and move on to the end of |
| 975 | the extra data */ |
| 976 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 977 | if (classCharCount > 0) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 978 | *code++ |= XCL_MAP; |
| 979 | memcpy(code, classbits, 32); |
| 980 | code = class_utf8data; |
| 981 | } |
| 982 | |
| 983 | /* If the map is not required, slide down the extra data. */ |
| 984 | |
eric@webkit.org | 43ea6d7 | 2007-11-29 11:11:23 +0000 | [diff] [blame] | 985 | else { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 986 | int len = class_utf8data - (code + 33); |
| 987 | memmove(code + 1, code + 33, len); |
| 988 | code += len + 1; |
| 989 | } |
| 990 | |
| 991 | /* Now fill in the complete length of the item */ |
| 992 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 993 | putLinkValue(previous + 1, code - previous); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 994 | break; /* End of class handling */ |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 995 | } |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 996 | |
| 997 | /* If there are no characters > 255, negate the 32-byte map if necessary, |
| 998 | and copy it into the code vector. If this is the first thing in the branch, |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 999 | there can be no first char setting, whatever the repeat count. Any reqByte |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1000 | setting must remain unchanged after any kind of repeat. */ |
| 1001 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1002 | *code++ = (negateClass == shouldFlipNegation) ? OP_CLASS : OP_NCLASS; |
| 1003 | if (negateClass) |
eric@webkit.org | 43ea6d7 | 2007-11-29 11:11:23 +0000 | [diff] [blame] | 1004 | for (c = 0; c < 32; c++) |
| 1005 | code[c] = ~classbits[c]; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1006 | else |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1007 | memcpy(code, classbits, 32); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1008 | code += 32; |
| 1009 | break; |
eric@webkit.org | e5416c0 | 2007-11-29 11:30:20 +0000 | [diff] [blame] | 1010 | } |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 1011 | |
| 1012 | /* Various kinds of repeat; '{' is not necessarily a quantifier, but this |
| 1013 | has been tested above. */ |
| 1014 | |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1015 | case '{': |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1016 | if (!isQuantifier) |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1017 | goto NORMAL_CHAR; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1018 | ptr = readRepeatCounts(ptr + 1, &repeatMin, &repeat_max, errorCodePtr); |
| 1019 | if (*errorCodePtr) |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1020 | goto FAILED; |
| 1021 | goto REPEAT; |
| 1022 | |
| 1023 | case '*': |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1024 | repeatMin = 0; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1025 | repeat_max = -1; |
| 1026 | goto REPEAT; |
| 1027 | |
| 1028 | case '+': |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1029 | repeatMin = 1; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1030 | repeat_max = -1; |
| 1031 | goto REPEAT; |
| 1032 | |
| 1033 | case '?': |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1034 | repeatMin = 0; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1035 | repeat_max = 1; |
| 1036 | |
| 1037 | REPEAT: |
| 1038 | if (!previous) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1039 | *errorCodePtr = ERR9; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1040 | goto FAILED; |
| 1041 | } |
| 1042 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1043 | if (repeatMin == 0) { |
| 1044 | firstByte = zeroFirstByte; /* Adjust for zero repeat */ |
| 1045 | reqByte = zeroReqByte; /* Ditto */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1046 | } |
| 1047 | |
| 1048 | /* Remember whether this is a variable length repeat */ |
| 1049 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1050 | reqvary = (repeatMin == repeat_max) ? 0 : REQ_VARY; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1051 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1052 | opType = 0; /* Default single-char op codes */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1053 | |
| 1054 | /* Save start of previous item, in case we have to move it up to make space |
| 1055 | for an inserted OP_ONCE for the additional '+' extension. */ |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1056 | /* FIXME: Probably don't need this because we don't use OP_ONCE. */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1057 | |
| 1058 | tempcode = previous; |
| 1059 | |
| 1060 | /* If the next character is '+', we have a possessive quantifier. This |
| 1061 | implies greediness, whatever the setting of the PCRE_UNGREEDY option. |
| 1062 | If the next character is '?' this is a minimizing repeat, by default, |
| 1063 | but if PCRE_UNGREEDY is set, it works the other way round. We change the |
| 1064 | repeat type to the non-default. */ |
| 1065 | |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 1066 | if (safelyCheckNextChar(ptr, patternEnd, '?')) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1067 | repeatType = 1; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1068 | ptr++; |
eric@webkit.org | a818f3a | 2007-11-29 11:23:11 +0000 | [diff] [blame] | 1069 | } else |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1070 | repeatType = 0; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1071 | |
| 1072 | /* If previous was a character match, abolish the item and generate a |
| 1073 | repeat item instead. If a char item has a minumum of more than one, ensure |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1074 | that it is set in reqByte - it might not be if a sequence such as x{3} is |
| 1075 | the first thing in a branch because the x will have gone into firstByte |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1076 | instead. */ |
| 1077 | |
eric@webkit.org | 5bc5d41 | 2007-11-29 11:32:46 +0000 | [diff] [blame] | 1078 | if (*previous == OP_CHAR || *previous == OP_CHAR_IGNORING_CASE) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1079 | /* Deal with UTF-8 characters that take up more than one byte. It's |
| 1080 | easier to write this out separately than try to macrify it. Use c to |
| 1081 | hold the length of the character in bytes, plus 0x80 to flag that it's a |
| 1082 | length rather than a small character. */ |
| 1083 | |
eric@webkit.org | a818f3a | 2007-11-29 11:23:11 +0000 | [diff] [blame] | 1084 | if (code[-1] & 0x80) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1085 | unsigned char *lastchar = code - 1; |
eric@webkit.org | cc9c277 | 2007-11-29 11:32:01 +0000 | [diff] [blame] | 1086 | while((*lastchar & 0xc0) == 0x80) |
| 1087 | lastchar--; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1088 | c = code - lastchar; /* Length of UTF-8 character */ |
| 1089 | memcpy(utf8_char, lastchar, c); /* Save the char */ |
| 1090 | c |= 0x80; /* Flag c as a length */ |
| 1091 | } |
eric@webkit.org | a818f3a | 2007-11-29 11:23:11 +0000 | [diff] [blame] | 1092 | else { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1093 | c = code[-1]; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1094 | if (repeatMin > 1) |
| 1095 | reqByte = c | reqCaseOpt | cd.reqVaryOpt; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1096 | } |
| 1097 | |
| 1098 | goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */ |
| 1099 | } |
| 1100 | |
eric@webkit.org | 5bc5d41 | 2007-11-29 11:32:46 +0000 | [diff] [blame] | 1101 | else if (*previous == OP_ASCII_CHAR || *previous == OP_ASCII_LETTER_IGNORING_CASE) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1102 | c = previous[1]; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1103 | if (repeatMin > 1) |
| 1104 | reqByte = c | reqCaseOpt | cd.reqVaryOpt; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1105 | goto OUTPUT_SINGLE_REPEAT; |
| 1106 | } |
| 1107 | |
| 1108 | /* If previous was a single negated character ([^a] or similar), we use |
| 1109 | one of the special opcodes, replacing it. The code is shared with single- |
| 1110 | character repeats by setting opt_type to add a suitable offset into |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1111 | repeatType. OP_NOT is currently used only for single-byte chars. */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1112 | |
eric@webkit.org | a818f3a | 2007-11-29 11:23:11 +0000 | [diff] [blame] | 1113 | else if (*previous == OP_NOT) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1114 | opType = OP_NOTSTAR - OP_STAR; /* Use "not" opcodes */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1115 | c = previous[1]; |
| 1116 | goto OUTPUT_SINGLE_REPEAT; |
| 1117 | } |
| 1118 | |
| 1119 | /* If previous was a character type match (\d or similar), abolish it and |
| 1120 | create a suitable repeat item. The code is shared with single-character |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1121 | repeats by setting opType to add a suitable offset into repeatType. */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1122 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 1123 | else if (*previous <= OP_NOT_NEWLINE) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1124 | opType = OP_TYPESTAR - OP_STAR; /* Use type opcodes */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1125 | c = *previous; |
| 1126 | |
| 1127 | OUTPUT_SINGLE_REPEAT: |
eric@webkit.org | a818f3a | 2007-11-29 11:23:11 +0000 | [diff] [blame] | 1128 | int prop_type = -1; |
| 1129 | int prop_value = -1; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1130 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1131 | unsigned char* oldcode = code; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1132 | code = previous; /* Usually overwrite previous item */ |
| 1133 | |
| 1134 | /* If the maximum is zero then the minimum must also be zero; Perl allows |
| 1135 | this case, so we do too - by simply omitting the item altogether. */ |
| 1136 | |
| 1137 | if (repeat_max == 0) |
| 1138 | goto END_REPEAT; |
| 1139 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1140 | /* Combine the opType with the repeatType */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1141 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1142 | repeatType += opType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1143 | |
| 1144 | /* A minimum of zero is handled either as the special case * or ?, or as |
| 1145 | an UPTO, with the maximum given. */ |
| 1146 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1147 | if (repeatMin == 0) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1148 | if (repeat_max == -1) |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1149 | *code++ = OP_STAR + repeatType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1150 | else if (repeat_max == 1) |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1151 | *code++ = OP_QUERY + repeatType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1152 | else { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1153 | *code++ = OP_UPTO + repeatType; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1154 | put2ByteValueAndAdvance(code, repeat_max); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1155 | } |
| 1156 | } |
| 1157 | |
| 1158 | /* A repeat minimum of 1 is optimized into some special cases. If the |
| 1159 | maximum is unlimited, we use OP_PLUS. Otherwise, the original item it |
| 1160 | left in place and, if the maximum is greater than 1, we use OP_UPTO with |
| 1161 | one less than the maximum. */ |
| 1162 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1163 | else if (repeatMin == 1) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1164 | if (repeat_max == -1) |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1165 | *code++ = OP_PLUS + repeatType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1166 | else { |
| 1167 | code = oldcode; /* leave previous item in place */ |
| 1168 | if (repeat_max == 1) |
| 1169 | goto END_REPEAT; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1170 | *code++ = OP_UPTO + repeatType; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1171 | put2ByteValueAndAdvance(code, repeat_max - 1); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1172 | } |
| 1173 | } |
| 1174 | |
| 1175 | /* The case {n,n} is just an EXACT, while the general case {n,m} is |
| 1176 | handled as an EXACT followed by an UPTO. */ |
| 1177 | |
eric@webkit.org | a818f3a | 2007-11-29 11:23:11 +0000 | [diff] [blame] | 1178 | else { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1179 | *code++ = OP_EXACT + opType; /* NB EXACT doesn't have repeatType */ |
| 1180 | put2ByteValueAndAdvance(code, repeatMin); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1181 | |
| 1182 | /* If the maximum is unlimited, insert an OP_STAR. Before doing so, |
| 1183 | we have to insert the character for the previous code. For a repeated |
| 1184 | Unicode property match, there are two extra bytes that define the |
| 1185 | required property. In UTF-8 mode, long characters have their length in |
| 1186 | c, with the 0x80 bit as a flag. */ |
| 1187 | |
| 1188 | if (repeat_max < 0) { |
| 1189 | if (c >= 128) { |
| 1190 | memcpy(code, utf8_char, c & 7); |
| 1191 | code += c & 7; |
| 1192 | } else { |
| 1193 | *code++ = c; |
| 1194 | if (prop_type >= 0) { |
| 1195 | *code++ = prop_type; |
| 1196 | *code++ = prop_value; |
| 1197 | } |
| 1198 | } |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1199 | *code++ = OP_STAR + repeatType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1200 | } |
| 1201 | |
| 1202 | /* Else insert an UPTO if the max is greater than the min, again |
| 1203 | preceded by the character, for the previously inserted code. */ |
| 1204 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1205 | else if (repeat_max != repeatMin) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1206 | if (c >= 128) { |
| 1207 | memcpy(code, utf8_char, c & 7); |
| 1208 | code += c & 7; |
| 1209 | } else |
| 1210 | *code++ = c; |
| 1211 | if (prop_type >= 0) { |
| 1212 | *code++ = prop_type; |
| 1213 | *code++ = prop_value; |
| 1214 | } |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1215 | repeat_max -= repeatMin; |
| 1216 | *code++ = OP_UPTO + repeatType; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1217 | put2ByteValueAndAdvance(code, repeat_max); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1218 | } |
| 1219 | } |
| 1220 | |
| 1221 | /* The character or character type itself comes last in all cases. */ |
| 1222 | |
| 1223 | if (c >= 128) { |
| 1224 | memcpy(code, utf8_char, c & 7); |
| 1225 | code += c & 7; |
| 1226 | } else |
| 1227 | *code++ = c; |
| 1228 | |
| 1229 | /* For a repeated Unicode property match, there are two extra bytes that |
| 1230 | define the required property. */ |
| 1231 | |
| 1232 | if (prop_type >= 0) { |
| 1233 | *code++ = prop_type; |
| 1234 | *code++ = prop_value; |
| 1235 | } |
| 1236 | } |
| 1237 | |
| 1238 | /* If previous was a character class or a back reference, we put the repeat |
| 1239 | stuff after it, but just skip the item if the repeat was {0,0}. */ |
| 1240 | |
| 1241 | else if (*previous == OP_CLASS || |
| 1242 | *previous == OP_NCLASS || |
| 1243 | *previous == OP_XCLASS || |
| 1244 | *previous == OP_REF) |
| 1245 | { |
| 1246 | if (repeat_max == 0) { |
| 1247 | code = previous; |
| 1248 | goto END_REPEAT; |
| 1249 | } |
| 1250 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1251 | if (repeatMin == 0 && repeat_max == -1) |
| 1252 | *code++ = OP_CRSTAR + repeatType; |
| 1253 | else if (repeatMin == 1 && repeat_max == -1) |
| 1254 | *code++ = OP_CRPLUS + repeatType; |
| 1255 | else if (repeatMin == 0 && repeat_max == 1) |
| 1256 | *code++ = OP_CRQUERY + repeatType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1257 | else { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1258 | *code++ = OP_CRRANGE + repeatType; |
| 1259 | put2ByteValueAndAdvance(code, repeatMin); |
eric@webkit.org | a818f3a | 2007-11-29 11:23:11 +0000 | [diff] [blame] | 1260 | if (repeat_max == -1) |
| 1261 | repeat_max = 0; /* 2-byte encoding for max */ |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1262 | put2ByteValueAndAdvance(code, repeat_max); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1263 | } |
| 1264 | } |
| 1265 | |
| 1266 | /* If previous was a bracket group, we may have to replicate it in certain |
| 1267 | cases. */ |
| 1268 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1269 | else if (*previous >= OP_BRA) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1270 | int ketoffset = 0; |
| 1271 | int len = code - previous; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1272 | unsigned char* bralink = NULL; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1273 | |
| 1274 | /* If the maximum repeat count is unlimited, find the end of the bracket |
| 1275 | by scanning through from the start, and compute the offset back to it |
| 1276 | from the current code pointer. There may be an OP_OPT setting following |
| 1277 | the final KET, so we can't find the end just by going back from the code |
| 1278 | pointer. */ |
| 1279 | |
| 1280 | if (repeat_max == -1) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1281 | const unsigned char* ket = previous; |
| 1282 | advanceToEndOfBracket(ket); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1283 | ketoffset = code - ket; |
| 1284 | } |
| 1285 | |
| 1286 | /* The case of a zero minimum is special because of the need to stick |
| 1287 | OP_BRAZERO in front of it, and because the group appears once in the |
| 1288 | data, whereas in other cases it appears the minimum number of times. For |
| 1289 | this reason, it is simplest to treat this case separately, as otherwise |
| 1290 | the code gets far too messy. There are several special subcases when the |
| 1291 | minimum is zero. */ |
| 1292 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1293 | if (repeatMin == 0) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1294 | /* If the maximum is also zero, we just omit the group from the output |
| 1295 | altogether. */ |
| 1296 | |
| 1297 | if (repeat_max == 0) { |
| 1298 | code = previous; |
| 1299 | goto END_REPEAT; |
| 1300 | } |
| 1301 | |
| 1302 | /* If the maximum is 1 or unlimited, we just have to stick in the |
| 1303 | BRAZERO and do no more at this point. However, we do need to adjust |
| 1304 | any OP_RECURSE calls inside the group that refer to the group itself or |
| 1305 | any internal group, because the offset is from the start of the whole |
| 1306 | regex. Temporarily terminate the pattern while doing this. */ |
| 1307 | |
| 1308 | if (repeat_max <= 1) { |
| 1309 | *code = OP_END; |
| 1310 | memmove(previous+1, previous, len); |
| 1311 | code++; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1312 | *previous++ = OP_BRAZERO + repeatType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1313 | } |
| 1314 | |
| 1315 | /* If the maximum is greater than 1 and limited, we have to replicate |
| 1316 | in a nested fashion, sticking OP_BRAZERO before each set of brackets. |
| 1317 | The first one has to be handled carefully because it's the original |
| 1318 | copy, which has to be moved up. The remainder can be handled by code |
| 1319 | that is common with the non-zero minimum case below. We have to |
darin@apple.com | e410bdf | 2007-12-04 19:08:28 +0000 | [diff] [blame] | 1320 | adjust the value of repeat_max, since one less copy is required. */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1321 | |
| 1322 | else { |
| 1323 | *code = OP_END; |
| 1324 | memmove(previous + 2 + LINK_SIZE, previous, len); |
| 1325 | code += 2 + LINK_SIZE; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1326 | *previous++ = OP_BRAZERO + repeatType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1327 | *previous++ = OP_BRA; |
| 1328 | |
| 1329 | /* We chain together the bracket offset fields that have to be |
| 1330 | filled in later when the ends of the brackets are reached. */ |
| 1331 | |
eric@webkit.org | a818f3a | 2007-11-29 11:23:11 +0000 | [diff] [blame] | 1332 | int offset = (!bralink) ? 0 : previous - bralink; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1333 | bralink = previous; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1334 | putLinkValueAllowZeroAndAdvance(previous, offset); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1335 | } |
| 1336 | |
| 1337 | repeat_max--; |
| 1338 | } |
| 1339 | |
| 1340 | /* If the minimum is greater than zero, replicate the group as many |
| 1341 | times as necessary, and adjust the maximum to the number of subsequent |
| 1342 | copies that we need. If we set a first char from the group, and didn't |
| 1343 | set a required char, copy the latter from the former. */ |
| 1344 | |
| 1345 | else { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1346 | if (repeatMin > 1) { |
| 1347 | if (didGroupSetFirstByte && reqByte < 0) |
| 1348 | reqByte = firstByte; |
| 1349 | for (int i = 1; i < repeatMin; i++) { |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1350 | memcpy(code, previous, len); |
| 1351 | code += len; |
| 1352 | } |
| 1353 | } |
| 1354 | if (repeat_max > 0) |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1355 | repeat_max -= repeatMin; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1356 | } |
| 1357 | |
| 1358 | /* This code is common to both the zero and non-zero minimum cases. If |
| 1359 | the maximum is limited, it replicates the group in a nested fashion, |
| 1360 | remembering the bracket starts on a stack. In the case of a zero minimum, |
| 1361 | the first one was set up above. In all cases the repeat_max now specifies |
| 1362 | the number of additional copies needed. */ |
| 1363 | |
| 1364 | if (repeat_max >= 0) { |
| 1365 | for (int i = repeat_max - 1; i >= 0; i--) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1366 | *code++ = OP_BRAZERO + repeatType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1367 | |
| 1368 | /* All but the final copy start a new nesting, maintaining the |
| 1369 | chain of brackets outstanding. */ |
| 1370 | |
| 1371 | if (i != 0) { |
| 1372 | *code++ = OP_BRA; |
| 1373 | int offset = (!bralink) ? 0 : code - bralink; |
| 1374 | bralink = code; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1375 | putLinkValueAllowZeroAndAdvance(code, offset); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1376 | } |
| 1377 | |
| 1378 | memcpy(code, previous, len); |
| 1379 | code += len; |
| 1380 | } |
| 1381 | |
| 1382 | /* Now chain through the pending brackets, and fill in their length |
| 1383 | fields (which are holding the chain links pro tem). */ |
| 1384 | |
| 1385 | while (bralink) { |
| 1386 | int offset = code - bralink + 1; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1387 | unsigned char* bra = code - offset; |
| 1388 | int oldlinkoffset = getLinkValueAllowZero(bra + 1); |
| 1389 | bralink = (!oldlinkoffset) ? 0 : bralink - oldlinkoffset; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1390 | *code++ = OP_KET; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1391 | putLinkValueAndAdvance(code, offset); |
| 1392 | putLinkValue(bra + 1, offset); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1393 | } |
| 1394 | } |
| 1395 | |
| 1396 | /* If the maximum is unlimited, set a repeater in the final copy. We |
| 1397 | can't just offset backwards from the current code point, because we |
| 1398 | don't know if there's been an options resetting after the ket. The |
| 1399 | correct offset was computed above. */ |
| 1400 | |
| 1401 | else |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1402 | code[-ketoffset] = OP_KETRMAX + repeatType; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1403 | } |
| 1404 | |
| 1405 | /* Else there's some kind of shambles */ |
| 1406 | |
| 1407 | else { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1408 | *errorCodePtr = ERR11; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1409 | goto FAILED; |
| 1410 | } |
| 1411 | |
| 1412 | /* In all case we no longer have a previous item. We also set the |
| 1413 | "follows varying string" flag for subsequently encountered reqbytes if |
| 1414 | it isn't already set and we have just passed a varying length item. */ |
| 1415 | |
| 1416 | END_REPEAT: |
| 1417 | previous = NULL; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1418 | cd.reqVaryOpt |= reqvary; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1419 | break; |
| 1420 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 1421 | /* Start of nested bracket sub-expression, or comment or lookahead or |
| 1422 | lookbehind or option setting or condition. First deal with special things |
| 1423 | that can come after a bracket; all are introduced by ?, and the appearance |
| 1424 | of any of them means that this is not a referencing group. They were |
| 1425 | checked for validity in the first pass over the string, so we don't have to |
| 1426 | check for syntax errors here. */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1427 | |
| 1428 | case '(': |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1429 | skipBytes = 0; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1430 | |
| 1431 | if (*(++ptr) == '?') { |
| 1432 | switch (*(++ptr)) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1433 | case ':': /* Non-extracting bracket */ |
| 1434 | bravalue = OP_BRA; |
| 1435 | ptr++; |
| 1436 | break; |
| 1437 | |
| 1438 | case '=': /* Positive lookahead */ |
| 1439 | bravalue = OP_ASSERT; |
| 1440 | ptr++; |
| 1441 | break; |
| 1442 | |
| 1443 | case '!': /* Negative lookahead */ |
| 1444 | bravalue = OP_ASSERT_NOT; |
| 1445 | ptr++; |
| 1446 | break; |
| 1447 | |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1448 | /* Character after (? not specially recognized */ |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1449 | |
| 1450 | default: |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1451 | *errorCodePtr = ERR12; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1452 | goto FAILED; |
| 1453 | } |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1454 | } |
| 1455 | |
| 1456 | /* Else we have a referencing group; adjust the opcode. If the bracket |
| 1457 | number is greater than EXTRACT_BASIC_MAX, we set the opcode one higher, and |
| 1458 | arrange for the true number to follow later, in an OP_BRANUMBER item. */ |
| 1459 | |
| 1460 | else { |
| 1461 | if (++(*brackets) > EXTRACT_BASIC_MAX) { |
| 1462 | bravalue = OP_BRA + EXTRACT_BASIC_MAX + 1; |
eric@webkit.org | a69618d | 2007-11-29 11:21:07 +0000 | [diff] [blame] | 1463 | code[1 + LINK_SIZE] = OP_BRANUMBER; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1464 | put2ByteValue(code + 2 + LINK_SIZE, *brackets); |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1465 | skipBytes = 3; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1466 | } |
| 1467 | else |
| 1468 | bravalue = OP_BRA + *brackets; |
| 1469 | } |
| 1470 | |
| 1471 | /* Process nested bracketed re. Assertions may not be repeated, but other |
| 1472 | kinds can be. We copy code into a non-variable in order to be able |
| 1473 | to pass its address because some compilers complain otherwise. Pass in a |
| 1474 | new setting for the ims options if they have changed. */ |
| 1475 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1476 | previous = (bravalue >= OP_BRAZERO) ? code : 0; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1477 | *code = bravalue; |
| 1478 | tempcode = code; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1479 | tempreqvary = cd.reqVaryOpt; /* Save value before bracket */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1480 | |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1481 | if (!compileBracket( |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1482 | options, |
| 1483 | brackets, /* Extracting bracket count */ |
| 1484 | &tempcode, /* Where to put code (updated) */ |
| 1485 | &ptr, /* Input pointer (updated) */ |
| 1486 | patternEnd, |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1487 | errorCodePtr, /* Where to put an error message */ |
| 1488 | skipBytes, /* Skip over OP_BRANUMBER */ |
| 1489 | &subFirstByte, /* For possible first char */ |
| 1490 | &subReqByte, /* For possible last char */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1491 | cd)) /* Tables block */ |
| 1492 | goto FAILED; |
| 1493 | |
| 1494 | /* At the end of compiling, code is still pointing to the start of the |
| 1495 | group, while tempcode has been updated to point past the end of the group |
| 1496 | and any option resetting that may follow it. The pattern pointer (ptr) |
| 1497 | is on the bracket. */ |
| 1498 | |
| 1499 | /* Handle updating of the required and first characters. Update for normal |
| 1500 | brackets of all kinds, and conditions with two branches (see code above). |
| 1501 | If the bracket is followed by a quantifier with zero repeat, we have to |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1502 | back off. Hence the definition of zeroReqByte and zeroFirstByte outside the |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1503 | main loop so that they can be accessed for the back off. */ |
| 1504 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1505 | zeroReqByte = reqByte; |
| 1506 | zeroFirstByte = firstByte; |
| 1507 | didGroupSetFirstByte = false; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1508 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1509 | if (bravalue >= OP_BRA) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1510 | /* If we have not yet set a firstByte in this branch, take it from the |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1511 | subpattern, remembering that it was set here so that a repeat of more |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1512 | than one can replicate it as reqByte if necessary. If the subpattern has |
| 1513 | no firstByte, set "none" for the whole branch. In both cases, a zero |
| 1514 | repeat forces firstByte to "none". */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1515 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1516 | if (firstByte == REQ_UNSET) { |
| 1517 | if (subFirstByte >= 0) { |
| 1518 | firstByte = subFirstByte; |
| 1519 | didGroupSetFirstByte = true; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1520 | } |
| 1521 | else |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1522 | firstByte = REQ_NONE; |
| 1523 | zeroFirstByte = REQ_NONE; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1524 | } |
| 1525 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1526 | /* If firstByte was previously set, convert the subpattern's firstByte |
| 1527 | into reqByte if there wasn't one, using the vary flag that was in |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1528 | existence beforehand. */ |
| 1529 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1530 | else if (subFirstByte >= 0 && subReqByte < 0) |
| 1531 | subReqByte = subFirstByte | tempreqvary; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1532 | |
| 1533 | /* If the subpattern set a required byte (or set a first byte that isn't |
| 1534 | really the first byte - see above), set it. */ |
| 1535 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1536 | if (subReqByte >= 0) |
| 1537 | reqByte = subReqByte; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1538 | } |
| 1539 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1540 | /* For a forward assertion, we take the reqByte, if set. This can be |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1541 | helpful if the pattern that follows the assertion doesn't set a different |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1542 | char. For example, it's useful for /(?=abcde).+/. We can't set firstByte |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1543 | for an assertion, however because it leads to incorrect effect for patterns |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1544 | such as /(?=a)a.+/ when the "real" "a" would then become a reqByte instead |
| 1545 | of a firstByte. This is overcome by a scan at the end if there's no |
| 1546 | firstByte, looking for an asserted first char. */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1547 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1548 | else if (bravalue == OP_ASSERT && subReqByte >= 0) |
| 1549 | reqByte = subReqByte; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1550 | |
| 1551 | /* Now update the main code pointer to the end of the group. */ |
| 1552 | |
| 1553 | code = tempcode; |
| 1554 | |
| 1555 | /* Error if hit end of pattern */ |
| 1556 | |
| 1557 | if (ptr >= patternEnd || *ptr != ')') { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1558 | *errorCodePtr = ERR14; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1559 | goto FAILED; |
| 1560 | } |
| 1561 | break; |
| 1562 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 1563 | /* Check \ for being a real metacharacter; if not, fall through and handle |
| 1564 | it as a data character at the start of a string. Escape items are checked |
| 1565 | for validity in the pre-compiling pass. */ |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1566 | |
| 1567 | case '\\': |
| 1568 | tempptr = ptr; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1569 | c = checkEscape(&ptr, patternEnd, errorCodePtr, cd.numCapturingBrackets, false); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1570 | |
| 1571 | /* Handle metacharacters introduced by \. For ones like \d, the ESC_ values |
| 1572 | are arranged to be the negation of the corresponding OP_values. For the |
| 1573 | back references, the values are ESC_REF plus the reference number. Only |
| 1574 | back references and those types that consume a character may be repeated. |
| 1575 | We can test for values between ESC_b and ESC_w for the latter; this may |
| 1576 | have to change if any new ones are ever created. */ |
| 1577 | |
| 1578 | if (c < 0) { |
| 1579 | /* For metasequences that actually match a character, we disable the |
| 1580 | setting of a first character if it hasn't already been set. */ |
| 1581 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1582 | if (firstByte == REQ_UNSET && -c > ESC_b && -c <= ESC_w) |
| 1583 | firstByte = REQ_NONE; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1584 | |
| 1585 | /* Set values to reset to if this is followed by a zero repeat. */ |
| 1586 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1587 | zeroFirstByte = firstByte; |
| 1588 | zeroReqByte = reqByte; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1589 | |
| 1590 | /* Back references are handled specially */ |
| 1591 | |
| 1592 | if (-c >= ESC_REF) { |
| 1593 | int number = -c - ESC_REF; |
| 1594 | previous = code; |
| 1595 | *code++ = OP_REF; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1596 | put2ByteValueAndAdvance(code, number); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1597 | } |
| 1598 | |
| 1599 | /* For the rest, we can obtain the OP value by negating the escape |
| 1600 | value */ |
| 1601 | |
| 1602 | else { |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1603 | previous = (-c > ESC_b && -c <= ESC_w) ? code : NULL; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1604 | *code++ = -c; |
| 1605 | } |
| 1606 | continue; |
| 1607 | } |
| 1608 | |
| 1609 | /* Fall through. */ |
| 1610 | |
| 1611 | /* Handle a literal character. It is guaranteed not to be whitespace or # |
| 1612 | when the extended flag is set. If we are in UTF-8 mode, it may be a |
| 1613 | multi-byte literal character. */ |
| 1614 | |
| 1615 | default: |
| 1616 | NORMAL_CHAR: |
| 1617 | |
| 1618 | previous = code; |
| 1619 | |
| 1620 | if (c < 128) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1621 | mcLength = 1; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1622 | mcbuffer[0] = c; |
| 1623 | |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 1624 | if ((options & IgnoreCaseOption) && (c | 0x20) >= 'a' && (c | 0x20) <= 'z') { |
eric@webkit.org | 5bc5d41 | 2007-11-29 11:32:46 +0000 | [diff] [blame] | 1625 | *code++ = OP_ASCII_LETTER_IGNORING_CASE; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1626 | *code++ = c | 0x20; |
| 1627 | } else { |
| 1628 | *code++ = OP_ASCII_CHAR; |
| 1629 | *code++ = c; |
| 1630 | } |
| 1631 | } else { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1632 | mcLength = encodeUTF8(c, mcbuffer); |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1633 | |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 1634 | *code++ = (options & IgnoreCaseOption) ? OP_CHAR_IGNORING_CASE : OP_CHAR; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1635 | for (c = 0; c < mcLength; c++) |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1636 | *code++ = mcbuffer[c]; |
| 1637 | } |
| 1638 | |
| 1639 | /* Set the first and required bytes appropriately. If no previous first |
| 1640 | byte, set it from this character, but revert to none on a zero repeat. |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1641 | Otherwise, leave the firstByte value alone, and don't change it on a zero |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1642 | repeat. */ |
| 1643 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1644 | if (firstByte == REQ_UNSET) { |
| 1645 | zeroFirstByte = REQ_NONE; |
| 1646 | zeroReqByte = reqByte; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1647 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1648 | /* If the character is more than one byte long, we can set firstByte |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1649 | only if it is not to be matched caselessly. */ |
| 1650 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1651 | if (mcLength == 1 || reqCaseOpt == 0) { |
| 1652 | firstByte = mcbuffer[0] | reqCaseOpt; |
| 1653 | if (mcLength != 1) |
| 1654 | reqByte = code[-1] | cd.reqVaryOpt; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1655 | } |
| 1656 | else |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1657 | firstByte = reqByte = REQ_NONE; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1658 | } |
| 1659 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1660 | /* firstByte was previously set; we can set reqByte only the length is |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1661 | 1 or the matching is caseful. */ |
| 1662 | |
| 1663 | else { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1664 | zeroFirstByte = firstByte; |
| 1665 | zeroReqByte = reqByte; |
| 1666 | if (mcLength == 1 || reqCaseOpt == 0) |
| 1667 | reqByte = code[-1] | reqCaseOpt | cd.reqVaryOpt; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1668 | } |
| 1669 | |
| 1670 | break; /* End of literal character handling */ |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1671 | } |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1672 | } /* end of big loop */ |
| 1673 | |
| 1674 | /* Control never reaches here by falling through, only by a goto for all the |
| 1675 | error states. Pass back the position in the pattern so that it can be displayed |
| 1676 | to the user for diagnosing the error. */ |
| 1677 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1678 | FAILED: |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1679 | *ptrPtr = ptr; |
eric@webkit.org | 5c35e22 | 2007-11-29 11:08:50 +0000 | [diff] [blame] | 1680 | return false; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1681 | } |
| 1682 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1683 | /************************************************* |
| 1684 | * Compile sequence of alternatives * |
| 1685 | *************************************************/ |
| 1686 | |
| 1687 | /* On entry, ptr is pointing past the bracket character, but on return |
| 1688 | it points to the closing bracket, or vertical bar, or end of string. |
| 1689 | The code variable is pointing at the byte into which the BRA operator has been |
| 1690 | stored. If the ims options are changed at the start (for a (?ims: group) or |
| 1691 | during any branch, we need to insert an OP_OPT item at the start of every |
| 1692 | following branch to ensure they get set correctly at run time, and also pass |
| 1693 | the new options into every subsequent branch compile. |
| 1694 | |
| 1695 | Argument: |
| 1696 | options option bits, including any changes for this subpattern |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1697 | brackets -> int containing the number of extracting brackets used |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1698 | codePtr -> the address of the current code pointer |
| 1699 | ptrPtr -> the address of the current pattern pointer |
| 1700 | errorCodePtr -> pointer to error code variable |
| 1701 | skipBytes skip this many bytes at start (for OP_BRANUMBER) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1702 | firstbyteptr place to put the first required character, or a negative number |
| 1703 | reqbyteptr place to put the last required character, or a negative number |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1704 | cd points to the data block with tables pointers etc. |
| 1705 | |
darin@apple.com | 7f98487 | 2007-11-12 23:04:41 +0000 | [diff] [blame] | 1706 | Returns: true on success |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1707 | */ |
| 1708 | |
eric@webkit.org | c8d4c7d | 2007-11-29 11:09:42 +0000 | [diff] [blame] | 1709 | static bool |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1710 | compileBracket(int options, int* brackets, unsigned char** codePtr, |
| 1711 | const UChar** ptrPtr, const UChar* patternEnd, ErrorCode* errorCodePtr, int skipBytes, |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 1712 | int* firstbyteptr, int* reqbyteptr, CompileData& cd) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1713 | { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1714 | const UChar* ptr = *ptrPtr; |
| 1715 | unsigned char* code = *codePtr; |
| 1716 | unsigned char* lastBranch = code; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1717 | unsigned char* start_bracket = code; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1718 | int firstByte = REQ_UNSET; |
| 1719 | int reqByte = REQ_UNSET; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1720 | |
| 1721 | /* Offset is set zero to mark that this bracket is still open */ |
| 1722 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1723 | putLinkValueAllowZero(code + 1, 0); |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1724 | code += 1 + LINK_SIZE + skipBytes; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1725 | |
| 1726 | /* Loop for each alternative branch */ |
| 1727 | |
| 1728 | while (true) { |
| 1729 | /* Now compile the branch */ |
| 1730 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1731 | int branchFirstByte; |
| 1732 | int branchReqByte; |
| 1733 | if (!compileBranch(options, brackets, &code, &ptr, patternEnd, errorCodePtr, |
| 1734 | &branchFirstByte, &branchReqByte, cd)) { |
| 1735 | *ptrPtr = ptr; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1736 | return false; |
| 1737 | } |
| 1738 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1739 | /* If this is the first branch, the firstByte and reqByte values for the |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1740 | branch become the values for the regex. */ |
| 1741 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1742 | if (*lastBranch != OP_ALT) { |
| 1743 | firstByte = branchFirstByte; |
| 1744 | reqByte = branchReqByte; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1745 | } |
| 1746 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1747 | /* If this is not the first branch, the first char and reqByte have to |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1748 | match the values from all the previous branches, except that if the previous |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1749 | value for reqByte didn't have REQ_VARY set, it can still match, and we set |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1750 | REQ_VARY for the regex. */ |
| 1751 | |
| 1752 | else { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1753 | /* If we previously had a firstByte, but it doesn't match the new branch, |
| 1754 | we have to abandon the firstByte for the regex, but if there was previously |
| 1755 | no reqByte, it takes on the value of the old firstByte. */ |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1756 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1757 | if (firstByte >= 0 && firstByte != branchFirstByte) { |
| 1758 | if (reqByte < 0) |
| 1759 | reqByte = firstByte; |
| 1760 | firstByte = REQ_NONE; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1761 | } |
| 1762 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1763 | /* If we (now or from before) have no firstByte, a firstByte from the |
| 1764 | branch becomes a reqByte if there isn't a branch reqByte. */ |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1765 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1766 | if (firstByte < 0 && branchFirstByte >= 0 && branchReqByte < 0) |
| 1767 | branchReqByte = branchFirstByte; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1768 | |
| 1769 | /* Now ensure that the reqbytes match */ |
| 1770 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1771 | if ((reqByte & ~REQ_VARY) != (branchReqByte & ~REQ_VARY)) |
| 1772 | reqByte = REQ_NONE; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1773 | else |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1774 | reqByte |= branchReqByte; /* To "or" REQ_VARY */ |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1775 | } |
| 1776 | |
| 1777 | /* Reached end of expression, either ')' or end of pattern. Go back through |
| 1778 | the alternative branches and reverse the chain of offsets, with the field in |
| 1779 | the BRA item now becoming an offset to the first alternative. If there are |
| 1780 | no alternatives, it points to the end of the group. The length in the |
| 1781 | terminating ket is always the length of the whole bracketed item. If any of |
| 1782 | the ims options were changed inside the group, compile a resetting op-code |
| 1783 | following, except at the very end of the pattern. Return leaving the pointer |
| 1784 | at the terminating char. */ |
| 1785 | |
| 1786 | if (ptr >= patternEnd || *ptr != '|') { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1787 | int length = code - lastBranch; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1788 | do { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1789 | int prevLength = getLinkValueAllowZero(lastBranch + 1); |
| 1790 | putLinkValue(lastBranch + 1, length); |
| 1791 | length = prevLength; |
| 1792 | lastBranch -= length; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1793 | } while (length > 0); |
| 1794 | |
| 1795 | /* Fill in the ket */ |
| 1796 | |
| 1797 | *code = OP_KET; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1798 | putLinkValue(code + 1, code - start_bracket); |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1799 | code += 1 + LINK_SIZE; |
| 1800 | |
| 1801 | /* Set values to pass back */ |
| 1802 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1803 | *codePtr = code; |
| 1804 | *ptrPtr = ptr; |
| 1805 | *firstbyteptr = firstByte; |
| 1806 | *reqbyteptr = reqByte; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1807 | return true; |
| 1808 | } |
| 1809 | |
| 1810 | /* Another branch follows; insert an "or" node. Its length field points back |
| 1811 | to the previous branch while the bracket remains open. At the end the chain |
| 1812 | is reversed. It's done like this so that the start of the bracket has a |
| 1813 | zero offset until it is closed, making it possible to detect recursion. */ |
| 1814 | |
| 1815 | *code = OP_ALT; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 1816 | putLinkValue(code + 1, code - lastBranch); |
| 1817 | lastBranch = code; |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1818 | code += 1 + LINK_SIZE; |
| 1819 | ptr++; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1820 | } |
eric@webkit.org | 326e202 | 2007-11-15 02:40:31 +0000 | [diff] [blame] | 1821 | ASSERT_NOT_REACHED(); |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1822 | } |
| 1823 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1824 | /************************************************* |
| 1825 | * Check for anchored expression * |
| 1826 | *************************************************/ |
| 1827 | |
| 1828 | /* Try to find out if this is an anchored regular expression. Consider each |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1829 | alternative branch. If they all start OP_CIRC, or with a bracket |
| 1830 | all of whose alternatives start OP_CIRC (recurse ad lib), then |
| 1831 | it's anchored. |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1832 | |
| 1833 | Arguments: |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1834 | code points to start of expression (the bracket) |
| 1835 | captureMap a bitmap of which brackets we are inside while testing; this |
| 1836 | handles up to substring 31; all brackets after that share |
| 1837 | the zero bit |
| 1838 | backrefMap the back reference bitmap |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1839 | */ |
| 1840 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1841 | static bool branchIsAnchored(const unsigned char* code) |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1842 | { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1843 | const unsigned char* scode = firstSignificantOpcode(code); |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1844 | int op = *scode; |
| 1845 | |
| 1846 | /* Brackets */ |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1847 | if (op >= OP_BRA || op == OP_ASSERT) |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1848 | return bracketIsAnchored(scode); |
| 1849 | |
| 1850 | /* Check for explicit anchoring */ |
| 1851 | return op == OP_CIRC; |
| 1852 | } |
| 1853 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1854 | static bool bracketIsAnchored(const unsigned char* code) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1855 | { |
eric@webkit.org | 76e87c2 | 2007-11-29 11:16:01 +0000 | [diff] [blame] | 1856 | do { |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1857 | if (!branchIsAnchored(code + 1 + LINK_SIZE)) |
eric@webkit.org | 76e87c2 | 2007-11-29 11:16:01 +0000 | [diff] [blame] | 1858 | return false; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1859 | code += getLinkValue(code + 1); |
eric@webkit.org | 76e87c2 | 2007-11-29 11:16:01 +0000 | [diff] [blame] | 1860 | } while (*code == OP_ALT); /* Loop for each alternative */ |
| 1861 | return true; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1862 | } |
| 1863 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1864 | /************************************************* |
| 1865 | * Check for starting with ^ or .* * |
| 1866 | *************************************************/ |
| 1867 | |
| 1868 | /* This is called to find out if every branch starts with ^ or .* so that |
| 1869 | "first char" processing can be done to speed things up in multiline |
| 1870 | matching and for non-DOTALL patterns that start with .* (which must start at |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1871 | the beginning or after \n) |
| 1872 | |
| 1873 | Except when the .* appears inside capturing parentheses, and there is a |
| 1874 | subsequent back reference to those parentheses. By keeping a bitmap of the |
| 1875 | first 31 back references, we can catch some of the more common cases more |
| 1876 | precisely; all the greater back references share a single bit. |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1877 | |
| 1878 | Arguments: |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1879 | code points to start of expression (the bracket) |
| 1880 | captureMap a bitmap of which brackets we are inside while testing; this |
| 1881 | handles up to substring 31; all brackets after that share |
| 1882 | the zero bit |
| 1883 | backrefMap the back reference bitmap |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1884 | */ |
| 1885 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1886 | static bool branchNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1887 | { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1888 | const unsigned char* scode = firstSignificantOpcode(code); |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1889 | int op = *scode; |
| 1890 | |
| 1891 | /* Capturing brackets */ |
| 1892 | if (op > OP_BRA) { |
| 1893 | int captureNum = op - OP_BRA; |
| 1894 | if (captureNum > EXTRACT_BASIC_MAX) |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1895 | captureNum = get2ByteValue(scode + 2 + LINK_SIZE); |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1896 | int bracketMask = (captureNum < 32) ? (1 << captureNum) : 1; |
| 1897 | return bracketNeedsLineStart(scode, captureMap | bracketMask, backrefMap); |
| 1898 | } |
| 1899 | |
| 1900 | /* Other brackets */ |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1901 | if (op == OP_BRA || op == OP_ASSERT) |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1902 | return bracketNeedsLineStart(scode, captureMap, backrefMap); |
| 1903 | |
| 1904 | /* .* means "start at start or after \n" if it isn't in brackets that |
| 1905 | may be referenced. */ |
| 1906 | |
| 1907 | if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR) |
| 1908 | return scode[1] == OP_NOT_NEWLINE && !(captureMap & backrefMap); |
| 1909 | |
| 1910 | /* Explicit ^ */ |
eric@webkit.org | 7fbd893 | 2008-03-31 08:01:09 +0000 | [diff] [blame] | 1911 | return op == OP_CIRC || op == OP_BOL; |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1912 | } |
| 1913 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1914 | static bool bracketNeedsLineStart(const unsigned char* code, unsigned captureMap, unsigned backrefMap) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1915 | { |
eric@webkit.org | dbdae8d | 2007-11-29 11:13:33 +0000 | [diff] [blame] | 1916 | do { |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 1917 | if (!branchNeedsLineStart(code + 1 + LINK_SIZE, captureMap, backrefMap)) |
eric@webkit.org | dbdae8d | 2007-11-29 11:13:33 +0000 | [diff] [blame] | 1918 | return false; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1919 | code += getLinkValue(code + 1); |
eric@webkit.org | 96e3d9b | 2007-11-29 11:15:13 +0000 | [diff] [blame] | 1920 | } while (*code == OP_ALT); /* Loop for each alternative */ |
eric@webkit.org | dbdae8d | 2007-11-29 11:13:33 +0000 | [diff] [blame] | 1921 | return true; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1922 | } |
| 1923 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1924 | /************************************************* |
| 1925 | * Check for asserted fixed first char * |
| 1926 | *************************************************/ |
| 1927 | |
| 1928 | /* During compilation, the "first char" settings from forward assertions are |
| 1929 | discarded, because they can cause conflicts with actual literals that follow. |
| 1930 | However, if we end up without a first char setting for an unanchored pattern, |
| 1931 | it is worth scanning the regex to see if there is an initial asserted first |
| 1932 | char. If all branches start with the same asserted char, or with a bracket all |
| 1933 | of whose alternatives start with the same asserted char (recurse ad lib), then |
| 1934 | we return that char, otherwise -1. |
| 1935 | |
| 1936 | Arguments: |
| 1937 | code points to start of expression (the bracket) |
| 1938 | options pointer to the options (used to check casing changes) |
darin@apple.com | 7f98487 | 2007-11-12 23:04:41 +0000 | [diff] [blame] | 1939 | inassert true if in an assertion |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1940 | |
| 1941 | Returns: -1 or the fixed first char |
| 1942 | */ |
| 1943 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1944 | static int branchFindFirstAssertedCharacter(const unsigned char* code, bool inassert) |
darin@apple.com | 4c77b71 | 2007-12-11 06:08:24 +0000 | [diff] [blame] | 1945 | { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1946 | const unsigned char* scode = firstSignificantOpcodeSkippingAssertions(code); |
darin@apple.com | 4c77b71 | 2007-12-11 06:08:24 +0000 | [diff] [blame] | 1947 | int op = *scode; |
| 1948 | |
| 1949 | if (op >= OP_BRA) |
| 1950 | op = OP_BRA; |
| 1951 | |
| 1952 | switch (op) { |
| 1953 | default: |
| 1954 | return -1; |
| 1955 | |
| 1956 | case OP_BRA: |
| 1957 | case OP_ASSERT: |
darin@apple.com | 4c77b71 | 2007-12-11 06:08:24 +0000 | [diff] [blame] | 1958 | return bracketFindFirstAssertedCharacter(scode, op == OP_ASSERT); |
| 1959 | |
| 1960 | case OP_EXACT: |
| 1961 | scode += 2; |
| 1962 | /* Fall through */ |
| 1963 | |
| 1964 | case OP_CHAR: |
| 1965 | case OP_CHAR_IGNORING_CASE: |
| 1966 | case OP_ASCII_CHAR: |
| 1967 | case OP_ASCII_LETTER_IGNORING_CASE: |
| 1968 | case OP_PLUS: |
| 1969 | case OP_MINPLUS: |
| 1970 | if (!inassert) |
| 1971 | return -1; |
| 1972 | return scode[1]; |
| 1973 | } |
| 1974 | } |
| 1975 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1976 | static int bracketFindFirstAssertedCharacter(const unsigned char* code, bool inassert) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1977 | { |
eric@webkit.org | 32f7c43 | 2007-11-29 11:12:11 +0000 | [diff] [blame] | 1978 | int c = -1; |
| 1979 | do { |
darin@apple.com | 4c77b71 | 2007-12-11 06:08:24 +0000 | [diff] [blame] | 1980 | int d = branchFindFirstAssertedCharacter(code + 1 + LINK_SIZE, inassert); |
| 1981 | if (d < 0) |
| 1982 | return -1; |
| 1983 | if (c < 0) |
| 1984 | c = d; |
| 1985 | else if (c != d) |
| 1986 | return -1; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 1987 | code += getLinkValue(code + 1); |
eric@webkit.org | 32f7c43 | 2007-11-29 11:12:11 +0000 | [diff] [blame] | 1988 | } while (*code == OP_ALT); |
| 1989 | return c; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 1990 | } |
| 1991 | |
mrowe@apple.com | cb17bd0 | 2008-03-28 06:41:17 +0000 | [diff] [blame] | 1992 | static inline int multiplyWithOverflowCheck(int a, int b) |
| 1993 | { |
| 1994 | if (!a || !b) |
| 1995 | return 0; |
| 1996 | if (a > MAX_PATTERN_SIZE / b) |
| 1997 | return -1; |
| 1998 | return a * b; |
| 1999 | } |
| 2000 | |
darin@apple.com | f9c8dd5 | 2008-01-03 06:39:50 +0000 | [diff] [blame] | 2001 | static int calculateCompiledPatternLength(const UChar* pattern, int patternLength, JSRegExpIgnoreCaseOption ignoreCase, |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 2002 | CompileData& cd, ErrorCode& errorcode) |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2003 | { |
| 2004 | /* Make a pass over the pattern to compute the |
| 2005 | amount of store required to hold the compiled code. This does not have to be |
darin@apple.com | f9c8dd5 | 2008-01-03 06:39:50 +0000 | [diff] [blame] | 2006 | perfect as long as errors are overestimates. */ |
mrowe@apple.com | cb17bd0 | 2008-03-28 06:41:17 +0000 | [diff] [blame] | 2007 | |
| 2008 | if (patternLength > MAX_PATTERN_SIZE) { |
| 2009 | errorcode = ERR16; |
| 2010 | return -1; |
| 2011 | } |
| 2012 | |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2013 | int length = 1 + LINK_SIZE; /* For initial BRA plus length */ |
| 2014 | int branch_extra = 0; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2015 | int lastitemlength = 0; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2016 | unsigned brastackptr = 0; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2017 | int brastack[BRASTACK_SIZE]; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2018 | unsigned char bralenstack[BRASTACK_SIZE]; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2019 | int bracount = 0; |
| 2020 | |
eric@webkit.org | 6402910 | 2007-11-29 11:06:57 +0000 | [diff] [blame] | 2021 | const UChar* ptr = (const UChar*)(pattern - 1); |
| 2022 | const UChar* patternEnd = (const UChar*)(pattern + patternLength); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2023 | |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2024 | while (++ptr < patternEnd) { |
| 2025 | int minRepeats = 0, maxRepeats = 0; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2026 | int c = *ptr; |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2027 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2028 | switch (c) { |
| 2029 | /* A backslashed item may be an escaped data character or it may be a |
| 2030 | character type. */ |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2031 | |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2032 | case '\\': |
darin@apple.com | f9c8dd5 | 2008-01-03 06:39:50 +0000 | [diff] [blame] | 2033 | c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, false); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2034 | if (errorcode != 0) |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2035 | return -1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2036 | |
| 2037 | lastitemlength = 1; /* Default length of last item for repeats */ |
| 2038 | |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2039 | if (c >= 0) { /* Data character */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2040 | length += 2; /* For a one-byte character */ |
| 2041 | |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2042 | if (c > 127) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2043 | int i; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2044 | for (i = 0; i < kjs_pcre_utf8_table1_size; i++) |
| 2045 | if (c <= kjs_pcre_utf8_table1[i]) break; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2046 | length += i; |
| 2047 | lastitemlength += i; |
| 2048 | } |
| 2049 | |
| 2050 | continue; |
| 2051 | } |
| 2052 | |
| 2053 | /* Other escapes need one byte */ |
| 2054 | |
| 2055 | length++; |
| 2056 | |
| 2057 | /* A back reference needs an additional 2 bytes, plus either one or 5 |
| 2058 | bytes for a repeat. We also need to keep the value of the highest |
| 2059 | back reference. */ |
| 2060 | |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2061 | if (c <= -ESC_REF) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2062 | int refnum = -c - ESC_REF; |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 2063 | cd.backrefMap |= (refnum < 32) ? (1 << refnum) : 1; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2064 | if (refnum > cd.topBackref) |
| 2065 | cd.topBackref = refnum; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2066 | length += 2; /* For single back reference */ |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2067 | if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { |
| 2068 | ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2069 | if (errorcode) |
| 2070 | return -1; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2071 | if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || |
| 2072 | (minRepeats == 1 && maxRepeats == -1)) |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2073 | length++; |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2074 | else |
| 2075 | length += 5; |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2076 | if (safelyCheckNextChar(ptr, patternEnd, '?')) |
darin@apple.com | 856001d | 2007-11-27 00:50:36 +0000 | [diff] [blame] | 2077 | ptr++; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2078 | } |
| 2079 | } |
| 2080 | continue; |
| 2081 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2082 | case '^': /* Single-byte metacharacters */ |
| 2083 | case '.': |
| 2084 | case '$': |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2085 | length++; |
| 2086 | lastitemlength = 1; |
| 2087 | continue; |
| 2088 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2089 | case '*': /* These repeats won't be after brackets; */ |
| 2090 | case '+': /* those are handled separately */ |
| 2091 | case '?': |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2092 | length++; |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2093 | goto POSSESSIVE; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2094 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2095 | /* This covers the cases of braced repeats after a single char, metachar, |
| 2096 | class, or back reference. */ |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2097 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2098 | case '{': |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2099 | if (!isCountedRepeat(ptr + 1, patternEnd)) |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2100 | goto NORMAL_CHAR; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2101 | ptr = readRepeatCounts(ptr + 1, &minRepeats, &maxRepeats, &errorcode); |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2102 | if (errorcode != 0) |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2103 | return -1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2104 | |
| 2105 | /* These special cases just insert one extra opcode */ |
| 2106 | |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2107 | if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || |
| 2108 | (minRepeats == 1 && maxRepeats == -1)) |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2109 | length++; |
| 2110 | |
| 2111 | /* These cases might insert additional copies of a preceding character. */ |
| 2112 | |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2113 | else { |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2114 | if (minRepeats != 1) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2115 | length -= lastitemlength; /* Uncount the original char or metachar */ |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2116 | if (minRepeats > 0) |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2117 | length += 3 + lastitemlength; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2118 | } |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 2119 | length += lastitemlength + ((maxRepeats > 0) ? 3 : 1); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2120 | } |
| 2121 | |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2122 | if (safelyCheckNextChar(ptr, patternEnd, '?')) |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2123 | ptr++; /* Needs no extra length */ |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2124 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2125 | POSSESSIVE: /* Test for possessive quantifier */ |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2126 | if (safelyCheckNextChar(ptr, patternEnd, '+')) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2127 | ptr++; |
eric@webkit.org | c83d57e | 2007-11-29 11:28:29 +0000 | [diff] [blame] | 2128 | length += 2 + 2 * LINK_SIZE; /* Allow for atomic brackets */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2129 | } |
| 2130 | continue; |
| 2131 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2132 | /* An alternation contains an offset to the next branch or ket. If any ims |
| 2133 | options changed in the previous branch(es), and/or if we are in a |
| 2134 | lookbehind assertion, extra space will be needed at the start of the |
| 2135 | branch. This is handled by branch_extra. */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2136 | |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2137 | case '|': |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 2138 | if (brastackptr == 0) |
| 2139 | cd.needOuterBracket = true; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2140 | length += 1 + LINK_SIZE + branch_extra; |
| 2141 | continue; |
| 2142 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2143 | /* A character class uses 33 characters provided that all the character |
| 2144 | values are less than 256. Otherwise, it uses a bit map for low valued |
| 2145 | characters, and individual items for others. Don't worry about character |
| 2146 | types that aren't allowed in classes - they'll get picked up during the |
| 2147 | compile. A character class that contains only one single-byte character |
| 2148 | uses 2 or 3 bytes, depending on whether it is negated or not. Notice this |
| 2149 | where we can. (In UTF-8 mode we can do this only for chars < 128.) */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2150 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2151 | case '[': { |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2152 | int class_optcount; |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2153 | if (*(++ptr) == '^') { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2154 | class_optcount = 10; /* Greater than one */ |
| 2155 | ptr++; |
| 2156 | } |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2157 | else |
| 2158 | class_optcount = 0; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2159 | |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2160 | bool class_utf8 = false; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2161 | |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2162 | for (; ptr < patternEnd && *ptr != ']'; ++ptr) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2163 | /* Check for escapes */ |
| 2164 | |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2165 | if (*ptr == '\\') { |
darin@apple.com | f9c8dd5 | 2008-01-03 06:39:50 +0000 | [diff] [blame] | 2166 | c = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2167 | if (errorcode != 0) |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2168 | return -1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2169 | |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2170 | /* Handle escapes that turn into characters */ |
| 2171 | |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2172 | if (c >= 0) |
| 2173 | goto NON_SPECIAL_CHARACTER; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2174 | |
| 2175 | /* Escapes that are meta-things. The normal ones just affect the |
| 2176 | bit map, but Unicode properties require an XCLASS extended item. */ |
| 2177 | |
| 2178 | else |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2179 | class_optcount = 10; /* \d, \s etc; make sure > 1 */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2180 | } |
| 2181 | |
| 2182 | /* Anything else increments the possible optimization count. We have to |
| 2183 | detect ranges here so that we can compute the number of extra ranges for |
| 2184 | caseless wide characters when UCP support is available. If there are wide |
| 2185 | characters, we are going to have to use an XCLASS, even for single |
| 2186 | characters. */ |
| 2187 | |
eric@webkit.org | 90a7a13 | 2007-11-29 11:10:33 +0000 | [diff] [blame] | 2188 | else { |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2189 | c = *ptr; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2190 | |
| 2191 | /* Come here from handling \ above when it escapes to a char value */ |
| 2192 | |
| 2193 | NON_SPECIAL_CHARACTER: |
| 2194 | class_optcount++; |
| 2195 | |
eric@webkit.org | 3c68351 | 2007-11-29 11:24:39 +0000 | [diff] [blame] | 2196 | int d = -1; |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2197 | if (safelyCheckNextChar(ptr, patternEnd, '-')) { |
eric@webkit.org | 6402910 | 2007-11-29 11:06:57 +0000 | [diff] [blame] | 2198 | UChar const *hyptr = ptr++; |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2199 | if (safelyCheckNextChar(ptr, patternEnd, '\\')) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2200 | ptr++; |
darin@apple.com | f9c8dd5 | 2008-01-03 06:39:50 +0000 | [diff] [blame] | 2201 | d = checkEscape(&ptr, patternEnd, &errorcode, cd.numCapturingBrackets, true); |
eric@webkit.org | 6402910 | 2007-11-29 11:06:57 +0000 | [diff] [blame] | 2202 | if (errorcode != 0) |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2203 | return -1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2204 | } |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2205 | else if ((ptr + 1 < patternEnd) && ptr[1] != ']') |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2206 | d = *++ptr; |
eric@webkit.org | 6402910 | 2007-11-29 11:06:57 +0000 | [diff] [blame] | 2207 | if (d < 0) |
| 2208 | ptr = hyptr; /* go back to hyphen as data */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2209 | } |
| 2210 | |
| 2211 | /* If d >= 0 we have a range. In UTF-8 mode, if the end is > 255, or > |
| 2212 | 127 for caseless matching, we will need to use an XCLASS. */ |
| 2213 | |
eric@webkit.org | 6402910 | 2007-11-29 11:06:57 +0000 | [diff] [blame] | 2214 | if (d >= 0) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2215 | class_optcount = 10; /* Ensure > 1 */ |
eric@webkit.org | 6402910 | 2007-11-29 11:06:57 +0000 | [diff] [blame] | 2216 | if (d < c) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2217 | errorcode = ERR8; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2218 | return -1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2219 | } |
| 2220 | |
eric@webkit.org | 6402910 | 2007-11-29 11:06:57 +0000 | [diff] [blame] | 2221 | if ((d > 255 || (ignoreCase && d > 127))) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2222 | unsigned char buffer[6]; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2223 | if (!class_utf8) /* Allow for XCLASS overhead */ |
| 2224 | { |
| 2225 | class_utf8 = true; |
| 2226 | length += LINK_SIZE + 2; |
| 2227 | } |
| 2228 | |
| 2229 | /* If we have UCP support, find out how many extra ranges are |
| 2230 | needed to map the other case of characters within this range. We |
| 2231 | have to mimic the range optimization here, because extending the |
eric@webkit.org | 32f7c43 | 2007-11-29 11:12:11 +0000 | [diff] [blame] | 2232 | range upwards might push d over a boundary that makes it use |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2233 | another byte in the UTF-8 representation. */ |
| 2234 | |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2235 | if (ignoreCase) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2236 | int occ, ocd; |
| 2237 | int cc = c; |
| 2238 | int origd = d; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2239 | while (getOthercaseRange(&cc, origd, &occ, &ocd)) { |
eric@webkit.org | 32f7c43 | 2007-11-29 11:12:11 +0000 | [diff] [blame] | 2240 | if (occ >= c && ocd <= d) |
| 2241 | continue; /* Skip embedded */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2242 | |
| 2243 | if (occ < c && ocd >= c - 1) /* Extend the basic range */ |
| 2244 | { /* if there is overlap, */ |
| 2245 | c = occ; /* noting that if occ < c */ |
| 2246 | continue; /* we can't have ocd > d */ |
| 2247 | } /* because a subrange is */ |
| 2248 | if (ocd > d && occ <= d + 1) /* always shorter than */ |
| 2249 | { /* the basic range. */ |
| 2250 | d = ocd; |
| 2251 | continue; |
| 2252 | } |
| 2253 | |
| 2254 | /* An extra item is needed */ |
| 2255 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2256 | length += 1 + encodeUTF8(occ, buffer) + |
| 2257 | ((occ == ocd) ? 0 : encodeUTF8(ocd, buffer)); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2258 | } |
| 2259 | } |
| 2260 | |
| 2261 | /* The length of the (possibly extended) range */ |
| 2262 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2263 | length += 1 + encodeUTF8(c, buffer) + encodeUTF8(d, buffer); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2264 | } |
| 2265 | |
| 2266 | } |
| 2267 | |
| 2268 | /* We have a single character. There is nothing to be done unless we |
| 2269 | are in UTF-8 mode. If the char is > 255, or 127 when caseless, we must |
| 2270 | allow for an XCL_SINGLE item, doubled for caselessness if there is UCP |
| 2271 | support. */ |
| 2272 | |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2273 | else { |
| 2274 | if ((c > 255 || (ignoreCase && c > 127))) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2275 | unsigned char buffer[6]; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2276 | class_optcount = 10; /* Ensure > 1 */ |
| 2277 | if (!class_utf8) /* Allow for XCLASS overhead */ |
| 2278 | { |
| 2279 | class_utf8 = true; |
| 2280 | length += LINK_SIZE + 2; |
| 2281 | } |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2282 | length += (ignoreCase ? 2 : 1) * (1 + encodeUTF8(c, buffer)); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2283 | } |
| 2284 | } |
| 2285 | } |
| 2286 | } |
| 2287 | |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2288 | if (ptr >= patternEnd) { /* Missing terminating ']' */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2289 | errorcode = ERR6; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2290 | return -1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2291 | } |
| 2292 | |
darin@apple.com | a7c5385 | 2007-12-06 20:24:52 +0000 | [diff] [blame] | 2293 | /* We can optimize when there was only one optimizable character. |
| 2294 | Note that this does not detect the case of a negated single character. |
| 2295 | In that case we do an incorrect length computation, but it's not a serious |
| 2296 | problem because the computed length is too large rather than too small. */ |
| 2297 | |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2298 | if (class_optcount == 1) |
darin@apple.com | a7c5385 | 2007-12-06 20:24:52 +0000 | [diff] [blame] | 2299 | goto NORMAL_CHAR; |
| 2300 | |
| 2301 | /* Here, we handle repeats for the class opcodes. */ |
| 2302 | { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2303 | length += 33; |
| 2304 | |
| 2305 | /* A repeat needs either 1 or 5 bytes. If it is a possessive quantifier, |
| 2306 | we also need extra for wrapping the whole thing in a sub-pattern. */ |
| 2307 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2308 | if (safelyCheckNextChar(ptr, patternEnd, '{') && isCountedRepeat(ptr + 2, patternEnd)) { |
| 2309 | ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2310 | if (errorcode != 0) |
| 2311 | return -1; |
| 2312 | if ((minRepeats == 0 && (maxRepeats == 1 || maxRepeats == -1)) || |
| 2313 | (minRepeats == 1 && maxRepeats == -1)) |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2314 | length++; |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2315 | else |
| 2316 | length += 5; |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2317 | if (safelyCheckNextChar(ptr, patternEnd, '+')) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2318 | ptr++; |
eric@webkit.org | c83d57e | 2007-11-29 11:28:29 +0000 | [diff] [blame] | 2319 | length += 2 + 2 * LINK_SIZE; |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2320 | } else if (safelyCheckNextChar(ptr, patternEnd, '?')) |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2321 | ptr++; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2322 | } |
| 2323 | } |
| 2324 | continue; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2325 | } |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2326 | |
| 2327 | /* Brackets may be genuine groups or special things */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2328 | |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2329 | case '(': { |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2330 | int branch_newextra = 0; |
| 2331 | int bracket_length = 1 + LINK_SIZE; |
| 2332 | bool capturing = false; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2333 | |
| 2334 | /* Handle special forms of bracket, which all start (? */ |
| 2335 | |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2336 | if (safelyCheckNextChar(ptr, patternEnd, '?')) { |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2337 | switch (c = (ptr + 2 < patternEnd ? ptr[2] : 0)) { |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2338 | /* Non-referencing groups and lookaheads just move the pointer on, and |
| 2339 | then behave like a non-special bracket, except that they don't increment |
| 2340 | the count of extracting brackets. Ditto for the "once only" bracket, |
| 2341 | which is in Perl from version 5.005. */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2342 | |
| 2343 | case ':': |
| 2344 | case '=': |
| 2345 | case '!': |
| 2346 | ptr += 2; |
| 2347 | break; |
| 2348 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2349 | /* Else loop checking valid options until ) is met. Anything else is an |
| 2350 | error. If we are without any brackets, i.e. at top level, the settings |
| 2351 | act as if specified in the options, so massage the options immediately. |
| 2352 | This is for backward compatibility with Perl 5.004. */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2353 | |
| 2354 | default: |
| 2355 | errorcode = ERR12; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2356 | return -1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2357 | } |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2358 | } else |
| 2359 | capturing = 1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2360 | |
| 2361 | /* Capturing brackets must be counted so we can process escapes in a |
| 2362 | Perlish way. If the number exceeds EXTRACT_BASIC_MAX we are going to need |
| 2363 | an additional 3 bytes of memory per capturing bracket. */ |
| 2364 | |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2365 | if (capturing) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2366 | bracount++; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2367 | if (bracount > EXTRACT_BASIC_MAX) |
| 2368 | bracket_length += 3; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2369 | } |
| 2370 | |
| 2371 | /* Save length for computing whole length at end if there's a repeat that |
| 2372 | requires duplication of the group. Also save the current value of |
| 2373 | branch_extra, and start the new group with the new value. If non-zero, this |
| 2374 | will either be 2 for a (?imsx: group, or 3 for a lookbehind assertion. */ |
| 2375 | |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2376 | if (brastackptr >= sizeof(brastack)/sizeof(int)) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2377 | errorcode = ERR17; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2378 | return -1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2379 | } |
| 2380 | |
| 2381 | bralenstack[brastackptr] = branch_extra; |
| 2382 | branch_extra = branch_newextra; |
| 2383 | |
| 2384 | brastack[brastackptr++] = length; |
| 2385 | length += bracket_length; |
| 2386 | continue; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2387 | } |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2388 | |
| 2389 | /* Handle ket. Look for subsequent maxRepeats/minRepeats; for certain sets of values we |
| 2390 | have to replicate this bracket up to that many times. If brastackptr is |
| 2391 | 0 this is an unmatched bracket which will generate an error, but take care |
| 2392 | not to try to access brastack[-1] when computing the length and restoring |
| 2393 | the branch_extra value. */ |
| 2394 | |
| 2395 | case ')': { |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2396 | int duplength; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2397 | length += 1 + LINK_SIZE; |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2398 | if (brastackptr > 0) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2399 | duplength = length - brastack[--brastackptr]; |
| 2400 | branch_extra = bralenstack[brastackptr]; |
| 2401 | } |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2402 | else |
| 2403 | duplength = 0; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2404 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2405 | /* Leave ptr at the final char; for readRepeatCounts this happens |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2406 | automatically; for the others we need an increment. */ |
| 2407 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2408 | if ((ptr + 1 < patternEnd) && (c = ptr[1]) == '{' && isCountedRepeat(ptr + 2, patternEnd)) { |
| 2409 | ptr = readRepeatCounts(ptr + 2, &minRepeats, &maxRepeats, &errorcode); |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2410 | if (errorcode) |
| 2411 | return -1; |
| 2412 | } else if (c == '*') { |
| 2413 | minRepeats = 0; |
| 2414 | maxRepeats = -1; |
| 2415 | ptr++; |
| 2416 | } else if (c == '+') { |
| 2417 | minRepeats = 1; |
| 2418 | maxRepeats = -1; |
| 2419 | ptr++; |
| 2420 | } else if (c == '?') { |
| 2421 | minRepeats = 0; |
| 2422 | maxRepeats = 1; |
| 2423 | ptr++; |
| 2424 | } else { |
| 2425 | minRepeats = 1; |
| 2426 | maxRepeats = 1; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2427 | } |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2428 | |
| 2429 | /* If the minimum is zero, we have to allow for an OP_BRAZERO before the |
| 2430 | group, and if the maximum is greater than zero, we have to replicate |
| 2431 | maxval-1 times; each replication acquires an OP_BRAZERO plus a nesting |
| 2432 | bracket set. */ |
| 2433 | |
mrowe@apple.com | cb17bd0 | 2008-03-28 06:41:17 +0000 | [diff] [blame] | 2434 | int repeatsLength; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2435 | if (minRepeats == 0) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2436 | length++; |
mrowe@apple.com | cb17bd0 | 2008-03-28 06:41:17 +0000 | [diff] [blame] | 2437 | if (maxRepeats > 0) { |
| 2438 | repeatsLength = multiplyWithOverflowCheck(maxRepeats - 1, duplength + 3 + 2 * LINK_SIZE); |
| 2439 | if (repeatsLength < 0) { |
| 2440 | errorcode = ERR16; |
| 2441 | return -1; |
| 2442 | } |
| 2443 | length += repeatsLength; |
| 2444 | if (length > MAX_PATTERN_SIZE) { |
| 2445 | errorcode = ERR16; |
| 2446 | return -1; |
| 2447 | } |
| 2448 | } |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2449 | } |
| 2450 | |
| 2451 | /* When the minimum is greater than zero, we have to replicate up to |
| 2452 | minval-1 times, with no additions required in the copies. Then, if there |
| 2453 | is a limited maximum we have to replicate up to maxval-1 times allowing |
| 2454 | for a BRAZERO item before each optional copy and nesting brackets for all |
| 2455 | but one of the optional copies. */ |
| 2456 | |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2457 | else { |
mrowe@apple.com | cb17bd0 | 2008-03-28 06:41:17 +0000 | [diff] [blame] | 2458 | repeatsLength = multiplyWithOverflowCheck(minRepeats - 1, duplength); |
| 2459 | if (repeatsLength < 0) { |
| 2460 | errorcode = ERR16; |
| 2461 | return -1; |
| 2462 | } |
| 2463 | length += repeatsLength; |
| 2464 | if (maxRepeats > minRepeats) { /* Need this test as maxRepeats=-1 means no limit */ |
| 2465 | repeatsLength = multiplyWithOverflowCheck(maxRepeats - minRepeats, duplength + 3 + 2 * LINK_SIZE); |
| 2466 | if (repeatsLength < 0) { |
| 2467 | errorcode = ERR16; |
| 2468 | return -1; |
| 2469 | } |
| 2470 | length += repeatsLength - (2 + 2 * LINK_SIZE); |
| 2471 | } |
| 2472 | if (length > MAX_PATTERN_SIZE) { |
| 2473 | errorcode = ERR16; |
| 2474 | return -1; |
| 2475 | } |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2476 | } |
| 2477 | |
| 2478 | /* Allow space for once brackets for "possessive quantifier" */ |
| 2479 | |
eric@webkit.org | 61e47bf | 2007-11-30 23:43:45 +0000 | [diff] [blame] | 2480 | if (safelyCheckNextChar(ptr, patternEnd, '+')) { |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2481 | ptr++; |
eric@webkit.org | c83d57e | 2007-11-29 11:28:29 +0000 | [diff] [blame] | 2482 | length += 2 + 2 * LINK_SIZE; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2483 | } |
| 2484 | continue; |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2485 | } |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2486 | |
| 2487 | /* Non-special character. It won't be space or # in extended mode, so it is |
| 2488 | always a genuine character. If we are in a \Q...\E sequence, check for the |
| 2489 | end; if not, we have a literal. */ |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2490 | |
eric@webkit.org | 70d2b41 | 2007-11-29 11:39:12 +0000 | [diff] [blame] | 2491 | default: |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2492 | NORMAL_CHAR: |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2493 | length += 2; /* For a one-byte character */ |
| 2494 | lastitemlength = 1; /* Default length of last item for repeats */ |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2495 | |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2496 | if (c > 127) { |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2497 | int i; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2498 | for (i = 0; i < kjs_pcre_utf8_table1_size; i++) |
| 2499 | if (c <= kjs_pcre_utf8_table1[i]) |
darin@apple.com | 6b652e8 | 2007-11-30 18:54:34 +0000 | [diff] [blame] | 2500 | break; |
| 2501 | length += i; |
| 2502 | lastitemlength += i; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2503 | } |
| 2504 | |
| 2505 | continue; |
| 2506 | } |
| 2507 | } |
| 2508 | |
| 2509 | length += 2 + LINK_SIZE; /* For final KET and END */ |
darin@apple.com | f9c8dd5 | 2008-01-03 06:39:50 +0000 | [diff] [blame] | 2510 | |
| 2511 | cd.numCapturingBrackets = bracount; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2512 | return length; |
| 2513 | } |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 2514 | |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 2515 | /************************************************* |
| 2516 | * Compile a Regular Expression * |
| 2517 | *************************************************/ |
| 2518 | |
| 2519 | /* This function takes a string and returns a pointer to a block of store |
| 2520 | holding a compiled version of the expression. The original API for this |
| 2521 | function had no error code return variable; it is retained for backwards |
| 2522 | compatibility. The new function is given a new name. |
| 2523 | |
| 2524 | Arguments: |
| 2525 | pattern the regular expression |
| 2526 | options various option bits |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2527 | errorCodePtr pointer to error code variable (pcre_compile2() only) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 2528 | can be NULL if you don't want a code value |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2529 | errorPtr pointer to pointer to error text |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 2530 | erroroffset ptr offset in pattern where error was detected |
| 2531 | tables pointer to character tables or NULL |
| 2532 | |
| 2533 | Returns: pointer to compiled data block, or NULL on error, |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2534 | with errorPtr and erroroffset set |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 2535 | */ |
| 2536 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2537 | static inline JSRegExp* returnError(ErrorCode errorcode, const char** errorPtr) |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2538 | { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2539 | *errorPtr = errorText(errorcode); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2540 | return 0; |
| 2541 | } |
| 2542 | |
eric@webkit.org | 6402910 | 2007-11-29 11:06:57 +0000 | [diff] [blame] | 2543 | JSRegExp* jsRegExpCompile(const UChar* pattern, int patternLength, |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2544 | JSRegExpIgnoreCaseOption ignoreCase, JSRegExpMultilineOption multiline, |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2545 | unsigned* numSubpatterns, const char** errorPtr) |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 2546 | { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2547 | /* We can't pass back an error message if errorPtr is NULL; I guess the best we |
eric@webkit.org | 487902b | 2007-11-15 02:00:15 +0000 | [diff] [blame] | 2548 | can do is just return NULL, but we can set a code value if there is a code pointer. */ |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2549 | if (!errorPtr) |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2550 | return 0; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2551 | *errorPtr = NULL; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2552 | |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 2553 | CompileData cd; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2554 | |
| 2555 | ErrorCode errorcode = ERR0; |
darin@apple.com | f9c8dd5 | 2008-01-03 06:39:50 +0000 | [diff] [blame] | 2556 | /* Call this once just to count the brackets. */ |
| 2557 | calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); |
| 2558 | /* Call it again to compute the length. */ |
| 2559 | int length = calculateCompiledPatternLength(pattern, patternLength, ignoreCase, cd, errorcode); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2560 | if (errorcode) |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2561 | return returnError(errorcode, errorPtr); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2562 | |
| 2563 | if (length > MAX_PATTERN_SIZE) |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2564 | return returnError(ERR16, errorPtr); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2565 | |
eric@webkit.org | 386a602 | 2007-11-29 11:04:06 +0000 | [diff] [blame] | 2566 | size_t size = length + sizeof(JSRegExp); |
darin@apple.com | cff4159 | 2008-06-28 22:21:20 +0000 | [diff] [blame] | 2567 | #if REGEXP_HISTOGRAM |
| 2568 | size_t stringOffset = (size + sizeof(UChar) - 1) / sizeof(UChar) * sizeof(UChar); |
| 2569 | size = stringOffset + patternLength * sizeof(UChar); |
| 2570 | #endif |
eric@webkit.org | 386a602 | 2007-11-29 11:04:06 +0000 | [diff] [blame] | 2571 | JSRegExp* re = reinterpret_cast<JSRegExp*>(new char[size]); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2572 | |
| 2573 | if (!re) |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2574 | return returnError(ERR13, errorPtr); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2575 | |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 2576 | re->options = (ignoreCase ? IgnoreCaseOption : 0) | (multiline ? MatchAcrossMultipleLinesOption : 0); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2577 | |
| 2578 | /* The starting points of the name/number translation table and of the code are |
| 2579 | passed around in the compile data block. */ |
| 2580 | |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2581 | const unsigned char* codeStart = (const unsigned char*)(re + 1); |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2582 | |
| 2583 | /* Set up a starting, non-extracting bracket, then compile the expression. On |
| 2584 | error, errorcode will be set non-zero, so we don't need to look at the result |
| 2585 | of the function here. */ |
| 2586 | |
eric@webkit.org | 6402910 | 2007-11-29 11:06:57 +0000 | [diff] [blame] | 2587 | const UChar* ptr = (const UChar*)pattern; |
| 2588 | const UChar* patternEnd = pattern + patternLength; |
darin@apple.com | 28e8eb9 | 2007-12-17 04:19:25 +0000 | [diff] [blame] | 2589 | unsigned char* code = (unsigned char*)codeStart; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2590 | int firstByte, reqByte; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2591 | int bracketCount = 0; |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 2592 | if (!cd.needOuterBracket) |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2593 | compileBranch(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, &firstByte, &reqByte, cd); |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 2594 | else { |
| 2595 | *code = OP_BRA; |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2596 | compileBracket(re->options, &bracketCount, &code, &ptr, patternEnd, &errorcode, 0, &firstByte, &reqByte, cd); |
darin@apple.com | 8ad18ea | 2007-12-07 19:59:58 +0000 | [diff] [blame] | 2597 | } |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2598 | re->topBracket = bracketCount; |
| 2599 | re->topBackref = cd.topBackref; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2600 | |
| 2601 | /* If not reached end of pattern on success, there's an excess bracket. */ |
| 2602 | |
| 2603 | if (errorcode == 0 && ptr < patternEnd) |
| 2604 | errorcode = ERR10; |
| 2605 | |
| 2606 | /* Fill in the terminating state and check for disastrous overflow, but |
| 2607 | if debugging, leave the test till after things are printed out. */ |
| 2608 | |
| 2609 | *code++ = OP_END; |
darin@apple.com | e410bdf | 2007-12-04 19:08:28 +0000 | [diff] [blame] | 2610 | |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 2611 | ASSERT(code - codeStart <= length); |
| 2612 | if (code - codeStart > length) |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2613 | errorcode = ERR7; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2614 | |
| 2615 | /* Give an error if there's back reference to a non-existent capturing |
| 2616 | subpattern. */ |
| 2617 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2618 | if (re->topBackref > re->topBracket) |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2619 | errorcode = ERR15; |
| 2620 | |
| 2621 | /* Failed to compile, or error while post-processing */ |
| 2622 | |
| 2623 | if (errorcode != ERR0) { |
| 2624 | delete [] reinterpret_cast<char*>(re); |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2625 | return returnError(errorcode, errorPtr); |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 2626 | } |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2627 | |
| 2628 | /* If the anchored option was not passed, set the flag if we can determine that |
| 2629 | the pattern is anchored by virtue of ^ characters or \A or anything else (such |
| 2630 | as starting with .* when DOTALL is set). |
| 2631 | |
| 2632 | Otherwise, if we know what the first character has to be, save it, because that |
| 2633 | speeds up unanchored matches no end. If not, see if we can set the |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 2634 | UseMultiLineFirstByteOptimizationOption flag. This is helpful for multiline matches when all branches |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2635 | start with ^. and also when all branches start with .* for non-DOTALL matches. |
| 2636 | */ |
| 2637 | |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 2638 | if (cd.needOuterBracket ? bracketIsAnchored(codeStart) : branchIsAnchored(codeStart)) |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 2639 | re->options |= IsAnchoredOption; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2640 | else { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2641 | if (firstByte < 0) { |
| 2642 | firstByte = (cd.needOuterBracket |
darin@apple.com | 4c77b71 | 2007-12-11 06:08:24 +0000 | [diff] [blame] | 2643 | ? bracketFindFirstAssertedCharacter(codeStart, false) |
| 2644 | : branchFindFirstAssertedCharacter(codeStart, false)) |
| 2645 | | ((re->options & IgnoreCaseOption) ? REQ_IGNORE_CASE : 0); |
| 2646 | } |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2647 | if (firstByte >= 0) { |
| 2648 | int ch = firstByte & 255; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2649 | if (ch < 127) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2650 | re->firstByte = ((firstByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? ch : firstByte; |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 2651 | re->options |= UseFirstByteOptimizationOption; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2652 | } |
darin@apple.com | d5cbb63 | 2007-12-10 06:22:04 +0000 | [diff] [blame] | 2653 | } else { |
| 2654 | if (cd.needOuterBracket ? bracketNeedsLineStart(codeStart, 0, cd.backrefMap) : branchNeedsLineStart(codeStart, 0, cd.backrefMap)) |
| 2655 | re->options |= UseMultiLineFirstByteOptimizationOption; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2656 | } |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2657 | } |
| 2658 | |
| 2659 | /* For an anchored pattern, we use the "required byte" only if it follows a |
| 2660 | variable length item in the regex. Remove the caseless flag for non-caseable |
| 2661 | bytes. */ |
| 2662 | |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2663 | if (reqByte >= 0 && (!(re->options & IsAnchoredOption) || (reqByte & REQ_VARY))) { |
| 2664 | int ch = reqByte & 255; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2665 | if (ch < 127) { |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2666 | re->reqByte = ((reqByte & REQ_IGNORE_CASE) && flipCase(ch) == ch) ? (reqByte & ~REQ_IGNORE_CASE) : reqByte; |
eric@webkit.org | 8a34467 | 2007-11-29 11:38:26 +0000 | [diff] [blame] | 2667 | re->options |= UseRequiredByteOptimizationOption; |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2668 | } |
| 2669 | } |
| 2670 | |
darin@apple.com | cff4159 | 2008-06-28 22:21:20 +0000 | [diff] [blame] | 2671 | #if REGEXP_HISTOGRAM |
| 2672 | re->stringOffset = stringOffset; |
| 2673 | re->stringLength = patternLength; |
| 2674 | memcpy(reinterpret_cast<char*>(re) + stringOffset, pattern, patternLength * 2); |
| 2675 | #endif |
| 2676 | |
eric@webkit.org | 1dab6f5 | 2007-11-15 01:17:31 +0000 | [diff] [blame] | 2677 | if (numSubpatterns) |
darin@apple.com | 51d6b26 | 2008-06-15 06:23:50 +0000 | [diff] [blame] | 2678 | *numSubpatterns = re->topBracket; |
eric@webkit.org | a28f14e | 2007-11-29 11:05:07 +0000 | [diff] [blame] | 2679 | return re; |
darin | d7737ab | 2005-09-09 00:51:07 +0000 | [diff] [blame] | 2680 | } |
| 2681 | |
darin@apple.com | a7c3b87 | 2007-11-04 05:22:44 +0000 | [diff] [blame] | 2682 | void jsRegExpFree(JSRegExp* re) |
| 2683 | { |
darin@apple.com | ee752e7 | 2007-11-11 18:56:13 +0000 | [diff] [blame] | 2684 | delete [] reinterpret_cast<char*>(re); |
darin@apple.com | a7c3b87 | 2007-11-04 05:22:44 +0000 | [diff] [blame] | 2685 | } |