/* * Regular Expression Engine * * Copyright (c) 2017-2018 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <inttypes.h>#include <string.h>#include <assert.h> #include "cutils.h"#include "libregexp.h" /* TODO: - Add full unicode canonicalize rules for character ranges (not really useful but needed for exact "ignorecase" compatibility). - Add a lock step execution mode (=linear time execution guaranteed) when the regular expression is "simple" i.e. no backreference nor complicated lookahead. The opcodes are designed for this execution model.*/ #if defined(TEST)#define DUMP_REOP#endif typedef enum {#define DEF(id, size) REOP_ ## id,#include "libregexp-opcode.h"#undef DEF REOP_COUNT,} REOPCodeEnum; #define CAPTURE_COUNT_MAX 255#define STACK_SIZE_MAX 255 /* unicode code points */#define CP_LS 0x2028#define CP_PS 0x2029 #define TMP_BUF_SIZE 128 typedef struct { DynBuf byte_code; const uint8_t *buf_ptr; const uint8_t *buf_end; const uint8_t *buf_start; int re_flags; BOOL is_utf16; BOOL ignore_case; BOOL dotall; int capture_count; int total_capture_count; /* -1 = not computed yet */ int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */ void *opaque; DynBuf group_names; union { char error_msg[TMP_BUF_SIZE]; char tmp_buf[TMP_BUF_SIZE]; } u;} REParseState; typedef struct {#ifdef DUMP_REOP const char *name;#endif uint8_t size;} REOpCode; static const REOpCode reopcode_info[REOP_COUNT] = {#ifdef DUMP_REOP#define DEF(id, size) { #id, size },#else#define DEF(id, size) { size },#endif#include "libregexp-opcode.h"#undef DEF}; #define RE_HEADER_FLAGS 0#define RE_HEADER_CAPTURE_COUNT 1#define RE_HEADER_STACK_SIZE 2 #define RE_HEADER_LEN 7 static inline int is_digit(int c) { return c >= '0' && c <= '9';} /* insert 'len' bytes at position 'pos'. Return < 0 if error. */static int dbuf_insert(DynBuf *s, int pos, int len){ if (dbuf_realloc(s, s->size + len)) return -1; memmove(s->buf + pos + len, s->buf + pos, s->size - pos); s->size += len; return 0;} /* canonicalize with the specific JS regexp rules */static uint32_t lre_canonicalize(uint32_t c, BOOL is_utf16){ uint32_t res[LRE_CC_RES_LEN_MAX]; int len; if (is_utf16) { if (likely(c < 128)) { if (c >= 'A' && c <= 'Z') c = c - 'A' + 'a'; } else { lre_case_conv(res, c, 2); c = res[0]; } } else { if (likely(c < 128)) { if (c >= 'a' && c <= 'z') c = c - 'a' + 'A'; } else { /* legacy regexp: to upper case if single char >= 128 */ len = lre_case_conv(res, c, FALSE); if (len == 1 && res[0] >= 128) c = res[0]; } } return c;} static const uint16_t char_range_d[] = { 1, 0x0030, 0x0039 + 1,}; /* code point ranges for Zs,Zl or Zp property */static const uint16_t char_range_s[] = { 10, 0x0009, 0x000D + 1, 0x0020, 0x0020 + 1, 0x00A0, 0x00A0 + 1, 0x1680, 0x1680 + 1, 0x2000, 0x200A + 1, /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */ /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */ 0x2028, 0x2029 + 1, 0x202F, 0x202F + 1, 0x205F, 0x205F + 1, 0x3000, 0x3000 + 1, /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */ 0xFEFF, 0xFEFF + 1,}; BOOL lre_is_space(int c){ int i, n, low, high; n = (countof(char_range_s) - 1) / 2; for(i = 0; i < n; i++) { low = char_range_s[2 * i + 1]; if (c < low) return FALSE; high = char_range_s[2 * i + 2]; if (c < high) return TRUE; } return FALSE;} uint32_t const lre_id_start_table_ascii[4] = { /* $ A-Z _ a-z */ 0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE}; uint32_t const lre_id_continue_table_ascii[4] = { /* $ 0-9 A-Z _ a-z */ 0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE}; static const uint16_t char_range_w[] = { 4, 0x0030, 0x0039 + 1, 0x0041, 0x005A + 1, 0x005F, 0x005F + 1, 0x0061, 0x007A + 1,}; #define CLASS_RANGE_BASE 0x40000000 typedef enum { CHAR_RANGE_d, CHAR_RANGE_D, CHAR_RANGE_s, CHAR_RANGE_S, CHAR_RANGE_w, CHAR_RANGE_W,} CharRangeEnum; static const uint16_t *char_range_table[] = { char_range_d, char_range_s, char_range_w,}; static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c){ BOOL invert; const uint16_t *c_pt; int len, i; invert = c & 1; c_pt = char_range_table[c >> 1]; len = *c_pt++; cr_init(cr, s->opaque, lre_realloc); for(i = 0; i < len * 2; i++) { if (cr_add_point(cr, c_pt[i])) goto fail; } if (invert) { if (cr_invert(cr)) goto fail; } return 0; fail: cr_free(cr); return -1;} static int cr_canonicalize(CharRange *cr){ CharRange a; uint32_t pt[2]; int i, ret; cr_init(&a, cr->mem_opaque, lre_realloc); pt[0] = 'a'; pt[1] = 'z' + 1; ret = cr_op(&a, cr->points, cr->len, pt, 2, CR_OP_INTER); if (ret) goto fail; /* convert to upper case */ /* XXX: the generic unicode case would be much more complicated and not really useful */ for(i = 0; i < a.len; i++) { a.points[i] += 'A' - 'a'; } /* Note: for simplicity we keep the lower case ranges */ ret = cr_union1(cr, a.points, a.len); fail: cr_free(&a); return ret;} #ifdef DUMP_REOPstatic __maybe_unused void lre_dump_bytecode(const uint8_t *buf, int buf_len){ int pos, len, opcode, bc_len, re_flags, i; uint32_t val; assert(buf_len >= RE_HEADER_LEN); re_flags= buf[0]; bc_len = get_u32(buf + 3); assert(bc_len + RE_HEADER_LEN <= buf_len); printf("flags: 0x%x capture_count=%d stack_size=%d\n", re_flags, buf[1], buf[2]); if (re_flags & LRE_FLAG_NAMED_GROUPS) { const char *p; p = (char *)buf + RE_HEADER_LEN + bc_len; printf("named groups: "); for(i = 1; i < buf[1]; i++) { if (i != 1) printf(","); printf("<%s>", p); p += strlen(p) + 1; } printf("\n"); assert(p == (char *)(buf + buf_len)); } printf("bytecode_len=%d\n", bc_len); buf += RE_HEADER_LEN; pos = 0; while (pos < bc_len) { printf("%5u: ", pos); opcode = buf[pos]; len = reopcode_info[opcode].size; if (opcode >= REOP_COUNT) { printf(" invalid opcode=0x%02x\n", opcode); break; } if ((pos + len) > bc_len) { printf(" buffer overflow (opcode=0x%02x)\n", opcode); break; } printf("%s", reopcode_info[opcode].name); switch(opcode) { case REOP_char: val = get_u16(buf + pos + 1); if (val >= ' ' && val <= 126) printf(" '%c'", val); else printf(" 0x%04x", val); break; case REOP_char32: val = get_u32(buf + pos + 1); if (val >= ' ' && val <= 126) printf(" '%c'", val); else printf(" 0x%08x", val); break; case REOP_goto: case REOP_split_goto_first: case REOP_split_next_first: case REOP_loop: case REOP_lookahead: case REOP_negative_lookahead: case REOP_bne_char_pos: val = get_u32(buf + pos + 1); val += (pos + 5); printf(" %u", val); break; case REOP_simple_greedy_quant: printf(" %u %u %u %u", get_u32(buf + pos + 1) + (pos + 17), get_u32(buf + pos + 1 + 4), get_u32(buf + pos + 1 + 8), get_u32(buf + pos + 1 + 12)); break; case REOP_save_start: case REOP_save_end: case REOP_back_reference: case REOP_backward_back_reference: printf(" %u", buf[pos + 1]); break; case REOP_save_reset: printf(" %u %u", buf[pos + 1], buf[pos + 2]); break; case REOP_push_i32: val = get_u32(buf + pos + 1); printf(" %d", val); break; case REOP_range: { int n, i; n = get_u16(buf + pos + 1); len += n * 4; for(i = 0; i < n * 2; i++) { val = get_u16(buf + pos + 3 + i * 2); printf(" 0x%04x", val); } } break; case REOP_range32: { int n, i; n = get_u16(buf + pos + 1); len += n * 8; for(i = 0; i < n * 2; i++) { val = get_u32(buf + pos + 3 + i * 4); printf(" 0x%08x", val); } } break; default: break; } printf("\n"); pos += len; }}#endif static void re_emit_op(REParseState *s, int op){ dbuf_putc(&s->byte_code, op);} /* return the offset of the u32 value */static int re_emit_op_u32(REParseState *s, int op, uint32_t val){ int pos; dbuf_putc(&s->byte_code, op); pos = s->byte_code.size; dbuf_put_u32(&s->byte_code, val); return pos;} static int re_emit_goto(REParseState *s, int op, uint32_t val){ int pos; dbuf_putc(&s->byte_code, op); pos = s->byte_code.size; dbuf_put_u32(&s->byte_code, val - (pos + 4)); return pos;} static void re_emit_op_u8(REParseState *s, int op, uint32_t val){ dbuf_putc(&s->byte_code, op); dbuf_putc(&s->byte_code, val);} static void re_emit_op_u16(REParseState *s, int op, uint32_t val){ dbuf_putc(&s->byte_code, op); dbuf_put_u16(&s->byte_code, val);} static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s, const char *fmt, ...){ va_list ap; va_start(ap, fmt); vsnprintf(s->u.error_msg, sizeof(s->u.error_msg), fmt, ap); va_end(ap); return -1;} static int re_parse_out_of_memory(REParseState *s){ return re_parse_error(s, "out of memory");} /* If allow_overflow is false, return -1 in case of overflow. Otherwise return INT32_MAX. */static int parse_digits(const uint8_t **pp, BOOL allow_overflow){ const uint8_t *p; uint64_t v; int c; p = *pp; v = 0; for(;;) { c = *p; if (c < '0' || c > '9') break; v = v * 10 + c - '0'; if (v >= INT32_MAX) { if (allow_overflow) v = INT32_MAX; else return -1; } p++; } *pp = p; return v;} static int re_parse_expect(REParseState *s, const uint8_t **pp, int c){ const uint8_t *p; p = *pp; if (*p != c) return re_parse_error(s, "expecting '%c'", c); p++; *pp = p; return 0;} /* Parse an escape sequence, *pp points after the '\': allow_utf16 value: 0 : no UTF-16 escapes allowed 1 : UTF-16 escapes allowed 2 : UTF-16 escapes allowed and escapes of surrogate pairs are converted to a unicode character (unicode regexp case). Return the unicode char and update *pp if recognized, return -1 if malformed escape, return -2 otherwise. */int lre_parse_escape(const uint8_t **pp, int allow_utf16){ const uint8_t *p; uint32_t c; p = *pp; c = *p++; switch(c) { case 'b':Lines 1–500 of 2611. Load more
/* * Regular Expression Engine * * Copyright (c) 2017-2018 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <inttypes.h> #include <string.h> #include <assert.h> #include "cutils.h" #include "libregexp.h" /* TODO: - Add full unicode canonicalize rules for character ranges (not really useful but needed for exact "ignorecase" compatibility). - Add a lock step execution mode (=linear time execution guaranteed) when the regular expression is "simple" i.e. no backreference nor complicated lookahead. The opcodes are designed for this execution model. */ #if defined(TEST) #define DUMP_REOP #endif typedef enum { #define DEF(id, size) REOP_ ## id, #include "libregexp-opcode.h" #undef DEF REOP_COUNT, } REOPCodeEnum; #define CAPTURE_COUNT_MAX 255 #define STACK_SIZE_MAX 255 /* unicode code points */ #define CP_LS 0x2028 #define CP_PS 0x2029 #define TMP_BUF_SIZE 128 typedef struct { DynBuf byte_code; const uint8_t *buf_ptr; const uint8_t *buf_end; const uint8_t *buf_start; int re_flags; BOOL is_utf16; BOOL ignore_case; BOOL dotall; int capture_count; int total_capture_count; /* -1 = not computed yet */ int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */ void *opaque; DynBuf group_names; union { char error_msg[TMP_BUF_SIZE]; char tmp_buf[TMP_BUF_SIZE]; } u; } REParseState; typedef struct { #ifdef DUMP_REOP const char *name; #endif uint8_t size; } REOpCode; static const REOpCode reopcode_info[REOP_COUNT] = { #ifdef DUMP_REOP #define DEF(id, size) { #id, size }, #else #define DEF(id, size) { size }, #endif #include "libregexp-opcode.h" #undef DEF }; #define RE_HEADER_FLAGS 0 #define RE_HEADER_CAPTURE_COUNT 1 #define RE_HEADER_STACK_SIZE 2 #define RE_HEADER_LEN 7 static inline int is_digit(int c) { return c >= '0' && c <= '9'; } /* insert 'len' bytes at position 'pos'. Return < 0 if error. */ static int dbuf_insert(DynBuf *s, int pos, int len) { if (dbuf_realloc(s, s->size + len)) return -1; memmove(s->buf + pos + len, s->buf + pos, s->size - pos); s->size += len; return 0; } /* canonicalize with the specific JS regexp rules */ static uint32_t lre_canonicalize(uint32_t c, BOOL is_utf16) { uint32_t res[LRE_CC_RES_LEN_MAX]; int len; if (is_utf16) { if (likely(c < 128)) { if (c >= 'A' && c <= 'Z') c = c - 'A' + 'a'; } else { lre_case_conv(res, c, 2); c = res[0]; } } else { if (likely(c < 128)) { if (c >= 'a' && c <= 'z') c = c - 'a' + 'A'; } else { /* legacy regexp: to upper case if single char >= 128 */ len = lre_case_conv(res, c, FALSE); if (len == 1 && res[0] >= 128) c = res[0]; } } return c; } static const uint16_t char_range_d[] = { 1, 0x0030, 0x0039 + 1, }; /* code point ranges for Zs,Zl or Zp property */ static const uint16_t char_range_s[] = { 10, 0x0009, 0x000D + 1, 0x0020, 0x0020 + 1, 0x00A0, 0x00A0 + 1, 0x1680, 0x1680 + 1, 0x2000, 0x200A + 1, /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */ /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */ 0x2028, 0x2029 + 1, 0x202F, 0x202F + 1, 0x205F, 0x205F + 1, 0x3000, 0x3000 + 1, /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */ 0xFEFF, 0xFEFF + 1, }; BOOL lre_is_space(int c) { int i, n, low, high; n = (countof(char_range_s) - 1) / 2; for(i = 0; i < n; i++) { low = char_range_s[2 * i + 1]; if (c < low) return FALSE; high = char_range_s[2 * i + 2]; if (c < high) return TRUE; } return FALSE; } uint32_t const lre_id_start_table_ascii[4] = { /* $ A-Z _ a-z */ 0x00000000, 0x00000010, 0x87FFFFFE, 0x07FFFFFE }; uint32_t const lre_id_continue_table_ascii[4] = { /* $ 0-9 A-Z _ a-z */ 0x00000000, 0x03FF0010, 0x87FFFFFE, 0x07FFFFFE }; static const uint16_t char_range_w[] = { 4, 0x0030, 0x0039 + 1, 0x0041, 0x005A + 1, 0x005F, 0x005F + 1, 0x0061, 0x007A + 1, }; #define CLASS_RANGE_BASE 0x40000000 typedef enum { CHAR_RANGE_d, CHAR_RANGE_D, CHAR_RANGE_s, CHAR_RANGE_S, CHAR_RANGE_w, CHAR_RANGE_W, } CharRangeEnum; static const uint16_t *char_range_table[] = { char_range_d, char_range_s, char_range_w, }; static int cr_init_char_range(REParseState *s, CharRange *cr, uint32_t c) { BOOL invert; const uint16_t *c_pt; int len, i; invert = c & 1; c_pt = char_range_table[c >> 1]; len = *c_pt++; cr_init(cr, s->opaque, lre_realloc); for(i = 0; i < len * 2; i++) { if (cr_add_point(cr, c_pt[i])) goto fail; } if (invert) { if (cr_invert(cr)) goto fail; } return 0; fail: cr_free(cr); return -1; } static int cr_canonicalize(CharRange *cr) { CharRange a; uint32_t pt[2]; int i, ret; cr_init(&a, cr->mem_opaque, lre_realloc); pt[0] = 'a'; pt[1] = 'z' + 1; ret = cr_op(&a, cr->points, cr->len, pt, 2, CR_OP_INTER); if (ret) goto fail; /* convert to upper case */ /* XXX: the generic unicode case would be much more complicated and not really useful */ for(i = 0; i < a.len; i++) { a.points[i] += 'A' - 'a'; } /* Note: for simplicity we keep the lower case ranges */ ret = cr_union1(cr, a.points, a.len); fail: cr_free(&a); return ret; } #ifdef DUMP_REOP static __maybe_unused void lre_dump_bytecode(const uint8_t *buf, int buf_len) { int pos, len, opcode, bc_len, re_flags, i; uint32_t val; assert(buf_len >= RE_HEADER_LEN); re_flags= buf[0]; bc_len = get_u32(buf + 3); assert(bc_len + RE_HEADER_LEN <= buf_len); printf("flags: 0x%x capture_count=%d stack_size=%d\n", re_flags, buf[1], buf[2]); if (re_flags & LRE_FLAG_NAMED_GROUPS) { const char *p; p = (char *)buf + RE_HEADER_LEN + bc_len; printf("named groups: "); for(i = 1; i < buf[1]; i++) { if (i != 1) printf(","); printf("<%s>", p); p += strlen(p) + 1; } printf("\n"); assert(p == (char *)(buf + buf_len)); } printf("bytecode_len=%d\n", bc_len); buf += RE_HEADER_LEN; pos = 0; while (pos < bc_len) { printf("%5u: ", pos); opcode = buf[pos]; len = reopcode_info[opcode].size; if (opcode >= REOP_COUNT) { printf(" invalid opcode=0x%02x\n", opcode); break; } if ((pos + len) > bc_len) { printf(" buffer overflow (opcode=0x%02x)\n", opcode); break; } printf("%s", reopcode_info[opcode].name); switch(opcode) { case REOP_char: val = get_u16(buf + pos + 1); if (val >= ' ' && val <= 126) printf(" '%c'", val); else printf(" 0x%04x", val); break; case REOP_char32: val = get_u32(buf + pos + 1); if (val >= ' ' && val <= 126) printf(" '%c'", val); else printf(" 0x%08x", val); break; case REOP_goto: case REOP_split_goto_first: case REOP_split_next_first: case REOP_loop: case REOP_lookahead: case REOP_negative_lookahead: case REOP_bne_char_pos: val = get_u32(buf + pos + 1); val += (pos + 5); printf(" %u", val); break; case REOP_simple_greedy_quant: printf(" %u %u %u %u", get_u32(buf + pos + 1) + (pos + 17), get_u32(buf + pos + 1 + 4), get_u32(buf + pos + 1 + 8), get_u32(buf + pos + 1 + 12)); break; case REOP_save_start: case REOP_save_end: case REOP_back_reference: case REOP_backward_back_reference: printf(" %u", buf[pos + 1]); break; case REOP_save_reset: printf(" %u %u", buf[pos + 1], buf[pos + 2]); break; case REOP_push_i32: val = get_u32(buf + pos + 1); printf(" %d", val); break; case REOP_range: { int n, i; n = get_u16(buf + pos + 1); len += n * 4; for(i = 0; i < n * 2; i++) { val = get_u16(buf + pos + 3 + i * 2); printf(" 0x%04x", val); } } break; case REOP_range32: { int n, i; n = get_u16(buf + pos + 1); len += n * 8; for(i = 0; i < n * 2; i++) { val = get_u32(buf + pos + 3 + i * 4); printf(" 0x%08x", val); } } break; default: break; } printf("\n"); pos += len; } } #endif static void re_emit_op(REParseState *s, int op) { dbuf_putc(&s->byte_code, op); } /* return the offset of the u32 value */ static int re_emit_op_u32(REParseState *s, int op, uint32_t val) { int pos; dbuf_putc(&s->byte_code, op); pos = s->byte_code.size; dbuf_put_u32(&s->byte_code, val); return pos; } static int re_emit_goto(REParseState *s, int op, uint32_t val) { int pos; dbuf_putc(&s->byte_code, op); pos = s->byte_code.size; dbuf_put_u32(&s->byte_code, val - (pos + 4)); return pos; } static void re_emit_op_u8(REParseState *s, int op, uint32_t val) { dbuf_putc(&s->byte_code, op); dbuf_putc(&s->byte_code, val); } static void re_emit_op_u16(REParseState *s, int op, uint32_t val) { dbuf_putc(&s->byte_code, op); dbuf_put_u16(&s->byte_code, val); } static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vsnprintf(s->u.error_msg, sizeof(s->u.error_msg), fmt, ap); va_end(ap); return -1; } static int re_parse_out_of_memory(REParseState *s) { return re_parse_error(s, "out of memory"); } /* If allow_overflow is false, return -1 in case of overflow. Otherwise return INT32_MAX. */ static int parse_digits(const uint8_t **pp, BOOL allow_overflow) { const uint8_t *p; uint64_t v; int c; p = *pp; v = 0; for(;;) { c = *p; if (c < '0' || c > '9') break; v = v * 10 + c - '0'; if (v >= INT32_MAX) { if (allow_overflow) v = INT32_MAX; else return -1; } p++; } *pp = p; return v; } static int re_parse_expect(REParseState *s, const uint8_t **pp, int c) { const uint8_t *p; p = *pp; if (*p != c) return re_parse_error(s, "expecting '%c'", c); p++; *pp = p; return 0; } /* Parse an escape sequence, *pp points after the '\': allow_utf16 value: 0 : no UTF-16 escapes allowed 1 : UTF-16 escapes allowed 2 : UTF-16 escapes allowed and escapes of surrogate pairs are converted to a unicode character (unicode regexp case). Return the unicode char and update *pp if recognized, return -1 if malformed escape, return -2 otherwise. */ int lre_parse_escape(const uint8_t **pp, int allow_utf16) { const uint8_t *p; uint32_t c; p = *pp; c = *p++; switch(c) { case 'b':