2003-12-23 Paolo Bonzini * posix/regex_internal.c (re_dfa_add_node): Initialize opt_subexp. * posix/regex_internal.h (re_token_type_t): Put OP_DUP_PLUS among the tokens, rather than among the epsilon-transiting nodes. (re_token_t): Add the opt_subexp flag. * posix/regcomp.c (optimize_utf8, calc_first, calc_next, calc_epsdest): Don't consider OP_DUP_PLUS. (mark_opt_subexp, mark_opt_subexp_iter): New functions. (parse_dup_op): Mostly rewritten, lowering OP_DUP_PLUS to OP_DUP_ASTERISK and marking optional subexpressions as such using mark_opt_subexp. * posix/regexec.c (set_regs): Initialize PREV_INDEX_MATCH and pass it to update_regs. (update_regs): Use the PREV_INDEX_MATCH parameter, together with the opt_subexp flag, in order to discard a final empty match of a repeated subexpression. * posix/BOOST.tests, posix/PCRE.tests, posix/rxspencer/tests: adjust test vectors diff -rpC3 libc-save/posix/BOOST.tests libc/posix/BOOST.tests *** libc-save/posix/BOOST.tests Fri Dec 26 00:27:19 2003 --- libc/posix/BOOST.tests Fri Dec 26 00:28:08 2003 *************** a(b|c){2,4}d abcbd 0 5 3 4 *** 432,458 **** a(b|c){2,4}d abcbcd 0 6 4 5 a(b|c){2,}d abcd 0 4 2 3 a(b|c){2,}d abcbd 0 5 3 4 ! ; perl only: ! a(b|c?)+d abcd 0 4 3 3 ! a(b+|((c)*))+d abd 0 3 2 2 2 2 -1 -1 ! a(b+|((c)*))+d abcd 0 4 3 3 3 3 2 3 ; posix only: - match_default extended REG_EXTENDED REG_STARTEND ! ; XXX FIXME the following 4 tests fail ATM ! ;a(b|c?)+d abcd 0 4 2 3 ! ;a(b|((c)*))+d abcd 0 4 2 3 2 3 2 3 ! ;a(b+|((c)*))+d abd 0 3 1 2 -1 -1 -1 -1 ! ;a(b+|((c)*))+d abcd 0 4 2 3 2 3 2 3 ! a(b|((c)*))+d ad 0 2 1 1 1 1 -1 -1 ! ! ; XXX FIXME the following 3 tests fail ATM ! ;a(b|((c)*))*d abcd 0 4 2 3 2 3 2 3 ! ;a(b+|((c)*))*d abd 0 3 1 2 -1 -1 -1 -1 ! ;a(b+|((c)*))*d abcd 0 4 2 3 2 3 2 3 ! a(b|((c)*))*d ad 0 2 1 1 1 1 -1 -1 - match_default normal REG_PERL --- 432,453 ---- a(b|c){2,4}d abcbcd 0 6 4 5 a(b|c){2,}d abcd 0 4 2 3 a(b|c){2,}d abcbd 0 5 3 4 ! ; perl only: these conflict with the POSIX test below ! ;a(b|c?)+d abcd 0 4 3 3 ! ;a(b+|((c)*))+d abd 0 3 2 2 2 2 -1 -1 ! ;a(b+|((c)*))+d abcd 0 4 3 3 3 3 2 3 ; posix only: - match_default extended REG_EXTENDED REG_STARTEND ! a(b|c?)+d abcd 0 4 2 3 ! a(b|((c)*))+d abcd 0 4 2 3 2 3 2 3 ! a(b+|((c)*))+d abd 0 3 1 2 -1 -1 -1 -1 ! a(b+|((c)*))+d abcd 0 4 2 3 2 3 2 3 a(b|((c)*))+d ad 0 2 1 1 1 1 -1 -1 ! a(b|((c)*))*d abcd 0 4 2 3 2 3 2 3 ! a(b+|((c)*))*d abd 0 3 1 2 -1 -1 -1 -1 ! a(b+|((c)*))*d abcd 0 4 2 3 2 3 2 3 a(b|((c)*))*d ad 0 2 1 1 1 1 -1 -1 - match_default normal REG_PERL diff -rpC3 libc-save/posix/PCRE.tests libc/posix/PCRE.tests *** libc-save/posix/PCRE.tests Fri Dec 26 00:27:19 2003 --- libc/posix/PCRE.tests Fri Dec 26 00:28:06 2003 *************** No match *** 1151,1163 **** /(abc|)+/ abc 0: abc ! 1: abcabc 0: abcabc ! 1: abcabcabc 0: abcabcabc ! 1: xyz 0: 1: --- 1151,1163 ---- /(abc|)+/ abc 0: abc ! 1: abc abcabc 0: abcabc ! 1: abc abcabcabc 0: abcabcabc ! 1: abc xyz 0: 1: *************** No match *** 1165,1210 **** /([a]*)*/ a 0: a ! 1: aaaaa 0: aaaaa ! 1: /([ab]*)*/ a 0: a ! 1: b 0: b ! 1: ababab 0: ababab ! 1: aaaabcde 0: aaaab ! 1: bbbb 0: bbbb ! 1: /([^a]*)*/ b 0: b ! 1: bbbb 0: bbbb ! 1: aaa 0: - 1: /([^ab]*)*/ cccc 0: cccc ! 1: abab 0: - 1: /abc/ abc --- 1165,1208 ---- /([a]*)*/ a 0: a ! 1: a aaaaa 0: aaaaa ! 1: aaaaa /([ab]*)*/ a 0: a ! 1: a b 0: b ! 1: b ababab 0: ababab ! 1: ababab aaaabcde 0: aaaab ! 1: aaaab bbbb 0: bbbb ! 1: bbbb /([^a]*)*/ b 0: b ! 1: b bbbb 0: bbbb ! 1: bbbb aaa 0: /([^ab]*)*/ cccc 0: cccc ! 1: cccc abab 0: /abc/ abc diff -rpC3 libc-save/posix/regcomp.c libc/posix/regcomp.c *** libc-save/posix/regcomp.c Fri Dec 26 00:27:19 2003 --- libc/posix/regcomp.c Fri Dec 26 00:31:46 2003 *************** static bin_tree_t *re_dfa_add_tree_node *** 135,140 **** --- 135,142 ---- const re_token_t *token) __attribute ((noinline)); static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa); + static void mark_opt_subexp (const bin_tree_t *src, re_dfa_t *dfa); + static void mark_opt_subexp_iter (const bin_tree_t *src, re_dfa_t *dfa, int idx); /* This table gives an error message for each of the error codes listed in regex.h. Obviously the order here has to be same as there. *************** optimize_utf8 (dfa) *** 1031,1037 **** case END_OF_RE: case OP_DUP_ASTERISK: case OP_DUP_QUESTION: - case OP_DUP_PLUS: case OP_OPEN_SUBEXP: case OP_CLOSE_SUBEXP: break; --- 1033,1038 ---- *************** calc_first (dfa, node) *** 1150,1155 **** --- 1151,1157 ---- case OP_CLOSE_BRACKET: case OP_OPEN_DUP_NUM: case OP_CLOSE_DUP_NUM: + case OP_DUP_PLUS: case OP_NON_MATCH_LIST: case OP_OPEN_COLL_ELEM: case OP_CLOSE_COLL_ELEM: *************** calc_first (dfa, node) *** 1176,1189 **** case OP_CLOSE_SUBEXP: node->first = idx; break; - case OP_DUP_PLUS: - #ifdef DEBUG - assert (node->left != NULL); - #endif - if (node->left->first == -1) - calc_first (dfa, node->left); - node->first = node->left->first; - break; case OP_ALT: node->first = idx; break; --- 1178,1183 ---- *************** calc_next (dfa, node) *** 1223,1229 **** switch (type) { case OP_DUP_ASTERISK: - case OP_DUP_PLUS: node->next = idx; break; case CONCAT: --- 1217,1222 ---- *************** calc_epsdest (dfa, node) *** 1258,1264 **** if (node->type == 0) { if (dfa->nodes[idx].type == OP_DUP_ASTERISK - || dfa->nodes[idx].type == OP_DUP_PLUS || dfa->nodes[idx].type == OP_DUP_QUESTION) { if (node->left->first == -1) --- 1251,1256 ---- *************** parse_sub_exp (regexp, preg, token, synt *** 2377,2384 **** /* This function parse repetition operators like "*", "+", "{1,3}" etc. */ static bin_tree_t * ! parse_dup_op (dup_elem, regexp, dfa, token, syntax, err) ! bin_tree_t *dup_elem; re_string_t *regexp; re_dfa_t *dfa; re_token_t *token; --- 2369,2376 ---- /* This function parse repetition operators like "*", "+", "{1,3}" etc. */ static bin_tree_t * ! parse_dup_op (elem, regexp, dfa, token, syntax, err) ! bin_tree_t *elem; re_string_t *regexp; re_dfa_t *dfa; re_token_t *token; *************** parse_dup_op (dup_elem, regexp, dfa, tok *** 2386,2400 **** reg_errcode_t *err; { re_token_t dup_token; ! bin_tree_t *tree = dup_elem, *work_tree; ! int start_idx = re_string_cur_idx (regexp); re_token_t start_token = *token; if (token->type == OP_OPEN_DUP_NUM) { ! int i; ! int end = 0; ! int start = fetch_number (regexp, token, syntax); ! bin_tree_t *elem; if (start == -1) { if (token->type == CHARACTER && token->opr.c == ',') --- 2378,2391 ---- reg_errcode_t *err; { re_token_t dup_token; ! bin_tree_t *tree = NULL; ! int i, start, end, start_idx = re_string_cur_idx (regexp); re_token_t start_token = *token; + if (token->type == OP_OPEN_DUP_NUM) { ! end = 0; ! start = fetch_number (regexp, token, syntax); if (start == -1) { if (token->type == CHARACTER && token->opr.c == ',') *************** parse_dup_op (dup_elem, regexp, dfa, tok *** 2415,2537 **** if (BE (start == -2 || end == -2, 0)) { /* Invalid sequence. */ ! if (token->type == OP_CLOSE_DUP_NUM) ! goto parse_dup_op_invalid_interval; ! else ! goto parse_dup_op_ebrace; ! } ! if (BE ((start == 0 && end == 0) || tree == NULL, 0)) ! { ! /* We treat "{0}" and "{0,0}" as null string. ! Similarly "{0}{m,n}". */ ! fetch_token (token, regexp, syntax); ! return NULL; ! } ! ! /* Extract "{n,m}" to "...{0,}". */ ! elem = tree; ! for (i = 1; i < start; ++i) ! { ! work_tree = duplicate_tree (elem, dfa); ! tree = create_tree (dfa, tree, work_tree, CONCAT, 0); ! if (BE (work_tree == NULL || tree == NULL, 0)) ! goto parse_dup_op_espace; ! } ! ! if (end == -1) ! { ! /* We treat "{0,}" as "*". */ ! dup_token.type = OP_DUP_ASTERISK; ! if (start > 0) ! { ! elem = duplicate_tree (elem, dfa); ! work_tree = re_dfa_add_tree_node (dfa, elem, NULL, &dup_token); ! tree = create_tree (dfa, tree, work_tree, CONCAT, 0); ! if (BE (elem == NULL || work_tree == NULL || tree == NULL, 0)) ! goto parse_dup_op_espace; ! } ! else { ! tree = re_dfa_add_tree_node (dfa, elem, NULL, &dup_token); ! if (BE (tree == NULL, 0)) ! goto parse_dup_op_espace; } } ! else if (BE (start > end, 0)) { ! /* First number greater than first. */ *err = REG_BADBR; return NULL; } ! else if (end - start > 0) { ! /* Then extract "{0,m}" to "??...?". */ ! dup_token.type = OP_DUP_QUESTION; ! if (start > 0) ! { ! elem = duplicate_tree (elem, dfa); ! elem = re_dfa_add_tree_node (dfa, elem, NULL, &dup_token); ! tree = create_tree (dfa, tree, elem, CONCAT, 0); ! if (BE (elem == NULL || tree == NULL, 0)) ! goto parse_dup_op_espace; ! } ! else ! { ! tree = elem = re_dfa_add_tree_node (dfa, elem, NULL, &dup_token); ! if (BE (tree == NULL, 0)) ! goto parse_dup_op_espace; ! } ! for (i = 1; i < end - start; ++i) ! { ! work_tree = duplicate_tree (elem, dfa); ! tree = create_tree (dfa, tree, work_tree, CONCAT, 0); ! if (BE (work_tree == NULL || tree == NULL, 0)) ! { ! *err = REG_ESPACE; ! return NULL; ! } ! } } } ! /* Treat "{0}*" etc. as "{0}". */ ! else if (tree == NULL) ! ; ! else { ! tree = re_dfa_add_tree_node (dfa, tree, NULL, token); ! if (BE (tree == NULL, 0)) { ! *err = REG_ESPACE; ! return NULL; } } fetch_token (token, regexp, syntax); return tree; parse_dup_op_espace: *err = REG_ESPACE; return NULL; - - parse_dup_op_ebrace: - if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) - { - *err = REG_EBRACE; - return NULL; - } - goto parse_dup_op_rollback; - parse_dup_op_invalid_interval: - if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) - { - *err = REG_BADBR; - return NULL; - } - parse_dup_op_rollback: - re_string_set_index (regexp, start_idx); - *token = start_token; - token->type = CHARACTER; - /* mb_partial and word_char bits should be already initialized by - peek_token. */ - return dup_elem; } /* Size of the names for collating symbol/equivalence_class/character_class. --- 2406,2509 ---- if (BE (start == -2 || end == -2, 0)) { /* Invalid sequence. */ ! if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) { ! if (token->type == END_OF_RE) ! *err = REG_EBRACE; ! else ! *err = REG_BADBR; ! ! return NULL; } + + /* If the syntax bit is set, rollback. */ + re_string_set_index (regexp, start_idx); + *token = start_token; + token->type = CHARACTER; + /* mb_partial and word_char bits should be already initialized by + peek_token. */ + return elem; } ! ! if (BE (end != -1 && start > end, 0)) { ! /* First number greater than second. */ *err = REG_BADBR; return NULL; } ! } ! else ! { ! start = (token->type == OP_DUP_PLUS) ? 1 : 0; ! end = (token->type == OP_DUP_QUESTION) ? 1 : -1; ! } ! ! /* Treat "{0}*" etc. as "{0}". */ ! if (BE (elem == NULL, 0)) ! start = end = 0; ! ! /* Extract "{n,m}" to "...{0,}". */ ! else if (BE (start > 0, 0)) ! { ! tree = elem; ! for (i = 2; i <= start; ++i) { ! elem = duplicate_tree (elem, dfa); ! tree = create_tree (dfa, tree, elem, CONCAT, 0); ! if (BE (elem == NULL || tree == NULL, 0)) ! goto parse_dup_op_espace; } } ! ! if (BE (end != start, 1)) { ! dup_token.type = (end == -1 ? OP_DUP_ASTERISK : OP_DUP_QUESTION); ! if (BE (start > 0, 0)) { ! elem = duplicate_tree (elem, dfa); ! if (BE (elem == NULL, 0)) ! goto parse_dup_op_espace; ! ! /* This subexpression will be marked as optional, so that ! empty matches do not touch the registers. */ ! mark_opt_subexp (elem, dfa); ! ! /* Prepare the tree with the modifier. */ ! elem = re_dfa_add_tree_node (dfa, elem, NULL, &dup_token); ! tree = create_tree (dfa, tree, elem, CONCAT, 0); } + else + { + /* We do not need to duplicate the tree because we have not + created it yet. */ + mark_opt_subexp (elem, dfa); + tree = elem = re_dfa_add_tree_node (dfa, elem, NULL, &dup_token); + } + + if (BE (elem == NULL || tree == NULL, 0)) + goto parse_dup_op_espace; + + /* This loop is actually executed only when end != -1, + to rewrite {0,n} as ???... We have + already created the start+1-th copy. */ + for (i = start + 2; i <= end; ++i) + { + elem = duplicate_tree (elem, dfa); + tree = create_tree (dfa, tree, elem, CONCAT, 0); + if (BE (elem == NULL || tree == NULL, 0)) + { + *err = REG_ESPACE; + return NULL; + } + } } + fetch_token (token, regexp, syntax); return tree; parse_dup_op_espace: *err = REG_ESPACE; return NULL; } /* Size of the names for collating symbol/equivalence_class/character_class. *************** re_dfa_add_tree_node (dfa, left, right, *** 3737,3742 **** --- 3709,3755 ---- return create_tree (dfa, left, right, 0, new_idx); } + /* Mark the tree SRC as an optional subexpression. */ + + static void + mark_opt_subexp (src, dfa) + const bin_tree_t *src; + re_dfa_t *dfa; + { + /* Pass an OPT_SUBEXP_IDX which is != 1 if the duplicated tree is + a subexpression. */ + if (src->type == CONCAT + && src->left->type == NON_TYPE + && dfa->nodes[src->left->node_idx].type == OP_OPEN_SUBEXP) + mark_opt_subexp_iter (src, dfa, dfa->nodes[src->left->node_idx].opr.idx); + } + + + /* Recursive tree walker for mark_opt_subexp. */ + + static void + mark_opt_subexp_iter (src, dfa, idx) + const bin_tree_t *src; + re_dfa_t *dfa; + { + int node_idx; + + if (src->type == NON_TYPE) + { + node_idx = src->node_idx; + if ((dfa->nodes[node_idx].type == OP_OPEN_SUBEXP + || dfa->nodes[node_idx].type == OP_CLOSE_SUBEXP) + && dfa->nodes[node_idx].opr.idx == idx) + dfa->nodes[node_idx].opt_subexp = 1; + } + + if (src->left != NULL) + mark_opt_subexp_iter (src->left, dfa, idx); + + if (src->right != NULL) + mark_opt_subexp_iter (src->right, dfa, idx); + } + /* Duplicate the node SRC, and return new node. */ diff -rpC3 libc-save/posix/regex_internal.c libc/posix/regex_internal.c *** libc-save/posix/regex_internal.c Fri Dec 26 00:27:19 2003 --- libc/posix/regex_internal.c Fri Dec 26 00:27:45 2003 *************** re_dfa_add_node (dfa, token, mode) *** 1306,1311 **** --- 1306,1312 ---- dfa->nodes_alloc = new_nodes_alloc; } dfa->nodes[dfa->nodes_len] = token; + dfa->nodes[dfa->nodes_len].opt_subexp = 0; dfa->nodes[dfa->nodes_len].duplicated = 0; dfa->nodes[dfa->nodes_len].constraint = 0; return dfa->nodes_len++; diff -rpC3 libc-save/posix/regex_internal.h libc/posix/regex_internal.h *** libc-save/posix/regex_internal.h Fri Dec 26 00:27:19 2003 --- libc/posix/regex_internal.h Fri Dec 26 00:27:45 2003 *************** typedef struct *** 281,286 **** --- 281,287 ---- #endif unsigned int constraint : 10; /* context constraint */ unsigned int duplicated : 1; + unsigned int opt_subexp : 1; #ifdef RE_ENABLE_I18N /* These 2 bits can be moved into the union if needed (e.g. if running out of bits; move opr.c to opr.c.c and move the flags to opr.c.flags). */ diff -rpC3 libc-save/posix/regexec.c libc/posix/regexec.c *** libc-save/posix/regexec.c Fri Dec 26 00:27:19 2003 --- libc/posix/regexec.c Fri Dec 26 00:27:45 2003 *************** static int check_halt_node_context (cons *** 62,68 **** static int check_halt_state_context (const regex_t *preg, const re_dfastate_t *state, const re_match_context_t *mctx, int idx) internal_function; ! static void update_regs (re_dfa_t *dfa, regmatch_t *pmatch, int cur_node, int cur_idx, int nmatch) internal_function; static int proceed_next_node (const regex_t *preg, int nregs, regmatch_t *regs, const re_match_context_t *mctx, --- 62,69 ---- static int check_halt_state_context (const regex_t *preg, const re_dfastate_t *state, const re_match_context_t *mctx, int idx) internal_function; ! static void update_regs (re_dfa_t *dfa, regmatch_t *pmatch, ! regmatch_t *prev_idx_match, int cur_node, int cur_idx, int nmatch) internal_function; static int proceed_next_node (const regex_t *preg, int nregs, regmatch_t *regs, const re_match_context_t *mctx, *************** set_regs (preg, mctx, nmatch, pmatch, fl *** 1282,1287 **** --- 1283,1290 ---- re_node_set eps_via_nodes; struct re_fail_stack_t *fs; struct re_fail_stack_t fs_body = {0, 2, NULL}; + regmatch_t *prev_idx_match; + #ifdef DEBUG assert (nmatch > 1); assert (mctx->state_log != NULL); *************** set_regs (preg, mctx, nmatch, pmatch, fl *** 1293,1304 **** } else fs = NULL; cur_node = dfa->init_node; real_nmatch = (nmatch <= preg->re_nsub) ? nmatch : preg->re_nsub + 1; re_node_set_init_empty (&eps_via_nodes); for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) { ! update_regs (dfa, pmatch, cur_node, idx, real_nmatch); if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) { int reg_idx; --- 1296,1313 ---- } else fs = NULL; + cur_node = dfa->init_node; real_nmatch = (nmatch <= preg->re_nsub) ? nmatch : preg->re_nsub + 1; re_node_set_init_empty (&eps_via_nodes); + + prev_idx_match = re_malloc (regmatch_t, real_nmatch); + memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * real_nmatch); + for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) { ! update_regs (dfa, pmatch, prev_idx_match, cur_node, idx, real_nmatch); ! if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) { int reg_idx; *************** free_fail_stack_return (fs) *** 1362,1392 **** } static void ! update_regs (dfa, pmatch, cur_node, cur_idx, nmatch) re_dfa_t *dfa; ! regmatch_t *pmatch; int cur_node, cur_idx, nmatch; { int type = dfa->nodes[cur_node].type; - int reg_num; - if (type != OP_OPEN_SUBEXP && type != OP_CLOSE_SUBEXP) - return; - reg_num = dfa->nodes[cur_node].opr.idx + 1; - if (reg_num >= nmatch) - return; if (type == OP_OPEN_SUBEXP) { /* We are at the first node of this sub expression. */ ! pmatch[reg_num].rm_so = cur_idx; ! pmatch[reg_num].rm_eo = -1; } else if (type == OP_CLOSE_SUBEXP) ! /* We are at the first node of this sub expression. */ ! pmatch[reg_num].rm_eo = cur_idx; } - #define NUMBER_OF_STATE 1 - /* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 and sift the nodes in each states according to the following rules. Updated state_log will be wrote to STATE_LOG. --- 1371,1425 ---- } static void ! update_regs (dfa, pmatch, prev_idx_match, cur_node, cur_idx, nmatch) re_dfa_t *dfa; ! regmatch_t *pmatch, *prev_idx_match; int cur_node, cur_idx, nmatch; { int type = dfa->nodes[cur_node].type; if (type == OP_OPEN_SUBEXP) { + int reg_num = dfa->nodes[cur_node].opr.idx + 1; + /* We are at the first node of this sub expression. */ ! if (reg_num < nmatch) ! { ! pmatch[reg_num].rm_so = cur_idx; ! pmatch[reg_num].rm_eo = -1; ! } } else if (type == OP_CLOSE_SUBEXP) ! { ! int reg_num = dfa->nodes[cur_node].opr.idx + 1; ! if (reg_num < nmatch) ! { ! /* We are at the last node of this sub expression. */ ! if (pmatch[reg_num].rm_so < cur_idx) ! { ! pmatch[reg_num].rm_eo = cur_idx; ! /* This is a non-empty match or we are not inside an optional ! subexpression. Accept this right away. */ ! memcpy (prev_idx_match, pmatch, sizeof (regmatch_t) * nmatch); ! } ! else ! { ! if (dfa->nodes[cur_node].opt_subexp ! && prev_idx_match[reg_num].rm_so != -1) ! /* We transited through an empty match for an optional ! subexpression, like (a?)*, and this is not the subexp's ! first match. Copy back the old content of the registers ! so that matches of an inner subexpression are undone as ! well, like in ((a?))*. */ ! memcpy (pmatch, prev_idx_match, sizeof (regmatch_t) * nmatch); ! else ! /* We completed a subexpression, but it may be part of ! an optional one, so do not update PREV_IDX_MATCH. */ ! pmatch[reg_num].rm_eo = cur_idx; ! } ! } ! } } /* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 and sift the nodes in each states according to the following rules. Updated state_log will be wrote to STATE_LOG. diff -rpC3 libc-save/posix/rxspencer/tests libc/posix/rxspencer/tests *** libc-save/posix/rxspencer/tests Fri Dec 26 00:27:19 2003 --- libc/posix/rxspencer/tests Fri Dec 26 00:32:48 2003 *************** a(b|c)*d - abcd abcd c *** 431,437 **** a(b|c)+d - abd abd b a(b|c)+d - abcd abcd c a(b|c?)+d - ad ad @d ! a(b|c?)+d - abcd abcd @d a(b|c){0,0}d - ad ad - a(b|c){0,1}d - ad ad - a(b|c){0,1}d - abd abd b --- 431,437 ---- a(b|c)+d - abd abd b a(b|c)+d - abcd abcd c a(b|c?)+d - ad ad @d ! a(b|c?)+d - abcd abcd c a(b|c){0,0}d - ad ad - a(b|c){0,1}d - ad ad - a(b|c){0,1}d - abd abd b *************** a(b|c){2,4}d - abcbd abcbd b *** 452,460 **** a(b|c){2,4}d - abcbcd abcbcd c a(b|c){2,}d - abcd abcd c a(b|c){2,}d - abcbd abcbd b ! a(b+|((c)*))+d - abd abd @d,@d,- ! # XXX Needs to be checked. ! #a(b+|((c)*))+d - abcd abcd @d,@d,- # check out the STARTEND option [abc] &# a(b)c b --- 452,459 ---- a(b|c){2,4}d - abcbcd abcbcd c a(b|c){2,}d - abcd abcd c a(b|c){2,}d - abcbd abcbd b ! a(b+|((c)*))+d - abd abd b,-,- ! a(b+|((c)*))+d - abcd abcd c,c,c # check out the STARTEND option [abc] &# a(b)c b