X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/ded05c2a789e70bb7204e21b2aa98c6d1ac776c2..a47a8f3cfedd88452255f9cef5132cb5a0be55ed:/regexec.c diff --git a/regexec.c b/regexec.c index cad8f61..5d31d73 100644 --- a/regexec.c +++ b/regexec.c @@ -2,7 +2,11 @@ */ /* - * "One Ring to rule them all, One Ring to find them..." + * One Ring to rule them all, One Ring to find them + & + * [p.v of _The Lord of the Rings_, opening poem] + * [p.50 of _The Lord of the Rings_, I/iii: "The Shadow of the Past"] + * [p.254 of _The Lord of the Rings_, II/ii: "The Council of Elrond"] */ /* This file contains functions for executing a regular expression. See @@ -56,7 +60,8 @@ **** Alterations to Henry's code are... **** **** Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - **** 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 by Larry Wall and others + **** 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + **** 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,8 +127,11 @@ /* 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) || \ @@ -181,25 +189,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); @@ -235,9 +242,10 @@ S_regcppop(pTHX_ const regexp *rex) dVAR; U32 i; char *input; - GET_RE_DEBUG_FLAGS_DECL; + PERL_ARGS_ASSERT_REGCPPOP; + /* Pop REGCP_OTHER_ELEMS before the parentheses loop starts. */ i = SSPOPINT; assert(i == SAVEt_REGCONTEXT); /* Check that the magic cookie is there. */ @@ -246,8 +254,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. */ @@ -256,20 +263,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", @@ -284,13 +291,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 */ + * 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; @@ -307,13 +313,15 @@ 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 */ /* minend: end of match must be >=minend after stringarg. */ /* nosave: For optimizations. */ { + PERL_ARGS_ASSERT_PREGEXEC; + return regexec_flags(prog, stringarg, strend, strbeg, minend, screamer, NULL, nosave ? 0 : REXEC_COPY_STR); @@ -371,10 +379,11 @@ 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 rx, SV *sv, char *strpos, + char *strend, const U32 flags, re_scream_pos_data *data) { dVAR; + struct regexp *const prog = (struct regexp *)SvANY(rx); register I32 start_shift = 0; /* Should be nonnegative! */ register I32 end_shift = 0; @@ -391,16 +400,17 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, #ifdef DEBUGGING const char * const i_strpos = strpos; #endif - GET_RE_DEBUG_FLAGS_DECL; - RX_MATCH_UTF8_set(prog,do_utf8); + PERL_ARGS_ASSERT_RE_INTUIT_START; + + RX_MATCH_UTF8_set(rx,do_utf8); - if (prog->extflags & RXf_UTF8) { + if (RX_UTF8(rx)) { PL_reg_flags |= RF_utf8; } DEBUG_EXECUTE_r( - debug_start_match(prog, do_utf8, strpos, strend, + debug_start_match(rx, do_utf8, strpos, strend, sv ? "Guessing start of match in sv for" : "Guessing start of match in string for"); ); @@ -498,10 +508,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: @@ -536,7 +546,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; @@ -989,24 +999,42 @@ 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, widecharmap, uc, uscan, len, \ uvc, charid, foldlen, foldbuf, uniflags) STMT_START { \ + UV uvc_unfolded = 0; \ switch (trie_type) { \ case trie_utf8_fold: \ if ( foldlen>0 ) { \ - uvc = utf8n_to_uvuni( uscan, UTF8_MAXLEN, &len, uniflags ); \ + uvc_unfolded = uvc = utf8n_to_uvuni( uscan, UTF8_MAXLEN, &len, uniflags ); \ foldlen -= len; \ uscan += len; \ len=0; \ } else { \ - uvc = utf8n_to_uvuni( (U8*)uc, UTF8_MAXLEN, &len, uniflags ); \ + uvc_unfolded = uvc = utf8n_to_uvuni( (U8*)uc, UTF8_MAXLEN, &len, uniflags ); \ uvc = to_uni_fold( uvc, foldbuf, &foldlen ); \ foldlen -= UNISKIP( uvc ); \ 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; \ @@ -1027,14 +1055,19 @@ uvc, charid, foldlen, foldbuf, uniflags) STMT_START { \ charid = (U16)SvIV(*svpp); \ } \ } \ + if (!charid && trie_type == trie_utf8_fold && !UTF) { \ + charid = trie->charmap[uvc_unfolded]; \ + } \ } 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]; \ @@ -1042,15 +1075,14 @@ uvc, charid, 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 { \ @@ -1109,6 +1141,15 @@ REXEC_FBC_SCAN( \ 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; \ @@ -1153,6 +1194,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, register I32 tmp = 1; /* Scratch variable? */ register const bool do_utf8 = PL_reg_match_utf8; RXi_GET_DECL(prog,progi); + + PERL_ARGS_ASSERT_FIND_BYCLASS; /* We know what class it must start with. */ switch (OP(c)) { @@ -1200,15 +1243,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++; @@ -1243,24 +1299,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 @@ -1278,6 +1343,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 @@ -1424,19 +1490,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*)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 ]; + HV *widecharmap = MUTABLE_HV(progi->data->data[ aho->trie + 1 ]); const char *last_start = strend - trie->minlen; #ifdef DEBUGGING @@ -1447,8 +1535,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; @@ -1646,11 +1734,12 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, return s; } + /* - 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 rx, 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 */ @@ -1661,6 +1750,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* nosave: For optimizations. */ { dVAR; + struct regexp *const prog = (struct regexp *)SvANY(rx); /*register*/ char *s; register regnode *c; /*register*/ char *startpos = stringarg; @@ -1669,14 +1759,14 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * 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 */ - + regexp_paren_pair *swap = NULL; GET_RE_DEBUG_FLAGS_DECL; + PERL_ARGS_ASSERT_REGEXEC_FLAGS; PERL_UNUSED_ARG(data); /* Be paranoid... */ @@ -1686,11 +1776,11 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * } multiline = prog->extflags & RXf_PMf_MULTILINE; - reginfo.prog = prog; + reginfo.prog = rx; /* Yes, sorry that this is confusing. */ - RX_MATCH_UTF8_set(prog, do_utf8); + RX_MATCH_UTF8_set(rx, do_utf8); DEBUG_EXECUTE_r( - debug_start_match(prog, do_utf8, startpos, strend, + debug_start_match(rx, do_utf8, startpos, strend, "Matching"); ); @@ -1712,7 +1802,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * PL_reg_eval_set = 0; PL_reg_maxiter = 0; - if (prog->extflags & RXf_UTF8) + if (RX_UTF8(rx)) PL_reg_flags |= RF_utf8; /* Mark beginning of line for ^ and lookbehind. */ @@ -1750,34 +1840,24 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * } else /* pos() not defined */ reginfo.ganch = strbeg; } - if (PL_curpm && (PM_GETRE(PL_curpm) == prog)) { - I32 *t; - if (!progi->swap) { + if (PL_curpm && (PM_GETRE(PL_curpm) == rx)) { /* 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. + was from this regex we don't want a subsequent partially + 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(progi->swap, 1, regexp_paren_ofs); - /* no need to copy these */ - Newxz(progi->swap->startp, prog->nparens + 1, I32); - Newxz(progi->swap->endp, prog->nparens + 1, I32); - } - t = progi->swap->startp; - progi->swap->startp = prog->startp; - prog->startp = t; - t = progi->swap->endp; - progi->swap->endp = prog->endp; - prog->endp = t; + swap = prog->offs; + /* do we need a save destructor here for eval dies? */ + Newxz(prog->offs, (prog->nparens + 1), regexp_paren_pair); } if (!(flags & REXEC_CHECKED) && (prog->check_substr != NULL || prog->check_utf8 != NULL)) { re_scream_pos_data d; d.scream_olds = &scream_olds; d.scream_pos = &scream_pos; - s = re_intuit_start(prog, sv, s, strend, flags, &d); + s = re_intuit_start(rx, sv, s, strend, flags, &d); if (!s) { DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "Not present...\n")); goto phooey; /* not present */ @@ -1807,10 +1887,10 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * if (regtry(®info, &s)) goto got_it; after_try: - if (s >= end) + if (s > end) goto phooey; if (prog->extflags & RXf_USE_INTUIT) { - s = re_intuit_start(prog, sv, s + 1, strend, flags, NULL); + s = re_intuit_start(rx, sv, s + 1, strend, flags, NULL); if (!s) goto phooey; } @@ -1934,7 +2014,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) { @@ -1983,7 +2063,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", @@ -2012,7 +2092,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 { @@ -2069,22 +2149,17 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * goto phooey; got_it: - RX_MATCH_TAINTED_set(prog, PL_reg_flags & RF_tainted); + Safefree(swap); + RX_MATCH_TAINTED_set(rx, 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); + if (RXp_PAREN_NAMES(prog)) + (void)hv_iterinit(RXp_PAREN_NAMES(prog)); /* make sure $`, $&, $', and $digit will work later */ if ( !(flags & REXEC_NOT_FIRST) ) { - RX_MATCH_COPY_FREE(prog); + RX_MATCH_COPY_FREE(rx); if (flags & REXEC_COPY_STR) { const I32 i = PL_regeol - startpos + (stringarg - strbeg); #ifdef PERL_OLD_COPY_ON_WRITE @@ -2101,7 +2176,7 @@ got_it: } else #endif { - RX_MATCH_COPIED_on(prog); + RX_MATCH_COPIED_on(rx); s = savepvn(strbeg, i); prog->subbeg = s; } @@ -2120,22 +2195,16 @@ phooey: PL_colors[4], PL_colors[5])); if (PL_reg_eval_set) restore_pos(aTHX_ prog); - if (progi->swap) { + if (swap) { /* we failed :-( roll it back */ - I32 *t; - t = progi->swap->startp; - progi->swap->startp = prog->startp; - prog->startp = t; - t = progi->swap->endp; - progi->swap->endp = prog->endp; - prog->endp = t; + Safefree(prog->offs); + prog->offs = swap; } + return 0; } - - /* - regtry - try match at specific point */ @@ -2143,12 +2212,14 @@ STATIC I32 /* 0 failure, 1 success */ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) { dVAR; - register I32 *sp; - register I32 *ep; CHECKPOINT lastcp; - regexp *prog = reginfo->prog; + REGEXP *const rx = reginfo->prog; + regexp *const prog = (struct regexp *)SvANY(rx); RXi_GET_DECL(prog,progi); GET_RE_DEBUG_FLAGS_DECL; + + PERL_ARGS_ASSERT_REGTRY; + reginfo->cutpoint=NULL; if ((prog->extflags & RXf_EVAL_SEEN) && !PL_reg_eval_set) { @@ -2171,7 +2242,7 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) /* Make $_ available to executed code. */ if (reginfo->sv != DEFSV) { SAVE_DEFSV; - DEFSV = reginfo->sv; + DEFSV_set(reginfo->sv); } if (!(SvTYPE(reginfo->sv) >= SVt_PVMG && SvMAGIC(reginfo->sv) @@ -2193,19 +2264,28 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) Newxz(PL_reg_curpm, 1, PMOP); #ifdef USE_ITHREADS { - SV* const repointer = newSViv(0); - /* so we know which PL_regex_padav element is PL_reg_curpm */ - SvFLAGS(repointer) |= SVf_BREAK; - av_push(PL_regex_padav,repointer); + SV* const repointer = &PL_sv_undef; + /* this regexp is also owned by the new PL_reg_curpm, which + will try to free it. */ + av_push(PL_regex_padav, repointer); PL_reg_curpm->op_pmoffset = av_len(PL_regex_padav); PL_regex_pad = AvARRAY(PL_regex_padav); } #endif } - PM_SETRE(PL_reg_curpm, prog); +#ifdef USE_ITHREADS + /* It seems that non-ithreads works both with and without this code. + So for efficiency reasons it seems best not to have the code + compiled when it is not needed. */ + /* This is safe against NULLs: */ + ReREFCNT_dec(PM_GETRE(PL_reg_curpm)); + /* PM_reg_curpm owns a reference to this regexp. */ + ReREFCNT_inc(rx); +#endif + PM_SETRE(PL_reg_curpm, rx); 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... */ @@ -2214,7 +2294,7 @@ S_regtry(pTHX_ 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; @@ -2222,15 +2302,14 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) prog->sublen = PL_regeol - PL_bostr; /* strend may have been modified */ } DEBUG_EXECUTE_r(PL_reg_starttry = *startpos); - prog->startp[0] = *startpos - PL_bostr; + 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) @@ -2246,27 +2325,26 @@ S_regtry(pTHX_ 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 = PL_regstartp; - ep = PL_regendp; 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, progi->program + 1)) { - PL_regendp[0] = PL_reginput - PL_bostr; + PL_regoffs[0].end = PL_reginput - PL_bostr; return 1; } if (reginfo->cutpoint) @@ -2308,7 +2386,7 @@ S_regtry(pTHX_ 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; @@ -2479,7 +2557,7 @@ regmatch(), slabs allocated since entry are freed. PerlIO_printf(Perl_debug_log, \ " %*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" : ""), \ @@ -2493,15 +2571,18 @@ regmatch(), slabs allocated since entry are freed. #ifdef DEBUGGING STATIC void -S_debug_start_match(pTHX_ const regexp *prog, const bool do_utf8, +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->extflags & RXf_UTF8 ? 1 : 0; + const bool utf8_pat = RX_UTF8(prog) ? 1 : 0; + + PERL_ARGS_ASSERT_DEBUG_START_MATCH; + if (!PL_colorset) reginitcolors(); { RE_PV_QUOTED_DECL(s0, utf8_pat, PERL_DEBUG_PAD_ZERO(0), - prog->precomp, prog->prelen, 60); + RX_PRECOMP_const(prog), RX_PRELEN(prog), 60); RE_PV_QUOTED_DECL(s1, do_utf8, PERL_DEBUG_PAD_ZERO(1), start, end - start, 60); @@ -2540,6 +2621,8 @@ S_dump_exec_pos(pTHX_ const char *locinput, ? (5 + taill) - l : locinput - loc_bostr; int pref0_len; + PERL_ARGS_ASSERT_DUMP_EXEC_POS; + while (do_utf8 && UTF8_IS_CONTINUATION(*(U8*)(locinput - pref_len))) pref_len++; pref0_len = pref_len - (locinput - loc_reg_starttry); @@ -2590,14 +2673,18 @@ S_dump_exec_pos(pTHX_ const char *locinput, * or 0 if non of the buffers matched. */ STATIC I32 -S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan) { +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 ) ]; + SV *sv_dat= MUTABLE_SV(rexi->data->data[ ARG( scan ) ]); I32 *nums=(I32*)SvPVX(sv_dat); + + PERL_ARGS_ASSERT_REG_CHECK_NAMED_BUFF_MATCHED; + for ( n=0; n= nums[n] && - PL_regendp[nums[n]] != -1) + PL_regoffs[nums[n]].end != -1) { return nums[n]; } @@ -2605,25 +2692,45 @@ S_reg_check_named_buff_matched(pTHX_ const regexp *rex, const regnode *scan) { 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_ regmatch_info *reginfo, regnode *prog) { -#if PERL_VERSION < 9 +#if PERL_VERSION < 9 && !defined(PERL_CORE) dMY_CXT; #endif dVAR; register const bool do_utf8 = PL_reg_match_utf8; const U32 uniflags = UTF8_ALLOW_DEFAULT; - - regexp *rex = reginfo->prog; + REGEXP *rex_sv = reginfo->prog; + regexp *rex = (struct regexp *)SvANY(rex_sv); RXi_GET_DECL(rex,rexi); - - regmatch_slab *orig_slab; - regmatch_state *orig_state; - + I32 oldsave; /* the current state. This is a cached copy of PL_regmatch_state */ register regmatch_state *st; - /* cache heavy used fields of st in registers */ register regnode *scan; register regnode *next; @@ -2634,13 +2741,15 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) bool result = 0; /* return value of S_regmatch */ int depth = 0; /* depth of backtrack stack */ - int nochange_depth = 0; /* depth of GOSUB 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; @@ -2653,8 +2762,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) 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 @@ -2669,14 +2777,15 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) false: plain (?=foo) true: used as a condition: (?(?=foo)) */ - #ifdef DEBUGGING GET_RE_DEBUG_FLAGS_DECL; #endif - DEBUG_OPTIMISE_r( { + PERL_ARGS_ASSERT_REGMATCH; + + 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); @@ -2685,10 +2794,10 @@ S_regmatch(pTHX_ 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; @@ -2720,6 +2829,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) state_num = OP(scan); reenter_switch: + + assert(PL_reglastparen == &rex->lastparen); + assert(PL_reglastcloseparen == &rex->lastcloseparen); + assert(PL_regoffs == rex->offs); + switch (state_num) { case BOL: if (locinput == PL_bostr) @@ -2746,14 +2860,14 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) case KEEPS: /* update the startpoint */ - st->u.keeper.val = PL_regstartp[0]; + st->u.keeper.val = PL_regoffs[0].start; PL_reginput = locinput; - PL_regstartp[0] = locinput - PL_bostr; + 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_regstartp[0] = st->u.keeper.val; + PL_regoffs[0].start = st->u.keeper.val; sayNO_SILENT; /*NOT-REACHED*/ case EOL: @@ -2824,15 +2938,12 @@ S_regmatch(pTHX_ 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*)rexi->data->data[ ARG( scan ) ]; - HV * widecharmap = (HV *)rexi->data->data[ ARG( scan ) + 1 ]; + HV * widecharmap = MUTABLE_HV(rexi->data->data[ ARG( scan ) + 1 ]); U32 state = trie->startstate; if (trie->bitmap && trie_type != trie_utf8_fold && @@ -2869,7 +2980,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) ST.B = next; ST.jump = trie->jump; ST.me = scan; - /* traverse the TRIE keeping track of all accepting states we transition through until we get to a failing node. @@ -2890,7 +3000,7 @@ S_regmatch(pTHX_ 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); @@ -2967,18 +3077,30 @@ S_regmatch(pTHX_ 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({ AV *const trie_words - = (AV *) rexi->data->data[ARG(ST.me)+TRIE_WORDS_OFFSET]; + = MUTABLE_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; @@ -3014,8 +3136,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) continue; /* execute rest of RE */ } - - if (!ST.accepted-- ) { + + if ( !ST.accepted-- ) { DEBUG_EXECUTE_r({ PerlIO_printf( Perl_debug_log, "%*s %sTRIE failed...%s\n", @@ -3026,7 +3148,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) FREETMPS; LEAVE; sayNO_SILENT; - } + /*NOTREACHED*/ + } /* There are at least two accepting states left. Presumably @@ -3059,7 +3182,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) DEBUG_EXECUTE_r({ AV *const trie_words - = (AV *) rexi->data->data[ARG(ST.me)+TRIE_WORDS_OFFSET]; + = MUTABLE_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]) ? @@ -3088,22 +3211,17 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PL_reginput = (char *)ST.accept_buff[ best ].endpos; if ( !ST.jump || !ST.jump[ST.accept_buff[best].wordnum]) { scan = ST.B; - /* NOTREACHED */ } else { scan = ST.me + ST.jump[ST.accept_buff[best].wordnum]; - /* NOTREACHED */ - } - if (has_cutgroup) { - PUSH_YES_STATE_GOTO(TRIE_next, scan); - /* NOTREACHED */ - } else { - PUSH_STATE_GOTO(TRIE_next, scan); - /* NOTREACHED */ } + PUSH_YES_STATE_GOTO(TRIE_next, scan); /* NOTREACHED */ } /* NOTREACHED */ case TRIE_next: + /* we dont want to throw this away, see bug 57042*/ + if (oreplsv != GvSV(PL_replgv)) + sv_setsv(oreplsv, GvSV(PL_replgv)); FREETMPS; LEAVE; sayYES; @@ -3179,8 +3297,9 @@ S_regmatch(pTHX_ 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 && @@ -3475,17 +3594,17 @@ S_regmatch(pTHX_ 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 (*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 @@ -3518,7 +3637,7 @@ S_regmatch(pTHX_ 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 @@ -3541,25 +3660,27 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) #define ST st->u.eval { SV *ret; + REGEXP *re_sv; regexp *re; regexp_internal *rei; regnode *startpoint; case GOSTART: - case GOSUB: /* /(...(?1))/ */ - if (cur_eval && cur_eval->locinput==locinput) { + 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_RECURSE_EVAL_NOCHANGE_DEPTH ) + if ( ++nochange_depth > max_nochange_depth ) Perl_croak(aTHX_ "Pattern subroutine nesting without pos change" " exceeded limit in regex"); } else { nochange_depth = 0; } + re_sv = rex_sv; re = rex; rei = rexi; - (void)ReREFCNT_inc(rex); + (void)ReREFCNT_inc(rex_sv); if (OP(scan)==GOSUB) { startpoint = scan + ARG2L(scan); ST.close_paren = ARG(scan); @@ -3571,14 +3692,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) /* 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 ) + if ( ++nochange_depth > max_nochange_depth ) Perl_croak(aTHX_ "EVAL without pos change exceeded limit in regex"); } else { nochange_depth = 0; } - { regexp *ocurpm = PM_GETRE(PL_curpm); - char *osubbeg = rex->subbeg; - STRLEN osublen = rex->sublen; { /* execute the code in the {...} */ dSP; @@ -3586,23 +3704,19 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) OP_4tree * const oop = PL_op; COP * const ocurcop = PL_curcop; PAD *old_comppad; - + char *saved_regeol = PL_regeol; n = ARG(scan); 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_regendp[0] = PL_reg_magic->mg_len = locinput - PL_bostr; + 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); } - /* make sure that $1 and friends are available with nested eval */ - PM_SETRE(PL_curpm,rex); - rex->subbeg = ocurpm->subbeg; - rex->sublen = ocurpm->sublen; CALLRUNOPS(aTHX); /* Scalar context. */ SPAGAIN; @@ -3616,7 +3730,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PL_op = oop; PAD_RESTORE_LOCAL(old_comppad); PL_curcop = ocurcop; - + PL_regeol = saved_regeol; if (!logical) { /* /(?{...})/ */ sv_setsv(save_scalar(PL_replgv), ret); @@ -3628,48 +3742,80 @@ S_regmatch(pTHX_ 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)) + REGEXP *rx = NULL; + + if (SvROK(ret)) { + SV *const sv = SvRV(ret); + + if (SvTYPE(sv) == SVt_REGEXP) { + rx = (REGEXP*) sv; + } else if (SvSMAGICAL(sv)) { + mg = mg_find(sv, PERL_MAGIC_qr); + assert(mg); + } + } else if (SvTYPE(ret) == SVt_REGEXP) { + rx = (REGEXP*) ret; + } 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); + rx = (REGEXP *) mg->mg_obj; /*XXX:dmq*/ + assert(rx); + } + if (rx) { + rx = reg_temp_copy(rx); } 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)) { + assert (SvUTF8(ret)); + } else if (SvUTF8(ret)) { + /* Not doing UTF-8, despite what the SV says. Is + this only if we're trapped in use 'bytes'? */ + /* Make a copy of the octet sequence, but without + the flag on, as the compiler now honours the + SvUTF8 flag on ret. */ + STRLEN len; + const char *const p = SvPV(ret, len); + ret = newSVpvn_flags(p, len, SVs_TEMP); + } + rx = CALLREGCOMP(ret, pm_flags); if (!(SvFLAGS(ret) & (SVs_TEMP | SVs_PADTMP | SVf_READONLY - | SVs_GMG))) - sv_magic(ret,(SV*)ReREFCNT_inc(re), - PERL_MAGIC_qr,0,0); + | SVs_GMG))) { + /* This isn't a first class regexp. Instead, it's + caching a regexp onto an existing, Perl visible + scalar. */ + sv_magic(ret, MUTABLE_SV(rx), PERL_MAGIC_qr, 0, 0); + } PL_regsize = osize; } + re_sv = rx; + re = (struct regexp *)SvANY(rx); } + RXp_MATCH_COPIED_off(re); + re->subbeg = rex->subbeg; + re->sublen = rex->sublen; rei = RXi_GET(re); - - /* restore PL_curpm after the eval */ - PM_SETRE(PL_curpm,ocurpm); - rex->sublen = osublen; - rex->subbeg = osubbeg; - DEBUG_EXECUTE_r( - debug_start_match(re, do_utf8, locinput, PL_regeol, + debug_start_match(re_sv, do_utf8, locinput, PL_regeol, "Matching embedded"); ); startpoint = rei->program + 1; @@ -3681,19 +3827,21 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) Renew(PL_reg_start_tmp, PL_reg_start_tmpl, char*); else Newx(PL_reg_start_tmp, PL_reg_start_tmpl, char*); - } - + } 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 GOSUB */ - PL_regendp = re->endp; /* essentially NOOP on GOSUB */ + PL_regoffs = re->offs; /* essentially NOOP on GOSUB */ - *PL_reglastparen = 0; - *PL_reglastcloseparen = 0; + /* see regtry, specifically PL_reglast(?:close)?paren is a pointer! (i dont know why) :dmq */ + PL_reglastparen = &re->lastparen; + PL_reglastcloseparen = &re->lastcloseparen; + re->lastparen = 0; + re->lastcloseparen = 0; + PL_reginput = locinput; PL_regsize = 0; @@ -3701,14 +3849,15 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PL_reg_maxiter = 0; ST.toggle_reg_flags = PL_reg_flags; - if (re->extflags & RXf_UTF8) + if (RX_UTF8(re_sv)) PL_reg_flags |= RF_utf8; else PL_reg_flags &= ~RF_utf8; ST.toggle_reg_flags ^= PL_reg_flags; /* diff of old and new */ - ST.prev_rex = rex; + ST.prev_rex = rex_sv; ST.prev_curlyx = cur_curlyx; + SETREX(rex_sv,re_sv); rex = re; rexi = rei; cur_curlyx = NULL; @@ -3719,11 +3868,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) PUSH_YES_STATE_GOTO(EVAL_AB, startpoint); /* NOTREACHED */ } - /* restore PL_curpm after the eval */ - PM_SETRE(PL_curpm,ocurpm); - rex->sublen = osublen; - rex->subbeg = osubbeg; - } /* logical is 1, /(?(?{...})X|Y)/ */ sw = (bool)SvTRUE(ret); logical = 0; @@ -3733,23 +3877,38 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) case EVAL_AB: /* cleanup after a successful (??{A})B */ /* 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; + ReREFCNT_dec(rex_sv); + SETREX(rex_sv,ST.prev_rex); + rex = (struct regexp *)SvANY(rex_sv); rexi = RXi_GET(rex); regcpblow(ST.cp); cur_eval = ST.prev_eval; cur_curlyx = ST.prev_curlyx; + + /* rex was changed so update the pointer in PL_reglastparen and PL_reglastcloseparen */ + PL_reglastparen = &rex->lastparen; + PL_reglastcloseparen = &rex->lastcloseparen; + /* also update PL_regoffs */ + PL_regoffs = rex->offs; + /* XXXX This is too dramatic a measure... */ PL_reg_maxiter = 0; + if ( nochange_depth ) + nochange_depth--; sayYES; case EVAL_AB_fail: /* unsuccessfully ran A or B in (??{A})B */ /* 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; + ReREFCNT_dec(rex_sv); + SETREX(rex_sv,ST.prev_rex); + rex = (struct regexp *)SvANY(rex_sv); rexi = RXi_GET(rex); + /* rex was changed so update the pointer in PL_reglastparen and PL_reglastcloseparen */ + PL_reglastparen = &rex->lastparen; + PL_reglastcloseparen = &rex->lastcloseparen; + PL_reginput = locinput; REGCP_UNWIND(ST.lastcp); regcppop(rex); @@ -3757,6 +3916,8 @@ S_regmatch(pTHX_ 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 @@ -3769,8 +3930,8 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) 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; + 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) @@ -3790,8 +3951,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) if ( OP(cursor)==CLOSE ){ n = ARG(cursor); if ( n <= lastopen ) { - PL_regstartp[n] = PL_reg_start_tmp[n] - PL_bostr; - PL_regendp[n] = locinput - PL_bostr; + 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) @@ -3808,7 +3970,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) /*NOTREACHED*/ case GROUPP: n = ARG(scan); /* which paren pair */ - sw = (bool)(*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 */ @@ -3956,15 +4118,6 @@ NULL } case CURLYX_end: /* just finished matching all of A*B */ - if (PL_reg_eval_set){ - SV *pres= GvSV(PL_replgv); - SvREFCNT_inc(pres); - regcpblow(ST.cp); - sv_setsv(GvSV(PL_replgv), pres); - SvREFCNT_dec(pres); - } else { - regcpblow(ST.cp); - } cur_curlyx = ST.prev_curlyx; sayYES; /* NOTREACHED */ @@ -4185,12 +4338,6 @@ NULL case BRANCH: /* /(...|A|...)/ */ scan = NEXTOPER(scan); /* scan now points to inner node */ - if ((!next || (OP(next) != BRANCH && OP(next) != BRANCHJ)) - && !has_cutgroup) - { - /* last branch; skip state push and jump direct to node */ - continue; - } ST.lastparen = *PL_reglastparen; ST.next_branch = next; REGCP_SET(ST.cp); @@ -4206,7 +4353,7 @@ NULL case CUTGROUP: PL_reginput = locinput; sv_yes_mark = st->u.mark.mark_name = scan->flags ? NULL : - (SV*)rexi->data->data[ ARG( scan ) ]; + MUTABLE_SV(rexi->data->data[ ARG( scan ) ]); PUSH_STATE_GOTO(CUTGROUP_next,next); /* NOTREACHED */ case CUTGROUP_next_fail: @@ -4226,7 +4373,7 @@ NULL } 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; @@ -4254,7 +4401,7 @@ NULL case CURLYM: /* /A{m,n}B/ where A is fixed-length */ /* This is an optimisation of CURLYX that enables us to push - * only a single backtracking state, no matter now many matches + * only a single backtracking state, no matter how many matches * there are in {m,n}. It relies on the pattern being constant * length, with no parens to influence future backrefs */ @@ -4321,8 +4468,11 @@ NULL 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 */ + { + I32 max = (ST.minmod ? ARG1(ST.me) : ARG2(ST.me)); + if ( max == REG_INFTY || ST.count < max ) + 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 */ @@ -4377,6 +4527,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; } @@ -4385,13 +4541,13 @@ 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) { @@ -4408,7 +4564,8 @@ NULL case CURLYM_B_fail: /* just failed to match a B */ REGCP_UNWIND(ST.cp); if (ST.minmod) { - if (ST.count == ARG2(ST.me) /* max */) + I32 max = ARG2(ST.me); + if (max != REG_INFTY && ST.count == max) sayNO; goto curlym_do_A; /* try to match a further A */ } @@ -4425,12 +4582,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 */ @@ -4603,7 +4760,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); @@ -4681,7 +4838,7 @@ 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 */ @@ -4728,7 +4885,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. */ @@ -4744,18 +4901,22 @@ NULL 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 */ + st->u.eval.prev_rex = rex_sv; /* inner */ + SETREX(rex_sv,cur_eval->u.eval.prev_rex); + rex = (struct regexp *)SvANY(rex_sv); rexi = RXi_GET(rex); cur_curlyx = cur_eval->u.eval.prev_curlyx; - ReREFCNT_inc(rex); + ReREFCNT_inc(rex_sv); st->u.eval.cp = regcppush(0); /* Save *all* the positions. */ + + /* rex was changed so update the pointer in PL_reglastparen and PL_reglastcloseparen */ + PL_reglastparen = &rex->lastparen; + PL_reglastcloseparen = &rex->lastcloseparen; + REGCP_SET(st->u.eval.lastcp); PL_reginput = locinput; @@ -4771,7 +4932,10 @@ NULL DEBUG_EXECUTE_r( PerlIO_printf(Perl_debug_log, "%*s EVAL trying tail ... %"UVxf"\n", REPORT_CODE_OFF+depth*2, "",PTR2UV(cur_eval));); - PUSH_YES_STATE_GOTO(EVAL_AB, + if ( nochange_depth ) + nochange_depth--; + + PUSH_YES_STATE_GOTO(EVAL_AB, st->u.eval.prev_eval->u.eval.B); /* match B */ } @@ -4834,6 +4998,8 @@ NULL do_ifmatch: ST.me = scan; ST.logical = logical; + logical = 0; /* XXX: reset state of logical once it has been saved into ST */ + /* execute body of (?...A) */ PUSH_YES_STATE_GOTO(IFMATCH_A, NEXTOPER(NEXTOPER(scan))); /* NOTREACHED */ @@ -4873,7 +5039,7 @@ NULL case PRUNE: PL_reginput = locinput; if (!scan->flags) - sv_yes_mark = sv_commit = (SV*)rexi->data->data[ ARG( scan ) ]; + sv_yes_mark = sv_commit = MUTABLE_SV(rexi->data->data[ ARG( scan ) ]); PUSH_STATE_GOTO(COMMIT_next,next); /* NOTREACHED */ case COMMIT_next_fail: @@ -4887,7 +5053,7 @@ NULL case MARKPOINT: ST.prev_mark = mark_state; ST.mark_name = sv_commit = sv_yes_mark - = (SV*)rexi->data->data[ ARG( scan ) ]; + = MUTABLE_SV(rexi->data->data[ ARG( scan ) ]); mark_state = st; ST.mark_loc = PL_reginput = locinput; PUSH_YES_STATE_GOTO(MARKPOINT_next,next); @@ -4928,7 +5094,7 @@ NULL otherwise do nothing. Meaning we need to scan */ regmatch_state *cur = mark_state; - SV *find = (SV*)rexi->data->data[ ARG( scan ) ]; + SV *find = MUTABLE_SV(rexi->data->data[ ARG( scan ) ]); while (cur) { if ( sv_eq( cur->u.mark.mark_name, @@ -4961,6 +5127,55 @@ NULL 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", @@ -4996,7 +5211,7 @@ NULL } PerlIO_printf(Perl_error_log, "%*s#%-3d %-10s %s\n", REPORT_CODE_OFF + 2 + depth * 2,"", - curd, reg_name[cur->resume_state], + curd, PL_reg_name[cur->resume_state], (curyes == cur) ? "yes" : "" ); if (curyes == cur) @@ -5075,6 +5290,15 @@ yes: 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; @@ -5131,20 +5355,9 @@ no_silent: sv_setsv(sv_err, sv_commit); sv_setsv(sv_mrk, sv_yes_mark); } - /* 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); - } - } + + /* clean up; in particular, free all slabs above current one */ + LEAVE_SCOPE(oldsave); return result; } @@ -5166,6 +5379,11 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth) register char *loceol = PL_regeol; register I32 hardcount = 0; register bool do_utf8 = PL_reg_match_utf8; +#ifndef DEBUGGING + PERL_UNUSED_ARG(depth); +#endif + + PERL_ARGS_ASSERT_REGREPEAT; scan = PL_reginput; if (max == REG_INFTY) @@ -5328,8 +5546,8 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth) } else { while (scan < loceol && !isSPACE(*scan)) scan++; - break; } + break; case NSPACEL: PL_reg_flags |= RF_tainted; if (do_utf8) { @@ -5371,7 +5589,77 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth) 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. */ } @@ -5412,12 +5700,14 @@ Perl_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bool RXi_GET_DECL(prog,progi); const struct reg_data * const data = prog ? progi->data : NULL; + PERL_ARGS_ASSERT_REGCLASS_SWASH; + if (data && data->count) { const U32 n = ARG(node); if (data->what[n] == 's') { - SV * const rv = (SV*)data->data[n]; - AV * const av = (AV*)SvRV((SV*)rv); + SV * const rv = MUTABLE_SV(data->data[n]); + AV * const av = MUTABLE_AV(SvRV(rv)); SV **const ary = AvARRAY(av); SV **a, **b; @@ -5425,8 +5715,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; @@ -5468,6 +5758,8 @@ S_reginclass(pTHX_ const regexp *prog, register const regnode *n, register const STRLEN len = 0; STRLEN plen; + PERL_ARGS_ASSERT_REGINCLASS; + if (do_utf8 && !UTF8_IS_INVARIANT(c)) { c = utf8n_to_uvchr(p, UTF8_MAXBYTES, &len, (UTF8_ALLOW_DEFAULT & UTF8_ALLOW_ANYUV) | UTF8_CHECK_ONLY); @@ -5491,7 +5783,14 @@ S_reginclass(pTHX_ const regexp *prog, register const regnode *n, register const SV * const sw = regclass_swash(prog, n, TRUE, 0, (SV**)&av); if (sw) { - if (swash_fetch(sw, p, do_utf8)) + U8 * utf8_p; + if (do_utf8) { + utf8_p = (U8 *) p; + } else { + STRLEN len = 1; + utf8_p = bytes_to_utf8(p, &len); + } + if (swash_fetch(sw, utf8_p, 1)) match = TRUE; else if (flags & ANYOF_FOLD) { if (!match && lenp && av) { @@ -5500,8 +5799,7 @@ S_reginclass(pTHX_ const regexp *prog, register const regnode *n, register const SV* const sv = *av_fetch(av, i, FALSE); STRLEN len; const char * const s = SvPV_const(sv, len); - - if (len <= plen && memEQ(s, (char*)p, len)) { + if (len <= plen && memEQ(s, (char*)utf8_p, len)) { *lenp = len; match = TRUE; break; @@ -5510,13 +5808,16 @@ S_reginclass(pTHX_ const regexp *prog, register const regnode *n, register const } if (!match) { U8 tmpbuf[UTF8_MAXBYTES_CASE+1]; - STRLEN tmplen; - to_utf8_fold(p, tmpbuf, &tmplen); - if (swash_fetch(sw, tmpbuf, do_utf8)) + STRLEN tmplen; + to_utf8_fold(utf8_p, tmpbuf, &tmplen); + if (swash_fetch(sw, tmpbuf, 1)) match = TRUE; } } + + /* If we allocated a string above, free it */ + if (! do_utf8) Safefree(utf8_p); } } if (match && lenp && *lenp == 0) @@ -5585,6 +5886,9 @@ STATIC U8 * S_reghop3(U8 *s, I32 off, const U8* lim) { dVAR; + + PERL_ARGS_ASSERT_REGHOP3; + if (off >= 0) { while (off-- && s < lim) { /* XXX could check well-formedness here */ @@ -5613,6 +5917,9 @@ STATIC U8 * S_reghop4(U8 *s, I32 off, const U8* llim, const U8* rlim) { dVAR; + + PERL_ARGS_ASSERT_REGHOP4; + if (off >= 0) { while (off-- && s < rlim) { /* XXX could check well-formedness here */ @@ -5637,6 +5944,9 @@ STATIC U8 * S_reghopmaybe3(U8* s, I32 off, const U8* lim) { dVAR; + + PERL_ARGS_ASSERT_REGHOPMAYBE3; + if (off >= 0) { while (off-- && s < lim) { /* XXX could check well-formedness here */ @@ -5672,7 +5982,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; @@ -5684,16 +5994,27 @@ STATIC void S_to_utf8_substr(pTHX_ register regexp *prog) { int i = 1; + + PERL_ARGS_ASSERT_TO_UTF8_SUBSTR; + 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)) - fbm_compile(sv, 0); - if (SvTAIL(prog->substrs->data[i].substr)) - SvTAIL_on(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; } @@ -5705,15 +6026,24 @@ S_to_byte_substr(pTHX_ register regexp *prog) { dVAR; int i = 1; + + PERL_ARGS_ASSERT_TO_BYTE_SUBSTR; + 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)) - fbm_compile(sv, 0); - if (SvTAIL(prog->substrs->data[i].utf8_substr)) - SvTAIL_on(sv); + 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;