X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/124ee91afb4a0db86a0ab6e7348e1f97ae18fc0d..22f163041726650629bf28dcd039ad3970b34019:/regexec.c diff --git a/regexec.c b/regexec.c index f932d17..17a0dc6 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. @@ -112,12 +117,130 @@ #define HOP3(pos,off,lim) (PL_reg_match_utf8 ? reghop3((U8*)(pos), off, (U8*)(lim)) : (U8*)(pos + off)) #define HOP3c(pos,off,lim) ((char*)HOP3(pos,off,lim)) +/* these are unrolled below in the CCC_TRY_XXX defined */ #define LOAD_UTF8_CHARCLASS(class,str) STMT_START { \ if (!CAT2(PL_utf8_,class)) { bool ok; ENTER; save_re_context(); ok=CAT2(is_utf8_,class)((const U8*)str); assert(ok); LEAVE; } } STMT_END + +/* Doesn't do an assert to verify that is correct */ +#define LOAD_UTF8_CHARCLASS_NO_CHECK(class) STMT_START { \ + if (!CAT2(PL_utf8_,class)) { bool ok; ENTER; save_re_context(); ok=CAT2(is_utf8_,class)((const U8*)" "); LEAVE; } } STMT_END + #define LOAD_UTF8_CHARCLASS_ALNUM() LOAD_UTF8_CHARCLASS(alnum,"a") #define LOAD_UTF8_CHARCLASS_DIGIT() LOAD_UTF8_CHARCLASS(digit,"0") #define LOAD_UTF8_CHARCLASS_SPACE() LOAD_UTF8_CHARCLASS(space," ") -#define LOAD_UTF8_CHARCLASS_MARK() LOAD_UTF8_CHARCLASS(mark, "\xcd\x86") + +#define LOAD_UTF8_CHARCLASS_GCB() /* Grapheme cluster boundaries */ \ + LOAD_UTF8_CHARCLASS(X_begin, " "); \ + LOAD_UTF8_CHARCLASS(X_non_hangul, "A"); \ + /* These are utf8 constants, and not utf-ebcdic constants, so the \ + * assert should likely and hopefully fail on an EBCDIC machine */ \ + LOAD_UTF8_CHARCLASS(X_extend, "\xcc\x80"); /* U+0300 */ \ + \ + /* No asserts are done for these, in case called on an early \ + * Unicode version in which they map to nothing */ \ + LOAD_UTF8_CHARCLASS_NO_CHECK(X_prepend);/* U+0E40 "\xe0\xb9\x80" */ \ + LOAD_UTF8_CHARCLASS_NO_CHECK(X_L); /* U+1100 "\xe1\x84\x80" */ \ + LOAD_UTF8_CHARCLASS_NO_CHECK(X_LV); /* U+AC00 "\xea\xb0\x80" */ \ + LOAD_UTF8_CHARCLASS_NO_CHECK(X_LVT); /* U+AC01 "\xea\xb0\x81" */ \ + LOAD_UTF8_CHARCLASS_NO_CHECK(X_LV_LVT_V);/* U+AC01 "\xea\xb0\x81" */\ + LOAD_UTF8_CHARCLASS_NO_CHECK(X_T); /* U+11A8 "\xe1\x86\xa8" */ \ + LOAD_UTF8_CHARCLASS_NO_CHECK(X_V) /* U+1160 "\xe1\x85\xa0" */ + +/* + We dont use PERL_LEGACY_UNICODE_CHARCLASS_MAPPINGS as the direct test + so that it is possible to override the option here without having to + rebuild the entire core. as we are required to do if we change regcomp.h + which is where PERL_LEGACY_UNICODE_CHARCLASS_MAPPINGS is defined. +*/ +#if PERL_LEGACY_UNICODE_CHARCLASS_MAPPINGS +#define BROKEN_UNICODE_CHARCLASS_MAPPINGS +#endif + +#ifdef BROKEN_UNICODE_CHARCLASS_MAPPINGS +#define LOAD_UTF8_CHARCLASS_PERL_WORD() LOAD_UTF8_CHARCLASS_ALNUM() +#define LOAD_UTF8_CHARCLASS_PERL_SPACE() LOAD_UTF8_CHARCLASS_SPACE() +#define LOAD_UTF8_CHARCLASS_POSIX_DIGIT() LOAD_UTF8_CHARCLASS_DIGIT() +#define RE_utf8_perl_word PL_utf8_alnum +#define RE_utf8_perl_space PL_utf8_space +#define RE_utf8_posix_digit PL_utf8_digit +#define perl_word alnum +#define perl_space space +#define posix_digit digit +#else +#define LOAD_UTF8_CHARCLASS_PERL_WORD() LOAD_UTF8_CHARCLASS(perl_word,"a") +#define LOAD_UTF8_CHARCLASS_PERL_SPACE() LOAD_UTF8_CHARCLASS(perl_space," ") +#define LOAD_UTF8_CHARCLASS_POSIX_DIGIT() LOAD_UTF8_CHARCLASS(posix_digit,"0") +#define RE_utf8_perl_word PL_utf8_perl_word +#define RE_utf8_perl_space PL_utf8_perl_space +#define RE_utf8_posix_digit PL_utf8_posix_digit +#endif + + +#define CCC_TRY_AFF(NAME,NAMEL,CLASS,STR,LCFUNC_utf8,FUNC,LCFUNC) \ + case NAMEL: \ + PL_reg_flags |= RF_tainted; \ + /* FALL THROUGH */ \ + case NAME: \ + if (!nextchr) \ + sayNO; \ + if (do_utf8 && UTF8_IS_CONTINUED(nextchr)) { \ + if (!CAT2(PL_utf8_,CLASS)) { \ + bool ok; \ + ENTER; \ + save_re_context(); \ + ok=CAT2(is_utf8_,CLASS)((const U8*)STR); \ + assert(ok); \ + LEAVE; \ + } \ + if (!(OP(scan) == NAME \ + ? (bool)swash_fetch(CAT2(PL_utf8_,CLASS), (U8*)locinput, do_utf8) \ + : LCFUNC_utf8((U8*)locinput))) \ + { \ + sayNO; \ + } \ + locinput += PL_utf8skip[nextchr]; \ + nextchr = UCHARAT(locinput); \ + break; \ + } \ + if (!(OP(scan) == NAME ? FUNC(nextchr) : LCFUNC(nextchr))) \ + sayNO; \ + nextchr = UCHARAT(++locinput); \ + break + +#define CCC_TRY_NEG(NAME,NAMEL,CLASS,STR,LCFUNC_utf8,FUNC,LCFUNC) \ + case NAMEL: \ + PL_reg_flags |= RF_tainted; \ + /* FALL THROUGH */ \ + case NAME : \ + if (!nextchr && locinput >= PL_regeol) \ + sayNO; \ + if (do_utf8 && UTF8_IS_CONTINUED(nextchr)) { \ + if (!CAT2(PL_utf8_,CLASS)) { \ + bool ok; \ + ENTER; \ + save_re_context(); \ + ok=CAT2(is_utf8_,CLASS)((const U8*)STR); \ + assert(ok); \ + LEAVE; \ + } \ + if ((OP(scan) == NAME \ + ? (bool)swash_fetch(CAT2(PL_utf8_,CLASS), (U8*)locinput, do_utf8) \ + : LCFUNC_utf8((U8*)locinput))) \ + { \ + sayNO; \ + } \ + locinput += PL_utf8skip[nextchr]; \ + nextchr = UCHARAT(locinput); \ + break; \ + } \ + if ((OP(scan) == NAME ? FUNC(nextchr) : LCFUNC(nextchr))) \ + sayNO; \ + nextchr = UCHARAT(++locinput); \ + break + + + + /* TODO: Combine JUMPABLE and HAS_TEXT to cache OP(rn) */ @@ -237,9 +360,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. */ @@ -314,6 +438,8 @@ Perl_pregexec(pTHX_ REGEXP * const prog, char* stringarg, register char *strend, /* 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 +497,11 @@ Perl_pregexec(pTHX_ REGEXP * const prog, char* stringarg, register char *strend, deleted from the finite automaton. */ char * -Perl_re_intuit_start(pTHX_ REGEXP * const prog, SV *sv, char *strpos, +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 +518,17 @@ Perl_re_intuit_start(pTHX_ REGEXP * const 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"); ); @@ -501,7 +629,7 @@ Perl_re_intuit_start(pTHX_ REGEXP * const prog, SV *sv, char *strpos, #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 +664,7 @@ Perl_re_intuit_start(pTHX_ REGEXP * const 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; @@ -853,9 +981,9 @@ Perl_re_intuit_start(pTHX_ REGEXP * const prog, SV *sv, char *strpos, { /* If flags & SOMETHING - do not do it many times on the same match */ DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "... Disabling check substring...\n")); + /* XXX Does the destruction order has to change with do_utf8? */ SvREFCNT_dec(do_utf8 ? prog->check_utf8 : prog->check_substr); - if (do_utf8 ? prog->check_substr : prog->check_utf8) - SvREFCNT_dec(do_utf8 ? prog->check_substr : prog->check_utf8); + SvREFCNT_dec(do_utf8 ? prog->check_substr : prog->check_utf8); prog->check_substr = prog->check_utf8 = NULL; /* disable */ prog->float_substr = prog->float_utf8 = NULL; /* clear */ check = NULL; /* abort */ @@ -1000,12 +1128,12 @@ uvc, charid, foldlen, foldbuf, uniflags) STMT_START { \ switch (trie_type) { \ case trie_utf8_fold: \ if ( foldlen>0 ) { \ - uvc = utf8n_to_uvuni( uscan, UTF8_MAXLEN, &len, uniflags ); \ + 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 = utf8n_to_uvuni( (U8*)uc, UTF8_MAXLEN, &len, uniflags ); \ uvc = to_uni_fold( uvc, foldbuf, &foldlen ); \ foldlen -= UNISKIP( uvc ); \ uscan = foldbuf + UNISKIP( uvc ); \ @@ -1031,7 +1159,6 @@ uvc, charid, foldlen, foldbuf, uniflags) STMT_START { \ uvc = (UV)*uc; \ len = 1; \ } \ - \ if (uvc < 256) { \ charid = trie->charmap[ uvc ]; \ } \ @@ -1180,6 +1307,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)) { @@ -1410,8 +1539,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, break; case ALNUM: REXEC_FBC_CSCAN_PRELOAD( - LOAD_UTF8_CHARCLASS_ALNUM(), - swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8), + LOAD_UTF8_CHARCLASS_PERL_WORD(), + swash_fetch(RE_utf8_perl_word, (U8*)s, do_utf8), isALNUM(*s) ); case ALNUML: @@ -1421,8 +1550,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, ); case NALNUM: REXEC_FBC_CSCAN_PRELOAD( - LOAD_UTF8_CHARCLASS_ALNUM(), - !swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8), + LOAD_UTF8_CHARCLASS_PERL_WORD(), + !swash_fetch(RE_utf8_perl_word, (U8*)s, do_utf8), !isALNUM(*s) ); case NALNUML: @@ -1432,8 +1561,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, ); case SPACE: REXEC_FBC_CSCAN_PRELOAD( - LOAD_UTF8_CHARCLASS_SPACE(), - *s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, do_utf8), + LOAD_UTF8_CHARCLASS_PERL_SPACE(), + *s == ' ' || swash_fetch(RE_utf8_perl_space,(U8*)s, do_utf8), isSPACE(*s) ); case SPACEL: @@ -1443,8 +1572,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, ); case NSPACE: REXEC_FBC_CSCAN_PRELOAD( - LOAD_UTF8_CHARCLASS_SPACE(), - !(*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, do_utf8)), + LOAD_UTF8_CHARCLASS_PERL_SPACE(), + !(*s == ' ' || swash_fetch(RE_utf8_perl_space,(U8*)s, do_utf8)), !isSPACE(*s) ); case NSPACEL: @@ -1454,8 +1583,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, ); case DIGIT: REXEC_FBC_CSCAN_PRELOAD( - LOAD_UTF8_CHARCLASS_DIGIT(), - swash_fetch(PL_utf8_digit,(U8*)s, do_utf8), + LOAD_UTF8_CHARCLASS_POSIX_DIGIT(), + swash_fetch(RE_utf8_posix_digit,(U8*)s, do_utf8), isDIGIT(*s) ); case DIGITL: @@ -1465,8 +1594,8 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, ); case NDIGIT: REXEC_FBC_CSCAN_PRELOAD( - LOAD_UTF8_CHARCLASS_DIGIT(), - !swash_fetch(PL_utf8_digit,(U8*)s, do_utf8), + LOAD_UTF8_CHARCLASS_POSIX_DIGIT(), + !swash_fetch(RE_utf8_posix_digit,(U8*)s, do_utf8), !isDIGIT(*s) ); case NDIGITL: @@ -1508,7 +1637,7 @@ S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s, = (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 @@ -1718,31 +1847,12 @@ 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_ REGEXP * const 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 */ @@ -1753,6 +1863,7 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st /* nosave: For optimizations. */ { dVAR; + struct regexp *const prog = (struct regexp *)SvANY(rx); /*register*/ char *s; register regnode *c; /*register*/ char *startpos = stringarg; @@ -1765,10 +1876,10 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st I32 multiline; RXi_GET_DECL(prog,progi); regmatch_info reginfo; /* create some info to pass to regtry etc */ - bool swap_on_fail = 0; - + regexp_paren_pair *swap = NULL; GET_RE_DEBUG_FLAGS_DECL; + PERL_ARGS_ASSERT_REGEXEC_FLAGS; PERL_UNUSED_ARG(data); /* Be paranoid... */ @@ -1778,11 +1889,11 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st } 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"); ); @@ -1804,7 +1915,7 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st 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. */ @@ -1823,36 +1934,57 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st if (prog->extflags & RXf_GPOS_SEEN) { /* Need to set reginfo->ganch */ MAGIC *mg; - - if (flags & REXEC_IGNOREPOS) /* Means: check only at start */ + if (flags & REXEC_IGNOREPOS){ /* Means: check only at start */ reginfo.ganch = startpos + prog->gofs; - else if (sv && SvTYPE(sv) >= SVt_PVMG + DEBUG_GPOS_r(PerlIO_printf(Perl_debug_log, + "GPOS IGNOREPOS: reginfo.ganch = startpos + %"UVxf"\n",(UV)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() */ + DEBUG_GPOS_r(PerlIO_printf(Perl_debug_log, + "GPOS MAGIC: reginfo.ganch = strbeg + %"IVdf"\n",(IV)mg->mg_len)); + if (prog->extflags & RXf_ANCH_GPOS) { if (s > reginfo.ganch) goto phooey; s = reginfo.ganch - prog->gofs; + DEBUG_GPOS_r(PerlIO_printf(Perl_debug_log, + "GPOS ANCH_GPOS: s = ganch - %"UVxf"\n",(UV)prog->gofs)); + if (s < strbeg) + goto phooey; } } else if (data) { reginfo.ganch = strbeg + PTR2UV(data); - } else /* pos() not defined */ + DEBUG_GPOS_r(PerlIO_printf(Perl_debug_log, + "GPOS DATA: reginfo.ganch= strbeg + %"UVxf"\n",PTR2UV(data))); + + } else { /* pos() not defined */ reginfo.ganch = strbeg; + DEBUG_GPOS_r(PerlIO_printf(Perl_debug_log, + "GPOS: reginfo.ganch = strbeg\n")); + } } - 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 (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 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. + */ + 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 */ @@ -1885,7 +2017,7 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st 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; } @@ -1910,7 +2042,8 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st is bogus -- we set it above, when prog->extflags & RXf_GPOS_SEEN and we only enter this block when the same bit is set. */ char *tmp_s = reginfo.ganch - prog->gofs; - if (regtry(®info, &tmp_s)) + + if (tmp_s >= strbeg && regtry(®info, &tmp_s)) goto got_it; goto phooey; } @@ -2009,7 +2142,7 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st (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) { @@ -2087,7 +2220,7 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st 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 { @@ -2144,16 +2277,17 @@ Perl_regexec_flags(pTHX_ REGEXP * const prog, char *stringarg, register char *st 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) 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 @@ -2170,7 +2304,7 @@ got_it: } else #endif { - RX_MATCH_COPIED_on(prog); + RX_MATCH_COPIED_on(rx); s = savepvn(strbeg, i); prog->subbeg = s; } @@ -2189,10 +2323,12 @@ phooey: PL_colors[4], PL_colors[5])); if (PL_reg_eval_set) restore_pos(aTHX_ prog); - if (swap_on_fail) + if (swap) { /* we failed :-( roll it back */ - swap_match_buff(prog); - + Safefree(prog->offs); + prog->offs = swap; + } + return 0; } @@ -2205,9 +2341,13 @@ S_regtry(pTHX_ regmatch_info *reginfo, char **startpos) { dVAR; 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) { @@ -2230,7 +2370,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) @@ -2252,19 +2392,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... */ @@ -2273,7 +2422,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; @@ -2550,15 +2699,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); @@ -2597,6 +2749,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); @@ -2647,11 +2801,15 @@ 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_regoffs[nums[n]].end != -1) @@ -2695,15 +2853,12 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) 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); - 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; @@ -2718,13 +2873,11 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) 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; @@ -2737,10 +2890,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 @@ -2755,11 +2905,12 @@ 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 + PERL_ARGS_ASSERT_REGMATCH; + DEBUG_OPTIMISE_r( DEBUG_EXECUTE_r({ PerlIO_printf(Perl_debug_log,"regmatch start\n"); })); @@ -2806,6 +2957,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) @@ -2915,7 +3071,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) /* 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 && @@ -2972,7 +3128,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) if ( got_wordnum ) { if ( ! ST.accepted ) { ENTER; - /* SAVETMPS; */ /* XXX is this necessary? dmq */ + SAVETMPS; /* XXX is this necessary? dmq */ bufflen = TRIE_INITAL_ACCEPT_BUFFLEN; sv_accept_buff=newSV(bufflen * sizeof(reg_trie_accepted) - 1); @@ -3072,7 +3228,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) /* 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; @@ -3154,7 +3310,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]) ? @@ -3191,6 +3347,9 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) } /* 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; @@ -3298,85 +3457,6 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) nextchr = UCHARAT(locinput); break; } - case ANYOF: - if (do_utf8) { - STRLEN inclasslen = PL_regeol - locinput; - - if (!reginclass(rex, scan, (U8*)locinput, &inclasslen, do_utf8)) - goto anyof_fail; - if (locinput >= PL_regeol) - sayNO; - locinput += inclasslen ? inclasslen : UTF8SKIP(locinput); - nextchr = UCHARAT(locinput); - break; - } - else { - if (nextchr < 0) - nextchr = UCHARAT(locinput); - if (!REGINCLASS(rex, scan, (U8*)locinput)) - goto anyof_fail; - if (!nextchr && locinput >= PL_regeol) - sayNO; - nextchr = UCHARAT(++locinput); - break; - } - anyof_fail: - /* If we might have the case of the German sharp s - * in a casefolding Unicode character class. */ - - if (ANYOF_FOLD_SHARP_S(scan, locinput, PL_regeol)) { - locinput += SHARP_S_SKIP; - nextchr = UCHARAT(locinput); - } - else - sayNO; - break; - case ALNUML: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case ALNUM: - if (!nextchr) - sayNO; - if (do_utf8) { - LOAD_UTF8_CHARCLASS_ALNUM(); - if (!(OP(scan) == ALNUM - ? (bool)swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8) - : isALNUM_LC_utf8((U8*)locinput))) - { - sayNO; - } - locinput += PL_utf8skip[nextchr]; - nextchr = UCHARAT(locinput); - break; - } - if (!(OP(scan) == ALNUM - ? isALNUM(nextchr) : isALNUM_LC(nextchr))) - sayNO; - nextchr = UCHARAT(++locinput); - break; - case NALNUML: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case NALNUM: - if (!nextchr && locinput >= PL_regeol) - sayNO; - if (do_utf8) { - LOAD_UTF8_CHARCLASS_ALNUM(); - if (OP(scan) == NALNUM - ? (bool)swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8) - : isALNUM_LC_utf8((U8*)locinput)) - { - sayNO; - } - locinput += PL_utf8skip[nextchr]; - nextchr = UCHARAT(locinput); - break; - } - if (OP(scan) == NALNUM - ? isALNUM(nextchr) : isALNUM_LC(nextchr)) - sayNO; - nextchr = UCHARAT(++locinput); - break; case BOUNDL: case NBOUNDL: PL_reg_flags |= RF_tainted; @@ -3389,7 +3469,7 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) ln = '\n'; else { const U8 * const r = reghop3((U8*)locinput, -1, (U8*)PL_bostr); - + ln = utf8n_to_uvchr(r, UTF8SKIP(r), 0, uniflags); } if (OP(scan) == BOUND || OP(scan) == NBOUND) { @@ -3418,122 +3498,259 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) OP(scan) == BOUNDL)) sayNO; break; - case SPACEL: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case SPACE: - if (!nextchr) - sayNO; + case ANYOF: if (do_utf8) { - if (UTF8_IS_CONTINUED(nextchr)) { - LOAD_UTF8_CHARCLASS_SPACE(); - if (!(OP(scan) == SPACE - ? (bool)swash_fetch(PL_utf8_space, (U8*)locinput, do_utf8) - : isSPACE_LC_utf8((U8*)locinput))) - { - sayNO; - } - locinput += PL_utf8skip[nextchr]; - nextchr = UCHARAT(locinput); - break; - } - if (!(OP(scan) == SPACE - ? isSPACE(nextchr) : isSPACE_LC(nextchr))) + STRLEN inclasslen = PL_regeol - locinput; + + if (!reginclass(rex, scan, (U8*)locinput, &inclasslen, do_utf8)) + goto anyof_fail; + if (locinput >= PL_regeol) sayNO; - nextchr = UCHARAT(++locinput); + locinput += inclasslen ? inclasslen : UTF8SKIP(locinput); + nextchr = UCHARAT(locinput); + break; } else { - if (!(OP(scan) == SPACE - ? isSPACE(nextchr) : isSPACE_LC(nextchr))) + if (nextchr < 0) + nextchr = UCHARAT(locinput); + if (!REGINCLASS(rex, scan, (U8*)locinput)) + goto anyof_fail; + if (!nextchr && locinput >= PL_regeol) sayNO; nextchr = UCHARAT(++locinput); - } - break; - case NSPACEL: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case NSPACE: - if (!nextchr && locinput >= PL_regeol) - sayNO; - if (do_utf8) { - LOAD_UTF8_CHARCLASS_SPACE(); - if (OP(scan) == NSPACE - ? (bool)swash_fetch(PL_utf8_space, (U8*)locinput, do_utf8) - : isSPACE_LC_utf8((U8*)locinput)) - { - sayNO; - } - locinput += PL_utf8skip[nextchr]; - nextchr = UCHARAT(locinput); break; } - if (OP(scan) == NSPACE - ? isSPACE(nextchr) : isSPACE_LC(nextchr)) - sayNO; - nextchr = UCHARAT(++locinput); - break; - case DIGITL: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case DIGIT: - if (!nextchr) - sayNO; - if (do_utf8) { - LOAD_UTF8_CHARCLASS_DIGIT(); - if (!(OP(scan) == DIGIT - ? (bool)swash_fetch(PL_utf8_digit, (U8*)locinput, do_utf8) - : isDIGIT_LC_utf8((U8*)locinput))) - { - sayNO; - } - locinput += PL_utf8skip[nextchr]; - nextchr = UCHARAT(locinput); - break; + anyof_fail: + /* If we might have the case of the German sharp s + * in a casefolding Unicode character class. */ + + if (ANYOF_FOLD_SHARP_S(scan, locinput, PL_regeol)) { + locinput += SHARP_S_SKIP; + nextchr = UCHARAT(locinput); } - if (!(OP(scan) == DIGIT - ? isDIGIT(nextchr) : isDIGIT_LC(nextchr))) - sayNO; - nextchr = UCHARAT(++locinput); + else + sayNO; break; - case NDIGITL: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case NDIGIT: - if (!nextchr && locinput >= PL_regeol) + /* Special char classes - The defines start on line 129 or so */ + CCC_TRY_AFF( ALNUM, ALNUML, perl_word, "a", isALNUM_LC_utf8, isALNUM, isALNUM_LC); + CCC_TRY_NEG(NALNUM, NALNUML, perl_word, "a", isALNUM_LC_utf8, isALNUM, isALNUM_LC); + + CCC_TRY_AFF( SPACE, SPACEL, perl_space, " ", isSPACE_LC_utf8, isSPACE, isSPACE_LC); + CCC_TRY_NEG(NSPACE, NSPACEL, perl_space, " ", isSPACE_LC_utf8, isSPACE, isSPACE_LC); + + CCC_TRY_AFF( DIGIT, DIGITL, posix_digit, "0", isDIGIT_LC_utf8, isDIGIT, isDIGIT_LC); + CCC_TRY_NEG(NDIGIT, NDIGITL, posix_digit, "0", isDIGIT_LC_utf8, isDIGIT, isDIGIT_LC); + + case CLUMP: /* Match \X: logical Unicode character. This is defined as + a Unicode extended Grapheme Cluster */ + /* From http://www.unicode.org/reports/tr29 (5.2 version). An + extended Grapheme Cluster is: + + CR LF + | Prepend* Begin Extend* + | . + + Begin is (Hangul-syllable | ! Control) + Extend is (Grapheme_Extend | Spacing_Mark) + Control is [ GCB_Control CR LF ] + + The discussion below shows how the code for CLUMP is derived + from this regex. Note that most of these concepts are from + property values of the Grapheme Cluster Boundary (GCB) property. + No code point can have multiple property values for a given + property. Thus a code point in Prepend can't be in Control, but + it must be in !Control. This is why Control above includes + GCB_Control plus CR plus LF. The latter two are used in the GCB + property separately, and so can't be in GCB_Control, even though + they logically are controls. Control is not the same as gc=cc, + but includes format and other characters as well. + + The Unicode definition of Hangul-syllable is: + L+ + | (L* ( ( V | LV ) V* | LVT ) T*) + | T+ + ) + Each of these is a value for the GCB property, and hence must be + disjoint, so the order they are tested is immaterial, so the + above can safely be changed to + T+ + | L+ + | (L* ( LVT | ( V | LV ) V*) T*) + + The last two terms can be combined like this: + L* ( L + | (( LVT | ( V | LV ) V*) T*)) + + And refactored into this: + L* (L | LVT T* | V V* T* | LV V* T*) + + That means that if we have seen any L's at all we can quit + there, but if the next character is a LVT, a V or and LV we + should keep going. + + There is a subtlety with Prepend* which showed up in testing. + Note that the Begin, and only the Begin is required in: + | Prepend* Begin Extend* + Also, Begin contains '! Control'. A Prepend must be a '! + Control', which means it must be a Begin. What it comes down to + is that if we match Prepend* and then find no suitable Begin + afterwards, that if we backtrack the last Prepend, that one will + be a suitable Begin. + */ + + if (locinput >= PL_regeol) sayNO; - if (do_utf8) { - LOAD_UTF8_CHARCLASS_DIGIT(); - if (OP(scan) == NDIGIT - ? (bool)swash_fetch(PL_utf8_digit, (U8*)locinput, do_utf8) - : isDIGIT_LC_utf8((U8*)locinput)) - { - sayNO; + if (! do_utf8) { + + /* Match either CR LF or '.', as all the other possibilities + * require utf8 */ + locinput++; /* Match the . or CR */ + if (nextchr == '\r' + && locinput < PL_regeol + && UCHARAT(locinput) == '\n') locinput++; + } + else { + + /* Utf8: See if is ( CR LF ); already know that locinput < + * PL_regeol, so locinput+1 is in bounds */ + if (nextchr == '\r' && UCHARAT(locinput + 1) == '\n') { + locinput += 2; } - locinput += PL_utf8skip[nextchr]; - nextchr = UCHARAT(locinput); - break; + else { + /* In case have to backtrack to beginning, then match '.' */ + char *starting = locinput; + + /* In case have to backtrack the last prepend */ + char *previous_prepend = 0; + + LOAD_UTF8_CHARCLASS_GCB(); + + /* Match (prepend)* */ + while (locinput < PL_regeol + && swash_fetch(PL_utf8_X_prepend, + (U8*)locinput, do_utf8)) + { + previous_prepend = locinput; + locinput += UTF8SKIP(locinput); + } + + /* As noted above, if we matched a prepend character, but + * the next thing won't match, back off the last prepend we + * matched, as it is guaranteed to match the begin */ + if (previous_prepend + && (locinput >= PL_regeol + || ! swash_fetch(PL_utf8_X_begin, + (U8*)locinput, do_utf8))) + { + locinput = previous_prepend; + } + + /* Note that here we know PL_regeol > locinput, as we + * tested that upon input to this switch case, and if we + * moved locinput forward, we tested the result just above + * and it either passed, or we backed off so that it will + * now pass */ + if (! swash_fetch(PL_utf8_X_begin, (U8*)locinput, do_utf8)) { + + /* Here did not match the required 'Begin' in the + * second term. So just match the very first + * character, the '.' of the final term of the regex */ + locinput = starting + UTF8SKIP(starting); + } else { + + /* Here is the beginning of a character that can have + * an extender. It is either a hangul syllable, or a + * non-control */ + if (swash_fetch(PL_utf8_X_non_hangul, + (U8*)locinput, do_utf8)) + { + + /* Here not a Hangul syllable, must be a + * ('! * Control') */ + locinput += UTF8SKIP(locinput); + } else { + + /* Here is a Hangul syllable. It can be composed + * of several individual characters. One + * possibility is T+ */ + if (swash_fetch(PL_utf8_X_T, + (U8*)locinput, do_utf8)) + { + while (locinput < PL_regeol + && swash_fetch(PL_utf8_X_T, + (U8*)locinput, do_utf8)) + { + locinput += UTF8SKIP(locinput); + } + } else { + + /* Here, not T+, but is a Hangul. That means + * it is one of the others: L, LV, LVT or V, + * and matches: + * L* (L | LVT T* | V V* T* | LV V* T*) */ + + /* Match L* */ + while (locinput < PL_regeol + && swash_fetch(PL_utf8_X_L, + (U8*)locinput, do_utf8)) + { + locinput += UTF8SKIP(locinput); + } + + /* Here, have exhausted L*. If the next + * character is not an LV, LVT nor V, it means + * we had to have at least one L, so matches L+ + * in the original equation, we have a complete + * hangul syllable. Are done. */ + + if (locinput < PL_regeol + && swash_fetch(PL_utf8_X_LV_LVT_V, + (U8*)locinput, do_utf8)) + { + + /* Otherwise keep going. Must be LV, LVT + * or V. See if LVT */ + if (swash_fetch(PL_utf8_X_LVT, + (U8*)locinput, do_utf8)) + { + locinput += UTF8SKIP(locinput); + } else { + + /* Must be V or LV. Take it, then + * match V* */ + locinput += UTF8SKIP(locinput); + while (locinput < PL_regeol + && swash_fetch(PL_utf8_X_V, + (U8*)locinput, do_utf8)) + { + locinput += UTF8SKIP(locinput); + } + } + + /* And any of LV, LVT, or V can be followed + * by T* */ + while (locinput < PL_regeol + && swash_fetch(PL_utf8_X_T, + (U8*)locinput, + do_utf8)) + { + locinput += UTF8SKIP(locinput); + } + } + } + } + + /* Match any extender */ + while (locinput < PL_regeol + && swash_fetch(PL_utf8_X_extend, + (U8*)locinput, do_utf8)) + { + locinput += UTF8SKIP(locinput); + } + } + } + if (locinput > PL_regeol) sayNO; } - if (OP(scan) == NDIGIT - ? isDIGIT(nextchr) : isDIGIT_LC(nextchr)) - sayNO; - nextchr = UCHARAT(++locinput); - break; - case CLUMP: - if (locinput >= PL_regeol) - sayNO; - if (do_utf8) { - LOAD_UTF8_CHARCLASS_MARK(); - if (swash_fetch(PL_utf8_mark,(U8*)locinput, do_utf8)) - sayNO; - locinput += PL_utf8skip[nextchr]; - while (locinput < PL_regeol && - swash_fetch(PL_utf8_mark,(U8*)locinput, do_utf8)) - locinput += UTF8SKIP(locinput); - if (locinput > PL_regeol) - sayNO; - } - else - locinput++; nextchr = UCHARAT(locinput); break; @@ -3629,6 +3846,7 @@ 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; @@ -3645,9 +3863,10 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) } 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); @@ -3671,6 +3890,7 @@ 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]; @@ -3696,6 +3916,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); @@ -3707,12 +3928,21 @@ 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)) { + 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. */ @@ -3730,30 +3960,48 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) } if (mg) { - re = reg_temp_copy((regexp *)mg->mg_obj); /*XXX:dmq*/ + rx = (REGEXP *) mg->mg_obj; /*XXX:dmq*/ + assert(rx); + } + if (rx) { + rx = reg_temp_copy(NULL, rx); } else { U32 pm_flags = 0; const I32 osize = PL_regsize; - if (DO_UTF8(ret)) pm_flags |= RXf_UTF8; - re = CALLREGCOMP(ret, pm_flags); + 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))) { - SvUPGRADE(ret, SVt_ORANGE); - sv_magic(ret,(SV*)ReREFCNT_inc(re), - PERL_MAGIC_qr,0,0); + /* 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); } - RX_MATCH_COPIED_off(re); + 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, + debug_start_match(re_sv, do_utf8, locinput, PL_regeol, "Matching embedded"); ); startpoint = rei->program + 1; @@ -3774,8 +4022,12 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) 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; @@ -3783,15 +4035,16 @@ 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,re); + SETREX(rex_sv,re_sv); + rex = re; rexi = rei; cur_curlyx = NULL; ST.B = next; @@ -3810,12 +4063,20 @@ 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); - SETREX(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 ) @@ -3826,9 +4087,14 @@ S_regmatch(pTHX_ regmatch_info *reginfo, regnode *prog) 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); - SETREX(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); @@ -4273,7 +4539,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: @@ -4321,7 +4587,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 */ @@ -4388,8 +4654,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 */ @@ -4481,7 +4750,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 */ } @@ -4821,12 +5091,18 @@ NULL = cur_eval->u.eval.toggle_reg_flags; PL_reg_flags ^= st->u.eval.toggle_reg_flags; - st->u.eval.prev_rex = rex; /* inner */ - SETREX(rex,cur_eval->u.eval.prev_rex); + 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; @@ -4908,6 +5184,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 */ @@ -4947,7 +5225,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: @@ -4961,7 +5239,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); @@ -5002,7 +5280,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, @@ -5291,6 +5569,8 @@ S_regrepeat(pTHX_ const regexp *prog, const regnode *p, I32 max, int depth) PERL_UNUSED_ARG(depth); #endif + PERL_ARGS_ASSERT_REGREPEAT; + scan = PL_reginput; if (max == REG_INFTY) max = I32_MAX; @@ -5606,12 +5886,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; @@ -5662,10 +5944,14 @@ 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); - /* see [perl #37836] for UTF8_ALLOW_ANYUV */ + (UTF8_ALLOW_DEFAULT & UTF8_ALLOW_ANYUV) + | UTF8_ALLOW_FFFF | UTF8_CHECK_ONLY); + /* see [perl #37836] for UTF8_ALLOW_ANYUV; [perl #38293] for + * UTF8_ALLOW_FFFF */ if (len == (STRLEN)-1) Perl_croak(aTHX_ "Malformed UTF-8 character (fatal)"); } @@ -5685,7 +5971,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) { @@ -5694,8 +5987,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; @@ -5704,13 +5996,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) @@ -5779,6 +6074,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 */ @@ -5807,6 +6105,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 */ @@ -5831,6 +6132,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 */ @@ -5866,7 +6170,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; @@ -5878,6 +6182,9 @@ 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) { @@ -5907,6 +6214,9 @@ 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) {