X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=regexec.c;h=59fc53e05188620cdef7ab53c4fd919c16313938;hb=07bc277f32c1d7aff237dd3f55d558b5d4b93314;hp=2743c539d54d5eaa12700015c8a4f1f0e74d437e;hpb=81714fb9c03d91d66b66cab6e899e81bf64a2ca7;p=p5sagit%2Fp5-mst-13.2.git diff --git a/regexec.c b/regexec.c index 2743c53..59fc53e 100644 --- a/regexec.c +++ b/regexec.c @@ -56,7 +56,7 @@ **** Alterations to Henry's code are... **** **** Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - **** 2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others + **** 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by Larry Wall and others **** **** You may distribute under the terms of either the GNU General Public **** License or the Artistic License, as specified in the README file. @@ -122,16 +122,34 @@ /* TODO: Combine JUMPABLE and HAS_TEXT to cache OP(rn) */ /* for use after a quantifier and before an EXACT-like node -- japhy */ -#define JUMPABLE(rn) ( \ - OP(rn) == OPEN || OP(rn) == CLOSE || OP(rn) == EVAL || \ +/* it would be nice to rework regcomp.sym to generate this stuff. sigh */ +#define JUMPABLE(rn) ( \ + OP(rn) == OPEN || \ + (OP(rn) == CLOSE && (!cur_eval || cur_eval->u.eval.close_paren != ARG(rn))) || \ + OP(rn) == EVAL || \ OP(rn) == SUSPEND || OP(rn) == IFMATCH || \ OP(rn) == PLUS || OP(rn) == MINMOD || \ + OP(rn) == KEEPS || (PL_regkind[OP(rn)] == VERB) || \ (PL_regkind[OP(rn)] == CURLY && ARG1(rn) > 0) \ ) +#define IS_EXACT(rn) (PL_regkind[OP(rn)] == EXACT) -#define HAS_TEXT(rn) ( \ - PL_regkind[OP(rn)] == EXACT || PL_regkind[OP(rn)] == REF \ -) +#define HAS_TEXT(rn) ( IS_EXACT(rn) || PL_regkind[OP(rn)] == REF ) + +#if 0 +/* Currently these are only used when PL_regkind[OP(rn)] == EXACT so + we don't need this definition. */ +#define IS_TEXT(rn) ( OP(rn)==EXACT || OP(rn)==REF || OP(rn)==NREF ) +#define IS_TEXTF(rn) ( OP(rn)==EXACTF || OP(rn)==REFF || OP(rn)==NREFF ) +#define IS_TEXTFL(rn) ( OP(rn)==EXACTFL || OP(rn)==REFFL || OP(rn)==NREFFL ) + +#else +/* ... so we use this as its faster. */ +#define IS_TEXT(rn) ( OP(rn)==EXACT ) +#define IS_TEXTF(rn) ( OP(rn)==EXACTF ) +#define IS_TEXTFL(rn) ( OP(rn)==EXACTFL ) + +#endif /* Search for mandatory following text node; for lookahead, the text must @@ -166,24 +184,24 @@ S_regcppush(pTHX_ I32 parenfloor) if (paren_elems_to_push < 0) Perl_croak(aTHX_ "panic: paren_elems_to_push < 0"); -#define REGCP_OTHER_ELEMS 8 +#define REGCP_OTHER_ELEMS 7 SSGROW(paren_elems_to_push + REGCP_OTHER_ELEMS); + for (p = PL_regsize; p > parenfloor; p--) { /* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */ - SSPUSHINT(PL_regendp[p]); - SSPUSHINT(PL_regstartp[p]); + SSPUSHINT(PL_regoffs[p].end); + SSPUSHINT(PL_regoffs[p].start); SSPUSHPTR(PL_reg_start_tmp[p]); SSPUSHINT(p); - DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, + DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log, " saving \\%"UVuf" %"IVdf"(%"IVdf")..%"IVdf"\n", - (UV)p, (IV)PL_regstartp[p], + (UV)p, (IV)PL_regoffs[p].start, (IV)(PL_reg_start_tmp[p] - PL_bostr), - (IV)PL_regendp[p] + (IV)PL_regoffs[p].end )); } /* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */ - SSPUSHPTR(PL_regstartp); - SSPUSHPTR(PL_regendp); + SSPUSHPTR(PL_regoffs); SSPUSHINT(PL_regsize); SSPUSHINT(*PL_reglastparen); SSPUSHINT(*PL_reglastcloseparen); @@ -217,7 +235,7 @@ STATIC char * S_regcppop(pTHX_ const regexp *rex) { dVAR; - I32 i; + U32 i; char *input; GET_RE_DEBUG_FLAGS_DECL; @@ -230,8 +248,7 @@ S_regcppop(pTHX_ const regexp *rex) *PL_reglastcloseparen = SSPOPINT; *PL_reglastparen = SSPOPINT; PL_regsize = SSPOPINT; - PL_regendp=(I32 *) SSPOPPTR; - PL_regstartp=(I32 *) SSPOPPTR; + PL_regoffs=(regexp_paren_pair *) SSPOPPTR; /* Now restore the parentheses context. */ @@ -240,20 +257,20 @@ S_regcppop(pTHX_ const regexp *rex) I32 tmps; U32 paren = (U32)SSPOPINT; PL_reg_start_tmp[paren] = (char *) SSPOPPTR; - PL_regstartp[paren] = SSPOPINT; + PL_regoffs[paren].start = SSPOPINT; tmps = SSPOPINT; if (paren <= *PL_reglastparen) - PL_regendp[paren] = tmps; - DEBUG_EXECUTE_r( + PL_regoffs[paren].end = tmps; + DEBUG_BUFFERS_r( PerlIO_printf(Perl_debug_log, " restoring \\%"UVuf" to %"IVdf"(%"IVdf")..%"IVdf"%s\n", - (UV)paren, (IV)PL_regstartp[paren], + (UV)paren, (IV)PL_regoffs[paren].start, (IV)(PL_reg_start_tmp[paren] - PL_bostr), - (IV)PL_regendp[paren], + (IV)PL_regoffs[paren].end, (paren > *PL_reglastparen ? "(no)" : "")); ); } - DEBUG_EXECUTE_r( + DEBUG_BUFFERS_r( if (*PL_reglastparen + 1 <= rex->nparens) { PerlIO_printf(Perl_debug_log, " restoring \\%"IVdf"..\\%"IVdf" to undef\n", @@ -268,13 +285,12 @@ S_regcppop(pTHX_ const regexp *rex) * requiring null fields (pat.t#187 and split.t#{13,14} * (as of patchlevel 7877) will fail. Then again, * this code seems to be necessary or otherwise - * building DynaLoader will fail: - * "Error: '*' not in typemap in DynaLoader.xs, line 164" - * --jhi */ - for (i = *PL_reglastparen + 1; (U32)i <= rex->nparens; i++) { + * this erroneously leaves $1 defined: "1" =~ /^(?:(\d)x)?\d$/ + * --jhi updated by dapm */ + for (i = *PL_reglastparen + 1; i <= rex->nparens; i++) { if (i > PL_regsize) - PL_regstartp[i] = -1; - PL_regendp[i] = -1; + PL_regoffs[i].start = -1; + PL_regoffs[i].end = -1; } #endif return input; @@ -291,7 +307,7 @@ S_regcppop(pTHX_ const regexp *rex) - pregexec - match a regexp against a string */ I32 -Perl_pregexec(pTHX_ register regexp *prog, char *stringarg, register char *strend, +Perl_pregexec(pTHX_ REGEXP * const prog, char* stringarg, register char *strend, char *strbeg, I32 minend, SV *screamer, U32 nosave) /* strend: pointer to null at end of string */ /* strbeg: real beginning of string */ @@ -330,7 +346,11 @@ Perl_pregexec(pTHX_ register regexp *prog, char *stringarg, register char *stren RExen without fixed substrings. Similarly, it is assumed that lengths of all the strings are no more than minlen, thus they cannot come from lookahead. - (Or minlen should take into account lookahead.) */ + (Or minlen should take into account lookahead.) + NOTE: Some of this comment is not correct. minlen does now take account + of lookahead/behind. Further research is required. -- demerphq + +*/ /* A failure to find a constant substring means that there is no need to make an expensive call to REx engine, thus we celebrate a failure. Similarly, @@ -351,8 +371,8 @@ Perl_pregexec(pTHX_ register regexp *prog, char *stringarg, register char *stren deleted from the finite automaton. */ char * -Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, - char *strend, U32 flags, re_scream_pos_data *data) +Perl_re_intuit_start(pTHX_ REGEXP * const prog, SV *sv, char *strpos, + char *strend, const U32 flags, re_scream_pos_data *data) { dVAR; register I32 start_shift = 0; @@ -366,7 +386,8 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, I32 ml_anch; register char *other_last = NULL; /* other substr checked before this */ char *check_at = NULL; /* check substr found at this pos */ - const I32 multiline = prog->reganch & PMf_MULTILINE; + const I32 multiline = prog->extflags & RXf_PMf_MULTILINE; + RXi_GET_DECL(prog,progi); #ifdef DEBUGGING const char * const i_strpos = strpos; #endif @@ -375,7 +396,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, RX_MATCH_UTF8_set(prog,do_utf8); - if (prog->reganch & ROPT_UTF8) { + if (prog->extflags & RXf_UTF8) { PL_reg_flags |= RF_utf8; } DEBUG_EXECUTE_r( @@ -407,14 +428,14 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, "Non-utf8 string cannot match utf8 check string\n")); goto fail; } - if (prog->reganch & ROPT_ANCH) { /* Match at beg-of-str or after \n */ - ml_anch = !( (prog->reganch & ROPT_ANCH_SINGLE) - || ( (prog->reganch & ROPT_ANCH_BOL) + if (prog->extflags & RXf_ANCH) { /* Match at beg-of-str or after \n */ + ml_anch = !( (prog->extflags & RXf_ANCH_SINGLE) + || ( (prog->extflags & RXf_ANCH_BOL) && !multiline ) ); /* Check after \n? */ if (!ml_anch) { - if ( !(prog->reganch & (ROPT_ANCH_GPOS /* Checked by the caller */ - | ROPT_IMPLICIT)) /* not a real BOL */ + if ( !(prog->extflags & RXf_ANCH_GPOS) /* Checked by the caller */ + && !(prog->intflags & PREGf_IMPLICIT) /* not a real BOL */ /* SvCUR is not set on references: SvRV and SvPVX_const overlap */ && sv && !SvROK(sv) && (strpos != strbeg)) { @@ -422,7 +443,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, goto fail; } if (prog->check_offset_min == prog->check_offset_max && - !(prog->reganch & ROPT_CANY_SEEN)) { + !(prog->extflags & RXf_CANY_SEEN)) { /* Substring at constant offset from beg-of-str... */ I32 slen; @@ -477,10 +498,10 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, /* end shift should be non negative here */ } -#ifdef DEBUGGING /* 7/99: reports of failure (with the older version) */ +#ifdef QDEBUGGING /* 7/99: reports of failure (with the older version) */ if (end_shift < 0) Perl_croak(aTHX_ "panic: end_shift: %"IVdf" pattern:\n%s\n ", - (IV)end_shift, prog->precomp); + (IV)end_shift, RX_PRECOMP(prog)); #endif restart: @@ -515,7 +536,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, else goto fail_finish; /* we may be pointing at the wrong string */ - if (s && RX_MATCH_COPIED(prog)) + if (s && RXp_MATCH_COPIED(prog)) s = strbeg + (s - SvPVX_const(sv)); if (data) *data->scream_olds = s; @@ -523,7 +544,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, else { U8* start_point; U8* end_point; - if (prog->reganch & ROPT_CANY_SEEN) { + if (prog->extflags & RXf_CANY_SEEN) { start_point= (U8*)(s + srch_start_shift); end_point= (U8*)(strend - srch_end_shift); } else { @@ -809,17 +830,17 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, if (ml_anch && sv && !SvROK(sv) /* See prev comment on SvROK */ && (strpos != strbeg) && strpos[-1] != '\n' /* May be due to an implicit anchor of m{.*foo} */ - && !(prog->reganch & ROPT_IMPLICIT)) + && !(prog->intflags & PREGf_IMPLICIT)) { t = strpos; goto find_anchor; } DEBUG_EXECUTE_r( if (ml_anch) PerlIO_printf(Perl_debug_log, "Position at offset %ld does not contradict /%s^%s/m...\n", - (long)(strpos - i_strpos), PL_colors[0], PL_colors[1]); + (long)(strpos - i_strpos), PL_colors[0], PL_colors[1]); ); success_at_start: - if (!(prog->reganch & ROPT_NAUGHTY) /* XXXX If strpos moved? */ + if (!(prog->intflags & PREGf_NAUGHTY) /* XXXX If strpos moved? */ && (do_utf8 ? ( prog->check_utf8 /* Could be deleted already */ && --BmUSEFUL(prog->check_utf8) < 0 @@ -842,7 +863,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, /* XXXX This is a remnant of the old implementation. It looks wasteful, since now INTUIT can use many other heuristics. */ - prog->reganch &= ~RE_USE_INTUIT; + prog->extflags &= ~RXf_USE_INTUIT; } else s = strpos; @@ -852,7 +873,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, /* XXXX BmUSEFUL already changed, maybe multiple change is meaningful... */ /* trie stclasses are too expensive to use here, we are better off to leave it to regmatch itself */ - if (prog->regstclass && PL_regkind[OP(prog->regstclass)]!=TRIE) { + if (progi->regstclass && PL_regkind[OP(progi->regstclass)]!=TRIE) { /* minlen == 0 is possible if regstclass is \b or \B, and the fixed substr is ''$. Since minlen is already taken into account, s+1 is before strend; @@ -861,9 +882,9 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, regstclass does not come from lookahead... */ /* If regstclass takes bytelength more than 1: If charlength==1, OK. This leaves EXACTF only, which is dealt with in find_byclass(). */ - const U8* const str = (U8*)STRING(prog->regstclass); - const int cl_l = (PL_regkind[OP(prog->regstclass)] == EXACT - ? CHR_DIST(str+STR_LEN(prog->regstclass), str) + const U8* const str = (U8*)STRING(progi->regstclass); + const int cl_l = (PL_regkind[OP(progi->regstclass)] == EXACT + ? CHR_DIST(str+STR_LEN(progi->regstclass), str) : 1); char * endpos; if (prog->anchored_substr || prog->anchored_utf8 || ml_anch) @@ -873,11 +894,11 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, else endpos= strend; - DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "start_shift: %"IVdf" check_at: %d s: %d endpos: %d\n", - (IV)start_shift, check_at - strbeg, s - strbeg, endpos - strbeg)); + DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "start_shift: %"IVdf" check_at: %"IVdf" s: %"IVdf" endpos: %"IVdf"\n", + (IV)start_shift, (IV)(check_at - strbeg), (IV)(s - strbeg), (IV)(endpos - strbeg))); t = s; - s = find_byclass(prog, prog->regstclass, s, endpos, NULL); + s = find_byclass(prog, progi->regstclass, s, endpos, NULL); if (!s) { #ifdef DEBUGGING const char *what = NULL; @@ -889,7 +910,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, } DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log, "This position contradicts STCLASS...\n") ); - if ((prog->reganch & ROPT_ANCH) && !ml_anch) + if ((prog->extflags & RXf_ANCH) && !ml_anch) goto fail; /* Contradict one of substrings */ if (prog->anchored_substr || prog->anchored_utf8) { @@ -968,10 +989,14 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, return NULL; } +#define DECL_TRIE_TYPE(scan) \ + const enum { trie_plain, trie_utf8, trie_utf8_fold, trie_latin_utf8_fold } \ + trie_type = (scan->flags != EXACT) \ + ? (do_utf8 ? trie_utf8_fold : (UTF ? trie_latin_utf8_fold : trie_plain)) \ + : (do_utf8 ? trie_utf8 : trie_plain) - -#define REXEC_TRIE_READ_CHAR(trie_type, trie, uc, uscan, len, uvc, charid, \ -foldlen, foldbuf, uniflags) STMT_START { \ +#define REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc, uscan, len, \ +uvc, charid, foldlen, foldbuf, uniflags) STMT_START { \ switch (trie_type) { \ case trie_utf8_fold: \ if ( foldlen>0 ) { \ @@ -986,6 +1011,19 @@ foldlen, foldbuf, uniflags) STMT_START { \ uscan = foldbuf + UNISKIP( uvc ); \ } \ break; \ + case trie_latin_utf8_fold: \ + if ( foldlen>0 ) { \ + uvc = utf8n_to_uvuni( uscan, UTF8_MAXLEN, &len, uniflags ); \ + foldlen -= len; \ + uscan += len; \ + len=0; \ + } else { \ + len = 1; \ + uvc = to_uni_fold( *(U8*)uc, foldbuf, &foldlen ); \ + foldlen -= UNISKIP( uvc ); \ + uscan = foldbuf + UNISKIP( uvc ); \ + } \ + break; \ case trie_utf8: \ uvc = utf8n_to_uvuni( (U8*)uc, UTF8_MAXLEN, &len, uniflags ); \ break; \ @@ -999,8 +1037,8 @@ foldlen, foldbuf, uniflags) STMT_START { \ } \ else { \ charid = 0; \ - if (trie->widecharmap) { \ - SV** const svpp = hv_fetch(trie->widecharmap, \ + if (widecharmap) { \ + SV** const svpp = hv_fetch(widecharmap, \ (char*)&uvc, sizeof(UV), 0); \ if (svpp) \ charid = (U16)SvIV(*svpp); \ @@ -1008,12 +1046,14 @@ foldlen, foldbuf, uniflags) STMT_START { \ } \ } STMT_END -#define REXEC_FBC_EXACTISH_CHECK(CoNd) \ +#define REXEC_FBC_EXACTISH_CHECK(CoNd) \ +{ \ + char *my_strend= (char *)strend; \ if ( (CoNd) \ && (ln == len || \ - ibcmp_utf8(s, NULL, 0, do_utf8, \ + !ibcmp_utf8(s, &my_strend, 0, do_utf8, \ m, NULL, ln, (bool)UTF)) \ - && (!reginfo || regtry(reginfo, s)) ) \ + && (!reginfo || regtry(reginfo, &s)) ) \ goto got_it; \ else { \ U8 foldbuf[UTF8_MAXBYTES_CASE+1]; \ @@ -1021,15 +1061,14 @@ foldlen, foldbuf, uniflags) STMT_START { \ f = to_utf8_fold(tmpbuf, foldbuf, &foldlen); \ if ( f != c \ && (f == c1 || f == c2) \ - && (ln == foldlen || \ - !ibcmp_utf8((char *) foldbuf, \ - NULL, foldlen, do_utf8, \ - m, \ - NULL, ln, (bool)UTF)) \ - && (!reginfo || regtry(reginfo, s)) ) \ + && (ln == len || \ + !ibcmp_utf8(s, &my_strend, 0, do_utf8,\ + m, NULL, ln, (bool)UTF)) \ + && (!reginfo || regtry(reginfo, &s)) ) \ goto got_it; \ } \ - s += len +} \ +s += len #define REXEC_FBC_EXACTISH_SCAN(CoNd) \ STMT_START { \ @@ -1038,7 +1077,7 @@ STMT_START { \ && (ln == 1 || !(OP(c) == EXACTF \ ? ibcmp(s, m, ln) \ : ibcmp_locale(s, m, ln))) \ - && (!reginfo || regtry(reginfo, s)) ) \ + && (!reginfo || regtry(reginfo, &s)) ) \ goto got_it; \ s++; \ } \ @@ -1063,7 +1102,7 @@ STMT_START { \ #define REXEC_FBC_UTF8_CLASS_SCAN(CoNd) \ REXEC_FBC_UTF8_SCAN( \ if (CoNd) { \ - if (tmp && (!reginfo || regtry(reginfo, s))) \ + if (tmp && (!reginfo || regtry(reginfo, &s))) \ goto got_it; \ else \ tmp = doevery; \ @@ -1075,7 +1114,7 @@ REXEC_FBC_UTF8_SCAN( \ #define REXEC_FBC_CLASS_SCAN(CoNd) \ REXEC_FBC_SCAN( \ if (CoNd) { \ - if (tmp && (!reginfo || regtry(reginfo, s))) \ + if (tmp && (!reginfo || regtry(reginfo, &s))) \ goto got_it; \ else \ tmp = doevery; \ @@ -1085,9 +1124,18 @@ REXEC_FBC_SCAN( \ ) #define REXEC_FBC_TRYIT \ -if ((!reginfo || regtry(reginfo, s))) \ +if ((!reginfo || regtry(reginfo, &s))) \ goto got_it +#define REXEC_FBC_CSCAN(CoNdUtF8,CoNd) \ + if (do_utf8) { \ + REXEC_FBC_UTF8_CLASS_SCAN(CoNdUtF8); \ + } \ + else { \ + REXEC_FBC_CLASS_SCAN(CoNd); \ + } \ + break + #define REXEC_FBC_CSCAN_PRELOAD(UtFpReLoAd,CoNdUtF8,CoNd) \ if (do_utf8) { \ UtFpReLoAd; \ @@ -1118,10 +1166,10 @@ if ((!reginfo || regtry(reginfo, s))) \ STATIC char * S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, - const char *strend, const regmatch_info *reginfo) + const char *strend, regmatch_info *reginfo) { dVAR; - const I32 doevery = (prog->reganch & ROPT_SKIP) == 0; + const I32 doevery = (prog->intflags & PREGf_SKIP) == 0; char *m; STRLEN ln; STRLEN lnc; @@ -1131,7 +1179,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, char *e; register I32 tmp = 1; /* Scratch variable? */ register const bool do_utf8 = PL_reg_match_utf8; - + RXi_GET_DECL(prog,progi); + /* We know what class it must start with. */ switch (OP(c)) { case ANYOF: @@ -1150,7 +1199,7 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, /* The assignment of 2 is intentional: * for the folded sharp s, the skip is 2. */ (skip = SHARP_S_SKIP))) { - if (tmp && (!reginfo || regtry(reginfo, s))) + if (tmp && (!reginfo || regtry(reginfo, &s))) goto got_it; else tmp = doevery; @@ -1163,7 +1212,7 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, break; case CANY: REXEC_FBC_SCAN( - if (tmp && (!reginfo || regtry(reginfo, s))) + if (tmp && (!reginfo || regtry(reginfo, &s))) goto got_it; else tmp = doevery; @@ -1178,15 +1227,28 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, U8 *sm = (U8 *) m; U8 tmpbuf1[UTF8_MAXBYTES_CASE+1]; U8 tmpbuf2[UTF8_MAXBYTES_CASE+1]; - const U32 uniflags = UTF8_ALLOW_DEFAULT; - - to_utf8_lower((U8*)m, tmpbuf1, &ulen1); - to_utf8_upper((U8*)m, tmpbuf2, &ulen2); - + /* used by commented-out code below */ + /*const U32 uniflags = UTF8_ALLOW_DEFAULT;*/ + + /* XXX: Since the node will be case folded at compile + time this logic is a little odd, although im not + sure that its actually wrong. --dmq */ + + c1 = to_utf8_lower((U8*)m, tmpbuf1, &ulen1); + c2 = to_utf8_upper((U8*)m, tmpbuf2, &ulen2); + + /* XXX: This is kinda strange. to_utf8_XYZ returns the + codepoint of the first character in the converted + form, yet originally we did the extra step. + No tests fail by commenting this code out however + so Ive left it out. -- dmq. + c1 = utf8n_to_uvchr(tmpbuf1, UTF8_MAXBYTES_CASE, 0, uniflags); c2 = utf8n_to_uvchr(tmpbuf2, UTF8_MAXBYTES_CASE, 0, uniflags); + */ + lnc = 0; while (sm < ((U8 *) m + ln)) { lnc++; @@ -1221,24 +1283,33 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, * matching (called "loose matching" in Unicode). * ibcmp_utf8() will do just that. */ - if (do_utf8) { + if (do_utf8 || UTF) { UV c, f; U8 tmpbuf [UTF8_MAXBYTES+1]; - STRLEN len, foldlen; + STRLEN len = 1; + STRLEN foldlen; const U32 uniflags = UTF8_ALLOW_DEFAULT; if (c1 == c2) { /* Upper and lower of 1st char are equal - * probably not a "letter". */ while (s <= e) { - c = utf8n_to_uvchr((U8*)s, UTF8_MAXBYTES, &len, + if (do_utf8) { + c = utf8n_to_uvchr((U8*)s, UTF8_MAXBYTES, &len, uniflags); + } else { + c = *((U8*)s); + } REXEC_FBC_EXACTISH_CHECK(c == c1); } } else { while (s <= e) { - c = utf8n_to_uvchr((U8*)s, UTF8_MAXBYTES, &len, + if (do_utf8) { + c = utf8n_to_uvchr((U8*)s, UTF8_MAXBYTES, &len, uniflags); + } else { + c = *((U8*)s); + } /* Handle some of the three Greek sigmas cases. * Note that not all the possible combinations @@ -1256,6 +1327,7 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, } } else { + /* Neither pattern nor string are UTF8 */ if (c1 == c2) REXEC_FBC_EXACTISH_SCAN(*(U8*)s == c1); else @@ -1297,7 +1369,7 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, } ); } - if ((!prog->minlen && tmp) && (!reginfo || regtry(reginfo, s))) + if ((!prog->minlen && tmp) && (!reginfo || regtry(reginfo, &s))) goto got_it; break; case NBOUNDL: @@ -1333,7 +1405,7 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, else REXEC_FBC_TRYIT; ); } - if ((!prog->minlen && !tmp) && (!reginfo || regtry(reginfo, s))) + if ((!prog->minlen && !tmp) && (!reginfo || regtry(reginfo, &s))) goto got_it; break; case ALNUM: @@ -1402,17 +1474,41 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, !isDIGIT_LC_utf8((U8*)s), !isDIGIT_LC(*s) ); + case LNBREAK: + REXEC_FBC_CSCAN( + is_LNBREAK_utf8(s), + is_LNBREAK_latin1(s) + ); + case VERTWS: + REXEC_FBC_CSCAN( + is_VERTWS_utf8(s), + is_VERTWS_latin1(s) + ); + case NVERTWS: + REXEC_FBC_CSCAN( + !is_VERTWS_utf8(s), + !is_VERTWS_latin1(s) + ); + case HORIZWS: + REXEC_FBC_CSCAN( + is_HORIZWS_utf8(s), + is_HORIZWS_latin1(s) + ); + case NHORIZWS: + REXEC_FBC_CSCAN( + !is_HORIZWS_utf8(s), + !is_HORIZWS_latin1(s) + ); case AHOCORASICKC: case AHOCORASICK: { - const enum { trie_plain, trie_utf8, trie_utf8_fold } - trie_type = do_utf8 ? - (c->flags == EXACT ? trie_utf8 : trie_utf8_fold) - : trie_plain; + DECL_TRIE_TYPE(c); /* what trie are we using right now */ reg_ac_data *aho - = (reg_ac_data*)prog->data->data[ ARG( c ) ]; - reg_trie_data *trie=aho->trie; + = (reg_ac_data*)progi->data->data[ ARG( c ) ]; + reg_trie_data *trie + = (reg_trie_data*)progi->data->data[ aho->trie ]; + HV *widecharmap = (HV*) progi->data->data[ aho->trie + 1 ]; const char *last_start = strend - trie->minlen; #ifdef DEBUGGING @@ -1423,8 +1519,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, U8 **points; /* map of where we were in the input string when reading a given char. For ASCII this is unnecessary overhead as the relationship - is always 1:1, but for unicode, especially - case folded unicode this is not true. */ + is always 1:1, but for Unicode, especially + case folded Unicode this is not true. */ U8 foldbuf[ UTF8_MAXBYTES_CASE + 1 ]; U8 *bitmap=NULL; @@ -1515,8 +1611,9 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, } points[pointpos++ % maxlen]= uc; - REXEC_TRIE_READ_CHAR(trie_type, trie, uc, uscan, len, - uvc, charid, foldlen, foldbuf, uniflags); + REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc, + uscan, len, uvc, charid, foldlen, + foldbuf, uniflags); DEBUG_TRIE_EXECUTE_r({ dump_exec_pos( (char *)uc, c, strend, real_start, s, do_utf8 ); @@ -1589,11 +1686,11 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, s = (char*)leftmost; DEBUG_TRIE_EXECUTE_r({ PerlIO_printf( - Perl_debug_log,"Matches word #%"UVxf" at position %d. Trying full pattern...\n", - (UV)accepted_word, s - real_start + Perl_debug_log,"Matches word #%"UVxf" at position %"IVdf". Trying full pattern...\n", + (UV)accepted_word, (IV)(s - real_start) ); }); - if (!reginfo || regtry(reginfo, s)) { + if (!reginfo || regtry(reginfo, &s)) { FREETMPS; LEAVE; goto got_it; @@ -1621,32 +1718,54 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, return s; } +static void +S_swap_match_buff (pTHX_ regexp *prog) { + regexp_paren_pair *t; + + if (!prog->swap) { + /* We have to be careful. If the previous successful match + was from this regex we don't want a subsequent paritally + successful match to clobber the old results. + So when we detect this possibility we add a swap buffer + to the re, and switch the buffer each match. If we fail + we switch it back, otherwise we leave it swapped. + */ + Newxz(prog->swap, (prog->nparens + 1), regexp_paren_pair); + } + t = prog->swap; + prog->swap = prog->offs; + prog->offs = t; +} + + /* - regexec_flags - match a regexp against a string */ I32 -Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char *strend, +Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *strend, char *strbeg, I32 minend, SV *sv, void *data, U32 flags) /* strend: pointer to null at end of string */ /* strbeg: real beginning of string */ /* minend: end of match must be >=minend after stringarg. */ -/* data: May be used for some additional optimizations. */ +/* data: May be used for some additional optimizations. + Currently its only used, with a U32 cast, for transmitting + the ganch offset when doing a /g match. This will change */ /* nosave: For optimizations. */ { dVAR; - register char *s; + /*register*/ char *s; register regnode *c; - register char *startpos = stringarg; + /*register*/ char *startpos = stringarg; I32 minlen; /* must match at least this many chars */ I32 dontbother = 0; /* how many characters not to try at end */ I32 end_shift = 0; /* Same for the end. */ /* CC */ I32 scream_pos = -1; /* Internal iterator of scream. */ char *scream_olds = NULL; - SV* const oreplsv = GvSV(PL_replgv); const bool do_utf8 = (bool)DO_UTF8(sv); I32 multiline; - + RXi_GET_DECL(prog,progi); regmatch_info reginfo; /* create some info to pass to regtry etc */ + bool swap_on_fail = 0; GET_RE_DEBUG_FLAGS_DECL; @@ -1658,7 +1777,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * return 0; } - multiline = prog->reganch & PMf_MULTILINE; + multiline = prog->extflags & RXf_PMf_MULTILINE; reginfo.prog = prog; RX_MATCH_UTF8_set(prog, do_utf8); @@ -1677,7 +1796,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* Check validity of program. */ - if (UCHARAT(prog->program) != REG_MAGIC) { + if (UCHARAT(progi->program) != REG_MAGIC) { Perl_croak(aTHX_ "corrupted regexp program"); } @@ -1685,7 +1804,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * PL_reg_eval_set = 0; PL_reg_maxiter = 0; - if (prog->reganch & ROPT_UTF8) + if (prog->extflags & RXf_UTF8) PL_reg_flags |= RF_utf8; /* Mark beginning of line for ^ and lookbehind. */ @@ -1702,26 +1821,32 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* If there is a "must appear" string, look for it. */ s = startpos; - if (prog->reganch & ROPT_GPOS_SEEN) { /* Need to set reginfo->ganch */ + if (prog->extflags & RXf_GPOS_SEEN) { /* Need to set reginfo->ganch */ MAGIC *mg; if (flags & REXEC_IGNOREPOS) /* Means: check only at start */ - reginfo.ganch = startpos; + reginfo.ganch = startpos + prog->gofs; else if (sv && SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv) && (mg = mg_find(sv, PERL_MAGIC_regex_global)) && mg->mg_len >= 0) { reginfo.ganch = strbeg + mg->mg_len; /* Defined pos() */ - if (prog->reganch & ROPT_ANCH_GPOS) { + if (prog->extflags & RXf_ANCH_GPOS) { if (s > reginfo.ganch) goto phooey; - s = reginfo.ganch; + s = reginfo.ganch - prog->gofs; } } - else /* pos() not defined */ + else if (data) { + reginfo.ganch = strbeg + PTR2UV(data); + } else /* pos() not defined */ reginfo.ganch = strbeg; } - + if (PL_curpm && (PM_GETRE(PL_curpm) == prog)) { + swap_on_fail = 1; + swap_match_buff(prog); /* do we need a save destructor here for + eval dies? */ + } if (!(flags & REXEC_CHECKED) && (prog->check_substr != NULL || prog->check_utf8 != NULL)) { re_scream_pos_data d; @@ -1738,11 +1863,11 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* Simplest case: anchored match need be tried only once. */ /* [unless only anchor is BOL and multiline is set] */ - if (prog->reganch & (ROPT_ANCH & ~ROPT_ANCH_GPOS)) { - if (s == startpos && regtry(®info, startpos)) + if (prog->extflags & (RXf_ANCH & ~RXf_ANCH_GPOS)) { + if (s == startpos && regtry(®info, &startpos)) goto got_it; - else if (multiline || (prog->reganch & ROPT_IMPLICIT) - || (prog->reganch & ROPT_ANCH_MBOL)) /* XXXX SBOL? */ + else if (multiline || (prog->intflags & PREGf_IMPLICIT) + || (prog->extflags & RXf_ANCH_MBOL)) /* XXXX SBOL? */ { char *end; @@ -1754,12 +1879,12 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * if (s == startpos) goto after_try; while (1) { - if (regtry(®info, s)) + if (regtry(®info, &s)) goto got_it; after_try: - if (s >= end) + if (s > end) goto phooey; - if (prog->reganch & RE_USE_INTUIT) { + if (prog->extflags & RXf_USE_INTUIT) { s = re_intuit_start(prog, sv, s + 1, strend, flags, NULL); if (!s) goto phooey; @@ -1772,25 +1897,26 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * s--; while (s < end) { if (*s++ == '\n') { /* don't need PL_utf8skip here */ - if (regtry(®info, s)) + if (regtry(®info, &s)) goto got_it; } } } } goto phooey; - } else if (ROPT_GPOS_CHECK == (prog->reganch & ROPT_GPOS_CHECK)) + } else if (RXf_GPOS_CHECK == (prog->extflags & RXf_GPOS_CHECK)) { /* the warning about reginfo.ganch being used without intialization - is bogus -- we set it above, when prog->reganch & ROPT_GPOS_SEEN + is bogus -- we set it above, when prog->extflags & RXf_GPOS_SEEN and we only enter this block when the same bit is set. */ - if (regtry(®info, reginfo.ganch)) + char *tmp_s = reginfo.ganch - prog->gofs; + if (regtry(®info, &tmp_s)) goto got_it; goto phooey; } /* Messy cases: unanchored match. */ - if ((prog->anchored_substr || prog->anchored_utf8) && prog->reganch & ROPT_SKIP) { + if ((prog->anchored_substr || prog->anchored_utf8) && prog->intflags & PREGf_SKIP) { /* we have /x+whatever/ */ /* it must be a one character string (XXXX Except UTF?) */ char ch; @@ -1805,7 +1931,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * REXEC_FBC_SCAN( if (*s == ch) { DEBUG_EXECUTE_r( did_match = 1 ); - if (regtry(®info, s)) goto got_it; + if (regtry(®info, &s)) goto got_it; s += UTF8SKIP(s); while (s < strend && *s == ch) s += UTF8SKIP(s); @@ -1816,7 +1942,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * REXEC_FBC_SCAN( if (*s == ch) { DEBUG_EXECUTE_r( did_match = 1 ); - if (regtry(®info, s)) goto got_it; + if (regtry(®info, &s)) goto got_it; s++; while (s < strend && *s == ch) s++; @@ -1883,7 +2009,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * (unsigned char*)strend, must, multiline ? FBMrf_MULTILINE : 0))) ) { /* we may be pointing at the wrong string */ - if ((flags & REXEC_SCREAM) && RX_MATCH_COPIED(prog)) + if ((flags & REXEC_SCREAM) && RXp_MATCH_COPIED(prog)) s = strbeg + (s - SvPVX_const(sv)); DEBUG_EXECUTE_r( did_match = 1 ); if (HOPc(s, -back_max) > last1) { @@ -1898,14 +2024,14 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * } if (do_utf8) { while (s <= last1) { - if (regtry(®info, s)) + if (regtry(®info, &s)) goto got_it; s += UTF8SKIP(s); } } else { while (s <= last1) { - if (regtry(®info, s)) + if (regtry(®info, &s)) goto got_it; s++; } @@ -1921,9 +2047,9 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * }); goto phooey; } - else if ( (c = prog->regstclass) ) { + else if ( (c = progi->regstclass) ) { if (minlen) { - const OPCODE op = OP(prog->regstclass); + const OPCODE op = OP(progi->regstclass); /* don't bother with what can't match */ if (PL_regkind[op] != EXACT && op != CANY && PL_regkind[op] != TRIE) strend = HOPc(strend, -(minlen - 1)); @@ -1932,7 +2058,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * SV * const prop = sv_newmortal(); regprop(prog, prop, c); { - RE_PV_QUOTED_DECL(quoted,UTF,PERL_DEBUG_PAD_ZERO(1), + RE_PV_QUOTED_DECL(quoted,do_utf8,PERL_DEBUG_PAD_ZERO(1), s,strend-s,60); PerlIO_printf(Perl_debug_log, "Matching stclass %.*s against %s (%d chars)\n", @@ -1961,7 +2087,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * if (!last) last = scream_olds; /* Only one occurrence. */ /* we may be pointing at the wrong string */ - else if (RX_MATCH_COPIED(prog)) + else if (RXp_MATCH_COPIED(prog)) s = strbeg + (s - SvPVX_const(sv)); } else { @@ -1999,7 +2125,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* We don't know much -- general case. */ if (do_utf8) { for (;;) { - if (regtry(®info, s)) + if (regtry(®info, &s)) goto got_it; if (s >= strend) break; @@ -2008,7 +2134,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * } else { do { - if (regtry(®info, s)) + if (regtry(®info, &s)) goto got_it; } while (s++ < strend); } @@ -2020,14 +2146,8 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * got_it: RX_MATCH_TAINTED_set(prog, PL_reg_flags & RF_tainted); - if (PL_reg_eval_set) { - /* Preserve the current value of $^R */ - if (oreplsv != GvSV(PL_replgv)) - sv_setsv(oreplsv, GvSV(PL_replgv));/* So that when GvSV(replgv) is - restored, the value remains - the same. */ + if (PL_reg_eval_set) restore_pos(aTHX_ prog); - } if (prog->paren_names) (void)hv_iterinit(prog->paren_names); @@ -2069,6 +2189,10 @@ phooey: PL_colors[4], PL_colors[5])); if (PL_reg_eval_set) restore_pos(aTHX_ prog); + if (swap_on_fail) + /* we failed :-( roll it back */ + swap_match_buff(prog); + return 0; } @@ -2077,16 +2201,16 @@ phooey: - regtry - try match at specific point */ STATIC I32 /* 0 failure, 1 success */ -S_regtry(pTHX_ const regmatch_info *reginfo, char *startpos) +S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) { dVAR; - register I32 *sp; - register I32 *ep; CHECKPOINT lastcp; regexp *prog = reginfo->prog; + RXi_GET_DECL(prog,progi); GET_RE_DEBUG_FLAGS_DECL; + reginfo->cutpoint=NULL; - if ((prog->reganch & ROPT_EVAL_SEEN) && !PL_reg_eval_set) { + if ((prog->extflags & RXf_EVAL_SEEN) && !PL_reg_eval_set) { MAGIC *mg; PL_reg_eval_set = RS_init; @@ -2094,7 +2218,7 @@ S_regtry(pTHX_ const regmatch_info *reginfo, char *startpos) PerlIO_printf(Perl_debug_log, " setting stack tmpbase at %"IVdf"\n", (IV)(PL_stack_sp - PL_stack_base)); )); - SAVEI32(cxstack[cxstack_ix].blk_oldsp); + SAVESTACK_CXPOS(); cxstack[cxstack_ix].blk_oldsp = PL_stack_sp - PL_stack_base; /* Otherwise OP_NEXTSTATE will free whatever on stack now. */ SAVETMPS; @@ -2113,8 +2237,8 @@ S_regtry(pTHX_ const regmatch_info *reginfo, char *startpos) && (mg = mg_find(reginfo->sv, PERL_MAGIC_regex_global)))) { /* prepare for quick setting of pos */ #ifdef PERL_OLD_COPY_ON_WRITE - if (SvIsCOW(sv)) - sv_force_normal_flags(sv, 0); + if (SvIsCOW(reginfo->sv)) + sv_force_normal_flags(reginfo->sv, 0); #endif mg = sv_magicext(reginfo->sv, NULL, PERL_MAGIC_regex_global, &PL_vtbl_mglob, NULL, 0); @@ -2140,7 +2264,7 @@ S_regtry(pTHX_ const regmatch_info *reginfo, char *startpos) PM_SETRE(PL_reg_curpm, prog); PL_reg_oldcurpm = PL_curpm; PL_curpm = PL_reg_curpm; - if (RX_MATCH_COPIED(prog)) { + if (RXp_MATCH_COPIED(prog)) { /* Here is a serious problem: we cannot rewrite subbeg, since it may be needed if this match fails. Thus $` inside (?{}) could fail... */ @@ -2149,23 +2273,22 @@ S_regtry(pTHX_ const regmatch_info *reginfo, char *startpos) #ifdef PERL_OLD_COPY_ON_WRITE PL_nrs = prog->saved_copy; #endif - RX_MATCH_COPIED_off(prog); + RXp_MATCH_COPIED_off(prog); } else PL_reg_oldsaved = NULL; prog->subbeg = PL_bostr; prog->sublen = PL_regeol - PL_bostr; /* strend may have been modified */ } - DEBUG_EXECUTE_r(PL_reg_starttry = startpos); - prog->startp[0] = startpos - PL_bostr; - PL_reginput = startpos; + DEBUG_EXECUTE_r(PL_reg_starttry = *startpos); + prog->offs[0].start = *startpos - PL_bostr; + PL_reginput = *startpos; PL_reglastparen = &prog->lastparen; PL_reglastcloseparen = &prog->lastcloseparen; prog->lastparen = 0; prog->lastcloseparen = 0; PL_regsize = 0; - PL_regstartp = prog->startp; - PL_regendp = prog->endp; + PL_regoffs = prog->offs; if (PL_reg_start_tmpl <= prog->nparens) { PL_reg_start_tmpl = prog->nparens*3/2 + 3; if(PL_reg_start_tmp) @@ -2181,29 +2304,30 @@ S_regtry(pTHX_ const regmatch_info *reginfo, char *startpos) /* Tests pat.t#187 and split.t#{13,14} seem to depend on this code. * Actually, the code in regcppop() (which Ilya may be meaning by * PL_reglastparen), is not needed at all by the test suite - * (op/regexp, op/pat, op/split), but that code is needed, oddly - * enough, for building DynaLoader, or otherwise this - * "Error: '*' not in typemap in DynaLoader.xs, line 164" - * will happen. Meanwhile, this code *is* needed for the + * (op/regexp, op/pat, op/split), but that code is needed otherwise + * this erroneously leaves $1 defined: "1" =~ /^(?:(\d)x)?\d$/ + * Meanwhile, this code *is* needed for the * above-mentioned test suite tests to succeed. The common theme * on those tests seems to be returning null fields from matches. - * --jhi */ + * --jhi updated by dapm */ #if 1 - sp = prog->startp; - ep = prog->endp; if (prog->nparens) { + regexp_paren_pair *pp = PL_regoffs; register I32 i; for (i = prog->nparens; i > (I32)*PL_reglastparen; i--) { - *++sp = -1; - *++ep = -1; + ++pp; + pp->start = -1; + pp->end = -1; } } #endif REGCP_SET(lastcp); - if (regmatch(reginfo, prog->program + 1)) { - prog->endp[0] = PL_reginput - PL_bostr; + if (regmatch(reginfo, progi->program + 1)) { + PL_regoffs[0].end = PL_reginput - PL_bostr; return 1; } + if (reginfo->cutpoint) + *startpos= reginfo->cutpoint; REGCP_UNWIND(lastcp); return 0; } @@ -2241,7 +2365,7 @@ S_regtry(pTHX_ const regmatch_info *reginfo, char *startpos) STATIC regmatch_state * S_push_slab(pTHX) { -#if PERL_VERSION < 9 +#if PERL_VERSION < 9 && !defined(PERL_CORE) dMY_CXT; #endif regmatch_slab *s = PL_regmatch_slab->next; @@ -2410,9 +2534,14 @@ regmatch(), slabs allocated since entry are freed. DEBUG_STATE_r({ \ DUMP_EXEC_POS(locinput, scan, do_utf8); \ PerlIO_printf(Perl_debug_log, \ - " %*s"pp" %s\n", \ + " %*s"pp" %s%s%s%s%s\n", \ depth*2, "", \ - reg_name[st->resume_state] ); \ + PL_reg_name[st->resume_state], \ + ((st==yes_state||st==mark_state) ? "[" : ""), \ + ((st==yes_state) ? "Y" : ""), \ + ((st==mark_state) ? "M" : ""), \ + ((st==yes_state||st==mark_state) ? "]" : "") \ + ); \ }); @@ -2424,12 +2553,12 @@ STATIC void S_debug_start_match(pTHX_ const regexp *prog, const bool do_utf8, const char *start, const char *end, const char *blurb) { - const bool utf8_pat= prog->reganch & ROPT_UTF8 ? 1 : 0; + const bool utf8_pat= prog->extflags & RXf_UTF8 ? 1 : 0; if (!PL_colorset) reginitcolors(); { RE_PV_QUOTED_DECL(s0, utf8_pat, PERL_DEBUG_PAD_ZERO(0), - prog->precomp, prog->prelen, 60); + RXp_PRECOMP(prog), RXp_PRELEN(prog), 60); RE_PV_QUOTED_DECL(s1, do_utf8, PERL_DEBUG_PAD_ZERO(1), start, end - start, 60); @@ -2508,10 +2637,59 @@ S_dump_exec_pos(pTHX_ const char *locinput, #endif +/* reg_check_named_buff_matched() + * Checks to see if a named buffer has matched. The data array of + * buffer numbers corresponding to the buffer is expected to reside + * in the regexp->data->data array in the slot stored in the ARG() of + * node involved. Note that this routine doesn't actually care about the + * name, that information is not preserved from compilation to execution. + * Returns the index of the leftmost defined buffer with the given name + * or 0 if non of the buffers matched. + */ +STATIC I32 +S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan) { + I32 n; + RXi_GET_DECL(rex,rexi); + SV *sv_dat=(SV*)rexi->data->data[ ARG( scan ) ]; + I32 *nums=(I32*)SvPVX(sv_dat); + for ( n=0; n= nums[n] && + PL_regoffs[nums[n]].end != -1) + { + return nums[n]; + } + } + return 0; +} + + +/* free all slabs above current one - called during LEAVE_SCOPE */ + +STATIC void +S_clear_backtrack_stack(pTHX_ void *p) +{ + regmatch_slab *s = PL_regmatch_slab->next; + PERL_UNUSED_ARG(p); + + if (!s) + return; + PL_regmatch_slab->next = NULL; + while (s) { + regmatch_slab * const osl = s; + s = s->next; + Safefree(osl); + } +} + + +#define SETREX(Re1,Re2) \ + if (PL_reg_eval_set) PM_SETRE((PL_reg_curpm), (Re2)); \ + Re1 = (Re2) + STATIC I32 /* 0 failure, 1 success */ -S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) +S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) { -#if PERL_VERSION < 9 +#if PERL_VERSION < 9 && !defined(PERL_CORE) dMY_CXT; #endif dVAR; @@ -2519,9 +2697,9 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) const U32 uniflags = UTF8_ALLOW_DEFAULT; regexp *rex = reginfo->prog; - - regmatch_slab *orig_slab; - regmatch_state *orig_state; + RXi_GET_DECL(rex,rexi); + + I32 oldsave; /* the current state. This is a cached copy of PL_regmatch_state */ register regmatch_state *st; @@ -2529,20 +2707,40 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) /* cache heavy used fields of st in registers */ register regnode *scan; register regnode *next; - register I32 n = 0; /* general value; init to avoid compiler warning */ + register U32 n = 0; /* general value; init to avoid compiler warning */ register I32 ln = 0; /* len or last; init to avoid compiler warning */ register char *locinput = PL_reginput; register I32 nextchr; /* is always set to UCHARAT(locinput) */ bool result = 0; /* return value of S_regmatch */ int depth = 0; /* depth of backtrack stack */ - int nochange_depth = 0; /* depth of RECURSE recursion with nochange*/ + U32 nochange_depth = 0; /* depth of GOSUB recursion with nochange */ + const U32 max_nochange_depth = + (3 * rex->nparens > MAX_RECURSE_EVAL_NOCHANGE_DEPTH) ? + 3 * rex->nparens : MAX_RECURSE_EVAL_NOCHANGE_DEPTH; + regmatch_state *yes_state = NULL; /* state to pop to on success of subpattern */ + /* mark_state piggy backs on the yes_state logic so that when we unwind + the stack on success we can update the mark_state as we go */ + regmatch_state *mark_state = NULL; /* last mark state we have seen */ + regmatch_state *cur_eval = NULL; /* most recent EVAL_AB state */ struct regmatch_state *cur_curlyx = NULL; /* most recent curlyx */ U32 state_num; + bool no_final = 0; /* prevent failure from backtracking? */ + bool do_cutgroup = 0; /* no_final only until next branch/trie entry */ + char *startpoint = PL_reginput; + SV *popmark = NULL; /* are we looking for a mark? */ + SV *sv_commit = NULL; /* last mark name seen in failure */ + SV *sv_yes_mark = NULL; /* last mark name we have seen + during a successfull match */ + U32 lastopen = 0; /* last open we saw */ + bool has_cutgroup = RX_HAS_CUTGROUP(rex) ? 1 : 0; + SV* const oreplsv = GvSV(PL_replgv); + + /* these three flags are set by various ops to signal information to * the very next op. They have a useful lifetime of exactly one loop * iteration, and are not preserved or restored by state pushes/pops @@ -2562,6 +2760,9 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) GET_RE_DEBUG_FLAGS_DECL; #endif + DEBUG_OPTIMISE_r( DEBUG_EXECUTE_r({ + PerlIO_printf(Perl_debug_log,"regmatch start\n"); + })); /* on first ever call to regmatch, allocate first slab */ if (!PL_regmatch_slab) { Newx(PL_regmatch_slab, 1, regmatch_slab); @@ -2570,10 +2771,10 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) PL_regmatch_state = SLAB_FIRST(PL_regmatch_slab); } - /* remember current high-water mark for exit */ - /* XXX this should be done with SAVE* instead */ - orig_slab = PL_regmatch_slab; - orig_state = PL_regmatch_state; + oldsave = PL_savestack_ix; + SAVEDESTRUCTOR_X(S_clear_backtrack_stack, NULL); + SAVEVPTR(PL_regmatch_slab); + SAVEVPTR(PL_regmatch_state); /* grab next free state slot */ st = ++PL_regmatch_state; @@ -2593,10 +2794,10 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) PerlIO_printf(Perl_debug_log, "%3"IVdf":%*s%s(%"IVdf")\n", - (IV)(scan - rex->program), depth*2, "", + (IV)(scan - rexi->program), depth*2, "", SvPVX_const(prop), (PL_regkind[OP(scan)] == END || !rnext) ? - 0 : (IV)(rnext - rex->program)); + 0 : (IV)(rnext - rexi->program)); }); next = scan + NEXT_OFF(scan); @@ -2628,6 +2829,19 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) if (locinput == reginfo->ganch) break; sayNO; + + case KEEPS: + /* update the startpoint */ + st->u.keeper.val = PL_regoffs[0].start; + PL_reginput = locinput; + PL_regoffs[0].start = locinput - PL_bostr; + PUSH_STATE_GOTO(KEEPS_next, next); + /*NOT-REACHED*/ + case KEEPS_next_fail: + /* rollback the start point change */ + PL_regoffs[0].start = st->u.keeper.val; + sayNO_SILENT; + /*NOT-REACHED*/ case EOL: goto seol; case MEOL: @@ -2696,14 +2910,12 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) case TRIE: { /* what type of TRIE am I? (utf8 makes this contextual) */ - const enum { trie_plain, trie_utf8, trie_utf8_fold } - trie_type = do_utf8 ? - (scan->flags == EXACT ? trie_utf8 : trie_utf8_fold) - : trie_plain; + DECL_TRIE_TYPE(scan); /* what trie are we using right now */ reg_trie_data * const trie - = (reg_trie_data*)rex->data->data[ ARG( scan ) ]; + = (reg_trie_data*)rexi->data->data[ ARG( scan ) ]; + HV * widecharmap = (HV *)rexi->data->data[ ARG( scan ) + 1 ]; U32 state = trie->startstate; if (trie->bitmap && trie_type != trie_utf8_fold && @@ -2739,13 +2951,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) ST.accepted = 0; /* how many accepting states we have seen */ ST.B = next; ST.jump = trie->jump; - -#ifdef DEBUGGING ST.me = scan; -#endif - - - /* traverse the TRIE keeping track of all accepting states we transition through until we get to a failing node. @@ -2766,7 +2972,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) if ( got_wordnum ) { if ( ! ST.accepted ) { ENTER; - SAVETMPS; + /* SAVETMPS; */ /* XXX is this necessary? dmq */ bufflen = TRIE_INITAL_ACCEPT_BUFFLEN; sv_accept_buff=newSV(bufflen * sizeof(reg_trie_accepted) - 1); @@ -2804,8 +3010,9 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) }); if ( base ) { - REXEC_TRIE_READ_CHAR(trie_type, trie, uc, uscan, len, - uvc, charid, foldlen, foldbuf, uniflags); + REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc, + uscan, len, uvc, charid, foldlen, + foldbuf, uniflags); if (charid && (base + charid > trie->uniquecharcount ) @@ -2842,47 +3049,79 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) PL_colors[4], (IV)ST.accepted, PL_colors[5] ); ); }} - - /* FALL THROUGH */ - + goto trie_first_try; /* jump into the fail handler */ + /* NOTREACHED */ case TRIE_next_fail: /* we failed - try next alterative */ + if ( ST.jump) { + REGCP_UNWIND(ST.cp); + for (n = *PL_reglastparen; n > ST.lastparen; n--) + PL_regoffs[n].end = -1; + *PL_reglastparen = n; + } + trie_first_try: + if (do_cutgroup) { + do_cutgroup = 0; + no_final = 0; + } + if ( ST.jump) { + ST.lastparen = *PL_reglastparen; + REGCP_SET(ST.cp); + } if ( ST.accepted == 1 ) { /* only one choice left - just continue */ DEBUG_EXECUTE_r({ - reg_trie_data * const trie - = (reg_trie_data*)rex->data->data[ ARG(ST.me) ]; - SV ** const tmp = RX_DEBUG(reginfo->prog) - ? av_fetch( trie->words, ST.accept_buff[ 0 ].wordnum-1, 0 ) - : NULL; + AV *const trie_words + = (AV *) rexi->data->data[ARG(ST.me)+TRIE_WORDS_OFFSET]; + SV ** const tmp = av_fetch( trie_words, + ST.accept_buff[ 0 ].wordnum-1, 0 ); + SV *sv= tmp ? sv_newmortal() : NULL; + PerlIO_printf( Perl_debug_log, "%*s %sonly one match left: #%d <%s>%s\n", REPORT_CODE_OFF+depth*2, "", PL_colors[4], ST.accept_buff[ 0 ].wordnum, - tmp ? SvPV_nolen_const( *tmp ) : "not compiled under -Dr", + tmp ? pv_pretty(sv, SvPV_nolen_const(*tmp), SvCUR(*tmp), 0, + PL_colors[0], PL_colors[1], + (SvUTF8(*tmp) ? PERL_PV_ESCAPE_UNI : 0) + ) + : "not compiled under -Dr", PL_colors[5] ); }); PL_reginput = (char *)ST.accept_buff[ 0 ].endpos; /* in this case we free tmps/leave before we call regmatch as we wont be using accept_buff again. */ - FREETMPS; - LEAVE; + locinput = PL_reginput; nextchr = UCHARAT(locinput); - - if ( !ST.jump ) - scan = ST.B; - else - scan = ST.B - ST.jump[ST.accept_buff[0].wordnum]; + if ( !ST.jump || !ST.jump[ST.accept_buff[0].wordnum]) + scan = ST.B; + else + scan = ST.me + ST.jump[ST.accept_buff[0].wordnum]; + if (!has_cutgroup) { + FREETMPS; + LEAVE; + } else { + ST.accepted--; + PUSH_YES_STATE_GOTO(TRIE_next, scan); + } continue; /* execute rest of RE */ } - - if (!ST.accepted-- ) { + + if ( !ST.accepted-- ) { + DEBUG_EXECUTE_r({ + PerlIO_printf( Perl_debug_log, + "%*s %sTRIE failed...%s\n", + REPORT_CODE_OFF+depth*2, "", + PL_colors[4], + PL_colors[5] ); + }); FREETMPS; LEAVE; - sayNO; - } + sayNO_SILENT; + /*NOTREACHED*/ + } /* There are at least two accepting states left. Presumably @@ -2914,19 +3153,23 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) } DEBUG_EXECUTE_r({ - reg_trie_data * const trie - = (reg_trie_data*)rex->data->data[ ARG(ST.me) ]; - SV ** const tmp = RX_DEBUG(reginfo->prog) - ? av_fetch( trie->words, ST.accept_buff[ best ].wordnum - 1, 0 ) - : NULL; - regnode *nextop=!ST.jump ? + AV *const trie_words + = (AV *) rexi->data->data[ARG(ST.me)+TRIE_WORDS_OFFSET]; + SV ** const tmp = av_fetch( trie_words, + ST.accept_buff[ best ].wordnum - 1, 0 ); + regnode *nextop=(!ST.jump || !ST.jump[ST.accept_buff[best].wordnum]) ? ST.B : - ST.B - ST.jump[ST.accept_buff[best].wordnum]; + ST.me + ST.jump[ST.accept_buff[best].wordnum]; + SV *sv= tmp ? sv_newmortal() : NULL; + PerlIO_printf( Perl_debug_log, "%*s %strying alternation #%d <%s> at node #%d %s\n", REPORT_CODE_OFF+depth*2, "", PL_colors[4], ST.accept_buff[best].wordnum, - tmp ? SvPV_nolen_const( *tmp ) : "not compiled under -Dr", + tmp ? pv_pretty(sv, SvPV_nolen_const(*tmp), SvCUR(*tmp), 0, + PL_colors[0], PL_colors[1], + (SvUTF8(*tmp) ? PERL_PV_ESCAPE_UNI : 0) + ) : "not compiled under -Dr", REG_NODE_NUM(nextop), PL_colors[5] ); }); @@ -2938,17 +3181,19 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) best = ST.accepted; } PL_reginput = (char *)ST.accept_buff[ best ].endpos; - if ( !ST.jump ) { - PUSH_STATE_GOTO(TRIE_next, ST.B); - /* NOTREACHED */ + if ( !ST.jump || !ST.jump[ST.accept_buff[best].wordnum]) { + scan = ST.B; } else { - PUSH_STATE_GOTO(TRIE_next, ST.B - ST.jump[ST.accept_buff[best].wordnum]); - /* NOTREACHED */ + scan = ST.me + ST.jump[ST.accept_buff[best].wordnum]; } + PUSH_YES_STATE_GOTO(TRIE_next, scan); /* NOTREACHED */ } /* NOTREACHED */ - + case TRIE_next: + FREETMPS; + LEAVE; + sayYES; #undef ST case EXACT: { @@ -3021,8 +3266,9 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) * pack("U0U*", 0xDF) =~ /ss/i, * the 0xC3 0x9F are the UTF-8 * byte sequence for the U+00DF. */ + if (!(do_utf8 && - toLOWER(s[0]) == 's' && + toLOWER(s[0]) == 's' && ln >= 2 && toLOWER(s[1]) == 's' && (U8)l[0] == 0xC3 && @@ -3294,27 +3540,21 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) case NREFFL: { char *s; - char type = OP(scan); + char type; PL_reg_flags |= RF_tainted; /* FALL THROUGH */ case NREF: case NREFF: - { - SV *sv_dat=(SV*)rex->data->data[ ARG( scan ) ]; - I32 *nums=(I32*)SvPVX(sv_dat); - for ( n=0; n= nums[n] && - PL_regstartp[nums[n]] != -1 && - PL_regendp[nums[n]] != -1) - { - n = nums[n]; - type = REF + ( type - NREF ); - goto do_ref; - } - } + type = OP(scan); + n = reg_check_named_buff_matched(rex,scan); + + if ( n ) { + type = REF + ( type - NREF ); + goto do_ref; + } else { sayNO; - /* unreached */ - } + } + /* unreached */ case REFFL: PL_reg_flags |= RF_tainted; /* FALL THROUGH */ @@ -3323,17 +3563,17 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) n = ARG(scan); /* which paren pair */ type = OP(scan); do_ref: - ln = PL_regstartp[n]; + ln = PL_regoffs[n].start; PL_reg_leftiter = PL_reg_maxiter; /* Void cache */ - if ((I32)*PL_reglastparen < n || ln == -1) + if (*PL_reglastparen < n || ln == -1) sayNO; /* Do not match unless seen CLOSEn. */ - if (ln == PL_regendp[n]) + if (ln == PL_regoffs[n].end) break; s = PL_bostr + ln; if (do_utf8 && type != REF) { /* REF can do byte comparison */ char *l = locinput; - const char *e = PL_bostr + PL_regendp[n]; + const char *e = PL_bostr + PL_regoffs[n].end; /* * Note that we can't do the "other character" lookup trick as * in the 8-bit case (no pun intended) because in Unicode we @@ -3366,7 +3606,7 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) (UCHARAT(s) != (type == REFF ? PL_fold : PL_fold_locale)[nextchr]))) sayNO; - ln = PL_regendp[n] - ln; + ln = PL_regoffs[n].end - ln; if (locinput + ln > PL_regeol) sayNO; if (ln > 1 && (type == REF @@ -3390,33 +3630,37 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) { SV *ret; regexp *re; - regnode *startpoint; - - case SRECURSE: - case RECURSE: /* /(...(?1))/ */ - if (cur_eval && cur_eval->locinput==locinput) { - if (cur_eval->u.eval.close_paren == ARG(scan)) - Perl_croak(aTHX_ "Infinite recursion in RECURSE in regexp"); - if ( ++nochange_depth > MAX_RECURSE_EVAL_NOCHANGE_DEPTH ) - Perl_croak(aTHX_ "RECURSE without pos change exceeded limit in regexp"); + regexp_internal *rei; + regnode *startpoint; + + case GOSTART: + case GOSUB: /* /(...(?1))/ /(...(?&foo))/ */ + if (cur_eval && cur_eval->locinput==locinput) { + if (cur_eval->u.eval.close_paren == (U32)ARG(scan)) + Perl_croak(aTHX_ "Infinite recursion in regex"); + if ( ++nochange_depth > max_nochange_depth ) + Perl_croak(aTHX_ + "Pattern subroutine nesting without pos change" + " exceeded limit in regex"); } else { nochange_depth = 0; - } + } re = rex; + rei = rexi; (void)ReREFCNT_inc(rex); - if (OP(scan)==RECURSE) { + if (OP(scan)==GOSUB) { startpoint = scan + ARG2L(scan); ST.close_paren = ARG(scan); } else { - startpoint = re->program+1; + startpoint = rei->program+1; ST.close_paren = 0; } goto eval_recurse_doit; /* NOTREACHED */ case EVAL: /* /(?{A})B/ /(??{A})B/ and /(?(?{A})X|Y)B/ */ if (cur_eval && cur_eval->locinput==locinput) { - if ( ++nochange_depth > MAX_RECURSE_EVAL_NOCHANGE_DEPTH ) - Perl_croak(aTHX_ "EVAL without pos change exceeded limit in regexp"); + if ( ++nochange_depth > max_nochange_depth ) + Perl_croak(aTHX_ "EVAL without pos change exceeded limit in regex"); } else { nochange_depth = 0; } @@ -3429,10 +3673,16 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) PAD *old_comppad; n = ARG(scan); - PL_op = (OP_4tree*)rex->data->data[n]; - DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log, " re_eval 0x%"UVxf"\n", PTR2UV(PL_op)) ); - PAD_SAVE_LOCAL(old_comppad, (PAD*)rex->data->data[n + 2]); - PL_regendp[0] = PL_reg_magic->mg_len = locinput - PL_bostr; + PL_op = (OP_4tree*)rexi->data->data[n]; + DEBUG_STATE_r( PerlIO_printf(Perl_debug_log, + " re_eval 0x%"UVxf"\n", PTR2UV(PL_op)) ); + PAD_SAVE_LOCAL(old_comppad, (PAD*)rexi->data->data[n + 2]); + PL_regoffs[0].end = PL_reg_magic->mg_len = locinput - PL_bostr; + + if (sv_yes_mark) { + SV *sv_mrk = get_sv("REGMARK", 1); + sv_setsv(sv_mrk, sv_yes_mark); + } CALLRUNOPS(aTHX); /* Scalar context. */ SPAGAIN; @@ -3457,45 +3707,71 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) { /* extract RE object from returned value; compiling if * necessary */ - MAGIC *mg = NULL; - const SV *sv; - if(SvROK(ret) && SvSMAGICAL(sv = SvRV(ret))) - mg = mg_find(sv, PERL_MAGIC_qr); - else if (SvSMAGICAL(ret)) { - if (SvGMAGICAL(ret)) + re = NULL; + + if (SvROK(ret)) { + const SV *const sv = SvRV(ret); + + if (SvTYPE(sv) == SVt_REGEXP) { + re = ((struct xregexp *)SvANY(sv))->xrx_regexp; + } else if (SvSMAGICAL(sv)) { + mg = mg_find(sv, PERL_MAGIC_qr); + assert(mg); + } + } else if (SvTYPE(ret) == SVt_REGEXP) { + re = ((struct xregexp *)SvANY(ret))->xrx_regexp; + } else if (SvSMAGICAL(ret)) { + if (SvGMAGICAL(ret)) { + /* I don't believe that there is ever qr magic + here. */ + assert(!mg_find(ret, PERL_MAGIC_qr)); sv_unmagic(ret, PERL_MAGIC_qr); - else + } + else { mg = mg_find(ret, PERL_MAGIC_qr); + /* testing suggests mg only ends up non-NULL for + scalars who were upgraded and compiled in the + else block below. In turn, this is only + triggered in the "postponed utf8 string" tests + in t/op/pat.t */ + } } if (mg) { - re = (regexp *)mg->mg_obj; - (void)ReREFCNT_inc(re); + re = (regexp *)mg->mg_obj; /*XXX:dmq*/ + assert(re); } + if (re) + re = reg_temp_copy(re); else { - STRLEN len; - const char * const t = SvPV_const(ret, len); - PMOP pm; + U32 pm_flags = 0; const I32 osize = PL_regsize; - Zero(&pm, 1, PMOP); - if (DO_UTF8(ret)) pm.op_pmdynflags |= PMdf_DYN_UTF8; - re = CALLREGCOMP((char*)t, (char*)t + len, &pm); + if (DO_UTF8(ret)) pm_flags |= RXf_UTF8; + re = CALLREGCOMP(ret, pm_flags); if (!(SvFLAGS(ret) & (SVs_TEMP | SVs_PADTMP | SVf_READONLY - | SVs_GMG))) + | SVs_GMG))) { + /* This isn't a first class regexp. Instead, it's + caching a regexp onto an existing, Perl visible + scalar. */ sv_magic(ret,(SV*)ReREFCNT_inc(re), PERL_MAGIC_qr,0,0); + } PL_regsize = osize; } } + RXp_MATCH_COPIED_off(re); + re->subbeg = rex->subbeg; + re->sublen = rex->sublen; + rei = RXi_GET(re); DEBUG_EXECUTE_r( debug_start_match(re, do_utf8, locinput, PL_regeol, "Matching embedded"); ); - startpoint = re->program + 1; - ST.close_paren = 0; /* only used for RECURSE */ + startpoint = rei->program + 1; + ST.close_paren = 0; /* only used for GOSUB */ /* borrowed from regtry */ if (PL_reg_start_tmpl <= re->nparens) { PL_reg_start_tmpl = re->nparens*3/2 + 3; @@ -3505,23 +3781,23 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) Newx(PL_reg_start_tmp, PL_reg_start_tmpl, char*); } - eval_recurse_doit: /* Share code with RECURSE below this line */ + eval_recurse_doit: /* Share code with GOSUB below this line */ /* run the pattern returned from (??{...}) */ ST.cp = regcppush(0); /* Save *all* the positions. */ REGCP_SET(ST.lastcp); - PL_regstartp = re->startp; /* essentially NOOP on RECURSE */ - PL_regendp = re->endp; /* essentially NOOP on RECURSE */ + PL_regoffs = re->offs; /* essentially NOOP on GOSUB */ *PL_reglastparen = 0; *PL_reglastcloseparen = 0; PL_reginput = locinput; + PL_regsize = 0; /* XXXX This is too dramatic a measure... */ PL_reg_maxiter = 0; ST.toggle_reg_flags = PL_reg_flags; - if (re->reganch & ROPT_UTF8) + if (re->extflags & RXf_UTF8) PL_reg_flags |= RF_utf8; else PL_reg_flags &= ~RF_utf8; @@ -3529,7 +3805,8 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) ST.prev_rex = rex; ST.prev_curlyx = cur_curlyx; - rex = re; + SETREX(rex,re); + rexi = rei; cur_curlyx = NULL; ST.B = next; ST.prev_eval = cur_eval; @@ -3548,12 +3825,15 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) /* note: this is called twice; first after popping B, then A */ PL_reg_flags ^= ST.toggle_reg_flags; ReREFCNT_dec(rex); - rex = ST.prev_rex; + SETREX(rex,ST.prev_rex); + rexi = RXi_GET(rex); regcpblow(ST.cp); cur_eval = ST.prev_eval; cur_curlyx = ST.prev_curlyx; /* XXXX This is too dramatic a measure... */ PL_reg_maxiter = 0; + if ( nochange_depth ) + nochange_depth--; sayYES; @@ -3561,7 +3841,8 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) /* note: this is called twice; first after popping B, then A */ PL_reg_flags ^= ST.toggle_reg_flags; ReREFCNT_dec(rex); - rex = ST.prev_rex; + SETREX(rex,ST.prev_rex); + rexi = RXi_GET(rex); PL_reginput = locinput; REGCP_UNWIND(ST.lastcp); regcppop(rex); @@ -3569,6 +3850,8 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) cur_curlyx = ST.prev_curlyx; /* XXXX This is too dramatic a measure... */ PL_reg_maxiter = 0; + if ( nochange_depth ) + nochange_depth--; sayNO_SILENT; #undef ST @@ -3577,22 +3860,63 @@ S_regmatch(pTHX_ const regmatch_info *reginfo, regnode *prog) PL_reg_start_tmp[n] = locinput; if (n > PL_regsize) PL_regsize = n; + lastopen = n; break; case CLOSE: n = ARG(scan); /* which paren pair */ - PL_regstartp[n] = PL_reg_start_tmp[n] - PL_bostr; - PL_regendp[n] = locinput - PL_bostr; - if (n > (I32)*PL_reglastparen) + PL_regoffs[n].start = PL_reg_start_tmp[n] - PL_bostr; + PL_regoffs[n].end = locinput - PL_bostr; + /*if (n > PL_regsize) + PL_regsize = n;*/ + if (n > *PL_reglastparen) *PL_reglastparen = n; *PL_reglastcloseparen = n; - if (cur_eval && cur_eval->u.eval.close_paren == (U32)n) { + if (cur_eval && cur_eval->u.eval.close_paren == n) { goto fake_end; } break; + case ACCEPT: + if (ARG(scan)){ + regnode *cursor; + for (cursor=scan; + cursor && OP(cursor)!=END; + cursor=regnext(cursor)) + { + if ( OP(cursor)==CLOSE ){ + n = ARG(cursor); + if ( n <= lastopen ) { + PL_regoffs[n].start + = PL_reg_start_tmp[n] - PL_bostr; + PL_regoffs[n].end = locinput - PL_bostr; + /*if (n > PL_regsize) + PL_regsize = n;*/ + if (n > *PL_reglastparen) + *PL_reglastparen = n; + *PL_reglastcloseparen = n; + if ( n == ARG(scan) || (cur_eval && + cur_eval->u.eval.close_paren == n)) + break; + } + } + } + } + goto fake_end; + /*NOTREACHED*/ case GROUPP: n = ARG(scan); /* which paren pair */ - sw = (bool)((I32)*PL_reglastparen >= n && PL_regendp[n] != -1); + sw = (bool)(*PL_reglastparen >= n && PL_regoffs[n].end != -1); + break; + case NGROUPP: + /* reg_check_named_buff_matched returns 0 for no match */ + sw = (bool)(0 < reg_check_named_buff_matched(rex,scan)); break; + case INSUBP: + n = ARG(scan); + sw = (cur_eval && (!n || cur_eval->u.eval.close_paren == n)); + break; + case DEFINEP: + sw = 0; + break; case IFTHEN: PL_reg_leftiter = PL_reg_maxiter; /* Void cache */ if (sw) @@ -3728,7 +4052,6 @@ NULL } case CURLYX_end: /* just finished matching all of A*B */ - regcpblow(ST.cp); cur_curlyx = ST.prev_curlyx; sayYES; /* NOTREACHED */ @@ -3746,7 +4069,6 @@ NULL case WHILEM: /* just matched an A in /A*B/ (for complex A) */ { /* see the discussion above about CURLYX/WHILEM */ - I32 n; assert(cur_curlyx); /* keep Coverity happy */ n = ++cur_curlyx->u.curlyx.count; /* how many A's matched */ @@ -3950,27 +4272,56 @@ NULL case BRANCH: /* /(...|A|...)/ */ scan = NEXTOPER(scan); /* scan now points to inner node */ - if (!next || (OP(next) != BRANCH && OP(next) != BRANCHJ)) - /* last branch; skip state push and jump direct to node */ - continue; ST.lastparen = *PL_reglastparen; ST.next_branch = next; REGCP_SET(ST.cp); PL_reginput = locinput; /* Now go into the branch */ - PUSH_STATE_GOTO(BRANCH_next, scan); + if (has_cutgroup) { + PUSH_YES_STATE_GOTO(BRANCH_next, scan); + } else { + PUSH_STATE_GOTO(BRANCH_next, scan); + } /* NOTREACHED */ - + case CUTGROUP: + PL_reginput = locinput; + sv_yes_mark = st->u.mark.mark_name = scan->flags ? NULL : + (SV*)rexi->data->data[ ARG( scan ) ]; + PUSH_STATE_GOTO(CUTGROUP_next,next); + /* NOTREACHED */ + case CUTGROUP_next_fail: + do_cutgroup = 1; + no_final = 1; + if (st->u.mark.mark_name) + sv_commit = st->u.mark.mark_name; + sayNO; + /* NOTREACHED */ + case BRANCH_next: + sayYES; + /* NOTREACHED */ case BRANCH_next_fail: /* that branch failed; try the next, if any */ + if (do_cutgroup) { + do_cutgroup = 0; + no_final = 0; + } REGCP_UNWIND(ST.cp); for (n = *PL_reglastparen; n > ST.lastparen; n--) - PL_regendp[n] = -1; + PL_regoffs[n].end = -1; *PL_reglastparen = n; + /*dmq: *PL_reglastcloseparen = n; */ scan = ST.next_branch; /* no more branches? */ - if (!scan || (OP(scan) != BRANCH && OP(scan) != BRANCHJ)) - sayNO; + if (!scan || (OP(scan) != BRANCH && OP(scan) != BRANCHJ)) { + DEBUG_EXECUTE_r({ + PerlIO_printf( Perl_debug_log, + "%*s %sBRANCH failed...%s\n", + REPORT_CODE_OFF+depth*2, "", + PL_colors[4], + PL_colors[5] ); + }); + sayNO_SILENT; + } continue; /* execute next BRANCH[J] op */ /* NOTREACHED */ @@ -3994,10 +4345,10 @@ NULL /* if paren positive, emulate an OPEN/CLOSE around A */ if (ST.me->flags) { - I32 paren = ST.me->flags; + U32 paren = ST.me->flags; if (paren > PL_regsize) PL_regsize = paren; - if (paren > (I32)*PL_reglastparen) + if (paren > *PL_reglastparen) *PL_reglastparen = paren; scan += NEXT_OFF(scan); /* Skip former OPEN. */ } @@ -4046,13 +4397,21 @@ NULL ); locinput = PL_reginput; - if (ST.count < (ST.minmod ? ARG1(ST.me) : ARG2(ST.me))) + + if (cur_eval && cur_eval->u.eval.close_paren && + cur_eval->u.eval.close_paren == (U32)ST.me->flags) + goto fake_end; + + if ( ST.count < (ST.minmod ? ARG1(ST.me) : ARG2(ST.me)) ) goto curlym_do_A; /* try to match another A */ goto curlym_do_B; /* try to match B */ case CURLYM_A_fail: /* just failed to match an A */ REGCP_UNWIND(ST.cp); - if (ST.minmod || ST.count < ARG1(ST.me) /* min*/ ) + + if (ST.minmod || ST.count < ARG1(ST.me) /* min*/ + || (cur_eval && cur_eval->u.eval.close_paren && + cur_eval->u.eval.close_paren == (U32)ST.me->flags)) sayNO; curlym_do_B: /* execute the B in /A{m,n}B/ */ @@ -4065,14 +4424,23 @@ NULL regnode *text_node = ST.B; if (! HAS_TEXT(text_node)) FIND_NEXT_IMPT(text_node); - if (HAS_TEXT(text_node) - && PL_regkind[OP(text_node)] != REF) + /* this used to be + + (HAS_TEXT(text_node) && PL_regkind[OP(text_node)] == EXACT) + + But the former is redundant in light of the latter. + + if this changes back then the macro for + IS_TEXT and friends need to change. + */ + if (PL_regkind[OP(text_node)] == EXACT) { + ST.c1 = (U8)*STRING(text_node); ST.c2 = - (OP(text_node) == EXACTF || OP(text_node) == REFF) + (IS_TEXTF(text_node)) ? PL_fold[ST.c1] - : (OP(text_node) == EXACTFL || OP(text_node) == REFFL) + : (IS_TEXTFL(text_node)) ? PL_fold_locale[ST.c1] : ST.c1; } @@ -4090,6 +4458,12 @@ NULL && UCHARAT(PL_reginput) != ST.c2) { /* simulate B failing */ + DEBUG_OPTIMISE_r( + PerlIO_printf(Perl_debug_log, + "%*s CURLYM Fast bail c1=%"IVdf" c2=%"IVdf"\n", + (int)(REPORT_CODE_OFF+(depth*2)),"", + (IV)ST.c1,(IV)ST.c2 + )); state_num = CURLYM_B_fail; goto reenter_switch; } @@ -4098,13 +4472,23 @@ NULL /* mark current A as captured */ I32 paren = ST.me->flags; if (ST.count) { - PL_regstartp[paren] + PL_regoffs[paren].start = HOPc(PL_reginput, -ST.alen) - PL_bostr; - PL_regendp[paren] = PL_reginput - PL_bostr; + PL_regoffs[paren].end = PL_reginput - PL_bostr; + /*dmq: *PL_reglastcloseparen = paren; */ } else - PL_regendp[paren] = -1; + PL_regoffs[paren].end = -1; + if (cur_eval && cur_eval->u.eval.close_paren && + cur_eval->u.eval.close_paren == (U32)ST.me->flags) + { + if (ST.count) + goto fake_end; + else + sayNO; + } } + PUSH_STATE_GOTO(CURLYM_B, ST.B); /* match B */ /* NOTREACHED */ @@ -4128,11 +4512,12 @@ NULL #define CURLY_SETPAREN(paren, success) \ if (paren) { \ if (success) { \ - PL_regstartp[paren] = HOPc(locinput, -1) - PL_bostr; \ - PL_regendp[paren] = locinput - PL_bostr; \ + PL_regoffs[paren].start = HOPc(locinput, -1) - PL_bostr; \ + PL_regoffs[paren].end = locinput - PL_bostr; \ + *PL_reglastcloseparen = paren; \ } \ else \ - PL_regendp[paren] = -1; \ + PL_regoffs[paren].end = -1; \ } case STAR: /* /A*B/ where A is width 1 */ @@ -4151,10 +4536,15 @@ NULL ST.paren = scan->flags; /* Which paren to set */ if (ST.paren > PL_regsize) PL_regsize = ST.paren; - if (ST.paren > (I32)*PL_reglastparen) + if (ST.paren > *PL_reglastparen) *PL_reglastparen = ST.paren; ST.min = ARG1(scan); /* min to match */ ST.max = ARG2(scan); /* max to match */ + if (cur_eval && cur_eval->u.eval.close_paren && + cur_eval->u.eval.close_paren == (U32)ST.paren) { + ST.min=1; + ST.max=1; + } scan = regnext(NEXTOPER(scan) + NODE_STEP_REGNODE); goto repeat; case CURLY: /* /A{m,n}B/ where A is width 1 */ @@ -4184,22 +4574,28 @@ NULL if (! HAS_TEXT(text_node)) ST.c1 = ST.c2 = CHRTEST_VOID; else { - if (PL_regkind[OP(text_node)] == REF) { + if ( PL_regkind[OP(text_node)] != EXACT ) { ST.c1 = ST.c2 = CHRTEST_VOID; goto assume_ok_easy; } else s = (U8*)STRING(text_node); - + + /* Currently we only get here when + + PL_rekind[OP(text_node)] == EXACT + + if this changes back then the macro for IS_TEXT and + friends need to change. */ if (!UTF) { ST.c2 = ST.c1 = *s; - if (OP(text_node) == EXACTF || OP(text_node) == REFF) + if (IS_TEXTF(text_node)) ST.c2 = PL_fold[ST.c1]; - else if (OP(text_node) == EXACTFL || OP(text_node) == REFFL) + else if (IS_TEXTFL(text_node)) ST.c2 = PL_fold_locale[ST.c1]; } else { /* UTF */ - if (OP(text_node) == EXACTF || OP(text_node) == REFF) { + if (IS_TEXTF(text_node)) { STRLEN ulen1, ulen2; U8 tmpbuf1[UTF8_MAXBYTES_CASE+1]; U8 tmpbuf2[UTF8_MAXBYTES_CASE+1]; @@ -4236,7 +4632,7 @@ NULL PL_reginput = locinput; if (minmod) { minmod = 0; - if (ST.min && regrepeat(rex, ST.A, ST.min) < ST.min) + if (ST.min && regrepeat(rex, ST.A, ST.min, depth) < ST.min) sayNO; ST.count = ST.min; locinput = PL_reginput; @@ -4269,7 +4665,7 @@ NULL } else { - ST.count = regrepeat(rex, ST.A, ST.max); + ST.count = regrepeat(rex, ST.A, ST.max, depth); locinput = PL_reginput; if (ST.count < ST.min) sayNO; @@ -4294,7 +4690,7 @@ NULL case CURLY_B_min_known_fail: /* failed to find B in a non-greedy match where c1,c2 valid */ if (ST.paren && ST.count) - PL_regendp[ST.paren] = -1; + PL_regoffs[ST.paren].end = -1; PL_reginput = locinput; /* Could be reset... */ REGCP_UNWIND(ST.cp); @@ -4355,11 +4751,15 @@ NULL /* PL_reginput == oldloc now */ if (n) { ST.count += n; - if (regrepeat(rex, ST.A, n) < n) + if (regrepeat(rex, ST.A, n, depth) < n) sayNO; } PL_reginput = locinput; CURLY_SETPAREN(ST.paren, ST.count); + if (cur_eval && cur_eval->u.eval.close_paren && + cur_eval->u.eval.close_paren == (U32)ST.paren) { + goto fake_end; + } PUSH_STATE_GOTO(CURLY_B_min_known, ST.B); } /* NOTREACHED */ @@ -4368,12 +4768,12 @@ NULL case CURLY_B_min_fail: /* failed to find B in a non-greedy match where c1,c2 invalid */ if (ST.paren && ST.count) - PL_regendp[ST.paren] = -1; + PL_regoffs[ST.paren].end = -1; REGCP_UNWIND(ST.cp); /* failed -- move forward one */ PL_reginput = locinput; - if (regrepeat(rex, ST.A, 1)) { + if (regrepeat(rex, ST.A, 1, depth)) { ST.count++; locinput = PL_reginput; if (ST.count <= ST.max || (ST.max == REG_INFTY && @@ -4381,6 +4781,10 @@ NULL { curly_try_B_min: CURLY_SETPAREN(ST.paren, ST.count); + if (cur_eval && cur_eval->u.eval.close_paren && + cur_eval->u.eval.close_paren == (U32)ST.paren) { + goto fake_end; + } PUSH_STATE_GOTO(CURLY_B_min, ST.B); } } @@ -4390,6 +4794,10 @@ NULL curly_try_B_max: /* a successful greedy match: now try to match B */ + if (cur_eval && cur_eval->u.eval.close_paren && + cur_eval->u.eval.close_paren == (U32)ST.paren) { + goto fake_end; + } { UV c = 0; if (ST.c1 != CHRTEST_VOID) @@ -4407,7 +4815,7 @@ NULL case CURLY_B_max_fail: /* failed to find B in a greedy match */ if (ST.paren && ST.count) - PL_regendp[ST.paren] = -1; + PL_regoffs[ST.paren].end = -1; REGCP_UNWIND(ST.cp); /* back up. */ @@ -4418,20 +4826,18 @@ NULL #undef ST - case END: fake_end: if (cur_eval) { /* we've just finished A in /(??{A})B/; now continue with B */ I32 tmpix; - - st->u.eval.toggle_reg_flags = cur_eval->u.eval.toggle_reg_flags; PL_reg_flags ^= st->u.eval.toggle_reg_flags; st->u.eval.prev_rex = rex; /* inner */ - rex = cur_eval->u.eval.prev_rex; /* outer */ + SETREX(rex,cur_eval->u.eval.prev_rex); + rexi = RXi_GET(rex); cur_curlyx = cur_eval->u.eval.prev_curlyx; ReREFCNT_inc(rex); st->u.eval.cp = regcppush(0); /* Save *all* the positions. */ @@ -4448,9 +4854,12 @@ NULL st->u.eval.prev_eval = cur_eval; cur_eval = cur_eval->u.eval.prev_eval; DEBUG_EXECUTE_r( - PerlIO_printf(Perl_debug_log, "%*s EVAL trying tail ... %x\n", - REPORT_CODE_OFF+depth*2, "",(int)cur_eval);); - PUSH_YES_STATE_GOTO(EVAL_AB, + PerlIO_printf(Perl_debug_log, "%*s EVAL trying tail ... %"UVxf"\n", + REPORT_CODE_OFF+depth*2, "",PTR2UV(cur_eval));); + if ( nochange_depth ) + nochange_depth--; + + PUSH_YES_STATE_GOTO(EVAL_AB, st->u.eval.prev_eval->u.eval.B); /* match B */ } @@ -4461,6 +4870,7 @@ NULL (long)(locinput - PL_reg_starttry), (long)(reginfo->till - PL_reg_starttry), PL_colors[5])); + sayNO_SILENT; /* Cannot match: too short. */ } PL_reginput = locinput; /* put where regtry can find it */ @@ -4545,14 +4955,160 @@ NULL if (next == scan) next = NULL; break; + case COMMIT: + reginfo->cutpoint = PL_regeol; + /* FALLTHROUGH */ + case PRUNE: + PL_reginput = locinput; + if (!scan->flags) + sv_yes_mark = sv_commit = (SV*)rexi->data->data[ ARG( scan ) ]; + PUSH_STATE_GOTO(COMMIT_next,next); + /* NOTREACHED */ + case COMMIT_next_fail: + no_final = 1; + /* FALLTHROUGH */ + case OPFAIL: + sayNO; + /* NOTREACHED */ + +#define ST st->u.mark + case MARKPOINT: + ST.prev_mark = mark_state; + ST.mark_name = sv_commit = sv_yes_mark + = (SV*)rexi->data->data[ ARG( scan ) ]; + mark_state = st; + ST.mark_loc = PL_reginput = locinput; + PUSH_YES_STATE_GOTO(MARKPOINT_next,next); + /* NOTREACHED */ + case MARKPOINT_next: + mark_state = ST.prev_mark; + sayYES; + /* NOTREACHED */ + case MARKPOINT_next_fail: + if (popmark && sv_eq(ST.mark_name,popmark)) + { + if (ST.mark_loc > startpoint) + reginfo->cutpoint = HOPBACKc(ST.mark_loc, 1); + popmark = NULL; /* we found our mark */ + sv_commit = ST.mark_name; + + DEBUG_EXECUTE_r({ + PerlIO_printf(Perl_debug_log, + "%*s %ssetting cutpoint to mark:%"SVf"...%s\n", + REPORT_CODE_OFF+depth*2, "", + PL_colors[4], SVfARG(sv_commit), PL_colors[5]); + }); + } + mark_state = ST.prev_mark; + sv_yes_mark = mark_state ? + mark_state->u.mark.mark_name : NULL; + sayNO; + /* NOTREACHED */ + case SKIP: + PL_reginput = locinput; + if (scan->flags) { + /* (*SKIP) : if we fail we cut here*/ + ST.mark_name = NULL; + ST.mark_loc = locinput; + PUSH_STATE_GOTO(SKIP_next,next); + } else { + /* (*SKIP:NAME) : if there is a (*MARK:NAME) fail where it was, + otherwise do nothing. Meaning we need to scan + */ + regmatch_state *cur = mark_state; + SV *find = (SV*)rexi->data->data[ ARG( scan ) ]; + + while (cur) { + if ( sv_eq( cur->u.mark.mark_name, + find ) ) + { + ST.mark_name = find; + PUSH_STATE_GOTO( SKIP_next, next ); + } + cur = cur->u.mark.prev_mark; + } + } + /* Didn't find our (*MARK:NAME) so ignore this (*SKIP:NAME) */ + break; + case SKIP_next_fail: + if (ST.mark_name) { + /* (*CUT:NAME) - Set up to search for the name as we + collapse the stack*/ + popmark = ST.mark_name; + } else { + /* (*CUT) - No name, we cut here.*/ + if (ST.mark_loc > startpoint) + reginfo->cutpoint = HOPBACKc(ST.mark_loc, 1); + /* but we set sv_commit to latest mark_name if there + is one so they can test to see how things lead to this + cut */ + if (mark_state) + sv_commit=mark_state->u.mark.mark_name; + } + no_final = 1; + sayNO; + /* NOTREACHED */ +#undef ST + case FOLDCHAR: + n = ARG(scan); + if ( n == (U32)what_len_TRICKYFOLD(locinput,do_utf8,ln) ) { + locinput += ln; + } else if ( 0xDF == n && !do_utf8 && !UTF ) { + sayNO; + } else { + U8 folded[UTF8_MAXBYTES_CASE+1]; + STRLEN foldlen; + const char * const l = locinput; + char *e = PL_regeol; + to_uni_fold(n, folded, &foldlen); + + if (ibcmp_utf8((const char*) folded, 0, foldlen, 1, + l, &e, 0, do_utf8)) { + sayNO; + } + locinput = e; + } + nextchr = UCHARAT(locinput); + break; + case LNBREAK: + if ((n=is_LNBREAK(locinput,do_utf8))) { + locinput += n; + nextchr = UCHARAT(locinput); + } else + sayNO; + break; + +#define CASE_CLASS(nAmE) \ + case nAmE: \ + if ((n=is_##nAmE(locinput,do_utf8))) { \ + locinput += n; \ + nextchr = UCHARAT(locinput); \ + } else \ + sayNO; \ + break; \ + case N##nAmE: \ + if ((n=is_##nAmE(locinput,do_utf8))) { \ + sayNO; \ + } else { \ + locinput += UTF8SKIP(locinput); \ + nextchr = UCHARAT(locinput); \ + } \ + break + + CASE_CLASS(VERTWS); + CASE_CLASS(HORIZWS); +#undef CASE_CLASS + default: PerlIO_printf(Perl_error_log, "%"UVxf" %d\n", PTR2UV(scan), OP(scan)); Perl_croak(aTHX_ "regexp memory corruption"); - } + + } /* end switch */ - scan = next; - continue; + /* switch break jumps here */ + scan = next; /* prepare to execute the next op and ... */ + continue; /* ... jump back to the top, reusing st */ /* NOTREACHED */ push_yes_state: @@ -4565,7 +5121,27 @@ NULL { regmatch_state *newst; - DEBUG_STATE_pp("push"); + DEBUG_STACK_r({ + regmatch_state *cur = st; + regmatch_state *curyes = yes_state; + int curd = depth; + regmatch_slab *slab = PL_regmatch_slab; + for (;curd > -1;cur--,curd--) { + if (cur < SLAB_FIRST(slab)) { + slab = slab->prev; + cur = SLAB_LAST(slab); + } + PerlIO_printf(Perl_error_log, "%*s#%-3d %-10s %s\n", + REPORT_CODE_OFF + 2 + depth * 2,"", + curd, PL_reg_name[cur->resume_state], + (curyes == cur) ? "yes" : "" + ); + if (curyes == cur) + curyes = cur->u.yes.prev_yes_state; + } + } else + DEBUG_STATE_pp("push") + ); depth++; st->locinput = locinput; newst = st+1; @@ -4601,7 +5177,13 @@ yes: PL_regmatch_slab = PL_regmatch_slab->prev; st = SLAB_LAST(PL_regmatch_slab); } - DEBUG_STATE_pp("pop (yes)"); + DEBUG_STATE_r({ + if (no_final) { + DEBUG_STATE_pp("pop (no final)"); + } else { + DEBUG_STATE_pp("pop (yes)"); + } + }); depth--; } #else @@ -4618,14 +5200,27 @@ yes: st = yes_state; yes_state = st->u.yes.prev_yes_state; PL_regmatch_state = st; - - state_num = st->resume_state; + + if (no_final) { + locinput= st->locinput; + nextchr = UCHARAT(locinput); + } + state_num = st->resume_state + no_final; goto reenter_switch; } DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "%sMatch successful!%s\n", PL_colors[4], PL_colors[5])); + if (PL_reg_eval_set) { + /* each successfully executed (?{...}) block does the equivalent of + * local $^R = do {...} + * When popping the save stack, all these locals would be undone; + * bypass this by setting the outermost saved $^R to the latest + * value */ + if (oreplsv != GvSV(PL_replgv)) + sv_setsv(oreplsv, GvSV(PL_replgv)); + } result = 1; goto final_exit; @@ -4638,6 +5233,13 @@ no: ); no_silent: + if (no_final) { + if (yes_state) { + goto yes; + } else { + goto final_exit; + } + } if (depth) { /* there's a previous state to backtrack to */ st--; @@ -4660,22 +5262,25 @@ no_silent: result = 0; final_exit: - - /* restore original high-water mark */ - PL_regmatch_slab = orig_slab; - PL_regmatch_state = orig_state; - - /* free all slabs above current one */ - if (orig_slab->next) { - regmatch_slab *sl = orig_slab->next; - orig_slab->next = NULL; - while (sl) { - regmatch_slab * const osl = sl; - sl = sl->next; - Safefree(osl); - } + if (rex->intflags & PREGf_VERBARG_SEEN) { + SV *sv_err = get_sv("REGERROR", 1); + SV *sv_mrk = get_sv("REGMARK", 1); + if (result) { + sv_commit = &PL_sv_no; + if (!sv_yes_mark) + sv_yes_mark = &PL_sv_yes; + } else { + if (!sv_commit) + sv_commit = &PL_sv_yes; + sv_yes_mark = &PL_sv_no; + } + sv_setsv(sv_err, sv_commit); + sv_setsv(sv_mrk, sv_yes_mark); } + /* clean up; in particular, free all slabs above current one */ + LEAVE_SCOPE(oldsave); + return result; } @@ -4688,7 +5293,7 @@ no_silent: * rather than incrementing count on every character. [Er, except utf8.]] */ STATIC I32 -S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max) +S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth) { dVAR; register char *scan; @@ -4696,6 +5301,9 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max) register char *loceol = PL_regeol; register I32 hardcount = 0; register bool do_utf8 = PL_reg_match_utf8; +#ifndef DEBUGGING + PERL_UNUSED_ARG(depth); +#endif scan = PL_reginput; if (max == REG_INFTY) @@ -4858,8 +5466,8 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max) } else { while (scan < loceol && !isSPACE(*scan)) scan++; - break; } + break; case NSPACEL: PL_reg_flags |= RF_tainted; if (do_utf8) { @@ -4901,7 +5509,77 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max) while (scan < loceol && !isDIGIT(*scan)) scan++; } + case LNBREAK: + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && (c=is_LNBREAK_utf8(scan))) { + scan += c; + hardcount++; + } + } else { + /* + LNBREAK can match two latin chars, which is ok, + because we have a null terminated string, but we + have to use hardcount in this situation + */ + while (scan < loceol && (c=is_LNBREAK_latin1(scan))) { + scan+=c; + hardcount++; + } + } + break; + case HORIZWS: + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && (c=is_HORIZWS_utf8(scan))) { + scan += c; + hardcount++; + } + } else { + while (scan < loceol && is_HORIZWS_latin1(scan)) + scan++; + } break; + case NHORIZWS: + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && !is_HORIZWS_utf8(scan)) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && !is_HORIZWS_latin1(scan)) + scan++; + + } + break; + case VERTWS: + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && (c=is_VERTWS_utf8(scan))) { + scan += c; + hardcount++; + } + } else { + while (scan < loceol && is_VERTWS_latin1(scan)) + scan++; + + } + break; + case NVERTWS: + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && !is_VERTWS_utf8(scan)) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && !is_VERTWS_latin1(scan)) + scan++; + + } + break; + default: /* Called on something of 0 width. */ break; /* So match right here or not at all. */ } @@ -4919,7 +5597,7 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max) regprop(prog, prop, p); PerlIO_printf(Perl_debug_log, "%*s %s can match %"IVdf" times out of %"IVdf"...\n", - REPORT_CODE_OFF+1, "", SvPVX_const(prop),(IV)c,(IV)max); + REPORT_CODE_OFF + depth*2, "", SvPVX_const(prop),(IV)c,(IV)max); }); }); @@ -4939,7 +5617,8 @@ Perl_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bool SV *sw = NULL; SV *si = NULL; SV *alt = NULL; - const struct reg_data * const data = prog ? prog->data : NULL; + RXi_GET_DECL(prog,progi); + const struct reg_data * const data = prog ? progi->data : NULL; if (data && data->count) { const U32 n = ARG(node); @@ -4954,8 +5633,8 @@ Perl_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bool * documentation of these array elements. */ si = *ary; - a = SvROK(ary[1]) ? &ary[1] : 0; - b = SvTYPE(ary[2]) == SVt_PVAV ? &ary[2] : 0; + a = SvROK(ary[1]) ? &ary[1] : NULL; + b = SvTYPE(ary[2]) == SVt_PVAV ? &ary[2] : NULL; if (a) sw = *a; @@ -5201,7 +5880,7 @@ restore_pos(pTHX_ void *arg) #ifdef PERL_OLD_COPY_ON_WRITE rex->saved_copy = PL_nrs; #endif - RX_MATCH_COPIED_on(rex); + RXp_MATCH_COPIED_on(rex); } PL_reg_magic->mg_len = PL_reg_oldpos; PL_reg_eval_set = 0; @@ -5212,56 +5891,60 @@ restore_pos(pTHX_ void *arg) STATIC void S_to_utf8_substr(pTHX_ register regexp *prog) { - if (prog->float_substr && !prog->float_utf8) { - SV* const sv = newSVsv(prog->float_substr); - prog->float_utf8 = sv; - sv_utf8_upgrade(sv); - if (SvTAIL(prog->float_substr)) - SvTAIL_on(sv); - if (prog->float_substr == prog->check_substr) - prog->check_utf8 = sv; - } - if (prog->anchored_substr && !prog->anchored_utf8) { - SV* const sv = newSVsv(prog->anchored_substr); - prog->anchored_utf8 = sv; - sv_utf8_upgrade(sv); - if (SvTAIL(prog->anchored_substr)) - SvTAIL_on(sv); - if (prog->anchored_substr == prog->check_substr) - prog->check_utf8 = sv; - } + int i = 1; + do { + if (prog->substrs->data[i].substr + && !prog->substrs->data[i].utf8_substr) { + SV* const sv = newSVsv(prog->substrs->data[i].substr); + prog->substrs->data[i].utf8_substr = sv; + sv_utf8_upgrade(sv); + if (SvVALID(prog->substrs->data[i].substr)) { + const U8 flags = BmFLAGS(prog->substrs->data[i].substr); + if (flags & FBMcf_TAIL) { + /* Trim the trailing \n that fbm_compile added last + time. */ + SvCUR_set(sv, SvCUR(sv) - 1); + /* Whilst this makes the SV technically "invalid" (as its + buffer is no longer followed by "\0") when fbm_compile() + adds the "\n" back, a "\0" is restored. */ + } + fbm_compile(sv, flags); + } + if (prog->substrs->data[i].substr == prog->check_substr) + prog->check_utf8 = sv; + } + } while (i--); } STATIC void S_to_byte_substr(pTHX_ register regexp *prog) { dVAR; - if (prog->float_utf8 && !prog->float_substr) { - SV* sv = newSVsv(prog->float_utf8); - prog->float_substr = sv; - if (sv_utf8_downgrade(sv, TRUE)) { - if (SvTAIL(prog->float_utf8)) - SvTAIL_on(sv); - } else { - SvREFCNT_dec(sv); - prog->float_substr = sv = &PL_sv_undef; - } - if (prog->float_utf8 == prog->check_utf8) - prog->check_substr = sv; - } - if (prog->anchored_utf8 && !prog->anchored_substr) { - SV* sv = newSVsv(prog->anchored_utf8); - prog->anchored_substr = sv; - if (sv_utf8_downgrade(sv, TRUE)) { - if (SvTAIL(prog->anchored_utf8)) - SvTAIL_on(sv); - } else { - SvREFCNT_dec(sv); - prog->anchored_substr = sv = &PL_sv_undef; + int i = 1; + do { + if (prog->substrs->data[i].utf8_substr + && !prog->substrs->data[i].substr) { + SV* sv = newSVsv(prog->substrs->data[i].utf8_substr); + if (sv_utf8_downgrade(sv, TRUE)) { + if (SvVALID(prog->substrs->data[i].utf8_substr)) { + const U8 flags + = BmFLAGS(prog->substrs->data[i].utf8_substr); + if (flags & FBMcf_TAIL) { + /* Trim the trailing \n that fbm_compile added last + time. */ + SvCUR_set(sv, SvCUR(sv) - 1); + } + fbm_compile(sv, flags); + } + } else { + SvREFCNT_dec(sv); + sv = &PL_sv_undef; + } + prog->substrs->data[i].substr = sv; + if (prog->substrs->data[i].utf8_substr == prog->check_utf8) + prog->check_substr = sv; } - if (prog->anchored_utf8 == prog->check_utf8) - prog->check_substr = sv; - } + } while (i--); } /*