diff options
Diffstat (limited to 'regcomp.c')
| -rw-r--r-- | regcomp.c | 3255 |
1 files changed, 1844 insertions, 1411 deletions
@@ -1,8 +1,9 @@ /********************************************************************** - regcomp.c - Oniguruma (regular expression library) + regcomp.c - Onigmo (Oniguruma-mod) (regular expression library) **********************************************************************/ /*- - * Copyright (c) 2002-2007 K.Kosako <sndgk393 AT ybb DOT ne DOT jp> + * Copyright (c) 2002-2018 K.Kosako <sndgk393 AT ybb DOT ne DOT jp> + * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,10 +50,11 @@ onig_set_default_case_fold_flag(OnigCaseFoldType case_fold_flag) static unsigned char PadBuf[WORD_ALIGNMENT_SIZE]; #endif +#if 0 static UChar* str_dup(UChar* s, UChar* end) { - int len = end - s; + ptrdiff_t len = end - s; if (len > 0) { UChar* r = (UChar* )xmalloc(len + 1); @@ -63,6 +65,7 @@ str_dup(UChar* s, UChar* end) } else return NULL; } +#endif static void swap_node(Node* a, Node* b) @@ -73,7 +76,7 @@ swap_node(Node* a, Node* b) if (NTYPE(a) == NT_STR) { StrNode* sn = NSTR(a); if (sn->capa == 0) { - int len = sn->end - sn->s; + size_t len = sn->end - sn->s; sn->s = sn->buf; sn->end = sn->s + len; } @@ -82,7 +85,7 @@ swap_node(Node* a, Node* b) if (NTYPE(b) == NT_STR) { StrNode* sn = NSTR(b); if (sn->capa == 0) { - int len = sn->end - sn->s; + size_t len = sn->end - sn->s; sn->s = sn->buf; sn->end = sn->s + len; } @@ -135,8 +138,29 @@ bitset_on_num(BitSetRef bs) } #endif +// Attempt to right size allocated buffers for a regex post compile +static void +onig_reg_resize(regex_t *reg) +{ + do { + if (!reg->used) { + xfree(reg->p); + reg->alloc = 0; + reg->p = 0; + } + else if (reg->alloc > reg->used) { + unsigned char *new_ptr = xrealloc(reg->p, reg->used); + // Skip the right size optimization if memory allocation fails + if (new_ptr) { + reg->alloc = reg->used; + reg->p = new_ptr; + } + } + } while ((reg = reg->chain) != 0); +} + extern int -onig_bbuf_init(BBuf* buf, int size) +onig_bbuf_init(BBuf* buf, OnigDistance size) { if (size <= 0) { size = 0; @@ -147,7 +171,7 @@ onig_bbuf_init(BBuf* buf, int size) if (IS_NULL(buf->p)) return(ONIGERR_MEMORY); } - buf->alloc = size; + buf->alloc = (unsigned int )size; buf->used = 0; return 0; } @@ -171,8 +195,7 @@ unset_addr_list_init(UnsetAddrList* uslist, int size) static void unset_addr_list_end(UnsetAddrList* uslist) { - if (IS_NOT_NULL(uslist->us)) - xfree(uslist->us); + xfree(uslist->us); } static int @@ -234,7 +257,7 @@ add_abs_addr(regex_t* reg, int addr) } static int -add_length(regex_t* reg, int len) +add_length(regex_t* reg, OnigDistance len) { LengthType l = (LengthType )len; @@ -251,6 +274,7 @@ add_mem_num(regex_t* reg, int num) return 0; } +#if 0 static int add_pointer(regex_t* reg, void* addr) { @@ -259,6 +283,7 @@ add_pointer(regex_t* reg, void* addr) BBUF_ADD(reg, &ptr, SIZE_POINTER); return 0; } +#endif static int add_option(regex_t* reg, OnigOptionType option) @@ -279,7 +304,7 @@ add_opcode_rel_addr(regex_t* reg, int opcode, int addr) } static int -add_bytes(regex_t* reg, UChar* bytes, int len) +add_bytes(regex_t* reg, UChar* bytes, OnigDistance len) { BBUF_ADD(reg, bytes, len); return 0; @@ -312,9 +337,10 @@ static int compile_tree(Node* node, regex_t* reg); (op) == OP_EXACTMB3N || (op) == OP_EXACTMBN || (op) == OP_EXACTN_IC) static int -select_str_opcode(int mb_len, int str_len, int ignore_case) +select_str_opcode(int mb_len, OnigDistance byte_len, int ignore_case) { int op; + OnigDistance str_len = roomof(byte_len, mb_len); if (ignore_case) { switch (str_len) { @@ -416,11 +442,11 @@ compile_tree_n_times(Node* node, int n, regex_t* reg) } static int -add_compile_string_length(UChar* s, int mb_len, int str_len, - regex_t* reg, int ignore_case) +add_compile_string_length(UChar* s ARG_UNUSED, int mb_len, OnigDistance byte_len, + regex_t* reg ARG_UNUSED, int ignore_case) { int len; - int op = select_str_opcode(mb_len, str_len, ignore_case); + int op = select_str_opcode(mb_len, byte_len, ignore_case); len = SIZE_OPCODE; @@ -428,15 +454,15 @@ add_compile_string_length(UChar* s, int mb_len, int str_len, if (IS_NEED_STR_LEN_OP_EXACT(op)) len += SIZE_LENGTH; - len += mb_len * str_len; + len += (int )byte_len; return len; } static int -add_compile_string(UChar* s, int mb_len, int str_len, +add_compile_string(UChar* s, int mb_len, OnigDistance byte_len, regex_t* reg, int ignore_case) { - int op = select_str_opcode(mb_len, str_len, ignore_case); + int op = select_str_opcode(mb_len, byte_len, ignore_case); add_opcode(reg, op); if (op == OP_EXACTMBN) @@ -444,12 +470,12 @@ add_compile_string(UChar* s, int mb_len, int str_len, if (IS_NEED_STR_LEN_OP_EXACT(op)) { if (op == OP_EXACTN_IC) - add_length(reg, mb_len * str_len); + add_length(reg, byte_len); else - add_length(reg, str_len); + add_length(reg, byte_len / mb_len); } - add_bytes(reg, s, mb_len * str_len); + add_bytes(reg, s, byte_len); return 0; } @@ -457,7 +483,7 @@ add_compile_string(UChar* s, int mb_len, int str_len, static int compile_length_string_node(Node* node, regex_t* reg) { - int rlen, r, len, prev_len, slen, ambig; + int rlen, r, len, prev_len, blen, ambig; OnigEncoding enc = reg->enc; UChar *p, *prev; StrNode* sn; @@ -469,26 +495,26 @@ compile_length_string_node(Node* node, regex_t* reg) ambig = NSTRING_IS_AMBIG(node); p = prev = sn->s; - prev_len = enc_len(enc, p, sn->end); + prev_len = enclen(enc, p, sn->end); p += prev_len; - slen = 1; + blen = prev_len; rlen = 0; for (; p < sn->end; ) { - len = enc_len(enc, p, sn->end); - if (len == prev_len) { - slen++; + len = enclen(enc, p, sn->end); + if (len == prev_len || ambig) { + blen += len; } else { - r = add_compile_string_length(prev, prev_len, slen, reg, ambig); + r = add_compile_string_length(prev, prev_len, blen, reg, ambig); rlen += r; prev = p; - slen = 1; + blen = len; prev_len = len; } p += len; } - r = add_compile_string_length(prev, prev_len, slen, reg, ambig); + r = add_compile_string_length(prev, prev_len, blen, reg, ambig); rlen += r; return rlen; } @@ -505,7 +531,7 @@ compile_length_string_raw_node(StrNode* sn, regex_t* reg) static int compile_string_node(Node* node, regex_t* reg) { - int r, len, prev_len, slen, ambig; + int r, len, prev_len, blen, ambig; OnigEncoding enc = reg->enc; UChar *p, *prev, *end; StrNode* sn; @@ -518,27 +544,27 @@ compile_string_node(Node* node, regex_t* reg) ambig = NSTRING_IS_AMBIG(node); p = prev = sn->s; - prev_len = enc_len(enc, p, end); + prev_len = enclen(enc, p, end); p += prev_len; - slen = 1; + blen = prev_len; for (; p < end; ) { - len = enc_len(enc, p, end); - if (len == prev_len) { - slen++; + len = enclen(enc, p, end); + if (len == prev_len || ambig) { + blen += len; } else { - r = add_compile_string(prev, prev_len, slen, reg, ambig); + r = add_compile_string(prev, prev_len, blen, reg, ambig); if (r) return r; prev = p; - slen = 1; + blen = len; prev_len = len; } p += len; } - return add_compile_string(prev, prev_len, slen, reg, ambig); + return add_compile_string(prev, prev_len, blen, reg, ambig); } static int @@ -578,11 +604,6 @@ compile_length_cclass_node(CClassNode* cc, regex_t* reg) { int len; - if (IS_NCCLASS_SHARE(cc)) { - len = SIZE_OPCODE + SIZE_POINTER; - return len; - } - if (IS_NULL(cc->mbuf)) { len = SIZE_OPCODE + SIZE_BITSET; } @@ -608,12 +629,6 @@ compile_cclass_node(CClassNode* cc, regex_t* reg) { int r; - if (IS_NCCLASS_SHARE(cc)) { - add_opcode(reg, OP_CCLASS_NODE); - r = add_pointer(reg, cc); - return r; - } - if (IS_NULL(cc->mbuf)) { if (IS_NCCLASS_NOT(cc)) add_opcode(reg, OP_CCLASS_NOT); @@ -761,23 +776,23 @@ compile_length_quantifier_node(QtfrNode* qn, regex_t* reg) if (infinite && qn->lower <= 1) { if (qn->greedy) { if (qn->lower == 1) - len = SIZE_OP_JUMP; + len = SIZE_OP_JUMP; else - len = 0; + len = 0; len += SIZE_OP_PUSH + cklen + mod_tlen + SIZE_OP_JUMP; } else { if (qn->lower == 0) - len = SIZE_OP_JUMP; + len = SIZE_OP_JUMP; else - len = 0; + len = 0; len += mod_tlen + SIZE_OP_PUSH + cklen; } } else if (qn->upper == 0) { - if (qn->is_refered != 0) /* /(?<n>..){0}/ */ + if (qn->is_referred != 0) /* /(?<n>..){0}/ */ len = SIZE_OP_JUMP + tlen; else len = 0; @@ -785,10 +800,10 @@ compile_length_quantifier_node(QtfrNode* qn, regex_t* reg) else if (qn->upper == 1 && qn->greedy) { if (qn->lower == 0) { if (CKN_ON) { - len = SIZE_OP_STATE_CHECK_PUSH + tlen; + len = SIZE_OP_STATE_CHECK_PUSH + tlen; } else { - len = SIZE_OP_PUSH + tlen; + len = SIZE_OP_PUSH + tlen; } } else { @@ -826,31 +841,31 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg) if (r) return r; if (IS_NOT_NULL(qn->next_head_exact) && !CKN_ON) { if (IS_MULTILINE(reg->options)) - r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT); + r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT); else - r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT); + r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT); if (r) return r; if (CKN_ON) { - r = add_state_check_num(reg, ckn); - if (r) return r; + r = add_state_check_num(reg, ckn); + if (r) return r; } return add_bytes(reg, NSTR(qn->next_head_exact)->s, 1); } else { if (IS_MULTILINE(reg->options)) { - r = add_opcode(reg, (CKN_ON ? - OP_STATE_CHECK_ANYCHAR_ML_STAR - : OP_ANYCHAR_ML_STAR)); + r = add_opcode(reg, (CKN_ON ? + OP_STATE_CHECK_ANYCHAR_ML_STAR + : OP_ANYCHAR_ML_STAR)); } else { - r = add_opcode(reg, (CKN_ON ? - OP_STATE_CHECK_ANYCHAR_STAR - : OP_ANYCHAR_STAR)); + r = add_opcode(reg, (CKN_ON ? + OP_STATE_CHECK_ANYCHAR_STAR + : OP_ANYCHAR_STAR)); } if (r) return r; if (CKN_ON) - r = add_state_check_num(reg, ckn); + r = add_state_check_num(reg, ckn); return r; } @@ -864,49 +879,49 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg) if (infinite && qn->lower <= 1) { if (qn->greedy) { if (qn->lower == 1) { - r = add_opcode_rel_addr(reg, OP_JUMP, - (CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH)); - if (r) return r; + r = add_opcode_rel_addr(reg, OP_JUMP, + (CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH)); + if (r) return r; } if (CKN_ON) { - r = add_opcode(reg, OP_STATE_CHECK_PUSH); - if (r) return r; - r = add_state_check_num(reg, ckn); - if (r) return r; - r = add_rel_addr(reg, mod_tlen + SIZE_OP_JUMP); + r = add_opcode(reg, OP_STATE_CHECK_PUSH); + if (r) return r; + r = add_state_check_num(reg, ckn); + if (r) return r; + r = add_rel_addr(reg, mod_tlen + SIZE_OP_JUMP); } else { - r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP); + r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP); } if (r) return r; r = compile_tree_empty_check(qn->target, reg, empty_info); if (r) return r; r = add_opcode_rel_addr(reg, OP_JUMP, - -(mod_tlen + (int )SIZE_OP_JUMP - + (int )(CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH))); + -(mod_tlen + (int )SIZE_OP_JUMP + + (int )(CKN_ON ? SIZE_OP_STATE_CHECK_PUSH : SIZE_OP_PUSH))); } else { if (qn->lower == 0) { - r = add_opcode_rel_addr(reg, OP_JUMP, mod_tlen); - if (r) return r; + r = add_opcode_rel_addr(reg, OP_JUMP, mod_tlen); + if (r) return r; } r = compile_tree_empty_check(qn->target, reg, empty_info); if (r) return r; if (CKN_ON) { - r = add_opcode(reg, OP_STATE_CHECK_PUSH_OR_JUMP); - if (r) return r; - r = add_state_check_num(reg, ckn); - if (r) return r; - r = add_rel_addr(reg, - -(mod_tlen + (int )SIZE_OP_STATE_CHECK_PUSH_OR_JUMP)); + r = add_opcode(reg, OP_STATE_CHECK_PUSH_OR_JUMP); + if (r) return r; + r = add_state_check_num(reg, ckn); + if (r) return r; + r = add_rel_addr(reg, + -(mod_tlen + (int )SIZE_OP_STATE_CHECK_PUSH_OR_JUMP)); } else - r = add_opcode_rel_addr(reg, OP_PUSH, -(mod_tlen + (int )SIZE_OP_PUSH)); + r = add_opcode_rel_addr(reg, OP_PUSH, -(mod_tlen + (int )SIZE_OP_PUSH)); } } else if (qn->upper == 0) { - if (qn->is_refered != 0) { /* /(?<n>..){0}/ */ + if (qn->is_referred != 0) { /* /(?<n>..){0}/ */ r = add_opcode_rel_addr(reg, OP_JUMP, tlen); if (r) return r; r = compile_tree(qn->target, reg); @@ -917,14 +932,14 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg) else if (qn->upper == 1 && qn->greedy) { if (qn->lower == 0) { if (CKN_ON) { - r = add_opcode(reg, OP_STATE_CHECK_PUSH); - if (r) return r; - r = add_state_check_num(reg, ckn); - if (r) return r; - r = add_rel_addr(reg, tlen); + r = add_opcode(reg, OP_STATE_CHECK_PUSH); + if (r) return r; + r = add_state_check_num(reg, ckn); + if (r) return r; + r = add_rel_addr(reg, tlen); } else { - r = add_opcode_rel_addr(reg, OP_PUSH, tlen); + r = add_opcode_rel_addr(reg, OP_PUSH, tlen); } if (r) return r; } @@ -997,17 +1012,20 @@ compile_length_quantifier_node(QtfrNode* qn, regex_t* reg) } if (qn->greedy) { +#ifdef USE_OP_PUSH_OR_JUMP_EXACT if (IS_NOT_NULL(qn->head_exact)) - len += SIZE_OP_PUSH_OR_JUMP_EXACT1 + mod_tlen + SIZE_OP_JUMP; - else if (IS_NOT_NULL(qn->next_head_exact)) - len += SIZE_OP_PUSH_IF_PEEK_NEXT + mod_tlen + SIZE_OP_JUMP; + len += SIZE_OP_PUSH_OR_JUMP_EXACT1 + mod_tlen + SIZE_OP_JUMP; else - len += SIZE_OP_PUSH + mod_tlen + SIZE_OP_JUMP; +#endif + if (IS_NOT_NULL(qn->next_head_exact)) + len += SIZE_OP_PUSH_IF_PEEK_NEXT + mod_tlen + SIZE_OP_JUMP; + else + len += SIZE_OP_PUSH + mod_tlen + SIZE_OP_JUMP; } else len += SIZE_OP_JUMP + mod_tlen + SIZE_OP_PUSH; } - else if (qn->upper == 0 && qn->is_refered != 0) { /* /(?<n>..){0}/ */ + else if (qn->upper == 0 && qn->is_referred != 0) { /* /(?<n>..){0}/ */ len = SIZE_OP_JUMP + tlen; } else if (!infinite && qn->greedy && @@ -1042,17 +1060,17 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg) if (r) return r; if (IS_NOT_NULL(qn->next_head_exact)) { if (IS_MULTILINE(reg->options)) - r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT); + r = add_opcode(reg, OP_ANYCHAR_ML_STAR_PEEK_NEXT); else - r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT); + r = add_opcode(reg, OP_ANYCHAR_STAR_PEEK_NEXT); if (r) return r; return add_bytes(reg, NSTR(qn->next_head_exact)->s, 1); } else { if (IS_MULTILINE(reg->options)) - return add_opcode(reg, OP_ANYCHAR_ML_STAR); + return add_opcode(reg, OP_ANYCHAR_ML_STAR); else - return add_opcode(reg, OP_ANYCHAR_STAR); + return add_opcode(reg, OP_ANYCHAR_STAR); } } @@ -1065,15 +1083,18 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg) (qn->lower <= 1 || tlen * qn->lower <= QUANTIFIER_EXPAND_LIMIT_SIZE)) { if (qn->lower == 1 && tlen > QUANTIFIER_EXPAND_LIMIT_SIZE) { if (qn->greedy) { - if (IS_NOT_NULL(qn->head_exact)) - r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_OR_JUMP_EXACT1); - else if (IS_NOT_NULL(qn->next_head_exact)) - r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_IF_PEEK_NEXT); - else - r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH); +#ifdef USE_OP_PUSH_OR_JUMP_EXACT + if (IS_NOT_NULL(qn->head_exact)) + r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_OR_JUMP_EXACT1); + else +#endif + if (IS_NOT_NULL(qn->next_head_exact)) + r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH_IF_PEEK_NEXT); + else + r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_PUSH); } else { - r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_JUMP); + r = add_opcode_rel_addr(reg, OP_JUMP, SIZE_OP_JUMP); } if (r) return r; } @@ -1083,33 +1104,36 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg) } if (qn->greedy) { +#ifdef USE_OP_PUSH_OR_JUMP_EXACT if (IS_NOT_NULL(qn->head_exact)) { - r = add_opcode_rel_addr(reg, OP_PUSH_OR_JUMP_EXACT1, - mod_tlen + SIZE_OP_JUMP); - if (r) return r; - add_bytes(reg, NSTR(qn->head_exact)->s, 1); - r = compile_tree_empty_check(qn->target, reg, empty_info); - if (r) return r; - r = add_opcode_rel_addr(reg, OP_JUMP, - -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH_OR_JUMP_EXACT1)); + r = add_opcode_rel_addr(reg, OP_PUSH_OR_JUMP_EXACT1, + mod_tlen + SIZE_OP_JUMP); + if (r) return r; + add_bytes(reg, NSTR(qn->head_exact)->s, 1); + r = compile_tree_empty_check(qn->target, reg, empty_info); + if (r) return r; + r = add_opcode_rel_addr(reg, OP_JUMP, + -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH_OR_JUMP_EXACT1)); } - else if (IS_NOT_NULL(qn->next_head_exact)) { - r = add_opcode_rel_addr(reg, OP_PUSH_IF_PEEK_NEXT, - mod_tlen + SIZE_OP_JUMP); - if (r) return r; - add_bytes(reg, NSTR(qn->next_head_exact)->s, 1); - r = compile_tree_empty_check(qn->target, reg, empty_info); - if (r) return r; - r = add_opcode_rel_addr(reg, OP_JUMP, + else +#endif + if (IS_NOT_NULL(qn->next_head_exact)) { + r = add_opcode_rel_addr(reg, OP_PUSH_IF_PEEK_NEXT, + mod_tlen + SIZE_OP_JUMP); + if (r) return r; + add_bytes(reg, NSTR(qn->next_head_exact)->s, 1); + r = compile_tree_empty_check(qn->target, reg, empty_info); + if (r) return r; + r = add_opcode_rel_addr(reg, OP_JUMP, -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH_IF_PEEK_NEXT)); } else { - r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP); - if (r) return r; - r = compile_tree_empty_check(qn->target, reg, empty_info); - if (r) return r; - r = add_opcode_rel_addr(reg, OP_JUMP, - -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH)); + r = add_opcode_rel_addr(reg, OP_PUSH, mod_tlen + SIZE_OP_JUMP); + if (r) return r; + r = compile_tree_empty_check(qn->target, reg, empty_info); + if (r) return r; + r = add_opcode_rel_addr(reg, OP_JUMP, + -(mod_tlen + (int )SIZE_OP_JUMP + (int )SIZE_OP_PUSH)); } } else { @@ -1120,7 +1144,7 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg) r = add_opcode_rel_addr(reg, OP_PUSH, -(mod_tlen + (int )SIZE_OP_PUSH)); } } - else if (qn->upper == 0 && qn->is_refered != 0) { /* /(?<n>..){0}/ */ + else if (qn->upper == 0 && qn->is_referred != 0) { /* /(?<n>..){0}/ */ r = add_opcode_rel_addr(reg, OP_JUMP, tlen); if (r) return r; r = compile_tree(qn->target, reg); @@ -1135,7 +1159,7 @@ compile_quantifier_node(QtfrNode* qn, regex_t* reg) for (i = 0; i < n; i++) { r = add_opcode_rel_addr(reg, OP_PUSH, - (n - i) * tlen + (n - i - 1) * SIZE_OP_PUSH); + (n - i) * tlen + (n - i - 1) * SIZE_OP_PUSH); if (r) return r; r = compile_tree(qn->target, reg); if (r) return r; @@ -1222,41 +1246,77 @@ compile_length_enclose_node(EncloseNode* node, regex_t* reg) #ifdef USE_SUBEXP_CALL if (IS_ENCLOSE_CALLED(node)) { len = SIZE_OP_MEMORY_START_PUSH + tlen - + SIZE_OP_CALL + SIZE_OP_JUMP + SIZE_OP_RETURN; + + SIZE_OP_CALL + SIZE_OP_JUMP + SIZE_OP_RETURN; if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum)) - len += (IS_ENCLOSE_RECURSION(node) - ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH); + len += (IS_ENCLOSE_RECURSION(node) + ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH); else - len += (IS_ENCLOSE_RECURSION(node) - ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END); + len += (IS_ENCLOSE_RECURSION(node) + ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END); + } + else if (IS_ENCLOSE_RECURSION(node)) { + len = SIZE_OP_MEMORY_START_PUSH; + len += tlen + (BIT_STATUS_AT(reg->bt_mem_end, node->regnum) + ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_REC); } else #endif { if (BIT_STATUS_AT(reg->bt_mem_start, node->regnum)) - len = SIZE_OP_MEMORY_START_PUSH; + len = SIZE_OP_MEMORY_START_PUSH; else - len = SIZE_OP_MEMORY_START; + len = SIZE_OP_MEMORY_START; len += tlen + (BIT_STATUS_AT(reg->bt_mem_end, node->regnum) - ? SIZE_OP_MEMORY_END_PUSH : SIZE_OP_MEMORY_END); + ? SIZE_OP_MEMORY_END_PUSH : SIZE_OP_MEMORY_END); } break; case ENCLOSE_STOP_BACKTRACK: + /* Disable POP_STOP_BT optimization for simple repeat under the match cache */ + /* optimization because the match cache optimization pushes an extra item to */ + /* the stack and it breaks the assumption for this optimization. */ +#ifndef USE_MATCH_CACHE if (IS_ENCLOSE_STOP_BT_SIMPLE_REPEAT(node)) { QtfrNode* qn = NQTFR(node->target); tlen = compile_length_tree(qn->target, reg); if (tlen < 0) return tlen; len = tlen * qn->lower - + SIZE_OP_PUSH + tlen + SIZE_OP_POP + SIZE_OP_JUMP; + + SIZE_OP_PUSH + tlen + SIZE_OP_POP + SIZE_OP_JUMP; } else { +#endif len = SIZE_OP_PUSH_STOP_BT + tlen + SIZE_OP_POP_STOP_BT; +#ifndef USE_MATCH_CACHE + } +#endif + break; + + case ENCLOSE_CONDITION: + len = SIZE_OP_CONDITION; + if (NTYPE(node->target) == NT_ALT) { + Node* x = node->target; + + tlen = compile_length_tree(NCAR(x), reg); /* yes-node */ + if (tlen < 0) return tlen; + len += tlen + SIZE_OP_JUMP; + if (NCDR(x) == NULL) return ONIGERR_PARSER_BUG; + x = NCDR(x); + tlen = compile_length_tree(NCAR(x), reg); /* no-node */ + if (tlen < 0) return tlen; + len += tlen; + if (NCDR(x) != NULL) return ONIGERR_INVALID_CONDITION_PATTERN; + } + else { + return ONIGERR_PARSER_BUG; } break; + case ENCLOSE_ABSENT: + len = SIZE_OP_PUSH_ABSENT_POS + SIZE_OP_ABSENT + tlen + SIZE_OP_ABSENT_END; + break; + default: return ONIGERR_TYPE_BUG; break; @@ -1288,11 +1348,11 @@ compile_enclose_node(EncloseNode* node, regex_t* reg) len = compile_length_tree(node->target, reg); len += (SIZE_OP_MEMORY_START_PUSH + SIZE_OP_RETURN); if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum)) - len += (IS_ENCLOSE_RECURSION(node) - ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH); + len += (IS_ENCLOSE_RECURSION(node) + ? SIZE_OP_MEMORY_END_PUSH_REC : SIZE_OP_MEMORY_END_PUSH); else - len += (IS_ENCLOSE_RECURSION(node) - ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END); + len += (IS_ENCLOSE_RECURSION(node) + ? SIZE_OP_MEMORY_END_REC : SIZE_OP_MEMORY_END); r = add_opcode_rel_addr(reg, OP_JUMP, len); if (r) return r; @@ -1310,30 +1370,42 @@ compile_enclose_node(EncloseNode* node, regex_t* reg) #ifdef USE_SUBEXP_CALL if (IS_ENCLOSE_CALLED(node)) { if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum)) - r = add_opcode(reg, (IS_ENCLOSE_RECURSION(node) - ? OP_MEMORY_END_PUSH_REC : OP_MEMORY_END_PUSH)); + r = add_opcode(reg, (IS_ENCLOSE_RECURSION(node) + ? OP_MEMORY_END_PUSH_REC : OP_MEMORY_END_PUSH)); else - r = add_opcode(reg, (IS_ENCLOSE_RECURSION(node) - ? OP_MEMORY_END_REC : OP_MEMORY_END)); + r = add_opcode(reg, (IS_ENCLOSE_RECURSION(node) + ? OP_MEMORY_END_REC : OP_MEMORY_END)); if (r) return r; r = add_mem_num(reg, node->regnum); if (r) return r; r = add_opcode(reg, OP_RETURN); } + else if (IS_ENCLOSE_RECURSION(node)) { + if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum)) + r = add_opcode(reg, OP_MEMORY_END_PUSH_REC); + else + r = add_opcode(reg, OP_MEMORY_END_REC); + if (r) return r; + r = add_mem_num(reg, node->regnum); + } else #endif { if (BIT_STATUS_AT(reg->bt_mem_end, node->regnum)) - r = add_opcode(reg, OP_MEMORY_END_PUSH); + r = add_opcode(reg, OP_MEMORY_END_PUSH); else - r = add_opcode(reg, OP_MEMORY_END); + r = add_opcode(reg, OP_MEMORY_END); if (r) return r; r = add_mem_num(reg, node->regnum); } break; case ENCLOSE_STOP_BACKTRACK: + /* Disable POP_STOP_BT optimization for simple repeat under the match cache */ + /* optimization because the match cache optimization pushes an extra item to */ + /* the stack and it breaks the assumption for this optimization. */ +#ifndef USE_MATCH_CACHE if (IS_ENCLOSE_STOP_BT_SIMPLE_REPEAT(node)) { QtfrNode* qn = NQTFR(node->target); r = compile_tree_n_times(qn->target, qn->lower, reg); @@ -1349,17 +1421,66 @@ compile_enclose_node(EncloseNode* node, regex_t* reg) r = add_opcode(reg, OP_POP); if (r) return r; r = add_opcode_rel_addr(reg, OP_JUMP, - -((int )SIZE_OP_PUSH + len + (int )SIZE_OP_POP + (int )SIZE_OP_JUMP)); + -((int )SIZE_OP_PUSH + len + (int )SIZE_OP_POP + (int )SIZE_OP_JUMP)); } else { +#endif r = add_opcode(reg, OP_PUSH_STOP_BT); if (r) return r; r = compile_tree(node->target, reg); if (r) return r; r = add_opcode(reg, OP_POP_STOP_BT); +#ifndef USE_MATCH_CACHE + } +#endif + break; + + case ENCLOSE_CONDITION: + r = add_opcode(reg, OP_CONDITION); + if (r) return r; + r = add_mem_num(reg, node->regnum); + if (r) return r; + + if (NTYPE(node->target) == NT_ALT) { + Node* x = node->target; + int len2; + + len = compile_length_tree(NCAR(x), reg); /* yes-node */ + if (len < 0) return len; + if (NCDR(x) == NULL) return ONIGERR_PARSER_BUG; + x = NCDR(x); + len2 = compile_length_tree(NCAR(x), reg); /* no-node */ + if (len2 < 0) return len2; + if (NCDR(x) != NULL) return ONIGERR_INVALID_CONDITION_PATTERN; + + x = node->target; + r = add_rel_addr(reg, len + SIZE_OP_JUMP); + if (r) return r; + r = compile_tree(NCAR(x), reg); /* yes-node */ + if (r) return r; + r = add_opcode_rel_addr(reg, OP_JUMP, len2); + if (r) return r; + x = NCDR(x); + r = compile_tree(NCAR(x), reg); /* no-node */ + } + else { + return ONIGERR_PARSER_BUG; } break; + case ENCLOSE_ABSENT: + len = compile_length_tree(node->target, reg); + if (len < 0) return len; + + r = add_opcode(reg, OP_PUSH_ABSENT_POS); + if (r) return r; + r = add_opcode_rel_addr(reg, OP_ABSENT, len + SIZE_OP_ABSENT_END); + if (r) return r; + r = compile_tree(node->target, reg); + if (r) return r; + r = add_opcode(reg, OP_ABSENT_END); + break; + default: return ONIGERR_TYPE_BUG; break; @@ -1414,12 +1535,25 @@ compile_anchor_node(AnchorNode* node, regex_t* reg) case ANCHOR_SEMI_END_BUF: r = add_opcode(reg, OP_SEMI_END_BUF); break; case ANCHOR_BEGIN_POSITION: r = add_opcode(reg, OP_BEGIN_POSITION); break; - case ANCHOR_WORD_BOUND: r = add_opcode(reg, OP_WORD_BOUND); break; - case ANCHOR_NOT_WORD_BOUND: r = add_opcode(reg, OP_NOT_WORD_BOUND); break; + case ANCHOR_WORD_BOUND: + if (node->ascii_range) r = add_opcode(reg, OP_ASCII_WORD_BOUND); + else r = add_opcode(reg, OP_WORD_BOUND); + break; + case ANCHOR_NOT_WORD_BOUND: + if (node->ascii_range) r = add_opcode(reg, OP_NOT_ASCII_WORD_BOUND); + else r = add_opcode(reg, OP_NOT_WORD_BOUND); + break; #ifdef USE_WORD_BEGIN_END - case ANCHOR_WORD_BEGIN: r = add_opcode(reg, OP_WORD_BEGIN); break; - case ANCHOR_WORD_END: r = add_opcode(reg, OP_WORD_END); break; + case ANCHOR_WORD_BEGIN: + if (node->ascii_range) r = add_opcode(reg, OP_ASCII_WORD_BEGIN); + else r = add_opcode(reg, OP_WORD_BEGIN); + break; + case ANCHOR_WORD_END: + if (node->ascii_range) r = add_opcode(reg, OP_ASCII_WORD_END); + else r = add_opcode(reg, OP_WORD_END); + break; #endif + case ANCHOR_KEEP: r = add_opcode(reg, OP_KEEP); break; case ANCHOR_PREC_READ: r = add_opcode(reg, OP_PUSH_POS); @@ -1445,11 +1579,11 @@ compile_anchor_node(AnchorNode* node, regex_t* reg) r = add_opcode(reg, OP_LOOK_BEHIND); if (r) return r; if (node->char_len < 0) { - r = get_char_length_tree(node->target, reg, &n); - if (r) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN; + r = get_char_length_tree(node->target, reg, &n); + if (r) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN; } else - n = node->char_len; + n = node->char_len; r = add_length(reg, n); if (r) return r; r = compile_tree(node->target, reg); @@ -1461,14 +1595,14 @@ compile_anchor_node(AnchorNode* node, regex_t* reg) int n; len = compile_length_tree(node->target, reg); r = add_opcode_rel_addr(reg, OP_PUSH_LOOK_BEHIND_NOT, - len + SIZE_OP_FAIL_LOOK_BEHIND_NOT); + len + SIZE_OP_FAIL_LOOK_BEHIND_NOT); if (r) return r; if (node->char_len < 0) { - r = get_char_length_tree(node->target, reg, &n); - if (r) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN; + r = get_char_length_tree(node->target, reg, &n); + if (r) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN; } else - n = node->char_len; + n = node->char_len; r = add_length(reg, n); if (r) return r; r = compile_tree(node->target, reg); @@ -1504,13 +1638,15 @@ compile_length_tree(Node* node, regex_t* reg) case NT_ALT: { - int n; - - n = r = 0; + int n = 0; + len = 0; do { - r += compile_length_tree(NCAR(node), reg); - n++; + r = compile_length_tree(NCAR(node), reg); + if (r < 0) return r; + len += r; + n++; } while (IS_NOT_NULL(node = NCDR(node))); + r = len; r += (SIZE_OP_PUSH + SIZE_OP_JUMP) * (n - 1); } break; @@ -1535,7 +1671,7 @@ compile_length_tree(Node* node, regex_t* reg) { BRefNode* br = NBREF(node); -#ifdef USE_BACKREF_AT_LEVEL +#ifdef USE_BACKREF_WITH_LEVEL if (IS_BACKREF_NEST_LEVEL(br)) { r = SIZE_OPCODE + SIZE_OPTION + SIZE_LENGTH + SIZE_LENGTH + (SIZE_MEMNUM * br->back_num); @@ -1543,11 +1679,11 @@ compile_length_tree(Node* node, regex_t* reg) else #endif if (br->back_num == 1) { - r = ((!IS_IGNORECASE(reg->options) && br->back_static[0] <= 2) - ? SIZE_OPCODE : (SIZE_OPCODE + SIZE_MEMNUM)); + r = ((!IS_IGNORECASE(reg->options) && br->back_static[0] <= 2) + ? SIZE_OPCODE : (SIZE_OPCODE + SIZE_MEMNUM)); } else { - r = SIZE_OPCODE + SIZE_LENGTH + (SIZE_MEMNUM * br->back_num); + r = SIZE_OPCODE + SIZE_LENGTH + (SIZE_MEMNUM * br->back_num); } } break; @@ -1596,26 +1732,26 @@ compile_tree(Node* node, regex_t* reg) Node* x = node; len = 0; do { - len += compile_length_tree(NCAR(x), reg); - if (NCDR(x) != NULL) { - len += SIZE_OP_PUSH + SIZE_OP_JUMP; - } + len += compile_length_tree(NCAR(x), reg); + if (NCDR(x) != NULL) { + len += SIZE_OP_PUSH + SIZE_OP_JUMP; + } } while (IS_NOT_NULL(x = NCDR(x))); pos = reg->used + len; /* goal position */ do { - len = compile_length_tree(NCAR(node), reg); - if (IS_NOT_NULL(NCDR(node))) { - r = add_opcode_rel_addr(reg, OP_PUSH, len + SIZE_OP_JUMP); - if (r) break; - } - r = compile_tree(NCAR(node), reg); - if (r) break; - if (IS_NOT_NULL(NCDR(node))) { - len = pos - (reg->used + SIZE_OP_JUMP); - r = add_opcode_rel_addr(reg, OP_JUMP, len); - if (r) break; - } + len = compile_length_tree(NCAR(node), reg); + if (IS_NOT_NULL(NCDR(node))) { + r = add_opcode_rel_addr(reg, OP_PUSH, len + SIZE_OP_JUMP); + if (r) break; + } + r = compile_tree(NCAR(node), reg); + if (r) break; + if (IS_NOT_NULL(NCDR(node))) { + len = pos - (reg->used + SIZE_OP_JUMP); + r = add_opcode_rel_addr(reg, OP_JUMP, len); + if (r) break; + } } while (IS_NOT_NULL(node = NCDR(node))); } break; @@ -1637,12 +1773,18 @@ compile_tree(Node* node, regex_t* reg) switch (NCTYPE(node)->ctype) { case ONIGENC_CTYPE_WORD: - if (NCTYPE(node)->not != 0) op = OP_NOT_WORD; - else op = OP_WORD; - break; + if (NCTYPE(node)->ascii_range != 0) { + if (NCTYPE(node)->not != 0) op = OP_NOT_ASCII_WORD; + else op = OP_ASCII_WORD; + } + else { + if (NCTYPE(node)->not != 0) op = OP_NOT_WORD; + else op = OP_WORD; + } + break; default: - return ONIGERR_TYPE_BUG; - break; + return ONIGERR_TYPE_BUG; + break; } r = add_opcode(reg, op); } @@ -1659,41 +1801,41 @@ compile_tree(Node* node, regex_t* reg) { BRefNode* br = NBREF(node); -#ifdef USE_BACKREF_AT_LEVEL +#ifdef USE_BACKREF_WITH_LEVEL if (IS_BACKREF_NEST_LEVEL(br)) { - r = add_opcode(reg, OP_BACKREF_AT_LEVEL); - if (r) return r; - r = add_option(reg, (reg->options & ONIG_OPTION_IGNORECASE)); - if (r) return r; - r = add_length(reg, br->nest_level); - if (r) return r; - - goto add_bacref_mems; + r = add_opcode(reg, OP_BACKREF_WITH_LEVEL); + if (r) return r; + r = add_option(reg, (reg->options & ONIG_OPTION_IGNORECASE)); + if (r) return r; + r = add_length(reg, br->nest_level); + if (r) return r; + + goto add_bacref_mems; } else #endif if (br->back_num == 1) { - n = br->back_static[0]; - if (IS_IGNORECASE(reg->options)) { - r = add_opcode(reg, OP_BACKREFN_IC); - if (r) return r; - r = add_mem_num(reg, n); - } - else { - switch (n) { - case 1: r = add_opcode(reg, OP_BACKREF1); break; - case 2: r = add_opcode(reg, OP_BACKREF2); break; - default: - r = add_opcode(reg, OP_BACKREFN); - if (r) return r; - r = add_mem_num(reg, n); - break; - } - } + n = br->back_static[0]; + if (IS_IGNORECASE(reg->options)) { + r = add_opcode(reg, OP_BACKREFN_IC); + if (r) return r; + r = add_mem_num(reg, n); + } + else { + switch (n) { + case 1: r = add_opcode(reg, OP_BACKREF1); break; + case 2: r = add_opcode(reg, OP_BACKREF2); break; + default: + r = add_opcode(reg, OP_BACKREFN); + if (r) return r; + r = add_mem_num(reg, n); + break; + } + } } else { - int i; - int* p; + int i; + int* p; if (IS_IGNORECASE(reg->options)) { r = add_opcode(reg, OP_BACKREF_MULTI_IC); @@ -1701,18 +1843,18 @@ compile_tree(Node* node, regex_t* reg) else { r = add_opcode(reg, OP_BACKREF_MULTI); } - if (r) return r; + if (r) return r; -#ifdef USE_BACKREF_AT_LEVEL +#ifdef USE_BACKREF_WITH_LEVEL add_bacref_mems: #endif - r = add_length(reg, br->back_num); - if (r) return r; - p = BACKREFS_P(br); - for (i = br->back_num - 1; i >= 0; i--) { - r = add_mem_num(reg, p[i]); - if (r) return r; - } + r = add_length(reg, br->back_num); + if (r) return r; + p = BACKREFS_P(br); + for (i = br->back_num - 1; i >= 0; i--) { + r = add_mem_num(reg, p[i]); + if (r) return r; + } } } break; @@ -1767,7 +1909,7 @@ noname_disable_map(Node** plink, GroupNumRemap* map, int* counter) Node* old = *ptarget; r = noname_disable_map(ptarget, map, counter); if (*ptarget != old && NTYPE(*ptarget) == NT_QTFR) { - onig_reduce_nested_quantifier(node, *ptarget); + onig_reduce_nested_quantifier(node, *ptarget); } } break; @@ -1776,24 +1918,28 @@ noname_disable_map(Node** plink, GroupNumRemap* map, int* counter) { EncloseNode* en = NENCLOSE(node); if (en->type == ENCLOSE_MEMORY) { - if (IS_ENCLOSE_NAMED_GROUP(en)) { - (*counter)++; - map[en->regnum].new_val = *counter; - en->regnum = *counter; - r = noname_disable_map(&(en->target), map, counter); - } - else { - *plink = en->target; - en->target = NULL_NODE; - onig_node_free(node); - r = noname_disable_map(plink, map, counter); - } + if (IS_ENCLOSE_NAMED_GROUP(en)) { + (*counter)++; + map[en->regnum].new_val = *counter; + en->regnum = *counter; + } + else if (en->regnum != 0) { + *plink = en->target; + en->target = NULL_NODE; + onig_node_free(node); + r = noname_disable_map(plink, map, counter); + break; + } } - else - r = noname_disable_map(&(en->target), map, counter); + r = noname_disable_map(&(en->target), map, counter); } break; + case NT_ANCHOR: + if (NANCHOR(node)->target) + r = noname_disable_map(&(NANCHOR(node)->target), map, counter); + break; + default: break; } @@ -1802,7 +1948,7 @@ noname_disable_map(Node** plink, GroupNumRemap* map, int* counter) } static int -renumber_node_backref(Node* node, GroupNumRemap* map) +renumber_node_backref(Node* node, GroupNumRemap* map, const int num_mem) { int i, pos, n, old_num; int *backs; @@ -1818,6 +1964,7 @@ renumber_node_backref(Node* node, GroupNumRemap* map) backs = bn->back_dynamic; for (i = 0, pos = 0; i < old_num; i++) { + if (backs[i] > num_mem) return ONIGERR_INVALID_BACKREF; n = map[backs[i]].new_val; if (n > 0) { backs[pos] = n; @@ -1830,7 +1977,7 @@ renumber_node_backref(Node* node, GroupNumRemap* map) } static int -renumber_by_map(Node* node, GroupNumRemap* map) +renumber_by_map(Node* node, GroupNumRemap* map, const int num_mem) { int r = 0; @@ -1838,18 +1985,30 @@ renumber_by_map(Node* node, GroupNumRemap* map) case NT_LIST: case NT_ALT: do { - r = renumber_by_map(NCAR(node), map); + r = renumber_by_map(NCAR(node), map, num_mem); } while (r == 0 && IS_NOT_NULL(node = NCDR(node))); break; case NT_QTFR: - r = renumber_by_map(NQTFR(node)->target, map); + r = renumber_by_map(NQTFR(node)->target, map, num_mem); break; case NT_ENCLOSE: - r = renumber_by_map(NENCLOSE(node)->target, map); + { + EncloseNode* en = NENCLOSE(node); + if (en->type == ENCLOSE_CONDITION) { + if (en->regnum > num_mem) return ONIGERR_INVALID_BACKREF; + en->regnum = map[en->regnum].new_val; + } + r = renumber_by_map(en->target, map, num_mem); + } break; case NT_BREF: - r = renumber_node_backref(node, map); + r = renumber_node_backref(node, map, num_mem); + break; + + case NT_ANCHOR: + if (NANCHOR(node)->target) + r = renumber_by_map(NANCHOR(node)->target, map, num_mem); break; default: @@ -1883,6 +2042,11 @@ numbered_ref_check(Node* node) return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED; break; + case NT_ANCHOR: + if (NANCHOR(node)->target) + r = numbered_ref_check(NANCHOR(node)->target); + break; + default: break; } @@ -1906,7 +2070,7 @@ disable_noname_group_capture(Node** root, regex_t* reg, ScanEnv* env) r = noname_disable_map(root, map, &counter); if (r != 0) return r; - r = renumber_by_map(*root, map); + r = renumber_by_map(*root, map, env->num_mem); if (r != 0) return r; for (i = 1, pos = 1; i <= env->num_mem; i++) { @@ -1951,7 +2115,7 @@ unset_addr_list_fix(UnsetAddrList* uslist, regex_t* reg) } #endif -#ifdef USE_INFINITE_REPEAT_MONOMANIAC_MEM_STATUS_CHECK +#ifdef USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT static int quantifiers_memory_node_info(Node* node) { @@ -1963,13 +2127,13 @@ quantifiers_memory_node_info(Node* node) { int v; do { - v = quantifiers_memory_node_info(NCAR(node)); - if (v > r) r = v; + v = quantifiers_memory_node_info(NCAR(node)); + if (v > r) r = v; } while (v >= 0 && IS_NOT_NULL(node = NCDR(node))); } break; -#ifdef USE_SUBEXP_CALL +# ifdef USE_SUBEXP_CALL case NT_CALL: if (IS_CALL_RECURSION(NCALL(node))) { return NQ_TARGET_IS_EMPTY_REC; /* tiny version */ @@ -1977,13 +2141,13 @@ quantifiers_memory_node_info(Node* node) else r = quantifiers_memory_node_info(NCALL(node)->target); break; -#endif +# endif case NT_QTFR: { QtfrNode* qn = NQTFR(node); if (qn->upper != 0) { - r = quantifiers_memory_node_info(qn->target); + r = quantifiers_memory_node_info(qn->target); } } break; @@ -1993,15 +2157,17 @@ quantifiers_memory_node_info(Node* node) EncloseNode* en = NENCLOSE(node); switch (en->type) { case ENCLOSE_MEMORY: - return NQ_TARGET_IS_EMPTY_MEM; - break; + return NQ_TARGET_IS_EMPTY_MEM; + break; case ENCLOSE_OPTION: case ENCLOSE_STOP_BACKTRACK: - r = quantifiers_memory_node_info(en->target); - break; + case ENCLOSE_CONDITION: + case ENCLOSE_ABSENT: + r = quantifiers_memory_node_info(en->target); + break; default: - break; + break; } } break; @@ -2018,7 +2184,7 @@ quantifiers_memory_node_info(Node* node) return r; } -#endif /* USE_INFINITE_REPEAT_MONOMANIAC_MEM_STATUS_CHECK */ +#endif /* USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT */ static int get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env) @@ -2041,10 +2207,10 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env) r = get_min_match_length(nodes[backs[0]], min, env); if (r != 0) break; for (i = 1; i < br->back_num; i++) { - if (backs[i] > env->num_mem) return ONIGERR_INVALID_BACKREF; - r = get_min_match_length(nodes[backs[i]], &tmin, env); - if (r != 0) break; - if (*min > tmin) *min = tmin; + if (backs[i] > env->num_mem) return ONIGERR_INVALID_BACKREF; + r = get_min_match_length(nodes[backs[i]], &tmin, env); + if (r != 0) break; + if (*min > tmin) *min = tmin; } } break; @@ -2054,7 +2220,7 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env) if (IS_CALL_RECURSION(NCALL(node))) { EncloseNode* en = NENCLOSE(NCALL(node)->target); if (IS_ENCLOSE_MIN_FIXED(en)) - *min = en->min_len; + *min = en->min_len; } else r = get_min_match_length(NCALL(node)->target, min, env); @@ -2073,11 +2239,11 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env) Node *x, *y; y = node; do { - x = NCAR(y); - r = get_min_match_length(x, &tmin, env); - if (r != 0) break; - if (y == node) *min = tmin; - else if (*min > tmin) *min = tmin; + x = NCAR(y); + r = get_min_match_length(x, &tmin, env); + if (r != 0) break; + if (y == node) *min = tmin; + else if (*min > tmin) *min = tmin; } while (r == 0 && IS_NOT_NULL(y = NCDR(y))); } break; @@ -2103,9 +2269,9 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env) QtfrNode* qn = NQTFR(node); if (qn->lower > 0) { - r = get_min_match_length(qn->target, min, env); - if (r == 0) - *min = distance_multiply(*min, qn->lower); + r = get_min_match_length(qn->target, min, env); + if (r == 0) + *min = distance_multiply(*min, qn->lower); } } break; @@ -2115,22 +2281,31 @@ get_min_match_length(Node* node, OnigDistance *min, ScanEnv* env) EncloseNode* en = NENCLOSE(node); switch (en->type) { case ENCLOSE_MEMORY: -#ifdef USE_SUBEXP_CALL - if (IS_ENCLOSE_MIN_FIXED(en)) - *min = en->min_len; - else { - r = get_min_match_length(en->target, min, env); - if (r == 0) { - en->min_len = *min; - SET_ENCLOSE_STATUS(node, NST_MIN_FIXED); - } - } - break; -#endif + if (IS_ENCLOSE_MIN_FIXED(en)) + *min = en->min_len; + else { + if (IS_ENCLOSE_MARK1(NENCLOSE(node))) + *min = 0; /* recursive */ + else { + SET_ENCLOSE_STATUS(node, NST_MARK1); + r = get_min_match_length(en->target, min, env); + CLEAR_ENCLOSE_STATUS(node, NST_MARK1); + if (r == 0) { + en->min_len = *min; + SET_ENCLOSE_STATUS(node, NST_MIN_FIXED); + } + } + } + break; + case ENCLOSE_OPTION: case ENCLOSE_STOP_BACKTRACK: - r = get_min_match_length(en->target, min, env); - break; + case ENCLOSE_CONDITION: + r = get_min_match_length(en->target, min, env); + break; + + case ENCLOSE_ABSENT: + break; } } break; @@ -2155,7 +2330,7 @@ get_max_match_length(Node* node, OnigDistance *max, ScanEnv* env) do { r = get_max_match_length(NCAR(node), &tmax, env); if (r == 0) - *max = distance_add(*max, tmax); + *max = distance_add(*max, tmax); } while (r == 0 && IS_NOT_NULL(node = NCDR(node))); break; @@ -2189,15 +2364,15 @@ get_max_match_length(Node* node, OnigDistance *max, ScanEnv* env) Node** nodes = SCANENV_MEM_NODES(env); BRefNode* br = NBREF(node); if (br->state & NST_RECURSION) { - *max = ONIG_INFINITE_DISTANCE; - break; + *max = ONIG_INFINITE_DISTANCE; + break; } backs = BACKREFS_P(br); for (i = 0; i < br->back_num; i++) { - if (backs[i] > env->num_mem) return ONIGERR_INVALID_BACKREF; - r = get_max_match_length(nodes[backs[i]], &tmax, env); - if (r != 0) break; - if (*max < tmax) *max = tmax; + if (backs[i] > env->num_mem) return ONIGERR_INVALID_BACKREF; + r = get_max_match_length(nodes[backs[i]], &tmax, env); + if (r != 0) break; + if (*max < tmax) *max = tmax; } } break; @@ -2216,13 +2391,13 @@ get_max_match_length(Node* node, OnigDistance *max, ScanEnv* env) QtfrNode* qn = NQTFR(node); if (qn->upper != 0) { - r = get_max_match_length(qn->target, max, env); - if (r == 0 && *max != 0) { - if (! IS_REPEAT_INFINITE(qn->upper)) - *max = distance_multiply(*max, qn->upper); - else - *max = ONIG_INFINITE_DISTANCE; - } + r = get_max_match_length(qn->target, max, env); + if (r == 0 && *max != 0) { + if (! IS_REPEAT_INFINITE(qn->upper)) + *max = distance_multiply(*max, qn->upper); + else + *max = ONIG_INFINITE_DISTANCE; + } } } break; @@ -2232,22 +2407,31 @@ get_max_match_length(Node* node, OnigDistance *max, ScanEnv* env) EncloseNode* en = NENCLOSE(node); switch (en->type) { case ENCLOSE_MEMORY: -#ifdef USE_SUBEXP_CALL - if (IS_ENCLOSE_MAX_FIXED(en)) - *max = en->max_len; - else { - r = get_max_match_length(en->target, max, env); - if (r == 0) { - en->max_len = *max; - SET_ENCLOSE_STATUS(node, NST_MAX_FIXED); - } - } - break; -#endif + if (IS_ENCLOSE_MAX_FIXED(en)) + *max = en->max_len; + else { + if (IS_ENCLOSE_MARK1(NENCLOSE(node))) + *max = ONIG_INFINITE_DISTANCE; + else { + SET_ENCLOSE_STATUS(node, NST_MARK1); + r = get_max_match_length(en->target, max, env); + CLEAR_ENCLOSE_STATUS(node, NST_MARK1); + if (r == 0) { + en->max_len = *max; + SET_ENCLOSE_STATUS(node, NST_MAX_FIXED); + } + } + } + break; + case ENCLOSE_OPTION: case ENCLOSE_STOP_BACKTRACK: - r = get_max_match_length(en->target, max, env); - break; + case ENCLOSE_CONDITION: + r = get_max_match_length(en->target, max, env); + break; + + case ENCLOSE_ABSENT: + break; } } break; @@ -2277,7 +2461,7 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level) do { r = get_char_length_tree1(NCAR(node), reg, &tlen, level); if (r == 0) - *len = distance_add(*len, tlen); + *len = (int )distance_add(*len, tlen); } while (r == 0 && IS_NOT_NULL(node = NCDR(node))); break; @@ -2288,21 +2472,21 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level) r = get_char_length_tree1(NCAR(node), reg, &tlen, level); while (r == 0 && IS_NOT_NULL(node = NCDR(node))) { - r = get_char_length_tree1(NCAR(node), reg, &tlen2, level); - if (r == 0) { - if (tlen != tlen2) - varlen = 1; - } + r = get_char_length_tree1(NCAR(node), reg, &tlen2, level); + if (r == 0) { + if (tlen != tlen2) + varlen = 1; + } } if (r == 0) { - if (varlen != 0) { - if (level == 1) - r = GET_CHAR_LEN_TOP_ALT_VARLEN; - else - r = GET_CHAR_LEN_VARLEN; - } - else - *len = tlen; + if (varlen != 0) { + if (level == 1) + r = GET_CHAR_LEN_TOP_ALT_VARLEN; + else + r = GET_CHAR_LEN_VARLEN; + } + else + *len = tlen; } } break; @@ -2312,8 +2496,8 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level) StrNode* sn = NSTR(node); UChar *s = sn->s; while (s < sn->end) { - s += enc_len(reg->enc, s, sn->end); - (*len)++; + s += enclen(reg->enc, s, sn->end); + (*len)++; } } break; @@ -2322,12 +2506,12 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level) { QtfrNode* qn = NQTFR(node); if (qn->lower == qn->upper) { - r = get_char_length_tree1(qn->target, reg, &tlen, level); - if (r == 0) - *len = distance_multiply(tlen, qn->lower); + r = get_char_length_tree1(qn->target, reg, &tlen, level); + if (r == 0) + *len = (int )distance_multiply(tlen, qn->lower); } else - r = GET_CHAR_LEN_VARLEN; + r = GET_CHAR_LEN_VARLEN; } break; @@ -2355,23 +2539,25 @@ get_char_length_tree1(Node* node, regex_t* reg, int* len, int level) switch (en->type) { case ENCLOSE_MEMORY: #ifdef USE_SUBEXP_CALL - if (IS_ENCLOSE_CLEN_FIXED(en)) - *len = en->char_len; - else { - r = get_char_length_tree1(en->target, reg, len, level); - if (r == 0) { - en->char_len = *len; - SET_ENCLOSE_STATUS(node, NST_CLEN_FIXED); - } - } - break; + if (IS_ENCLOSE_CLEN_FIXED(en)) + *len = en->char_len; + else { + r = get_char_length_tree1(en->target, reg, len, level); + if (r == 0) { + en->char_len = *len; + SET_ENCLOSE_STATUS(node, NST_CLEN_FIXED); + } + } + break; #endif case ENCLOSE_OPTION: case ENCLOSE_STOP_BACKTRACK: - r = get_char_length_tree1(en->target, reg, len, level); - break; + case ENCLOSE_CONDITION: + r = get_char_length_tree1(en->target, reg, len, level); + break; + case ENCLOSE_ABSENT: default: - break; + break; } } break; @@ -2397,9 +2583,10 @@ get_char_length_tree(Node* node, regex_t* reg, int* len) static int is_not_included(Node* x, Node* y, regex_t* reg) { - int i, len; + int i; + OnigDistance len; OnigCodePoint code; - UChar *p, c; + UChar *p; int ytype; retry: @@ -2409,28 +2596,29 @@ is_not_included(Node* x, Node* y, regex_t* reg) { switch (ytype) { case NT_CTYPE: - if (NCTYPE(y)->ctype == NCTYPE(x)->ctype && - NCTYPE(y)->not != NCTYPE(x)->not) - return 1; - else - return 0; - break; + if (NCTYPE(y)->ctype == NCTYPE(x)->ctype && + NCTYPE(y)->not != NCTYPE(x)->not && + NCTYPE(y)->ascii_range == NCTYPE(x)->ascii_range) + return 1; + else + return 0; + break; case NT_CCLASS: swap: - { - Node* tmp; - tmp = x; x = y; y = tmp; - goto retry; - } - break; + { + Node* tmp; + tmp = x; x = y; y = tmp; + goto retry; + } + break; case NT_STR: - goto swap; - break; + goto swap; + break; default: - break; + break; } } break; @@ -2440,69 +2628,80 @@ is_not_included(Node* x, Node* y, regex_t* reg) CClassNode* xc = NCCLASS(x); switch (ytype) { case NT_CTYPE: - switch (NCTYPE(y)->ctype) { - case ONIGENC_CTYPE_WORD: - if (NCTYPE(y)->not == 0) { - if (IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) { - for (i = 0; i < SINGLE_BYTE_SIZE; i++) { - if (BITSET_AT(xc->bs, i)) { - if (IS_CODE_SB_WORD(reg->enc, i)) return 0; - } - } - return 1; - } - return 0; - } - else { - for (i = 0; i < SINGLE_BYTE_SIZE; i++) { - if (! IS_CODE_SB_WORD(reg->enc, i)) { - if (!IS_NCCLASS_NOT(xc)) { - if (BITSET_AT(xc->bs, i)) - return 0; - } - else { - if (! BITSET_AT(xc->bs, i)) - return 0; - } - } - } - return 1; - } - break; - - default: - break; - } - break; + switch (NCTYPE(y)->ctype) { + case ONIGENC_CTYPE_WORD: + if (NCTYPE(y)->not == 0) { + if (IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) { + for (i = 0; i < SINGLE_BYTE_SIZE; i++) { + if (BITSET_AT(xc->bs, i)) { + if (NCTYPE(y)->ascii_range) { + if (IS_CODE_SB_WORD(reg->enc, i)) return 0; + } + else { + if (ONIGENC_IS_CODE_WORD(reg->enc, i)) return 0; + } + } + } + return 1; + } + return 0; + } + else { + if (IS_NOT_NULL(xc->mbuf)) return 0; + for (i = 0; i < SINGLE_BYTE_SIZE; i++) { + int is_word; + if (NCTYPE(y)->ascii_range) + is_word = IS_CODE_SB_WORD(reg->enc, i); + else + is_word = ONIGENC_IS_CODE_WORD(reg->enc, i); + if (! is_word) { + if (!IS_NCCLASS_NOT(xc)) { + if (BITSET_AT(xc->bs, i)) + return 0; + } + else { + if (! BITSET_AT(xc->bs, i)) + return 0; + } + } + } + return 1; + } + break; + + default: + break; + } + break; case NT_CCLASS: - { - int v; - CClassNode* yc = NCCLASS(y); + { + int v; + CClassNode* yc = NCCLASS(y); - for (i = 0; i < SINGLE_BYTE_SIZE; i++) { - v = BITSET_AT(xc->bs, i); - if ((v != 0 && !IS_NCCLASS_NOT(xc)) || + for (i = 0; i < SINGLE_BYTE_SIZE; i++) { + v = BITSET_AT(xc->bs, i); + if ((v != 0 && !IS_NCCLASS_NOT(xc)) || (v == 0 && IS_NCCLASS_NOT(xc))) { - v = BITSET_AT(yc->bs, i); - if ((v != 0 && !IS_NCCLASS_NOT(yc)) || + v = BITSET_AT(yc->bs, i); + if ((v != 0 && !IS_NCCLASS_NOT(yc)) || (v == 0 && IS_NCCLASS_NOT(yc))) - return 0; - } - } - if ((IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) || - (IS_NULL(yc->mbuf) && !IS_NCCLASS_NOT(yc))) - return 1; - return 0; - } - break; + return 0; + } + } + if ((IS_NULL(xc->mbuf) && !IS_NCCLASS_NOT(xc)) || + (IS_NULL(yc->mbuf) && !IS_NCCLASS_NOT(yc))) + return 1; + return 0; + } + break; case NT_STR: - goto swap; - break; + goto swap; + break; default: - break; + break; } } break; @@ -2511,53 +2710,60 @@ is_not_included(Node* x, Node* y, regex_t* reg) { StrNode* xs = NSTR(x); if (NSTRING_LEN(x) == 0) - break; + break; - c = *(xs->s); switch (ytype) { case NT_CTYPE: - switch (NCTYPE(y)->ctype) { - case ONIGENC_CTYPE_WORD: - if (ONIGENC_IS_MBC_WORD(reg->enc, xs->s, xs->end)) - return NCTYPE(y)->not; - else - return !(NCTYPE(y)->not); - break; - default: - break; - } - break; + switch (NCTYPE(y)->ctype) { + case ONIGENC_CTYPE_WORD: + if (NCTYPE(y)->ascii_range) { + if (ONIGENC_IS_MBC_ASCII_WORD(reg->enc, xs->s, xs->end)) + return NCTYPE(y)->not; + else + return !(NCTYPE(y)->not); + } + else { + if (ONIGENC_IS_MBC_WORD(reg->enc, xs->s, xs->end)) + return NCTYPE(y)->not; + else + return !(NCTYPE(y)->not); + } + break; + default: + break; + } + break; case NT_CCLASS: - { - CClassNode* cc = NCCLASS(y); + { + CClassNode* cc = NCCLASS(y); - code = ONIGENC_MBC_TO_CODE(reg->enc, xs->s, - xs->s + ONIGENC_MBC_MAXLEN(reg->enc)); - return (onig_is_code_in_cc(reg->enc, code, cc) != 0 ? 0 : 1); - } - break; + code = ONIGENC_MBC_TO_CODE(reg->enc, xs->s, + xs->s + ONIGENC_MBC_MAXLEN(reg->enc)); + return (onig_is_code_in_cc(reg->enc, code, cc) != 0 ? 0 : 1); + } + break; case NT_STR: - { - UChar *q; - StrNode* ys = NSTR(y); - len = NSTRING_LEN(x); - if (len > NSTRING_LEN(y)) len = NSTRING_LEN(y); - if (NSTRING_IS_AMBIG(x) || NSTRING_IS_AMBIG(y)) { + { + UChar *q; + StrNode* ys = NSTR(y); + len = NSTRING_LEN(x); + if (len > NSTRING_LEN(y)) len = NSTRING_LEN(y); + if (NSTRING_IS_AMBIG(x) || NSTRING_IS_AMBIG(y)) { /* tiny version */ return 0; - } - else { - for (i = 0, p = ys->s, q = xs->s; i < len; i++, p++, q++) { - if (*p != *q) return 1; - } - } - } - break; - + } + else { + for (i = 0, p = ys->s, q = xs->s; (OnigDistance )i < len; i++, p++, q++) { + if (*p != *q) return 1; + } + } + } + break; + default: - break; + break; } } break; @@ -2597,15 +2803,12 @@ get_head_value_node(Node* node, int exact, regex_t* reg) case NT_STR: { StrNode* sn = NSTR(node); - if (sn->end <= sn->s) - break; + break; - if (exact != 0 && - !NSTRING_IS_RAW(node) && IS_IGNORECASE(reg->options)) { - } - else { - n = node; + if (exact == 0 || + NSTRING_IS_RAW(node) || !IS_IGNORECASE(reg->options)) { + n = node; } } break; @@ -2614,10 +2817,12 @@ get_head_value_node(Node* node, int exact, regex_t* reg) { QtfrNode* qn = NQTFR(node); if (qn->lower > 0) { - if (IS_NOT_NULL(qn->head_exact)) - n = qn->head_exact; - else - n = get_head_value_node(qn->target, exact, reg); +#ifdef USE_OP_PUSH_OR_JUMP_EXACT + if (IS_NOT_NULL(qn->head_exact)) + n = qn->head_exact; + else +#endif + n = get_head_value_node(qn->target, exact, reg); } } break; @@ -2627,19 +2832,23 @@ get_head_value_node(Node* node, int exact, regex_t* reg) EncloseNode* en = NENCLOSE(node); switch (en->type) { case ENCLOSE_OPTION: - { - OnigOptionType options = reg->options; + { + OnigOptionType options = reg->options; - reg->options = NENCLOSE(node)->option; - n = get_head_value_node(NENCLOSE(node)->target, exact, reg); - reg->options = options; - } - break; + reg->options = NENCLOSE(node)->option; + n = get_head_value_node(NENCLOSE(node)->target, exact, reg); + reg->options = options; + } + break; case ENCLOSE_MEMORY: case ENCLOSE_STOP_BACKTRACK: - n = get_head_value_node(en->target, exact, reg); - break; + case ENCLOSE_CONDITION: + n = get_head_value_node(en->target, exact, reg); + break; + + case ENCLOSE_ABSENT: + break; } } break; @@ -2670,20 +2879,20 @@ check_type_tree(Node* node, int type_mask, int enclose_mask, int anchor_mask) case NT_ALT: do { r = check_type_tree(NCAR(node), type_mask, enclose_mask, - anchor_mask); + anchor_mask); } while (r == 0 && IS_NOT_NULL(node = NCDR(node))); break; case NT_QTFR: r = check_type_tree(NQTFR(node)->target, type_mask, enclose_mask, - anchor_mask); + anchor_mask); break; case NT_ENCLOSE: { EncloseNode* en = NENCLOSE(node); if ((en->type & enclose_mask) == 0) - return 1; + return 1; r = check_type_tree(en->target, type_mask, enclose_mask, anchor_mask); } @@ -2696,7 +2905,7 @@ check_type_tree(Node* node, int type_mask, int enclose_mask, int anchor_mask) if (NANCHOR(node)->target) r = check_type_tree(NANCHOR(node)->target, - type_mask, enclose_mask, anchor_mask); + type_mask, enclose_mask, anchor_mask); break; default: @@ -2707,8 +2916,8 @@ check_type_tree(Node* node, int type_mask, int enclose_mask, int anchor_mask) #ifdef USE_SUBEXP_CALL -#define RECURSION_EXIST 1 -#define RECURSION_INFINITE 2 +# define RECURSION_EXIST 1 +# define RECURSION_INFINITE 2 static int subexp_inf_recursive_check(Node* node, ScanEnv* env, int head) @@ -2726,14 +2935,14 @@ subexp_inf_recursive_check(Node* node, ScanEnv* env, int head) x = node; do { - ret = subexp_inf_recursive_check(NCAR(x), env, head); - if (ret < 0 || ret == RECURSION_INFINITE) return ret; - r |= ret; - if (head) { - ret = get_min_match_length(NCAR(x), &min, env); - if (ret != 0) return ret; - if (min != 0) head = 0; - } + ret = subexp_inf_recursive_check(NCAR(x), env, head); + if (ret < 0 || ret == RECURSION_INFINITE) return ret; + r |= ret; + if (head) { + ret = get_min_match_length(NCAR(x), &min, env); + if (ret != 0) return ret; + if (min != 0) head = 0; + } } while (IS_NOT_NULL(x = NCDR(x))); } break; @@ -2743,9 +2952,9 @@ subexp_inf_recursive_check(Node* node, ScanEnv* env, int head) int ret; r = RECURSION_EXIST; do { - ret = subexp_inf_recursive_check(NCAR(node), env, head); - if (ret < 0 || ret == RECURSION_INFINITE) return ret; - r &= ret; + ret = subexp_inf_recursive_check(NCAR(node), env, head); + if (ret < 0 || ret == RECURSION_INFINITE) return ret; + r &= ret; } while (IS_NOT_NULL(node = NCDR(node))); } break; @@ -2765,8 +2974,8 @@ subexp_inf_recursive_check(Node* node, ScanEnv* env, int head) case ANCHOR_PREC_READ_NOT: case ANCHOR_LOOK_BEHIND: case ANCHOR_LOOK_BEHIND_NOT: - r = subexp_inf_recursive_check(an->target, env, head); - break; + r = subexp_inf_recursive_check(an->target, env, head); + break; } } break; @@ -2821,8 +3030,8 @@ subexp_inf_recursive_check_trav(Node* node, ScanEnv* env) case ANCHOR_PREC_READ_NOT: case ANCHOR_LOOK_BEHIND: case ANCHOR_LOOK_BEHIND_NOT: - r = subexp_inf_recursive_check_trav(an->target, env); - break; + r = subexp_inf_recursive_check_trav(an->target, env); + break; } } break; @@ -2832,10 +3041,10 @@ subexp_inf_recursive_check_trav(Node* node, ScanEnv* env) EncloseNode* en = NENCLOSE(node); if (IS_ENCLOSE_RECURSION(en)) { - SET_ENCLOSE_STATUS(node, NST_MARK1); - r = subexp_inf_recursive_check(en->target, env, 1); - if (r > 0) return ONIGERR_NEVER_ENDING_RECURSION; - CLEAR_ENCLOSE_STATUS(node, NST_MARK1); + SET_ENCLOSE_STATUS(node, NST_MARK1); + r = subexp_inf_recursive_check(en->target, env, 1); + if (r > 0) return ONIGERR_NEVER_ENDING_RECURSION; + CLEAR_ENCLOSE_STATUS(node, NST_MARK1); } r = subexp_inf_recursive_check_trav(en->target, env); } @@ -2874,8 +3083,8 @@ subexp_recursive_check(Node* node) case ANCHOR_PREC_READ_NOT: case ANCHOR_LOOK_BEHIND: case ANCHOR_LOOK_BEHIND_NOT: - r = subexp_recursive_check(an->target); - break; + r = subexp_recursive_check(an->target); + break; } } break; @@ -2908,7 +3117,7 @@ subexp_recursive_check(Node* node) static int subexp_recursive_check_trav(Node* node, ScanEnv* env) { -#define FOUND_CALLED_NODE 1 +# define FOUND_CALLED_NODE 1 int type; int r = 0; @@ -2920,9 +3129,9 @@ subexp_recursive_check_trav(Node* node, ScanEnv* env) { int ret; do { - ret = subexp_recursive_check_trav(NCAR(node), env); - if (ret == FOUND_CALLED_NODE) r = FOUND_CALLED_NODE; - else if (ret < 0) return ret; + ret = subexp_recursive_check_trav(NCAR(node), env); + if (ret == FOUND_CALLED_NODE) r = FOUND_CALLED_NODE; + else if (ret < 0) return ret; } while (IS_NOT_NULL(node = NCDR(node))); } break; @@ -2931,7 +3140,7 @@ subexp_recursive_check_trav(Node* node, ScanEnv* env) r = subexp_recursive_check_trav(NQTFR(node)->target, env); if (NQTFR(node)->upper == 0) { if (r == FOUND_CALLED_NODE) - NQTFR(node)->is_refered = 1; + NQTFR(node)->is_referred = 1; } break; @@ -2943,8 +3152,8 @@ subexp_recursive_check_trav(Node* node, ScanEnv* env) case ANCHOR_PREC_READ_NOT: case ANCHOR_LOOK_BEHIND: case ANCHOR_LOOK_BEHIND_NOT: - r = subexp_recursive_check_trav(an->target, env); - break; + r = subexp_recursive_check_trav(an->target, env); + break; } } break; @@ -2954,16 +3163,16 @@ subexp_recursive_check_trav(Node* node, ScanEnv* env) EncloseNode* en = NENCLOSE(node); if (! IS_ENCLOSE_RECURSION(en)) { - if (IS_ENCLOSE_CALLED(en)) { - SET_ENCLOSE_STATUS(node, NST_MARK1); - r = subexp_recursive_check(en->target); - if (r != 0) SET_ENCLOSE_STATUS(node, NST_RECURSION); - CLEAR_ENCLOSE_STATUS(node, NST_MARK1); - } + if (IS_ENCLOSE_CALLED(en)) { + SET_ENCLOSE_STATUS(node, NST_MARK1); + r = subexp_recursive_check(en->target); + if (r != 0) SET_ENCLOSE_STATUS(node, NST_RECURSION); + CLEAR_ENCLOSE_STATUS(node, NST_MARK1); + } } r = subexp_recursive_check_trav(en->target, env); if (IS_ENCLOSE_CALLED(en)) - r |= FOUND_CALLED_NODE; + r |= FOUND_CALLED_NODE; } break; @@ -3003,58 +3212,66 @@ setup_subexp_call(Node* node, ScanEnv* env) case NT_CALL: { - int n, num, *refs; - UChar *p; CallNode* cn = NCALL(node); Node** nodes = SCANENV_MEM_NODES(env); -#ifdef USE_NAMED_GROUP - n = onig_name_to_group_numbers(env->reg, cn->name, cn->name_end, &refs); -#else - n = -1; -#endif - if (n <= 0) { - /* name not found, check group number. (?*ddd) */ - p = cn->name; - num = onig_scan_unsigned_number(&p, cn->name_end, env->enc); - if (num <= 0 || p != cn->name_end) { - onig_scan_env_set_error_string(env, - ONIGERR_UNDEFINED_NAME_REFERENCE, cn->name, cn->name_end); - return ONIGERR_UNDEFINED_NAME_REFERENCE; - } -#ifdef USE_NAMED_GROUP - if (env->num_named > 0 && - IS_SYNTAX_BV(env->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) && - !ONIG_IS_OPTION_ON(env->option, ONIG_OPTION_CAPTURE_GROUP)) { - return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED; - } -#endif - if (num > env->num_mem) { - onig_scan_env_set_error_string(env, - ONIGERR_UNDEFINED_GROUP_REFERENCE, cn->name, cn->name_end); - return ONIGERR_UNDEFINED_GROUP_REFERENCE; - } - cn->ref_num = num; - goto set_call_attr; + if (cn->group_num != 0) { + int gnum = cn->group_num; + +# ifdef USE_NAMED_GROUP + if (env->num_named > 0 && + IS_SYNTAX_BV(env->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) && + !ONIG_IS_OPTION_ON(env->option, ONIG_OPTION_CAPTURE_GROUP)) { + return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED; + } +# endif + if (gnum > env->num_mem) { + onig_scan_env_set_error_string(env, + ONIGERR_UNDEFINED_GROUP_REFERENCE, cn->name, cn->name_end); + return ONIGERR_UNDEFINED_GROUP_REFERENCE; + } + +# ifdef USE_NAMED_GROUP + set_call_attr: +# endif + cn->target = nodes[cn->group_num]; + if (IS_NULL(cn->target)) { + onig_scan_env_set_error_string(env, + ONIGERR_UNDEFINED_NAME_REFERENCE, cn->name, cn->name_end); + return ONIGERR_UNDEFINED_NAME_REFERENCE; + } + SET_ENCLOSE_STATUS(cn->target, NST_CALLED); + BIT_STATUS_ON_AT(env->bt_mem_start, cn->group_num); + cn->unset_addr_list = env->unset_addr_list; } - else if (n > 1) { - onig_scan_env_set_error_string(env, - ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL, cn->name, cn->name_end); - return ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL; +# ifdef USE_NAMED_GROUP +# ifdef USE_PERL_SUBEXP_CALL + else if (cn->name == cn->name_end) { + goto set_call_attr; } +# endif else { - cn->ref_num = refs[0]; - set_call_attr: - cn->target = nodes[cn->ref_num]; - if (IS_NULL(cn->target)) { - onig_scan_env_set_error_string(env, - ONIGERR_UNDEFINED_NAME_REFERENCE, cn->name, cn->name_end); - return ONIGERR_UNDEFINED_NAME_REFERENCE; - } - SET_ENCLOSE_STATUS(cn->target, NST_CALLED); - BIT_STATUS_ON_AT(env->bt_mem_start, cn->ref_num); - cn->unset_addr_list = env->unset_addr_list; + int *refs; + + int n = onig_name_to_group_numbers(env->reg, cn->name, cn->name_end, + &refs); + if (n <= 0) { + onig_scan_env_set_error_string(env, + ONIGERR_UNDEFINED_NAME_REFERENCE, cn->name, cn->name_end); + return ONIGERR_UNDEFINED_NAME_REFERENCE; + } + else if (n > 1 && + ! IS_SYNTAX_BV(env->syntax, ONIG_SYN_ALLOW_MULTIPLEX_DEFINITION_NAME_CALL)) { + onig_scan_env_set_error_string(env, + ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL, cn->name, cn->name_end); + return ONIGERR_MULTIPLEX_DEFINITION_NAME_CALL; + } + else { + cn->group_num = refs[0]; + goto set_call_attr; + } } +# endif } break; @@ -3067,8 +3284,8 @@ setup_subexp_call(Node* node, ScanEnv* env) case ANCHOR_PREC_READ_NOT: case ANCHOR_LOOK_BEHIND: case ANCHOR_LOOK_BEHIND_NOT: - r = setup_subexp_call(an->target, env); - break; + r = setup_subexp_call(an->target, env); + break; } } break; @@ -3081,6 +3298,14 @@ setup_subexp_call(Node* node, ScanEnv* env) } #endif +#define IN_ALT (1<<0) +#define IN_NOT (1<<1) +#define IN_REPEAT (1<<2) +#define IN_VAR_REPEAT (1<<3) +#define IN_CALL (1<<4) +#define IN_RECCALL (1<<5) +#define IN_LOOK_BEHIND (1<<6) + /* divide different length alternatives in look-behind. (?<=A|B) ==> (?<=A)|(?<=B) (?<!A|B) ==> (?<!A)(?<!B) @@ -3150,32 +3375,32 @@ next_setup(Node* node, Node* next_node, regex_t* reg) Node* n = get_head_value_node(next_node, 1, reg); /* '\0': for UTF-16BE etc... */ if (IS_NOT_NULL(n) && NSTR(n)->s[0] != '\0') { - qn->next_head_exact = n; + qn->next_head_exact = n; } #endif - /* automatic posseivation a*b ==> (?>a*)b */ + /* automatic possessification a*b ==> (?>a*)b */ if (qn->lower <= 1) { - int ttype = NTYPE(qn->target); - if (IS_NODE_TYPE_SIMPLE(ttype)) { - Node *x, *y; - x = get_head_value_node(qn->target, 0, reg); - if (IS_NOT_NULL(x)) { - y = get_head_value_node(next_node, 0, reg); - if (IS_NOT_NULL(y) && is_not_included(x, y, reg)) { - Node* en = onig_node_new_enclose(ENCLOSE_STOP_BACKTRACK); - CHECK_NULL_RETURN_MEMERR(en); - SET_ENCLOSE_STATUS(en, NST_STOP_BT_SIMPLE_REPEAT); - swap_node(node, en); - NENCLOSE(node)->target = en; - } - } - } + int ttype = NTYPE(qn->target); + if (IS_NODE_TYPE_SIMPLE(ttype)) { + Node *x, *y; + x = get_head_value_node(qn->target, 0, reg); + if (IS_NOT_NULL(x)) { + y = get_head_value_node(next_node, 0, reg); + if (IS_NOT_NULL(y) && is_not_included(x, y, reg)) { + Node* en = onig_node_new_enclose(ENCLOSE_STOP_BACKTRACK); + CHECK_NULL_RETURN_MEMERR(en); + SET_ENCLOSE_STATUS(en, NST_STOP_BT_SIMPLE_REPEAT); + swap_node(node, en); + NENCLOSE(node)->target = en; + } + } + } } } } else if (type == NT_ENCLOSE) { EncloseNode* en = NENCLOSE(node); - if (en->type == ENCLOSE_MEMORY) { + if (en->type == ENCLOSE_MEMORY && !IS_ENCLOSE_CALLED(en)) { node = en->target; goto retry; } @@ -3187,9 +3412,10 @@ next_setup(Node* node, Node* next_node, regex_t* reg) static int update_string_node_case_fold(regex_t* reg, Node *node) { - UChar *p, *q, *end, buf[ONIGENC_MBC_CASE_FOLD_MAXLEN]; + UChar *p, *end, buf[ONIGENC_MBC_CASE_FOLD_MAXLEN]; UChar *sbuf, *ebuf, *sp; - int r, i, len, sbuf_size; + int r, i, len; + OnigDistance sbuf_size; StrNode* sn = NSTR(node); end = sn->end; @@ -3202,14 +3428,17 @@ update_string_node_case_fold(regex_t* reg, Node *node) p = sn->s; while (p < end) { len = ONIGENC_MBC_CASE_FOLD(reg->enc, reg->case_fold_flag, &p, end, buf); - q = buf; for (i = 0; i < len; i++) { if (sp >= ebuf) { - sbuf = (UChar* )xrealloc(sbuf, sbuf_size * 2); - CHECK_NULL_RETURN_MEMERR(sbuf); - sp = sbuf + sbuf_size; - sbuf_size *= 2; - ebuf = sbuf + sbuf_size; + UChar* p = (UChar* )xrealloc(sbuf, sbuf_size * 2); + if (IS_NULL(p)) { + xfree(sbuf); + return ONIGERR_MEMORY; + } + sbuf = p; + sp = sbuf + sbuf_size; + sbuf_size *= 2; + ebuf = sbuf + sbuf_size; } *sp++ = buf[i]; @@ -3217,18 +3446,14 @@ update_string_node_case_fold(regex_t* reg, Node *node) } r = onig_node_str_set(node, sbuf, sp); - if (r != 0) { - xfree(sbuf); - return r; - } xfree(sbuf); - return 0; + return r; } static int expand_case_fold_make_rem_string(Node** rnode, UChar *s, UChar *end, - regex_t* reg) + regex_t* reg) { int r; Node *node; @@ -3249,9 +3474,26 @@ expand_case_fold_make_rem_string(Node** rnode, UChar *s, UChar *end, } static int +is_case_fold_variable_len(int item_num, OnigCaseFoldCodeItem items[], + int slen) +{ + int i; + + for (i = 0; i < item_num; i++) { + if (items[i].byte_len != slen) { + return 1; + } + if (items[i].code_len != 1) { + return 1; + } + } + return 0; +} + +static int expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[], - UChar *p, int slen, UChar *end, - regex_t* reg, Node **rnode) + UChar *p, int slen, UChar *end, + regex_t* reg, Node **rnode) { int r, i, j, len, varlen; Node *anode, *var_anode, *snode, *xnode, *an; @@ -3292,12 +3534,12 @@ expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[], for (i = 0; i < item_num; i++) { snode = onig_node_new_str(NULL, NULL); if (IS_NULL(snode)) goto mem_err; - + for (j = 0; j < items[i].code_len; j++) { len = ONIGENC_CODE_TO_MBC(reg->enc, items[i].code[j], buf); if (len < 0) { - r = len; - goto mem_err2; + r = len; + goto mem_err2; } r = onig_node_str_cat(snode, buf, buf + len); @@ -3314,29 +3556,29 @@ expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[], UChar *q = p + items[i].byte_len; if (q < end) { - r = expand_case_fold_make_rem_string(&rem, q, end, reg); - if (r != 0) { - onig_node_free(an); - goto mem_err2; - } + r = expand_case_fold_make_rem_string(&rem, q, end, reg); + if (r != 0) { + onig_node_free(an); + goto mem_err2; + } - xnode = onig_node_list_add(NULL_NODE, snode); - if (IS_NULL(xnode)) { - onig_node_free(an); - onig_node_free(rem); - goto mem_err2; - } - if (IS_NULL(onig_node_list_add(xnode, rem))) { - onig_node_free(an); - onig_node_free(xnode); - onig_node_free(rem); - goto mem_err; - } + xnode = onig_node_list_add(NULL_NODE, snode); + if (IS_NULL(xnode)) { + onig_node_free(an); + onig_node_free(rem); + goto mem_err2; + } + if (IS_NULL(onig_node_list_add(xnode, rem))) { + onig_node_free(an); + onig_node_free(xnode); + onig_node_free(rem); + goto mem_err; + } - NCAR(an) = xnode; + NCAR(an) = xnode; } else { - NCAR(an) = snode; + NCAR(an) = snode; } NCDR(var_anode) = an; @@ -3360,55 +3602,63 @@ expand_case_fold_string_alt(int item_num, OnigCaseFoldCodeItem items[], return ONIGERR_MEMORY; } -static int -expand_case_fold_string(Node* node, regex_t* reg) -{ #define THRESHOLD_CASE_FOLD_ALT_FOR_EXPANSION 8 +static int +expand_case_fold_string(Node* node, regex_t* reg, int state) +{ int r, n, len, alt_num; + int varlen = 0; + int is_in_look_behind; UChar *start, *end, *p; Node *top_root, *root, *snode, *prev_node; OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM]; - StrNode* sn = NSTR(node); + StrNode* sn; if (NSTRING_IS_AMBIG(node)) return 0; + sn = NSTR(node); + start = sn->s; end = sn->end; if (start >= end) return 0; + is_in_look_behind = (state & IN_LOOK_BEHIND) != 0; + r = 0; top_root = root = prev_node = snode = NULL_NODE; alt_num = 1; p = start; while (p < end) { n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(reg->enc, reg->case_fold_flag, - p, end, items); + p, end, items); if (n < 0) { r = n; goto err; } - len = enc_len(reg->enc, p, end); + len = enclen(reg->enc, p, end); - if (n == 0) { + varlen = is_case_fold_variable_len(n, items, len); + if (n == 0 || varlen == 0 || is_in_look_behind) { if (IS_NULL(snode)) { - if (IS_NULL(root) && IS_NOT_NULL(prev_node)) { - top_root = root = onig_node_list_add(NULL_NODE, prev_node); - if (IS_NULL(root)) { - onig_node_free(prev_node); - goto mem_err; - } - } + if (IS_NULL(root) && IS_NOT_NULL(prev_node)) { + onig_node_free(top_root); + top_root = root = onig_node_list_add(NULL_NODE, prev_node); + if (IS_NULL(root)) { + onig_node_free(prev_node); + goto mem_err; + } + } - prev_node = snode = onig_node_new_str(NULL, NULL); - if (IS_NULL(snode)) goto mem_err; - if (IS_NOT_NULL(root)) { - if (IS_NULL(onig_node_list_add(root, snode))) { - onig_node_free(snode); - goto mem_err; - } - } + prev_node = snode = onig_node_new_str(NULL, NULL); + if (IS_NULL(snode)) goto mem_err; + if (IS_NOT_NULL(root)) { + if (IS_NULL(onig_node_list_add(root, snode))) { + onig_node_free(snode); + goto mem_err; + } + } } r = onig_node_str_cat(snode, p, p + len); @@ -3418,36 +3668,43 @@ expand_case_fold_string(Node* node, regex_t* reg) alt_num *= (n + 1); if (alt_num > THRESHOLD_CASE_FOLD_ALT_FOR_EXPANSION) break; + if (IS_NOT_NULL(snode)) { + r = update_string_node_case_fold(reg, snode); + if (r == 0) { + NSTRING_SET_AMBIG(snode); + } + } if (IS_NULL(root) && IS_NOT_NULL(prev_node)) { - top_root = root = onig_node_list_add(NULL_NODE, prev_node); - if (IS_NULL(root)) { - onig_node_free(prev_node); - goto mem_err; - } + onig_node_free(top_root); + top_root = root = onig_node_list_add(NULL_NODE, prev_node); + if (IS_NULL(root)) { + onig_node_free(prev_node); + goto mem_err; + } } r = expand_case_fold_string_alt(n, items, p, len, end, reg, &prev_node); if (r < 0) goto mem_err; if (r == 1) { - if (IS_NULL(root)) { - top_root = prev_node; - } - else { - if (IS_NULL(onig_node_list_add(root, prev_node))) { - onig_node_free(prev_node); - goto mem_err; - } - } + if (IS_NULL(root)) { + top_root = prev_node; + } + else { + if (IS_NULL(onig_node_list_add(root, prev_node))) { + onig_node_free(prev_node); + goto mem_err; + } + } - root = NCAR(prev_node); + root = NCAR(prev_node); } else { /* r == 0 */ - if (IS_NOT_NULL(root)) { - if (IS_NULL(onig_node_list_add(root, prev_node))) { - onig_node_free(prev_node); - goto mem_err; - } - } + if (IS_NOT_NULL(root)) { + if (IS_NULL(onig_node_list_add(root, prev_node))) { + onig_node_free(prev_node); + goto mem_err; + } + } } snode = NULL_NODE; @@ -3455,6 +3712,12 @@ expand_case_fold_string(Node* node, regex_t* reg) p += len; } + if (IS_NOT_NULL(snode)) { + r = update_string_node_case_fold(reg, snode); + if (r == 0) { + NSTRING_SET_AMBIG(snode); + } + } if (p < end) { Node *srem; @@ -3463,11 +3726,12 @@ expand_case_fold_string(Node* node, regex_t* reg) if (r != 0) goto mem_err; if (IS_NOT_NULL(prev_node) && IS_NULL(root)) { + onig_node_free(top_root); top_root = root = onig_node_list_add(NULL_NODE, prev_node); if (IS_NULL(root)) { - onig_node_free(srem); - onig_node_free(prev_node); - goto mem_err; + onig_node_free(srem); + onig_node_free(prev_node); + goto mem_err; } } @@ -3476,8 +3740,8 @@ expand_case_fold_string(Node* node, regex_t* reg) } else { if (IS_NULL(onig_node_list_add(root, srem))) { - onig_node_free(srem); - goto mem_err; + onig_node_free(srem); + goto mem_err; } } } @@ -3499,12 +3763,12 @@ expand_case_fold_string(Node* node, regex_t* reg) #ifdef USE_COMBINATION_EXPLOSION_CHECK -#define CEC_THRES_NUM_BIG_REPEAT 512 -#define CEC_INFINITE_NUM 0x7fffffff +# define CEC_THRES_NUM_BIG_REPEAT 512 +# define CEC_INFINITE_NUM 0x7fffffff -#define CEC_IN_INFINITE_REPEAT (1<<0) -#define CEC_IN_FINITE_REPEAT (1<<1) -#define CEC_CONT_BIG_REPEAT (1<<2) +# define CEC_IN_INFINITE_REPEAT (1<<0) +# define CEC_IN_FINITE_REPEAT (1<<1) +# define CEC_CONT_BIG_REPEAT (1<<2) static int setup_comb_exp_check(Node* node, int state, ScanEnv* env) @@ -3516,10 +3780,8 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env) switch (type) { case NT_LIST: { - Node* prev = NULL_NODE; do { - r = setup_comb_exp_check(NCAR(node), r, env); - prev = NCAR(node); + r = setup_comb_exp_check(NCAR(node), r, env); } while (r >= 0 && IS_NOT_NULL(node = NCDR(node))); } break; @@ -3528,8 +3790,8 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env) { int ret; do { - ret = setup_comb_exp_check(NCAR(node), state, env); - r |= ret; + ret = setup_comb_exp_check(NCAR(node), state, env); + r |= ret; } while (ret >= 0 && IS_NOT_NULL(node = NCDR(node))); } break; @@ -3543,55 +3805,55 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env) int var_num; if (! IS_REPEAT_INFINITE(qn->upper)) { - if (qn->upper > 1) { - /* {0,1}, {1,1} are allowed */ - child_state |= CEC_IN_FINITE_REPEAT; - - /* check (a*){n,m}, (a+){n,m} => (a*){n,n}, (a+){n,n} */ - if (env->backrefed_mem == 0) { - if (NTYPE(qn->target) == NT_ENCLOSE) { - EncloseNode* en = NENCLOSE(qn->target); - if (en->type == ENCLOSE_MEMORY) { - if (NTYPE(en->target) == NT_QTFR) { - QtfrNode* q = NQTFR(en->target); - if (IS_REPEAT_INFINITE(q->upper) - && q->greedy == qn->greedy) { - qn->upper = (qn->lower == 0 ? 1 : qn->lower); - if (qn->upper == 1) - child_state = state; - } - } - } - } - } - } + if (qn->upper > 1) { + /* {0,1}, {1,1} are allowed */ + child_state |= CEC_IN_FINITE_REPEAT; + + /* check (a*){n,m}, (a+){n,m} => (a*){n,n}, (a+){n,n} */ + if (env->backrefed_mem == 0) { + if (NTYPE(qn->target) == NT_ENCLOSE) { + EncloseNode* en = NENCLOSE(qn->target); + if (en->type == ENCLOSE_MEMORY) { + if (NTYPE(en->target) == NT_QTFR) { + QtfrNode* q = NQTFR(en->target); + if (IS_REPEAT_INFINITE(q->upper) + && q->greedy == qn->greedy) { + qn->upper = (qn->lower == 0 ? 1 : qn->lower); + if (qn->upper == 1) + child_state = state; + } + } + } + } + } + } } if (state & CEC_IN_FINITE_REPEAT) { - qn->comb_exp_check_num = -1; + qn->comb_exp_check_num = -1; } else { - if (IS_REPEAT_INFINITE(qn->upper)) { - var_num = CEC_INFINITE_NUM; - child_state |= CEC_IN_INFINITE_REPEAT; - } - else { - var_num = qn->upper - qn->lower; - } + if (IS_REPEAT_INFINITE(qn->upper)) { + var_num = CEC_INFINITE_NUM; + child_state |= CEC_IN_INFINITE_REPEAT; + } + else { + var_num = qn->upper - qn->lower; + } - if (var_num >= CEC_THRES_NUM_BIG_REPEAT) - add_state |= CEC_CONT_BIG_REPEAT; - - if (((state & CEC_IN_INFINITE_REPEAT) != 0 && var_num != 0) || - ((state & CEC_CONT_BIG_REPEAT) != 0 && - var_num >= CEC_THRES_NUM_BIG_REPEAT)) { - if (qn->comb_exp_check_num == 0) { - env->num_comb_exp_check++; - qn->comb_exp_check_num = env->num_comb_exp_check; - if (env->curr_max_regnum > env->comb_exp_max_regnum) - env->comb_exp_max_regnum = env->curr_max_regnum; - } - } + if (var_num >= CEC_THRES_NUM_BIG_REPEAT) + add_state |= CEC_CONT_BIG_REPEAT; + + if (((state & CEC_IN_INFINITE_REPEAT) != 0 && var_num != 0) || + ((state & CEC_CONT_BIG_REPEAT) != 0 && + var_num >= CEC_THRES_NUM_BIG_REPEAT)) { + if (qn->comb_exp_check_num == 0) { + env->num_comb_exp_check++; + qn->comb_exp_check_num = env->num_comb_exp_check; + if (env->curr_max_regnum > env->comb_exp_max_regnum) + env->comb_exp_max_regnum = env->curr_max_regnum; + } + } } r = setup_comb_exp_check(target, child_state, env); @@ -3605,29 +3867,29 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env) switch (en->type) { case ENCLOSE_MEMORY: - { - if (env->curr_max_regnum < en->regnum) - env->curr_max_regnum = en->regnum; + { + if (env->curr_max_regnum < en->regnum) + env->curr_max_regnum = en->regnum; - r = setup_comb_exp_check(en->target, state, env); - } - break; + r = setup_comb_exp_check(en->target, state, env); + } + break; default: - r = setup_comb_exp_check(en->target, state, env); - break; + r = setup_comb_exp_check(en->target, state, env); + break; } } break; -#ifdef USE_SUBEXP_CALL +# ifdef USE_SUBEXP_CALL case NT_CALL: if (IS_CALL_RECURSION(NCALL(node))) env->has_recursion = 1; else r = setup_comb_exp_check(NCALL(node)->target, state, env); break; -#endif +# endif default: break; @@ -3637,11 +3899,6 @@ setup_comb_exp_check(Node* node, int state, ScanEnv* env) } #endif -#define IN_ALT (1<<0) -#define IN_NOT (1<<1) -#define IN_REPEAT (1<<2) -#define IN_VAR_REPEAT (1<<3) - /* setup_tree does the following work. 1. check empty loop. (set qn->target_empty_info) 2. expand ignore-case in char class. @@ -3656,17 +3913,18 @@ setup_tree(Node* node, regex_t* reg, int state, ScanEnv* env) int type; int r = 0; +restart: type = NTYPE(node); switch (type) { case NT_LIST: { Node* prev = NULL_NODE; do { - r = setup_tree(NCAR(node), reg, state, env); - if (IS_NOT_NULL(prev) && r == 0) { - r = next_setup(prev, NCAR(node), reg); - } - prev = NCAR(node); + r = setup_tree(NCAR(node), reg, state, env); + if (IS_NOT_NULL(prev) && r == 0) { + r = next_setup(prev, NCAR(node), reg); + } + prev = NCAR(node); } while (r == 0 && IS_NOT_NULL(node = NCDR(node))); } break; @@ -3682,7 +3940,7 @@ setup_tree(Node* node, regex_t* reg, int state, ScanEnv* env) case NT_STR: if (IS_IGNORECASE(reg->options) && !NSTRING_IS_RAW(node)) { - r = expand_case_fold_string(node, reg); + r = expand_case_fold_string(node, reg, state); } break; @@ -3703,15 +3961,15 @@ setup_tree(Node* node, regex_t* reg, int state, ScanEnv* env) BRefNode* br = NBREF(node); p = BACKREFS_P(br); for (i = 0; i < br->back_num; i++) { - if (p[i] > env->num_mem) return ONIGERR_INVALID_BACKREF; - BIT_STATUS_ON_AT(env->backrefed_mem, p[i]); - BIT_STATUS_ON_AT(env->bt_mem_start, p[i]); -#ifdef USE_BACKREF_AT_LEVEL - if (IS_BACKREF_NEST_LEVEL(br)) { - BIT_STATUS_ON_AT(env->bt_mem_end, p[i]); - } + if (p[i] > env->num_mem) return ONIGERR_INVALID_BACKREF; + BIT_STATUS_ON_AT(env->backrefed_mem, p[i]); + BIT_STATUS_ON_AT(env->bt_mem_start, p[i]); +#ifdef USE_BACKREF_WITH_LEVEL + if (IS_BACKREF_NEST_LEVEL(br)) { + BIT_STATUS_ON_AT(env->bt_mem_end, p[i]); + } #endif - SET_ENCLOSE_STATUS(nodes[p[i]], NST_MEM_BACKREFED); + SET_ENCLOSE_STATUS(nodes[p[i]], NST_MEM_BACKREFED); } } break; @@ -3727,70 +3985,96 @@ setup_tree(Node* node, regex_t* reg, int state, ScanEnv* env) } if (IS_REPEAT_INFINITE(qn->upper) || qn->upper >= 1) { - r = get_min_match_length(target, &d, env); - if (r) break; - if (d == 0) { - qn->target_empty_info = NQ_TARGET_IS_EMPTY; -#ifdef USE_INFINITE_REPEAT_MONOMANIAC_MEM_STATUS_CHECK - r = quantifiers_memory_node_info(target); - if (r < 0) break; - if (r > 0) { - qn->target_empty_info = r; - } + r = get_min_match_length(target, &d, env); + if (r) break; + if (d == 0) { + qn->target_empty_info = NQ_TARGET_IS_EMPTY; +#ifdef USE_MONOMANIAC_CHECK_CAPTURES_IN_ENDLESS_REPEAT + r = quantifiers_memory_node_info(target); + if (r < 0) break; + if (r > 0) { + qn->target_empty_info = r; + } #endif #if 0 - r = get_max_match_length(target, &d, env); - if (r == 0 && d == 0) { - /* ()* ==> ()?, ()+ ==> () */ - qn->upper = 1; - if (qn->lower > 1) qn->lower = 1; - if (NTYPE(target) == NT_STR) { - qn->upper = qn->lower = 0; /* /(?:)+/ ==> // */ - } - } + r = get_max_match_length(target, &d, env); + if (r == 0 && d == 0) { + /* ()* ==> ()?, ()+ ==> () */ + qn->upper = 1; + if (qn->lower > 1) qn->lower = 1; + if (NTYPE(target) == NT_STR) { + qn->upper = qn->lower = 0; /* /(?:)+/ ==> // */ + } + } #endif - } + } } state |= IN_REPEAT; if (qn->lower != qn->upper) - state |= IN_VAR_REPEAT; + state |= IN_VAR_REPEAT; r = setup_tree(target, reg, state, env); if (r) break; /* expand string */ #define EXPAND_STRING_MAX_LENGTH 100 if (NTYPE(target) == NT_STR) { - if (!IS_REPEAT_INFINITE(qn->lower) && qn->lower == qn->upper && - qn->lower > 1 && qn->lower <= EXPAND_STRING_MAX_LENGTH) { - int len = NSTRING_LEN(target); - StrNode* sn = NSTR(target); - - if (len * qn->lower <= EXPAND_STRING_MAX_LENGTH) { - int i, n = qn->lower; - onig_node_conv_to_str_node(node, NSTR(target)->flag); - for (i = 0; i < n; i++) { - r = onig_node_str_cat(node, sn->s, sn->end); - if (r) break; - } - onig_node_free(target); - break; /* break case NT_QTFR: */ - } - } + if (qn->lower > 1) { + int i, n = qn->lower; + OnigDistance len = NSTRING_LEN(target); + StrNode* sn = NSTR(target); + Node* np; + + np = onig_node_new_str(sn->s, sn->end); + if (IS_NULL(np)) return ONIGERR_MEMORY; + NSTR(np)->flag = sn->flag; + + for (i = 1; i < n && (i+1) * len <= EXPAND_STRING_MAX_LENGTH; i++) { + r = onig_node_str_cat(np, sn->s, sn->end); + if (r) { + onig_node_free(np); + return r; + } + } + if (i < qn->upper || IS_REPEAT_INFINITE(qn->upper)) { + Node *np1, *np2; + + qn->lower -= i; + if (! IS_REPEAT_INFINITE(qn->upper)) + qn->upper -= i; + + np1 = onig_node_new_list(np, NULL); + if (IS_NULL(np1)) { + onig_node_free(np); + return ONIGERR_MEMORY; + } + swap_node(np1, node); + np2 = onig_node_list_add(node, np1); + if (IS_NULL(np2)) { + onig_node_free(np1); + return ONIGERR_MEMORY; + } + } + else { + swap_node(np, node); + onig_node_free(np); + } + break; /* break case NT_QTFR: */ + } } #ifdef USE_OP_PUSH_OR_JUMP_EXACT if (qn->greedy && (qn->target_empty_info != 0)) { - if (NTYPE(target) == NT_QTFR) { - QtfrNode* tqn = NQTFR(target); - if (IS_NOT_NULL(tqn->head_exact)) { - qn->head_exact = tqn->head_exact; - tqn->head_exact = NULL; - } - } - else { - qn->head_exact = get_head_value_node(qn->target, 1, reg); - } + if (NTYPE(target) == NT_QTFR) { + QtfrNode* tqn = NQTFR(target); + if (IS_NOT_NULL(tqn->head_exact)) { + qn->head_exact = tqn->head_exact; + tqn->head_exact = NULL; + } + } + else { + qn->head_exact = get_head_value_node(qn->target, 1, reg); + } } #endif } @@ -3802,37 +4086,61 @@ setup_tree(Node* node, regex_t* reg, int state, ScanEnv* env) switch (en->type) { case ENCLOSE_OPTION: - { - OnigOptionType options = reg->options; - reg->options = NENCLOSE(node)->option; - r = setup_tree(NENCLOSE(node)->target, reg, state, env); - reg->options = options; - } - break; + { + OnigOptionType options = reg->options; + reg->options = NENCLOSE(node)->option; + r = setup_tree(NENCLOSE(node)->target, reg, state, env); + reg->options = options; + } + break; case ENCLOSE_MEMORY: - if ((state & (IN_ALT | IN_NOT | IN_VAR_REPEAT)) != 0) { - BIT_STATUS_ON_AT(env->bt_mem_start, en->regnum); - /* SET_ENCLOSE_STATUS(node, NST_MEM_IN_ALT_NOT); */ - } + if ((state & (IN_ALT | IN_NOT | IN_VAR_REPEAT | IN_CALL)) != 0) { + BIT_STATUS_ON_AT(env->bt_mem_start, en->regnum); + /* SET_ENCLOSE_STATUS(node, NST_MEM_IN_ALT_NOT); */ + } + if (IS_ENCLOSE_CALLED(en)) + state |= IN_CALL; + if (IS_ENCLOSE_RECURSION(en)) + state |= IN_RECCALL; + else if ((state & IN_RECCALL) != 0) + SET_CALL_RECURSION(node); r = setup_tree(en->target, reg, state, env); break; case ENCLOSE_STOP_BACKTRACK: - { - Node* target = en->target; - r = setup_tree(target, reg, state, env); - if (NTYPE(target) == NT_QTFR) { - QtfrNode* tqn = NQTFR(target); - if (IS_REPEAT_INFINITE(tqn->upper) && tqn->lower <= 1 && - tqn->greedy != 0) { /* (?>a*), a*+ etc... */ - int qtype = NTYPE(tqn->target); - if (IS_NODE_TYPE_SIMPLE(qtype)) - SET_ENCLOSE_STATUS(node, NST_STOP_BT_SIMPLE_REPEAT); - } - } - } - break; + { + Node* target = en->target; + r = setup_tree(target, reg, state, env); + if (NTYPE(target) == NT_QTFR) { + QtfrNode* tqn = NQTFR(target); + if (IS_REPEAT_INFINITE(tqn->upper) && tqn->lower <= 1 && + tqn->greedy != 0) { /* (?>a*), a*+ etc... */ + int qtype = NTYPE(tqn->target); + if (IS_NODE_TYPE_SIMPLE(qtype)) + SET_ENCLOSE_STATUS(node, NST_STOP_BT_SIMPLE_REPEAT); + } + } + } + break; + + case ENCLOSE_CONDITION: +#ifdef USE_NAMED_GROUP + if (! IS_ENCLOSE_NAME_REF(NENCLOSE(node)) && + env->num_named > 0 && + IS_SYNTAX_BV(env->syntax, ONIG_SYN_CAPTURE_ONLY_NAMED_GROUP) && + !ONIG_IS_OPTION_ON(env->option, ONIG_OPTION_CAPTURE_GROUP)) { + return ONIGERR_NUMBERED_BACKREF_OR_CALL_NOT_ALLOWED; + } +#endif + if (NENCLOSE(node)->regnum > env->num_mem) + return ONIGERR_INVALID_BACKREF; + r = setup_tree(NENCLOSE(node)->target, reg, state, env); + break; + + case ENCLOSE_ABSENT: + r = setup_tree(NENCLOSE(node)->target, reg, state, env); + break; } } break; @@ -3843,48 +4151,57 @@ setup_tree(Node* node, regex_t* reg, int state, ScanEnv* env) switch (an->type) { case ANCHOR_PREC_READ: - r = setup_tree(an->target, reg, state, env); - break; + r = setup_tree(an->target, reg, state, env); + break; case ANCHOR_PREC_READ_NOT: - r = setup_tree(an->target, reg, (state | IN_NOT), env); - break; + r = setup_tree(an->target, reg, (state | IN_NOT), env); + break; /* allowed node types in look-behind */ #define ALLOWED_TYPE_IN_LB \ ( BIT_NT_LIST | BIT_NT_ALT | BIT_NT_STR | BIT_NT_CCLASS | BIT_NT_CTYPE | \ BIT_NT_CANY | BIT_NT_ANCHOR | BIT_NT_ENCLOSE | BIT_NT_QTFR | BIT_NT_CALL ) -#define ALLOWED_ENCLOSE_IN_LB ( ENCLOSE_MEMORY ) -#define ALLOWED_ENCLOSE_IN_LB_NOT 0 +#define ALLOWED_ENCLOSE_IN_LB ( ENCLOSE_MEMORY | ENCLOSE_OPTION ) +#define ALLOWED_ENCLOSE_IN_LB_NOT ENCLOSE_OPTION #define ALLOWED_ANCHOR_IN_LB \ -( ANCHOR_LOOK_BEHIND | ANCHOR_BEGIN_LINE | ANCHOR_END_LINE | ANCHOR_BEGIN_BUF | ANCHOR_BEGIN_POSITION ) +( ANCHOR_LOOK_BEHIND | ANCHOR_LOOK_BEHIND_NOT | ANCHOR_BEGIN_LINE | \ + ANCHOR_END_LINE | ANCHOR_BEGIN_BUF | ANCHOR_BEGIN_POSITION | ANCHOR_KEEP | \ + ANCHOR_WORD_BOUND | ANCHOR_NOT_WORD_BOUND | \ + ANCHOR_WORD_BEGIN | ANCHOR_WORD_END ) #define ALLOWED_ANCHOR_IN_LB_NOT \ -( ANCHOR_LOOK_BEHIND | ANCHOR_LOOK_BEHIND_NOT | ANCHOR_BEGIN_LINE | ANCHOR_END_LINE | ANCHOR_BEGIN_BUF | ANCHOR_BEGIN_POSITION ) +( ANCHOR_LOOK_BEHIND | ANCHOR_LOOK_BEHIND_NOT | ANCHOR_BEGIN_LINE | \ + ANCHOR_END_LINE | ANCHOR_BEGIN_BUF | ANCHOR_BEGIN_POSITION | ANCHOR_KEEP | \ + ANCHOR_WORD_BOUND | ANCHOR_NOT_WORD_BOUND | \ + ANCHOR_WORD_BEGIN | ANCHOR_WORD_END ) case ANCHOR_LOOK_BEHIND: - { - r = check_type_tree(an->target, ALLOWED_TYPE_IN_LB, - ALLOWED_ENCLOSE_IN_LB, ALLOWED_ANCHOR_IN_LB); - if (r < 0) return r; - if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN; - r = setup_look_behind(node, reg, env); - if (r != 0) return r; - r = setup_tree(an->target, reg, state, env); - } - break; + { + r = check_type_tree(an->target, ALLOWED_TYPE_IN_LB, + ALLOWED_ENCLOSE_IN_LB, ALLOWED_ANCHOR_IN_LB); + if (r < 0) return r; + if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN; + if (NTYPE(node) != NT_ANCHOR) goto restart; + r = setup_tree(an->target, reg, (state | IN_LOOK_BEHIND), env); + if (r != 0) return r; + r = setup_look_behind(node, reg, env); + } + break; case ANCHOR_LOOK_BEHIND_NOT: - { - r = check_type_tree(an->target, ALLOWED_TYPE_IN_LB, - ALLOWED_ENCLOSE_IN_LB_NOT, ALLOWED_ANCHOR_IN_LB_NOT); - if (r < 0) return r; - if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN; - r = setup_look_behind(node, reg, env); - if (r != 0) return r; - r = setup_tree(an->target, reg, (state | IN_NOT), env); - } - break; + { + r = check_type_tree(an->target, ALLOWED_TYPE_IN_LB, + ALLOWED_ENCLOSE_IN_LB_NOT, ALLOWED_ANCHOR_IN_LB_NOT); + if (r < 0) return r; + if (r > 0) return ONIGERR_INVALID_LOOK_BEHIND_PATTERN; + if (NTYPE(node) != NT_ANCHOR) goto restart; + r = setup_tree(an->target, reg, (state | IN_NOT | IN_LOOK_BEHIND), + env); + if (r != 0) return r; + r = setup_look_behind(node, reg, env); + } + break; } } break; @@ -3896,34 +4213,73 @@ setup_tree(Node* node, regex_t* reg, int state, ScanEnv* env) return r; } -/* set skip map for Boyer-Moor search */ +/* set skip map for Sunday's quick search */ static int -set_bm_skip(UChar* s, UChar* end, OnigEncoding enc, - UChar skip[], int** int_skip) +set_bm_skip(UChar* s, UChar* end, regex_t* reg, + UChar skip[], int ignore_case) { - int i, len; + OnigDistance i, len; + int clen, flen, n, j, k; + UChar *p, buf[ONIGENC_MBC_CASE_FOLD_MAXLEN]; + OnigCaseFoldCodeItem items[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM]; + OnigEncoding enc = reg->enc; len = end - s; - if (len < ONIG_CHAR_TABLE_SIZE) { - for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) skip[i] = len; - - for (i = 0; i < len - 1; i++) - skip[s[i]] = len - 1 - i; + if (len >= ONIG_CHAR_TABLE_SIZE) { + /* This should not happen. */ + return ONIGERR_TYPE_BUG; } - else { - if (IS_NULL(*int_skip)) { - *int_skip = (int* )xmalloc(sizeof(int) * ONIG_CHAR_TABLE_SIZE); - if (IS_NULL(*int_skip)) return ONIGERR_MEMORY; + + if (ignore_case) { + for (i = 0; i < len; i += clen) { + p = s + i; + n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag, + p, end, items); + clen = enclen(enc, p, end); + if (p + clen > end) + clen = (int )(end - p); + + for (j = 0; j < n; j++) { + if ((items[j].code_len != 1) || (items[j].byte_len != clen)) { + /* Different length isn't supported. Stop optimization at here. */ + end = p; + goto endcheck; + } + flen = ONIGENC_CODE_TO_MBC(enc, items[j].code[0], buf); + if (flen != clen) { + /* Different length isn't supported. Stop optimization at here. */ + end = p; + goto endcheck; + } + } } - for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) (*int_skip)[i] = len; +endcheck: + len = end - s; + } - for (i = 0; i < len - 1; i++) - (*int_skip)[s[i]] = len - 1 - i; + for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) + skip[i] = (UChar )(len + 1); + n = 0; + for (i = 0; i < len; i += clen) { + p = s + i; + if (ignore_case) + n = ONIGENC_GET_CASE_FOLD_CODES_BY_STR(enc, reg->case_fold_flag, + p, end, items); + clen = enclen(enc, p, end); + if (p + clen > end) + clen = (int )(end - p); + + for (j = 0; j < clen; j++) { + skip[s[i + j]] = (UChar )(len - i - j); + for (k = 0; k < n; k++) { + ONIGENC_CODE_TO_MBC(enc, items[k].code[0], buf); + skip[buf[j]] = (UChar )(len - i - j); + } + } } - return 0; -} -#define OPT_EXACT_MAXLEN 24 + return (int )len; +} typedef struct { OnigDistance min; /* min byte length */ @@ -3948,7 +4304,7 @@ typedef struct { OptAncInfo anc; int reach_end; - int ignore_case; + int ignore_case; /* -1: unset, 0: case sensitive, 1: ignore case */ int len; UChar s[OPT_EXACT_MAXLEN]; } OptExactInfo; @@ -3987,7 +4343,7 @@ map_position_value(OnigEncoding enc, int i) 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 1 }; - if (i < sizeof(ByteValTable)/sizeof(ByteValTable[0])) { + if (i < numberof(ByteValTable)) { if (i == 0 && ONIGENC_MBC_MINLEN(enc) > 1) return 20; else @@ -4002,24 +4358,24 @@ distance_value(MinMaxLen* mm) { /* 1000 / (min-max-dist + 1) */ static const short int dist_vals[] = { - 1000, 500, 333, 250, 200, 167, 143, 125, 111, 100, - 91, 83, 77, 71, 67, 63, 59, 56, 53, 50, - 48, 45, 43, 42, 40, 38, 37, 36, 34, 33, - 32, 31, 30, 29, 29, 28, 27, 26, 26, 25, - 24, 24, 23, 23, 22, 22, 21, 21, 20, 20, - 20, 19, 19, 19, 18, 18, 18, 17, 17, 17, - 16, 16, 16, 16, 15, 15, 15, 15, 14, 14, - 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, - 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, + 1000, 500, 333, 250, 200, 167, 143, 125, 111, 100, + 91, 83, 77, 71, 67, 63, 59, 56, 53, 50, + 48, 45, 43, 42, 40, 38, 37, 36, 34, 33, + 32, 31, 30, 29, 29, 28, 27, 26, 26, 25, + 24, 24, 23, 23, 22, 22, 21, 21, 20, 20, + 20, 19, 19, 19, 18, 18, 18, 17, 17, 17, + 16, 16, 16, 16, 15, 15, 15, 15, 14, 14, + 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, + 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10 }; - int d; + OnigDistance d; if (mm->max == ONIG_INFINITE_DISTANCE) return 0; d = mm->max - mm->min; - if (d < sizeof(dist_vals)/sizeof(dist_vals[0])) + if (d < numberof(dist_vals)) /* return dist_vals[d] * 16 / (mm->min + 12); */ return (int )dist_vals[d]; else @@ -4114,7 +4470,7 @@ copy_opt_anc_info(OptAncInfo* to, OptAncInfo* from) static void concat_opt_anc_info(OptAncInfo* to, OptAncInfo* left, OptAncInfo* right, - OnigDistance left_len, OnigDistance right_len) + OnigDistance left_len, OnigDistance right_len) { clear_opt_anc_info(to); @@ -4127,6 +4483,9 @@ concat_opt_anc_info(OptAncInfo* to, OptAncInfo* left, OptAncInfo* right, if (right_len == 0) { to->right_anchor |= left->right_anchor; } + else { + to->right_anchor |= (left->right_anchor & ANCHOR_PREC_READ_NOT); + } } static int @@ -4185,7 +4544,7 @@ clear_opt_exact_info(OptExactInfo* ex) clear_mml(&ex->mmd); clear_opt_anc_info(&ex->anc); ex->reach_end = 0; - ex->ignore_case = 0; + ex->ignore_case = -1; /* unset */ ex->len = 0; ex->s[0] = '\0'; } @@ -4203,16 +4562,15 @@ concat_opt_exact_info(OptExactInfo* to, OptExactInfo* add, OnigEncoding enc) UChar *p, *end; OptAncInfo tanc; - if (! to->ignore_case && add->ignore_case) { - if (to->len >= add->len) return ; /* avoid */ - - to->ignore_case = 1; - } + if (to->ignore_case < 0) + to->ignore_case = add->ignore_case; + else if (to->ignore_case != add->ignore_case) + return ; /* avoid */ p = add->s; end = p + add->len; for (i = to->len; p < end; ) { - len = enc_len(enc, p, end); + len = enclen(enc, p, end); if (i + len > OPT_EXACT_MAXLEN) break; for (j = 0; j < len && p < end; j++) to->s[i++] = *p++; @@ -4227,14 +4585,14 @@ concat_opt_exact_info(OptExactInfo* to, OptExactInfo* add, OnigEncoding enc) } static void -concat_opt_exact_info_str(OptExactInfo* to, - UChar* s, UChar* end, int raw, OnigEncoding enc) +concat_opt_exact_info_str(OptExactInfo* to, UChar* s, UChar* end, + int raw ARG_UNUSED, OnigEncoding enc) { int i, j, len; UChar *p; for (i = to->len, p = s; p < end && i < OPT_EXACT_MAXLEN; ) { - len = enc_len(enc, p, end); + len = enclen(enc, p, end); if (i + len > OPT_EXACT_MAXLEN) break; for (j = 0; j < len && p < end; j++) to->s[i++] = *p++; @@ -4260,7 +4618,7 @@ alt_merge_opt_exact_info(OptExactInfo* to, OptExactInfo* add, OptEnv* env) for (i = 0; i < to->len && i < add->len; ) { if (to->s[i] != add->s[i]) break; - len = enc_len(env->enc, to->s + i, to->s + to->len); + len = enclen(env->enc, to->s + i, to->s + to->len); for (j = 1; j < len; j++) { if (to->s[i+j] != add->s[i+j]) break; @@ -4273,7 +4631,10 @@ alt_merge_opt_exact_info(OptExactInfo* to, OptExactInfo* add, OptEnv* env) to->reach_end = 0; } to->len = i; - to->ignore_case |= add->ignore_case; + if (to->ignore_case < 0) + to->ignore_case = add->ignore_case; + else if (add->ignore_case >= 0) + to->ignore_case |= add->ignore_case; alt_merge_opt_anc_info(&to->anc, &add->anc); if (! to->reach_end) to->anc.right_anchor = 0; @@ -4303,8 +4664,8 @@ select_opt_exact_info(OnigEncoding enc, OptExactInfo* now, OptExactInfo* alt) if (alt->len > 1) v2 += 5; } - if (now->ignore_case == 0) v1 *= 2; - if (alt->ignore_case == 0) v2 *= 2; + if (now->ignore_case <= 0) v1 *= 2; + if (alt->ignore_case <= 0) v2 *= 2; if (comp_distance_value(&now->mmd, &alt->mmd, v1, v2) > 0) copy_opt_exact_info(now, alt); @@ -4378,7 +4739,7 @@ add_char_amb_opt_map_info(OptMapInfo* map, UChar* p, UChar* end, static void select_opt_map_info(OptMapInfo* now, OptMapInfo* alt) { - static int z = 1<<15; /* 32768: something big value */ + const int z = 1<<15; /* 32768: something big value */ int v1, v2; @@ -4402,7 +4763,7 @@ comp_opt_exact_or_map_info(OptExactInfo* e, OptMapInfo* m) if (m->value <= 0) return -1; - ve = COMP_EM_BASE * e->len * (e->ignore_case ? 1 : 2); + ve = COMP_EM_BASE * e->len * (e->ignore_case > 0 ? 1 : 2); vm = COMP_EM_BASE * 5 * 2 / m->value; return comp_distance_value(&e->mmd, &m->mmd, ve, vm); } @@ -4470,7 +4831,7 @@ concat_left_node_opt_info(OnigEncoding enc, NodeOptInfo* to, NodeOptInfo* add) if (add->exb.len > 0 && to->len.max == 0) { concat_opt_anc_info(&tanc, &to->anc, &add->exb.anc, - to->len.max, add->len.max); + to->len.max, add->len.max); copy_opt_anc_info(&add->exb.anc, &tanc); } @@ -4501,12 +4862,12 @@ concat_left_node_opt_info(OnigEncoding enc, NodeOptInfo* to, NodeOptInfo* add) if (to->expr.len > 0) { if (add->len.max > 0) { if (to->expr.len > (int )add->len.max) - to->expr.len = add->len.max; + to->expr.len = (int )add->len.max; if (to->expr.mmd.max == 0) - select_opt_exact_info(enc, &to->exb, &to->expr); + select_opt_exact_info(enc, &to->exb, &to->expr); else - select_opt_exact_info(enc, &to->exm, &to->expr); + select_opt_exact_info(enc, &to->exm, &to->expr); } } else if (add->expr.len > 0) { @@ -4552,11 +4913,11 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) copy_opt_env(&nenv, env); do { - r = optimize_node_left(NCAR(nd), &nopt, &nenv); - if (r == 0) { - add_mml(&nenv.mmd, &nopt.len); - concat_left_node_opt_info(env->enc, opt, &nopt); - } + r = optimize_node_left(NCAR(nd), &nopt, &nenv); + if (r == 0) { + add_mml(&nenv.mmd, &nopt.len); + concat_left_node_opt_info(env->enc, opt, &nopt); + } } while (r == 0 && IS_NOT_NULL(nd = NCDR(nd))); } break; @@ -4567,11 +4928,11 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) Node* nd = node; do { - r = optimize_node_left(NCAR(nd), &nopt, env); - if (r == 0) { - if (nd == node) copy_node_opt_info(opt, &nopt); - else alt_merge_node_opt_info(opt, &nopt, env); - } + r = optimize_node_left(NCAR(nd), &nopt, env); + if (r == 0) { + if (nd == node) copy_node_opt_info(opt, &nopt); + else alt_merge_node_opt_info(opt, &nopt, env); + } } while ((r == 0) && IS_NOT_NULL(nd = NCDR(nd))); } break; @@ -4579,43 +4940,44 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) case NT_STR: { StrNode* sn = NSTR(node); - int slen = sn->end - sn->s; + OnigDistance slen = sn->end - sn->s; int is_raw = NSTRING_IS_RAW(node); if (! NSTRING_IS_AMBIG(node)) { - concat_opt_exact_info_str(&opt->exb, sn->s, sn->end, - NSTRING_IS_RAW(node), env->enc); - if (slen > 0) { - add_char_opt_map_info(&opt->map, *(sn->s), env->enc); - } + concat_opt_exact_info_str(&opt->exb, sn->s, sn->end, + is_raw, env->enc); + opt->exb.ignore_case = 0; + if (slen > 0) { + add_char_opt_map_info(&opt->map, *(sn->s), env->enc); + } set_mml(&opt->len, slen, slen); } else { - int max; + OnigDistance max; - if (NSTRING_IS_DONT_GET_OPT_INFO(node)) { + if (NSTRING_IS_DONT_GET_OPT_INFO(node)) { int n = onigenc_strlen(env->enc, sn->s, sn->end); - max = ONIGENC_MBC_MAXLEN_DIST(env->enc) * n; - } - else { - concat_opt_exact_info_str(&opt->exb, sn->s, sn->end, - is_raw, env->enc); - opt->exb.ignore_case = 1; - - if (slen > 0) { - r = add_char_amb_opt_map_info(&opt->map, sn->s, sn->end, - env->enc, env->case_fold_flag); - if (r != 0) break; - } - - max = slen; - } + max = (OnigDistance )ONIGENC_MBC_MAXLEN_DIST(env->enc) * (OnigDistance)n; + } + else { + concat_opt_exact_info_str(&opt->exb, sn->s, sn->end, + is_raw, env->enc); + opt->exb.ignore_case = 1; + + if (slen > 0) { + r = add_char_amb_opt_map_info(&opt->map, sn->s, sn->end, + env->enc, env->case_fold_flag); + if (r != 0) break; + } + + max = slen; + } set_mml(&opt->len, slen, max); } - if (opt->exb.len == slen) - opt->exb.reach_end = 1; + if ((OnigDistance )opt->exb.len == slen) + opt->exb.reach_end = 1; } break; @@ -4624,13 +4986,13 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) int i, z; CClassNode* cc = NCCLASS(node); - /* no need to check ignore case. (setted in setup_tree()) */ + /* no need to check ignore case. (set in setup_tree()) */ if (IS_NOT_NULL(cc->mbuf) || IS_NCCLASS_NOT(cc)) { OnigDistance min = ONIGENC_MBC_MINLEN(env->enc); - OnigDistance max = ONIGENC_MBC_MAXLEN_DIST(env->enc); + OnigDistance max = ONIGENC_MBC_MAXLEN_DIST(env->enc); - set_mml(&opt->len, min, max); + set_mml(&opt->len, min, max); } else { for (i = 0; i < SINGLE_BYTE_SIZE; i++) { @@ -4639,7 +5001,7 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) add_char_opt_map_info(&opt->map, (UChar )i, env->enc); } } - set_mml(&opt->len, 1, 1); + set_mml(&opt->len, 1, 1); } } break; @@ -4647,30 +5009,32 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) case NT_CTYPE: { int i, min, max; + int maxcode; max = ONIGENC_MBC_MAXLEN_DIST(env->enc); if (max == 1) { min = 1; - switch (NCTYPE(node)->ctype) { - case ONIGENC_CTYPE_WORD: - if (NCTYPE(node)->not != 0) { - for (i = 0; i < SINGLE_BYTE_SIZE; i++) { - if (! ONIGENC_IS_CODE_WORD(env->enc, i)) { - add_char_opt_map_info(&opt->map, (UChar )i, env->enc); - } - } - } - else { - for (i = 0; i < SINGLE_BYTE_SIZE; i++) { - if (ONIGENC_IS_CODE_WORD(env->enc, i)) { - add_char_opt_map_info(&opt->map, (UChar )i, env->enc); - } - } - } - break; - } + maxcode = NCTYPE(node)->ascii_range ? 0x80 : SINGLE_BYTE_SIZE; + switch (NCTYPE(node)->ctype) { + case ONIGENC_CTYPE_WORD: + if (NCTYPE(node)->not != 0) { + for (i = 0; i < SINGLE_BYTE_SIZE; i++) { + if (! ONIGENC_IS_CODE_WORD(env->enc, i) || i >= maxcode) { + add_char_opt_map_info(&opt->map, (UChar )i, env->enc); + } + } + } + else { + for (i = 0; i < maxcode; i++) { + if (ONIGENC_IS_CODE_WORD(env->enc, i)) { + add_char_opt_map_info(&opt->map, (UChar )i, env->enc); + } + } + } + break; + } } else { min = ONIGENC_MBC_MINLEN(env->enc); @@ -4695,30 +5059,30 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) case ANCHOR_END_BUF: case ANCHOR_SEMI_END_BUF: case ANCHOR_END_LINE: + case ANCHOR_LOOK_BEHIND: /* just for (?<=x).* */ + case ANCHOR_PREC_READ_NOT: /* just for (?!x).* */ add_opt_anc_info(&opt->anc, NANCHOR(node)->type); break; case ANCHOR_PREC_READ: { - NodeOptInfo nopt; + NodeOptInfo nopt; - r = optimize_node_left(NANCHOR(node)->target, &nopt, env); - if (r == 0) { - if (nopt.exb.len > 0) - copy_opt_exact_info(&opt->expr, &nopt.exb); - else if (nopt.exm.len > 0) - copy_opt_exact_info(&opt->expr, &nopt.exm); + r = optimize_node_left(NANCHOR(node)->target, &nopt, env); + if (r == 0) { + if (nopt.exb.len > 0) + copy_opt_exact_info(&opt->expr, &nopt.exb); + else if (nopt.exm.len > 0) + copy_opt_exact_info(&opt->expr, &nopt.exm); - opt->expr.reach_end = 0; + opt->expr.reach_end = 0; - if (nopt.map.value > 0) - copy_opt_map_info(&opt->map, &nopt.map); - } + if (nopt.map.value > 0) + copy_opt_map_info(&opt->map, &nopt.map); + } } break; - case ANCHOR_PREC_READ_NOT: - case ANCHOR_LOOK_BEHIND: /* Sorry, I can't make use of it. */ case ANCHOR_LOOK_BEHIND_NOT: break; } @@ -4733,8 +5097,8 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) BRefNode* br = NBREF(node); if (br->state & NST_RECURSION) { - set_mml(&opt->len, 0, ONIG_INFINITE_DISTANCE); - break; + set_mml(&opt->len, 0, ONIG_INFINITE_DISTANCE); + break; } backs = BACKREFS_P(br); r = get_min_match_length(nodes[backs[0]], &min, env->scan_env); @@ -4742,12 +5106,12 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) r = get_max_match_length(nodes[backs[0]], &max, env->scan_env); if (r != 0) break; for (i = 1; i < br->back_num; i++) { - r = get_min_match_length(nodes[backs[i]], &tmin, env->scan_env); - if (r != 0) break; - r = get_max_match_length(nodes[backs[i]], &tmax, env->scan_env); - if (r != 0) break; - if (min > tmin) min = tmin; - if (max < tmax) max = tmax; + r = get_min_match_length(nodes[backs[i]], &tmin, env->scan_env); + if (r != 0) break; + r = get_max_match_length(nodes[backs[i]], &tmax, env->scan_env); + if (r != 0) break; + if (min > tmin) min = tmin; + if (max < tmax) max = tmax; } if (r == 0) set_mml(&opt->len, min, max); } @@ -4777,43 +5141,44 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) if (r) break; if (qn->lower == 0 && IS_REPEAT_INFINITE(qn->upper)) { - if (env->mmd.max == 0 && - NTYPE(qn->target) == NT_CANY && qn->greedy) { - if (IS_MULTILINE(env->options)) - add_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_ML); - else - add_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR); - } + if (env->mmd.max == 0 && + NTYPE(qn->target) == NT_CANY && qn->greedy) { + if (IS_MULTILINE(env->options)) + /* implicit anchor: /.*a/ ==> /\A.*a/ */ + add_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_ML); + else + add_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR); + } } else { - if (qn->lower > 0) { - copy_node_opt_info(opt, &nopt); - if (nopt.exb.len > 0) { - if (nopt.exb.reach_end) { - for (i = 2; i < qn->lower && - ! is_full_opt_exact_info(&opt->exb); i++) { - concat_opt_exact_info(&opt->exb, &nopt.exb, env->enc); - } - if (i < qn->lower) { - opt->exb.reach_end = 0; - } - } - } - - if (qn->lower != qn->upper) { - opt->exb.reach_end = 0; - opt->exm.reach_end = 0; - } - if (qn->lower > 1) - opt->exm.reach_end = 0; - } + if (qn->lower > 0) { + copy_node_opt_info(opt, &nopt); + if (nopt.exb.len > 0) { + if (nopt.exb.reach_end) { + for (i = 2; i <= qn->lower && + ! is_full_opt_exact_info(&opt->exb); i++) { + concat_opt_exact_info(&opt->exb, &nopt.exb, env->enc); + } + if (i < qn->lower) { + opt->exb.reach_end = 0; + } + } + } + + if (qn->lower != qn->upper) { + opt->exb.reach_end = 0; + opt->exm.reach_end = 0; + } + if (qn->lower > 1) + opt->exm.reach_end = 0; + } } min = distance_multiply(nopt.len.min, qn->lower); if (IS_REPEAT_INFINITE(qn->upper)) - max = (nopt.len.max > 0 ? ONIG_INFINITE_DISTANCE : 0); + max = (nopt.len.max > 0 ? ONIG_INFINITE_DISTANCE : 0); else - max = distance_multiply(nopt.len.max, qn->upper); + max = distance_multiply(nopt.len.max, qn->upper); set_mml(&opt->len, min, max); } @@ -4825,42 +5190,47 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) switch (en->type) { case ENCLOSE_OPTION: - { - OnigOptionType save = env->options; + { + OnigOptionType save = env->options; - env->options = en->option; - r = optimize_node_left(en->target, opt, env); - env->options = save; - } - break; + env->options = en->option; + r = optimize_node_left(en->target, opt, env); + env->options = save; + } + break; case ENCLOSE_MEMORY: #ifdef USE_SUBEXP_CALL - en->opt_count++; - if (en->opt_count > MAX_NODE_OPT_INFO_REF_COUNT) { - OnigDistance min, max; - - min = 0; - max = ONIG_INFINITE_DISTANCE; - if (IS_ENCLOSE_MIN_FIXED(en)) min = en->min_len; - if (IS_ENCLOSE_MAX_FIXED(en)) max = en->max_len; - set_mml(&opt->len, min, max); - } - else + en->opt_count++; + if (en->opt_count > MAX_NODE_OPT_INFO_REF_COUNT) { + OnigDistance min, max; + + min = 0; + max = ONIG_INFINITE_DISTANCE; + if (IS_ENCLOSE_MIN_FIXED(en)) min = en->min_len; + if (IS_ENCLOSE_MAX_FIXED(en)) max = en->max_len; + set_mml(&opt->len, min, max); + } + else #endif - { - r = optimize_node_left(en->target, opt, env); + { + r = optimize_node_left(en->target, opt, env); - if (is_set_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_MASK)) { - if (BIT_STATUS_AT(env->scan_env->backrefed_mem, en->regnum)) - remove_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_MASK); - } - } - break; + if (is_set_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_MASK)) { + if (BIT_STATUS_AT(env->scan_env->backrefed_mem, en->regnum)) + remove_opt_anc_info(&opt->anc, ANCHOR_ANYCHAR_STAR_MASK); + } + } + break; case ENCLOSE_STOP_BACKTRACK: - r = optimize_node_left(en->target, opt, env); - break; + case ENCLOSE_CONDITION: + r = optimize_node_left(en->target, opt, env); + break; + + case ENCLOSE_ABSENT: + set_mml(&opt->len, 0, ONIG_INFINITE_DISTANCE); + break; } } break; @@ -4868,7 +5238,7 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) default: #ifdef ONIG_DEBUG fprintf(stderr, "optimize_node_left: undefined node type %d\n", - NTYPE(node)); + NTYPE(node)); #endif r = ONIGERR_TYPE_BUG; break; @@ -4880,34 +5250,49 @@ optimize_node_left(Node* node, NodeOptInfo* opt, OptEnv* env) static int set_optimize_exact_info(regex_t* reg, OptExactInfo* e) { - int r; + int allow_reverse; if (e->len == 0) return 0; - if (e->ignore_case) { - reg->exact = (UChar* )xmalloc(e->len); - CHECK_NULL_RETURN_MEMERR(reg->exact); - xmemcpy(reg->exact, e->s, e->len); - reg->exact_end = reg->exact + e->len; - reg->optimize = ONIG_OPTIMIZE_EXACT_IC; - } - else { - int allow_reverse; + reg->exact = (UChar* )xmalloc(e->len); + CHECK_NULL_RETURN_MEMERR(reg->exact); + xmemcpy(reg->exact, e->s, e->len); + reg->exact_end = reg->exact + e->len; - reg->exact = str_dup(e->s, e->s + e->len); - CHECK_NULL_RETURN_MEMERR(reg->exact); - reg->exact_end = reg->exact + e->len; - - allow_reverse = - ONIGENC_IS_ALLOWED_REVERSE_MATCH(reg->enc, reg->exact, reg->exact_end); + allow_reverse = + ONIGENC_IS_ALLOWED_REVERSE_MATCH(reg->enc, reg->exact, reg->exact_end); + if (e->ignore_case > 0) { if (e->len >= 3 || (e->len >= 2 && allow_reverse)) { - r = set_bm_skip(reg->exact, reg->exact_end, reg->enc, - reg->map, &(reg->int_map)); - if (r) return r; - + int orig_len = e->len; + e->len = set_bm_skip(reg->exact, reg->exact_end, reg, + reg->map, 1); + if (e->len >= 3) { + reg->exact_end = reg->exact + e->len; + reg->optimize = (allow_reverse != 0 + ? ONIG_OPTIMIZE_EXACT_BM_IC : ONIG_OPTIMIZE_EXACT_BM_NOT_REV_IC); + } + else { + /* Even if BM skip table can't be built (e.g., pattern starts with + 's' or 'k' which have multi-byte case fold variants), we should + still use EXACT_IC optimization with the original pattern. + Without this fallback, patterns like /slackware/i have no + optimization at all, causing severe performance regression + especially with non-ASCII strings. See [Bug #21824] */ + e->len = orig_len; /* Restore original length for EXACT_IC */ + reg->optimize = ONIG_OPTIMIZE_EXACT_IC; + } + } + else { + reg->optimize = ONIG_OPTIMIZE_EXACT_IC; + } + } + else { + if (e->len >= 3 || (e->len >= 2 && allow_reverse)) { + set_bm_skip(reg->exact, reg->exact_end, reg, + reg->map, 0); reg->optimize = (allow_reverse != 0 - ? ONIG_OPTIMIZE_EXACT_BM : ONIG_OPTIMIZE_EXACT_BM_NOT_REV); + ? ONIG_OPTIMIZE_EXACT_BM : ONIG_OPTIMIZE_EXACT_BM_NOT_REV); } else { reg->optimize = ONIG_OPTIMIZE_EXACT; @@ -4918,7 +5303,7 @@ set_optimize_exact_info(regex_t* reg, OptExactInfo* e) reg->dmax = e->mmd.max; if (reg->dmin != ONIG_INFINITE_DISTANCE) { - reg->threshold_len = reg->dmin + (reg->exact_end - reg->exact); + reg->threshold_len = (int )(reg->dmin + (reg->exact_end - reg->exact)); } return 0; @@ -4937,7 +5322,7 @@ set_optimize_map_info(regex_t* reg, OptMapInfo* m) reg->dmax = m->mmd.max; if (reg->dmin != ONIG_INFINITE_DISTANCE) { - reg->threshold_len = reg->dmin + 1; + reg->threshold_len = (int )(reg->dmin + 1); } } @@ -4948,7 +5333,7 @@ set_sub_anchor(regex_t* reg, OptAncInfo* anc) reg->sub_anchor |= anc->right_anchor & ANCHOR_END_LINE; } -#ifdef ONIG_DEBUG +#if defined(ONIG_DEBUG_COMPILE) || defined(ONIG_DEBUG_MATCH) static void print_optimize_info(FILE* f, regex_t* reg); #endif @@ -4970,9 +5355,14 @@ set_optimize_info_from_tree(Node* node, regex_t* reg, ScanEnv* scan_env) if (r) return r; reg->anchor = opt.anc.left_anchor & (ANCHOR_BEGIN_BUF | - ANCHOR_BEGIN_POSITION | ANCHOR_ANYCHAR_STAR | ANCHOR_ANYCHAR_STAR_ML); + ANCHOR_BEGIN_POSITION | ANCHOR_ANYCHAR_STAR | ANCHOR_ANYCHAR_STAR_ML | + ANCHOR_LOOK_BEHIND); - reg->anchor |= opt.anc.right_anchor & (ANCHOR_END_BUF | ANCHOR_SEMI_END_BUF); + if ((opt.anc.left_anchor & (ANCHOR_LOOK_BEHIND | ANCHOR_PREC_READ_NOT)) != 0) + reg->anchor &= ~ANCHOR_ANYCHAR_STAR_ML; + + reg->anchor |= opt.anc.right_anchor & (ANCHOR_END_BUF | ANCHOR_SEMI_END_BUF | + ANCHOR_PREC_READ_NOT); if (reg->anchor & (ANCHOR_END_BUF | ANCHOR_SEMI_END_BUF)) { reg->anchor_dmin = opt.len.min; @@ -4982,7 +5372,7 @@ set_optimize_info_from_tree(Node* node, regex_t* reg, ScanEnv* scan_env) if (opt.exb.len > 0 || opt.exm.len > 0) { select_opt_exact_info(reg->enc, &opt.exb, &opt.exm); if (opt.map.value > 0 && - comp_opt_exact_or_map_info(&opt.exb, &opt.map) > 0) { + comp_opt_exact_or_map_info(&opt.exb, &opt.map) > 0) { goto set_map; } else { @@ -5017,16 +5407,14 @@ clear_optimize_info(regex_t* reg) reg->sub_anchor = 0; reg->exact_end = (UChar* )NULL; reg->threshold_len = 0; - if (IS_NOT_NULL(reg->exact)) { - xfree(reg->exact); - reg->exact = (UChar* )NULL; - } + xfree(reg->exact); + reg->exact = (UChar* )NULL; } #ifdef ONIG_DEBUG static void print_enc_string(FILE* fp, OnigEncoding enc, - const UChar *s, const UChar *end) + const UChar *s, const UChar *end) { fprintf(fp, "\nPATTERN: /"); @@ -5038,13 +5426,13 @@ static void print_enc_string(FILE* fp, OnigEncoding enc, while (p < end) { code = ONIGENC_MBC_TO_CODE(enc, p, end); if (code >= 0x80) { - fprintf(fp, " 0x%04x ", (int )code); + fprintf(fp, " 0x%04x ", (int )code); } else { - fputc((int )code, fp); + fputc((int )code, fp); } - p += enc_len(enc, p); + p += enclen(enc, p, end); } } else { @@ -5054,23 +5442,25 @@ static void print_enc_string(FILE* fp, OnigEncoding enc, } } - fprintf(fp, "/\n"); + fprintf(fp, "/ (%s)\n", enc->name); } +#endif /* ONIG_DEBUG */ +#if defined(ONIG_DEBUG_COMPILE) || defined(ONIG_DEBUG_MATCH) static void print_distance_range(FILE* f, OnigDistance a, OnigDistance b) { if (a == ONIG_INFINITE_DISTANCE) fputs("inf", f); else - fprintf(f, "(%u)", a); + fprintf(f, "(%"PRIuPTR")", a); fputs("-", f); if (b == ONIG_INFINITE_DISTANCE) fputs("inf", f); else - fprintf(f, "(%u)", b); + fprintf(f, "(%"PRIuPTR")", b); } static void @@ -5116,7 +5506,7 @@ print_anchor(FILE* f, int anchor) } if (anchor & ANCHOR_ANYCHAR_STAR_ML) { if (q) fprintf(f, ", "); - fprintf(f, "anychar-star-pl"); + fprintf(f, "anychar-star-ml"); } fprintf(f, "]"); @@ -5126,7 +5516,8 @@ static void print_optimize_info(FILE* f, regex_t* reg) { static const char* on[] = { "NONE", "EXACT", "EXACT_BM", "EXACT_BM_NOT_REV", - "EXACT_IC", "MAP" }; + "EXACT_IC", "MAP", + "EXACT_BM_IC", "EXACT_BM_NOT_REV_IC" }; fprintf(f, "optimize: %s\n", on[reg->optimize]); fprintf(f, " anchor: "); print_anchor(f, reg->anchor); @@ -5146,7 +5537,7 @@ print_optimize_info(FILE* f, regex_t* reg) for (p = reg->exact; p < reg->exact_end; p++) { fputc(*p, f); } - fprintf(f, "]: length: %d\n", (reg->exact_end - reg->exact)); + fprintf(f, "]: length: %"PRIdPTR"\n", (reg->exact_end - reg->exact)); } else if (reg->optimize & ONIG_OPTIMIZE_MAP) { int c, i, n = 0; @@ -5159,7 +5550,7 @@ print_optimize_info(FILE* f, regex_t* reg) c = 0; fputc('[', f); for (i = 0; i < ONIG_CHAR_TABLE_SIZE; i++) { - if (reg->map[i] != 0) { + if (reg->map[i] != 0) { if (c > 0) fputs(", ", f); c++; if (ONIGENC_MBC_MAXLEN(reg->enc) == 1 && @@ -5173,22 +5564,22 @@ print_optimize_info(FILE* f, regex_t* reg) } } } -#endif /* ONIG_DEBUG */ +#endif /* ONIG_DEBUG_COMPILE || ONIG_DEBUG_MATCH */ -static void +extern void onig_free_body(regex_t* reg) { - if (IS_NOT_NULL(reg->p)) xfree(reg->p); - if (IS_NOT_NULL(reg->exact)) xfree(reg->exact); - if (IS_NOT_NULL(reg->int_map)) xfree(reg->int_map); - if (IS_NOT_NULL(reg->int_map_backward)) xfree(reg->int_map_backward); - if (IS_NOT_NULL(reg->repeat_range)) xfree(reg->repeat_range); - if (IS_NOT_NULL(reg->chain)) onig_free(reg->chain); + if (IS_NOT_NULL(reg)) { + xfree(reg->p); + xfree(reg->exact); + xfree(reg->repeat_range); + onig_free(reg->chain); #ifdef USE_NAMED_GROUP - onig_names_free(reg); + onig_names_free(reg); #endif + } } extern void @@ -5200,153 +5591,148 @@ onig_free(regex_t* reg) } } -#define REGEX_TRANSFER(to,from) do {\ - (to)->state = ONIG_STATE_MODIFY;\ - onig_free_body(to);\ - xmemcpy(to, from, sizeof(regex_t));\ - xfree(from);\ -} while (0) - -extern void -onig_transfer(regex_t* to, regex_t* from) -{ - THREAD_ATOMIC_START; - REGEX_TRANSFER(to, from); - THREAD_ATOMIC_END; -} - -#define REGEX_CHAIN_HEAD(reg) do {\ - while (IS_NOT_NULL((reg)->chain)) {\ - (reg) = (reg)->chain;\ - }\ -} while (0) - -extern void -onig_chain_link_add(regex_t* to, regex_t* add) +static void* +dup_copy(const void *ptr, size_t size) { - THREAD_ATOMIC_START; - REGEX_CHAIN_HEAD(to); - to->chain = add; - THREAD_ATOMIC_END; -} - -extern void -onig_chain_reduce(regex_t* reg) -{ - regex_t *head, *prev; - - prev = reg; - head = prev->chain; - if (IS_NOT_NULL(head)) { - reg->state = ONIG_STATE_MODIFY; - while (IS_NOT_NULL(head->chain)) { - prev = head; - head = head->chain; - } - prev->chain = (regex_t* )NULL; - REGEX_TRANSFER(reg, head); + void *newptr = xmalloc(size); + if (IS_NOT_NULL(newptr)) { + memcpy(newptr, ptr, size); } + return newptr; } -#if 0 extern int -onig_clone(regex_t** to, regex_t* from) +onig_reg_copy(regex_t** nreg, regex_t* oreg) { - int r, size; - regex_t* reg; + if (IS_NOT_NULL(oreg)) { + regex_t *reg = *nreg = (regex_t* )xmalloc(sizeof(regex_t)); + if (IS_NULL(reg)) return ONIGERR_MEMORY; -#ifdef USE_MULTI_THREAD_SYSTEM - if (ONIG_STATE(from) >= ONIG_STATE_NORMAL) { - ONIG_STATE_INC(from); - if (IS_NOT_NULL(from->chain) && ONIG_STATE(reg) == ONIG_STATE_NORMAL) { - onig_chain_reduce(from); - ONIG_STATE_INC(from); - } - } - else { - int n = 0; - while (ONIG_STATE(from) < ONIG_STATE_NORMAL) { - if (++n > THREAD_PASS_LIMIT_COUNT) - return ONIGERR_OVER_THREAD_PASS_LIMIT_COUNT; - THREAD_PASS; - } - ONIG_STATE_INC(from); - } -#endif /* USE_MULTI_THREAD_SYSTEM */ - - r = onig_alloc_init(®, ONIG_OPTION_NONE, ONIGENC_CASE_FOLD_DEFAULT, - from->enc, ONIG_SYNTAX_DEFAULT); - if (r != 0) { - ONIG_STATE_DEC(from); - return r; - } + *reg = *oreg; - xmemcpy(reg, from, sizeof(onig_t)); - reg->chain = (regex_t* )NULL; - reg->state = ONIG_STATE_NORMAL; +# define COPY_FAILED(mem, size) IS_NULL(reg->mem = dup_copy(reg->mem, size)) - if (from->p) { - reg->p = (UChar* )xmalloc(reg->alloc); - if (IS_NULL(reg->p)) goto mem_error; - xmemcpy(reg->p, from->p, reg->alloc); - } + if (IS_NOT_NULL(reg->exact)) { + size_t exact_size = reg->exact_end - reg->exact; + if (COPY_FAILED(exact, exact_size)) + goto err; + (reg)->exact_end = (reg)->exact + exact_size; + } - if (from->exact) { - reg->exact = (UChar* )xmalloc(from->exact_end - from->exact); - if (IS_NULL(reg->exact)) goto mem_error; - reg->exact_end = reg->exact + (from->exact_end - from->exact); - xmemcpy(reg->exact, from->exact, reg->exact_end - reg->exact); + if (IS_NOT_NULL(reg->p)) { + if (COPY_FAILED(p, reg->alloc)) + goto err_p; + } + if (IS_NOT_NULL(reg->repeat_range)) { + if (COPY_FAILED(repeat_range, reg->repeat_range_alloc * sizeof(OnigRepeatRange))) + goto err_repeat_range; + } + if (IS_NOT_NULL(reg->name_table)) { + if (onig_names_copy(reg, oreg)) + goto err_name_table; + } + if (IS_NOT_NULL(reg->chain)) { + if (onig_reg_copy(®->chain, reg->chain)) + goto err_chain; + } + return 0; +# undef COPY_FAILED + + err_chain: + onig_names_free(reg); + err_name_table: + xfree(reg->repeat_range); + err_repeat_range: + xfree(reg->p); + err_p: + xfree(reg->exact); + err: + xfree(reg); + return ONIGERR_MEMORY; } + return 0; +} - if (from->int_map) { - size = sizeof(int) * ONIG_CHAR_TABLE_SIZE; - reg->int_map = (int* )xmalloc(size); - if (IS_NULL(reg->int_map)) goto mem_error; - xmemcpy(reg->int_map, from->int_map, size); - } +#ifdef RUBY +size_t +onig_memsize(const regex_t *reg) +{ + size_t size = sizeof(regex_t); + if (IS_NULL(reg)) return 0; + if (IS_NOT_NULL(reg->p)) size += reg->alloc; + if (IS_NOT_NULL(reg->exact)) size += reg->exact_end - reg->exact; + if (IS_NOT_NULL(reg->repeat_range)) size += reg->repeat_range_alloc * sizeof(OnigRepeatRange); + if (IS_NOT_NULL(reg->chain)) size += onig_memsize(reg->chain); - if (from->int_map_backward) { - size = sizeof(int) * ONIG_CHAR_TABLE_SIZE; - reg->int_map_backward = (int* )xmalloc(size); - if (IS_NULL(reg->int_map_backward)) goto mem_error; - xmemcpy(reg->int_map_backward, from->int_map_backward, size); - } + return size; +} -#ifdef USE_NAMED_GROUP - reg->name_table = names_clone(from); /* names_clone is not implemented */ +size_t +onig_region_memsize(const OnigRegion *regs) +{ + size_t size = sizeof(*regs); + if (IS_NULL(regs)) return 0; + size += regs->allocated * (sizeof(*regs->beg) + sizeof(*regs->end)); + return size; +} #endif - ONIG_STATE_DEC(from); - *to = reg; - return 0; +#define REGEX_TRANSFER(to,from) do {\ + onig_free_body(to);\ + xmemcpy(to, from, sizeof(regex_t));\ + xfree(from);\ +} while (0) - mem_error: - ONIG_STATE_DEC(from); - return ONIGERR_MEMORY; +#if 0 +extern void +onig_transfer(regex_t* to, regex_t* from) +{ + REGEX_TRANSFER(to, from); } #endif -#ifdef ONIG_DEBUG -static void print_compiled_byte_code_list P_((FILE* f, regex_t* reg)); +#ifdef ONIG_DEBUG_COMPILE +static void print_compiled_byte_code_list(FILE* f, regex_t* reg); #endif #ifdef ONIG_DEBUG_PARSE_TREE -static void print_tree P_((FILE* f, Node* node)); +static void print_tree(FILE* f, Node* node); #endif +#ifdef RUBY extern int onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end, - OnigErrorInfo* einfo) + OnigErrorInfo* einfo) +{ + return onig_compile_ruby(reg, pattern, pattern_end, einfo, NULL, 0); +} +#endif + +#ifdef RUBY +extern int +onig_compile_ruby(regex_t* reg, const UChar* pattern, const UChar* pattern_end, + OnigErrorInfo* einfo, const char *sourcefile, int sourceline) +#else +extern int +onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end, + OnigErrorInfo* einfo) +#endif { #define COMPILE_INIT_SIZE 20 - int r, init_size; + int r; + OnigDistance init_size; Node* root; - ScanEnv scan_env; + ScanEnv scan_env = {0}; #ifdef USE_SUBEXP_CALL UnsetAddrList uslist; #endif - reg->state = ONIG_STATE_COMPILING; + if (IS_NOT_NULL(einfo)) einfo->par = (UChar* )NULL; + +#ifdef RUBY + scan_env.sourcefile = sourcefile; + scan_env.sourceline = sourceline; +#endif #ifdef ONIG_DEBUG print_enc_string(stderr, reg->enc, pattern, pattern_end); @@ -5373,6 +5759,13 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end, r = onig_parse_make_tree(&root, pattern, pattern_end, reg, &scan_env); if (r != 0) goto err; +#ifdef ONIG_DEBUG_PARSE_TREE +# if 0 + fprintf(stderr, "ORIGINAL PARSE TREE:\n"); + print_tree(stderr, root); +# endif +#endif + #ifdef USE_NAMED_GROUP /* mixed use named group and no-named group */ if (scan_env.num_named > 0 && @@ -5424,24 +5817,24 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end, #ifdef USE_COMBINATION_EXPLOSION_CHECK if (scan_env.backrefed_mem == 0 -#ifdef USE_SUBEXP_CALL +# ifdef USE_SUBEXP_CALL || scan_env.num_call == 0 -#endif +# endif ) { setup_comb_exp_check(root, 0, &scan_env); -#ifdef USE_SUBEXP_CALL +# ifdef USE_SUBEXP_CALL if (scan_env.has_recursion != 0) { scan_env.num_comb_exp_check = 0; } else -#endif +# endif if (scan_env.comb_exp_max_regnum > 0) { int i; for (i = 1; i <= scan_env.comb_exp_max_regnum; i++) { - if (BIT_STATUS_AT(scan_env.backrefed_mem, i) != 0) { - scan_env.num_comb_exp_check = 0; - break; - } + if (BIT_STATUS_AT(scan_env.backrefed_mem, i) != 0) { + scan_env.num_comb_exp_check = 0; + break; + } } } } @@ -5475,9 +5868,9 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end, reg->stack_pop_level = STACK_POP_LEVEL_ALL; else { if (reg->bt_mem_start != 0) - reg->stack_pop_level = STACK_POP_LEVEL_MEM_START; + reg->stack_pop_level = STACK_POP_LEVEL_MEM_START; else - reg->stack_pop_level = STACK_POP_LEVEL_FREE; + reg->stack_pop_level = STACK_POP_LEVEL_FREE; } } #ifdef USE_SUBEXP_CALL @@ -5488,14 +5881,14 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end, onig_node_free(root); #ifdef ONIG_DEBUG_COMPILE -#ifdef USE_NAMED_GROUP +# ifdef USE_NAMED_GROUP onig_print_names(stderr, reg); -#endif +# endif print_compiled_byte_code_list(stderr, reg); #endif end: - reg->state = ONIG_STATE_NORMAL; + onig_reg_resize(reg); return r; err_unset: @@ -5514,54 +5907,38 @@ onig_compile(regex_t* reg, const UChar* pattern, const UChar* pattern_end, } onig_node_free(root); - if (IS_NOT_NULL(scan_env.mem_nodes_dynamic)) - xfree(scan_env.mem_nodes_dynamic); - return r; -} + xfree(scan_env.mem_nodes_dynamic); -#ifdef USE_RECOMPILE_API -extern int -onig_recompile(regex_t* reg, const UChar* pattern, const UChar* pattern_end, - OnigOptionType option, OnigEncoding enc, OnigSyntaxType* syntax, - OnigErrorInfo* einfo) -{ - int r; - regex_t *new_reg; - - r = onig_new(&new_reg, pattern, pattern_end, option, enc, syntax, einfo); - if (r) return r; - if (ONIG_STATE(reg) == ONIG_STATE_NORMAL) { - onig_transfer(reg, new_reg); - } - else { - onig_chain_link_add(reg, new_reg); - } - return 0; + return r; } -#endif static int onig_inited = 0; extern int -onig_alloc_init(regex_t** reg, OnigOptionType option, - OnigCaseFoldType case_fold_flag, - OnigEncoding enc, OnigSyntaxType* syntax) +onig_reg_init(regex_t* reg, OnigOptionType option, + OnigCaseFoldType case_fold_flag, + OnigEncoding enc, const OnigSyntaxType* syntax) { if (! onig_inited) onig_init(); + if (IS_NULL(reg)) + return ONIGERR_INVALID_ARGUMENT; + + (reg)->exact = (UChar* )NULL; + (reg)->chain = (regex_t* )NULL; + (reg)->p = (UChar* )NULL; + (reg)->name_table = (void* )NULL; + (reg)->repeat_range = (OnigRepeatRange* )NULL; + if (ONIGENC_IS_UNDEF(enc)) - return ONIGERR_DEFAULT_ENCODING_IS_NOT_SETTED; + return ONIGERR_DEFAULT_ENCODING_IS_NOT_SET; if ((option & (ONIG_OPTION_DONT_CAPTURE_GROUP|ONIG_OPTION_CAPTURE_GROUP)) == (ONIG_OPTION_DONT_CAPTURE_GROUP|ONIG_OPTION_CAPTURE_GROUP)) { return ONIGERR_INVALID_COMBINATION_OF_OPTIONS; } - *reg = (regex_t* )xmalloc(sizeof(regex_t)); - if (IS_NULL(*reg)) return ONIGERR_MEMORY; - (*reg)->state = ONIG_STATE_MODIFY; - if ((option & ONIG_OPTION_NEGATE_SINGLELINE) != 0) { option |= syntax->options; option &= ~ONIG_OPTION_SINGLELINE; @@ -5569,56 +5946,70 @@ onig_alloc_init(regex_t** reg, OnigOptionType option, else option |= syntax->options; - (*reg)->enc = enc; - (*reg)->options = option; - (*reg)->syntax = syntax; - (*reg)->optimize = 0; - (*reg)->exact = (UChar* )NULL; - (*reg)->int_map = (int* )NULL; - (*reg)->int_map_backward = (int* )NULL; - (*reg)->chain = (regex_t* )NULL; - - (*reg)->p = (UChar* )NULL; - (*reg)->alloc = 0; - (*reg)->used = 0; - (*reg)->name_table = (void* )NULL; - - (*reg)->case_fold_flag = case_fold_flag; + (reg)->enc = enc; + (reg)->options = option; + (reg)->syntax = syntax; + (reg)->optimize = 0; + + (reg)->alloc = 0; + (reg)->used = 0; + + (reg)->case_fold_flag = case_fold_flag; + + (reg)->timelimit = 0; + return 0; } extern int -onig_new(regex_t** reg, const UChar* pattern, const UChar* pattern_end, - OnigOptionType option, OnigEncoding enc, OnigSyntaxType* syntax, - OnigErrorInfo* einfo) +onig_new_without_alloc(regex_t* reg, const UChar* pattern, + const UChar* pattern_end, OnigOptionType option, OnigEncoding enc, + const OnigSyntaxType* syntax, OnigErrorInfo* einfo) { int r; - if (IS_NOT_NULL(einfo)) einfo->par = (UChar* )NULL; - - r = onig_alloc_init(reg, option, ONIGENC_CASE_FOLD_DEFAULT, - enc, syntax); + r = onig_reg_init(reg, option, ONIGENC_CASE_FOLD_DEFAULT, enc, syntax); if (r) return r; - r = onig_compile(*reg, pattern, pattern_end, einfo); + r = onig_compile(reg, pattern, pattern_end, einfo); + return r; +} + +extern int +onig_new(regex_t** reg, const UChar* pattern, const UChar* pattern_end, + OnigOptionType option, OnigEncoding enc, const OnigSyntaxType* syntax, + OnigErrorInfo* einfo) +{ + *reg = (regex_t* )xmalloc(sizeof(regex_t)); + if (IS_NULL(*reg)) return ONIGERR_MEMORY; + + int r = onig_new_without_alloc(*reg, pattern, pattern_end, option, enc, syntax, einfo); if (r) { onig_free(*reg); *reg = NULL; } + return r; } extern int +onig_initialize(OnigEncoding encodings[] ARG_UNUSED, int n ARG_UNUSED) +{ + return onig_init(); +} + +extern int onig_init(void) { if (onig_inited != 0) return 0; - THREAD_SYSTEM_INIT; - THREAD_ATOMIC_START; - onig_inited = 1; +#if defined(ONIG_DEBUG_MEMLEAK) && defined(_MSC_VER) + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif + onigenc_init(); /* onigenc_set_default_caseconv_table((UChar* )0); */ @@ -5626,34 +6017,56 @@ onig_init(void) onig_statistics_init(); #endif - THREAD_ATOMIC_END; return 0; } +static OnigEndCallListItemType* EndCallTop; + +extern void onig_add_end_call(void (*func)(void)) +{ + OnigEndCallListItemType* item; + + item = (OnigEndCallListItemType* )xmalloc(sizeof(*item)); + if (item == 0) return ; + + item->next = EndCallTop; + item->func = func; + + EndCallTop = item; +} + +static void +exec_end_call_list(void) +{ + OnigEndCallListItemType* prev; + void (*func)(void); + + while (EndCallTop != 0) { + func = EndCallTop->func; + (*func)(); + + prev = EndCallTop; + EndCallTop = EndCallTop->next; + xfree(prev); + } +} + extern int onig_end(void) { - extern int onig_free_shared_cclass_table(void); - - THREAD_ATOMIC_START; + exec_end_call_list(); #ifdef ONIG_DEBUG_STATISTICS onig_print_statistics(stderr); #endif -#ifdef USE_SHARED_CCLASS_TABLE - onig_free_shared_cclass_table(); -#endif - -#ifdef USE_PARSE_TREE_NODE_RECYCLE - onig_free_node_list(); +#if defined(ONIG_DEBUG_MEMLEAK) && defined(_MSC_VER) + _CrtDumpMemoryLeaks(); #endif onig_inited = 0; - THREAD_ATOMIC_END; - THREAD_SYSTEM_END; return 0; } @@ -5679,11 +6092,11 @@ onig_is_in_code_range(const UChar* p, OnigCodePoint code) } extern int -onig_is_code_in_cc_len(int enclen, OnigCodePoint code, CClassNode* cc) +onig_is_code_in_cc_len(int elen, OnigCodePoint code, CClassNode* cc) { int found; - if (enclen > 1 || (code >= SINGLE_BYTE_SIZE)) { + if (elen > 1 || (code >= SINGLE_BYTE_SIZE)) { if (IS_NULL(cc->mbuf)) { found = 0; } @@ -5719,14 +6132,14 @@ onig_is_code_in_cc(OnigEncoding enc, OnigCodePoint code, CClassNode* cc) #ifdef ONIG_DEBUG /* arguments type */ -#define ARG_SPECIAL -1 -#define ARG_NON 0 -#define ARG_RELADDR 1 -#define ARG_ABSADDR 2 -#define ARG_LENGTH 3 -#define ARG_MEMNUM 4 -#define ARG_OPTION 5 -#define ARG_STATE_CHECK 6 +# define ARG_SPECIAL -1 +# define ARG_NON 0 +# define ARG_RELADDR 1 +# define ARG_ABSADDR 2 +# define ARG_LENGTH 3 +# define ARG_MEMNUM 4 +# define ARG_OPTION 5 +# define ARG_STATE_CHECK 6 OnigOpInfoType OnigOpInfo[] = { { OP_FINISH, "finish", ARG_NON }, @@ -5751,7 +6164,6 @@ OnigOpInfoType OnigOpInfo[] = { { OP_CCLASS_NOT, "cclass-not", ARG_SPECIAL }, { OP_CCLASS_MB_NOT, "cclass-mb-not", ARG_SPECIAL }, { OP_CCLASS_MIX_NOT, "cclass-mix-not", ARG_SPECIAL }, - { OP_CCLASS_NODE, "cclass-node", ARG_SPECIAL }, { OP_ANYCHAR, "anychar", ARG_NON }, { OP_ANYCHAR_ML, "anychar-ml", ARG_NON }, { OP_ANYCHAR_STAR, "anychar*", ARG_NON }, @@ -5764,6 +6176,12 @@ OnigOpInfoType OnigOpInfo[] = { { OP_NOT_WORD_BOUND, "not-word-bound", ARG_NON }, { OP_WORD_BEGIN, "word-begin", ARG_NON }, { OP_WORD_END, "word-end", ARG_NON }, + { OP_ASCII_WORD, "ascii-word", ARG_NON }, + { OP_NOT_ASCII_WORD, "not-ascii-word", ARG_NON }, + { OP_ASCII_WORD_BOUND, "ascii-word-bound", ARG_NON }, + { OP_NOT_ASCII_WORD_BOUND,"not-ascii-word-bound", ARG_NON }, + { OP_ASCII_WORD_BEGIN, "ascii-word-begin", ARG_NON }, + { OP_ASCII_WORD_END, "ascii-word-end", ARG_NON }, { OP_BEGIN_BUF, "begin-buf", ARG_NON }, { OP_END_BUF, "end-buf", ARG_NON }, { OP_BEGIN_LINE, "begin-line", ARG_NON }, @@ -5776,7 +6194,7 @@ OnigOpInfoType OnigOpInfo[] = { { OP_BACKREFN_IC, "backrefn-ic", ARG_SPECIAL }, { OP_BACKREF_MULTI, "backref_multi", ARG_SPECIAL }, { OP_BACKREF_MULTI_IC, "backref_multi-ic", ARG_SPECIAL }, - { OP_BACKREF_AT_LEVEL, "backref_at_level", ARG_SPECIAL }, + { OP_BACKREF_WITH_LEVEL, "backref_at_level", ARG_SPECIAL }, { OP_MEMORY_START_PUSH, "mem-start-push", ARG_MEMNUM }, { OP_MEMORY_START, "mem-start", ARG_MEMNUM }, { OP_MEMORY_END_PUSH, "mem-end-push", ARG_MEMNUM }, @@ -5785,6 +6203,7 @@ OnigOpInfoType OnigOpInfo[] = { { OP_MEMORY_END_REC, "mem-end-rec", ARG_MEMNUM }, { OP_SET_OPTION_PUSH, "set-option-push", ARG_OPTION }, { OP_SET_OPTION, "set-option", ARG_OPTION }, + { OP_KEEP, "keep", ARG_NON }, { OP_FAIL, "fail", ARG_NON }, { OP_JUMP, "jump", ARG_RELADDR }, { OP_PUSH, "push", ARG_RELADDR }, @@ -5810,8 +6229,12 @@ OnigOpInfoType OnigOpInfo[] = { { OP_LOOK_BEHIND, "look-behind", ARG_SPECIAL }, { OP_PUSH_LOOK_BEHIND_NOT, "push-look-behind-not", ARG_SPECIAL }, { OP_FAIL_LOOK_BEHIND_NOT, "fail-look-behind-not", ARG_NON }, + { OP_PUSH_ABSENT_POS, "push-absent-pos", ARG_NON }, + { OP_ABSENT, "absent", ARG_RELADDR }, + { OP_ABSENT_END, "absent-end", ARG_NON }, { OP_CALL, "call", ARG_ABSADDR }, { OP_RETURN, "return", ARG_NON }, + { OP_CONDITION, "condition", ARG_SPECIAL }, { OP_STATE_CHECK_PUSH, "state-check-push", ARG_SPECIAL }, { OP_STATE_CHECK_PUSH_OR_JUMP, "state-check-push-or-jump", ARG_SPECIAL }, { OP_STATE_CHECK, "state-check", ARG_STATE_CHECK }, @@ -5821,7 +6244,7 @@ OnigOpInfoType OnigOpInfo[] = { { -1, "", ARG_NON } }; -static char* +static const char* op2name(int opcode) { int i; @@ -5845,15 +6268,17 @@ op2arg_type(int opcode) return ARG_SPECIAL; } +# ifdef ONIG_DEBUG_PARSE_TREE static void Indent(FILE* f, int indent) { int i; for (i = 0; i < indent; i++) putc(' ', f); } +# endif /* ONIG_DEBUG_PARSE_TREE */ static void -p_string(FILE* f, int len, UChar* s) +p_string(FILE* f, ptrdiff_t len, UChar* s) { fputs(":", f); while (len-- > 0) { fputc(*s++, f); } @@ -5869,7 +6294,7 @@ p_len_string(FILE* f, LengthType len, int mb_len, UChar* s) } extern void -onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, +onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar* bpend, UChar** nextp, OnigEncoding enc) { int i, n, arg_type; @@ -5889,7 +6314,7 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, break; case ARG_RELADDR: GET_RELADDR_INC(addr, bp); - fprintf(f, ":(%d)", addr); + fprintf(f, ":(%s%d)", (addr >= 0) ? "+" : "", addr); break; case ARG_ABSADDR: GET_ABSADDR_INC(addr, bp); @@ -5906,9 +6331,9 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, break; case ARG_OPTION: { - OnigOptionType option = *((OnigOptionType* )bp); - bp += SIZE_OPTION; - fprintf(f, ":%d", option); + OnigOptionType option = *((OnigOptionType* )bp); + bp += SIZE_OPTION; + fprintf(f, ":%d", option); } break; @@ -5938,7 +6363,7 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, p_len_string(f, len, 1, bp); bp += len; break; - + case OP_EXACTMB2N1: p_string(f, 2, bp); bp += 2; break; case OP_EXACTMB2N2: @@ -5957,18 +6382,18 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, break; case OP_EXACTMBN: { - int mb_len; - - GET_LENGTH_INC(mb_len, bp); - GET_LENGTH_INC(len, bp); - fprintf(f, ":%d:%d:", mb_len, len); - n = len * mb_len; - while (n-- > 0) { fputc(*bp++, f); } + int mb_len; + + GET_LENGTH_INC(mb_len, bp); + GET_LENGTH_INC(len, bp); + fprintf(f, ":%d:%d:", mb_len, len); + n = len * mb_len; + while (n-- > 0) { fputc(*bp++, f); } } break; case OP_EXACT1_IC: - len = enc_len(enc, bp); + len = enclen(enc, bp, bpend); p_string(f, len, bp); bp += len; break; @@ -5994,9 +6419,9 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, case OP_CCLASS_MB_NOT: GET_LENGTH_INC(len, bp); q = bp; -#ifndef PLATFORM_UNALIGNED_WORD_ACCESS +# ifndef PLATFORM_UNALIGNED_WORD_ACCESS ALIGNMENT_RIGHT(q); -#endif +# endif GET_CODE_POINT(code, q); bp += len; fprintf(f, ":%d:%d", (int )code, len); @@ -6008,24 +6433,14 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, bp += SIZE_BITSET; GET_LENGTH_INC(len, bp); q = bp; -#ifndef PLATFORM_UNALIGNED_WORD_ACCESS +# ifndef PLATFORM_UNALIGNED_WORD_ACCESS ALIGNMENT_RIGHT(q); -#endif +# endif GET_CODE_POINT(code, q); bp += len; fprintf(f, ":%d:%d:%d", n, (int )code, len); break; - case OP_CCLASS_NODE: - { - CClassNode *cc; - - GET_POINTER_INC(cc, bp); - n = bitset_on_num(cc->bs); - fprintf(f, ":%u:%d", (unsigned int )cc, n); - } - break; - case OP_BACKREFN_IC: mem = *((MemNumType* )bp); bp += SIZE_MEMNUM; @@ -6037,40 +6452,40 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, fputs(" ", f); GET_LENGTH_INC(len, bp); for (i = 0; i < len; i++) { - GET_MEMNUM_INC(mem, bp); - if (i > 0) fputs(", ", f); - fprintf(f, "%d", mem); + GET_MEMNUM_INC(mem, bp); + if (i > 0) fputs(", ", f); + fprintf(f, "%d", mem); } break; - case OP_BACKREF_AT_LEVEL: + case OP_BACKREF_WITH_LEVEL: { - OnigOptionType option; - LengthType level; - - GET_OPTION_INC(option, bp); - fprintf(f, ":%d", option); - GET_LENGTH_INC(level, bp); - fprintf(f, ":%d", level); - - fputs(" ", f); - GET_LENGTH_INC(len, bp); - for (i = 0; i < len; i++) { - GET_MEMNUM_INC(mem, bp); - if (i > 0) fputs(", ", f); - fprintf(f, "%d", mem); - } + OnigOptionType option; + LengthType level; + + GET_OPTION_INC(option, bp); + fprintf(f, ":%d", option); + GET_LENGTH_INC(level, bp); + fprintf(f, ":%d", level); + + fputs(" ", f); + GET_LENGTH_INC(len, bp); + for (i = 0; i < len; i++) { + GET_MEMNUM_INC(mem, bp); + if (i > 0) fputs(", ", f); + fprintf(f, "%d", mem); + } } break; case OP_REPEAT: case OP_REPEAT_NG: { - mem = *((MemNumType* )bp); - bp += SIZE_MEMNUM; - addr = *((RelAddrType* )bp); - bp += SIZE_RELADDR; - fprintf(f, ":%d:%d", mem, addr); + mem = *((MemNumType* )bp); + bp += SIZE_MEMNUM; + addr = *((RelAddrType* )bp); + bp += SIZE_RELADDR; + fprintf(f, ":%d:%d", mem, addr); } break; @@ -6078,7 +6493,7 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, case OP_PUSH_IF_PEEK_NEXT: addr = *((RelAddrType* )bp); bp += SIZE_RELADDR; - fprintf(f, ":(%d)", addr); + fprintf(f, ":(%s%d)", (addr >= 0) ? "+" : "", addr); p_string(f, 1, bp); bp += 1; break; @@ -6091,7 +6506,7 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, case OP_PUSH_LOOK_BEHIND_NOT: GET_RELADDR_INC(addr, bp); GET_LENGTH_INC(len, bp); - fprintf(f, ":%d:(%d)", len, addr); + fprintf(f, ":%d:(%s%d)", len, (addr >= 0) ? "+" : "", addr); break; case OP_STATE_CHECK_PUSH: @@ -6100,18 +6515,25 @@ onig_print_compiled_byte_code(FILE* f, UChar* bp, UChar** nextp, bp += SIZE_STATE_CHECK_NUM; addr = *((RelAddrType* )bp); bp += SIZE_RELADDR; - fprintf(f, ":%d:(%d)", scn, addr); + fprintf(f, ":%d:(%s%d)", scn, (addr >= 0) ? "+" : "", addr); + break; + + case OP_CONDITION: + GET_MEMNUM_INC(mem, bp); + GET_RELADDR_INC(addr, bp); + fprintf(f, ":%d:(%s%d)", mem, (addr >= 0) ? "+" : "", addr); break; default: fprintf(stderr, "onig_print_compiled_byte_code: undefined code %d\n", - *--bp); + bp[-1]); } } fputs("]", f); if (nextp) *nextp = bp; } +# ifdef ONIG_DEBUG_COMPILE static void print_compiled_byte_code_list(FILE* f, regex_t* reg) { @@ -6119,27 +6541,27 @@ print_compiled_byte_code_list(FILE* f, regex_t* reg) UChar* bp = reg->p; UChar* end = reg->p + reg->used; - fprintf(f, "code length: %d\n", reg->used); + fprintf(f, "code length: %d", reg->used); - ncode = 0; + ncode = -1; while (bp < end) { ncode++; - if (bp > reg->p) { - if (ncode % 5 == 0) - fprintf(f, "\n"); - else - fputs(" ", f); - } - onig_print_compiled_byte_code(f, bp, &bp, reg->enc); + if (ncode % 5 == 0) + fprintf(f, "\n%ld:", bp - reg->p); + else + fprintf(f, " %ld:", bp - reg->p); + onig_print_compiled_byte_code(f, bp, end, &bp, reg->enc); } fprintf(f, "\n"); } +# endif /* ONIG_DEBUG_COMPILE */ +# ifdef ONIG_DEBUG_PARSE_TREE static void print_indent_tree(FILE* f, Node* node, int indent) { - int i, type; + int i, type, container_p = 0; int add = 3; UChar* p; @@ -6154,52 +6576,55 @@ print_indent_tree(FILE* f, Node* node, int indent) case NT_LIST: case NT_ALT: if (NTYPE(node) == NT_LIST) - fprintf(f, "<list:%x>\n", (int )node); + fprintf(f, "<list:%"PRIxPTR">\n", (intptr_t )node); else - fprintf(f, "<alt:%x>\n", (int )node); + fprintf(f, "<alt:%"PRIxPTR">\n", (intptr_t )node); print_indent_tree(f, NCAR(node), indent + add); while (IS_NOT_NULL(node = NCDR(node))) { if (NTYPE(node) != type) { - fprintf(f, "ERROR: list/alt right is not a cons. %d\n", NTYPE(node)); - exit(0); + fprintf(f, "ERROR: list/alt right is not a cons. %d\n", NTYPE(node)); + exit(0); } print_indent_tree(f, NCAR(node), indent + add); } break; case NT_STR: - fprintf(f, "<string%s:%x>", - (NSTRING_IS_RAW(node) ? "-raw" : ""), (int )node); + fprintf(f, "<string%s:%"PRIxPTR">", + (NSTRING_IS_RAW(node) ? "-raw" : ""), (intptr_t )node); for (p = NSTR(node)->s; p < NSTR(node)->end; p++) { if (*p >= 0x20 && *p < 0x7f) - fputc(*p, f); + fputc(*p, f); else { - fprintf(f, " 0x%02x", *p); + fprintf(f, " 0x%02x", *p); } } break; case NT_CCLASS: - fprintf(f, "<cclass:%x>", (int )node); - if (IS_CCLASS_NOT(NCCLASS(node)) fputs(" not", f); + fprintf(f, "<cclass:%"PRIxPTR">", (intptr_t )node); + if (IS_NCCLASS_NOT(NCCLASS(node))) fputs("not ", f); if (NCCLASS(node)->mbuf) { BBuf* bbuf = NCCLASS(node)->mbuf; - for (i = 0; i < bbuf->used; i++) { - if (i > 0) fprintf(f, ","); - fprintf(f, "%0x", bbuf->p[i]); + OnigCodePoint* data = (OnigCodePoint* )bbuf->p; + OnigCodePoint* end = (OnigCodePoint* )(bbuf->p + bbuf->used); + fprintf(f, "%d", *data++); + for (; data < end; data+=2) { + fprintf(f, ","); + fprintf(f, "%04x-%04x", data[0], data[1]); } } break; case NT_CTYPE: - fprintf(f, "<ctype:%x> ", (int )node); + fprintf(f, "<ctype:%"PRIxPTR"> ", (intptr_t )node); switch (NCTYPE(node)->ctype) { case ONIGENC_CTYPE_WORD: if (NCTYPE(node)->not != 0) - fputs("not word", f); + fputs("not word", f); else - fputs("word", f); + fputs("word", f); break; default: @@ -6209,11 +6634,11 @@ print_indent_tree(FILE* f, Node* node, int indent) break; case NT_CANY: - fprintf(f, "<anychar:%x>", (int )node); + fprintf(f, "<anychar:%"PRIxPTR">", (intptr_t )node); break; case NT_ANCHOR: - fprintf(f, "<anchor:%x> ", (int )node); + fprintf(f, "<anchor:%"PRIxPTR"> ", (intptr_t )node); switch (NANCHOR(node)->type) { case ANCHOR_BEGIN_BUF: fputs("begin buf", f); break; case ANCHOR_END_BUF: fputs("end buf", f); break; @@ -6224,14 +6649,15 @@ print_indent_tree(FILE* f, Node* node, int indent) case ANCHOR_WORD_BOUND: fputs("word bound", f); break; case ANCHOR_NOT_WORD_BOUND: fputs("not word bound", f); break; -#ifdef USE_WORD_BEGIN_END +# ifdef USE_WORD_BEGIN_END case ANCHOR_WORD_BEGIN: fputs("word begin", f); break; case ANCHOR_WORD_END: fputs("word end", f); break; -#endif - case ANCHOR_PREC_READ: fputs("prec read", f); break; - case ANCHOR_PREC_READ_NOT: fputs("prec read not", f); break; - case ANCHOR_LOOK_BEHIND: fputs("look_behind", f); break; - case ANCHOR_LOOK_BEHIND_NOT: fputs("look_behind_not",f); break; +# endif + case ANCHOR_PREC_READ: fputs("prec read", f); container_p = TRUE; break; + case ANCHOR_PREC_READ_NOT: fputs("prec read not", f); container_p = TRUE; break; + case ANCHOR_LOOK_BEHIND: fputs("look_behind", f); container_p = TRUE; break; + case ANCHOR_LOOK_BEHIND_NOT: fputs("look_behind_not",f); container_p = TRUE; break; + case ANCHOR_KEEP: fputs("keep",f); break; default: fprintf(f, "ERROR: undefined anchor type.\n"); @@ -6244,37 +6670,36 @@ print_indent_tree(FILE* f, Node* node, int indent) int* p; BRefNode* br = NBREF(node); p = BACKREFS_P(br); - fprintf(f, "<backref:%x>", (int )node); + fprintf(f, "<backref:%"PRIxPTR">", (intptr_t )node); for (i = 0; i < br->back_num; i++) { - if (i > 0) fputs(", ", f); - fprintf(f, "%d", p[i]); + if (i > 0) fputs(", ", f); + fprintf(f, "%d", p[i]); } } break; -#ifdef USE_SUBEXP_CALL +# ifdef USE_SUBEXP_CALL case NT_CALL: { CallNode* cn = NCALL(node); - fprintf(f, "<call:%x>", (int )node); + fprintf(f, "<call:%"PRIxPTR">", (intptr_t )node); p_string(f, cn->name_end - cn->name, cn->name); } break; -#endif +# endif case NT_QTFR: - fprintf(f, "<quantifier:%x>{%d,%d}%s\n", (int )node, - NQTFR(node)->lower, NQTFR(node)->upper, - (NQTFR(node)->greedy ? "" : "?")); + fprintf(f, "<quantifier:%"PRIxPTR">{%d,%d}%s\n", (intptr_t )node, + NQTFR(node)->lower, NQTFR(node)->upper, + (NQTFR(node)->greedy ? "" : "?")); print_indent_tree(f, NQTFR(node)->target, indent + add); break; case NT_ENCLOSE: - fprintf(f, "<enclose:%x> ", (int )node); + fprintf(f, "<enclose:%"PRIxPTR"> ", (intptr_t )node); switch (NENCLOSE(node)->type) { case ENCLOSE_OPTION: - fprintf(f, "option:%d\n", NENCLOSE(node)->option); - print_indent_tree(f, NENCLOSE(node)->target, indent + add); + fprintf(f, "option:%d", NENCLOSE(node)->option); break; case ENCLOSE_MEMORY: fprintf(f, "memory:%d", NENCLOSE(node)->regnum); @@ -6282,6 +6707,12 @@ print_indent_tree(FILE* f, Node* node, int indent) case ENCLOSE_STOP_BACKTRACK: fprintf(f, "stop-bt"); break; + case ENCLOSE_CONDITION: + fprintf(f, "condition:%d", NENCLOSE(node)->regnum); + break; + case ENCLOSE_ABSENT: + fprintf(f, "absent"); + break; default: break; @@ -6298,14 +6729,16 @@ print_indent_tree(FILE* f, Node* node, int indent) if (type != NT_LIST && type != NT_ALT && type != NT_QTFR && type != NT_ENCLOSE) fprintf(f, "\n"); + + if (container_p) print_indent_tree(f, NANCHOR(node)->target, indent + add); + fflush(f); } -#endif /* ONIG_DEBUG */ -#ifdef ONIG_DEBUG_PARSE_TREE static void print_tree(FILE* f, Node* node) { print_indent_tree(f, node, 0); } -#endif +# endif /* ONIG_DEBUG_PARSE_TREE */ +#endif /* ONIG_DEBUG */ |
