X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=regexec.c;h=da4513bc95a5f8bdfbecfcdf4f4b812f741c3b61;hb=f022b9987cfef8a7e7c7c892f22c2e71c583bfc7;hp=6bddf2dc323cc9b9fb7f90b09f6cd5b73bb9391d;hpb=c2e66d9e68806a7000ee1a4760c35703a0e0ae89;p=p5sagit%2Fp5-mst-13.2.git diff --git a/regexec.c b/regexec.c index 6bddf2d..da4513b 100644 --- a/regexec.c +++ b/regexec.c @@ -38,10 +38,11 @@ # define Perl_re_intuit_start my_re_intuit_start /* *These* symbols are masked to allow static link. */ # define Perl_pregexec my_pregexec -# define Perl_reginitcolors my_reginitcolors +# define Perl_reginitcolors my_reginitcolors +# define Perl_regclass_swash my_regclass_swash # define PERL_NO_GET_CONTEXT -#endif +#endif /*SUPPRESS 112*/ /* @@ -66,7 +67,7 @@ * **** Alterations to Henry's code are... **** - **** Copyright (c) 1991-2000, Larry Wall + **** Copyright (c) 1991-2001, Larry Wall **** **** You may distribute under the terms of either the GNU General Public **** License or the Artistic License, as specified in the README file. @@ -105,69 +106,98 @@ * Forwards. */ -#define REGINCLASS(p,c) (ANYOF_FLAGS(p) ? reginclass(p,c) : ANYOF_BITMAP_TEST(p,c)) -#define REGINCLASSUTF8(f,p) (ARG1(f) ? reginclassutf8(f,p) : swash_fetch((SV*)PL_regdata->data[ARG2(f)],p)) - #define CHR_SVLEN(sv) (UTF ? sv_len_utf8(sv) : SvCUR(sv)) -#define CHR_DIST(a,b) (UTF ? utf8_distance(a,b) : a - b) +#define CHR_DIST(a,b) (DO_UTF8(PL_reg_sv) ? utf8_distance(a,b) : a - b) #define reghop_c(pos,off) ((char*)reghop((U8*)pos, off)) #define reghopmaybe_c(pos,off) ((char*)reghopmaybe((U8*)pos, off)) -#define HOP(pos,off) (UTF ? reghop((U8*)pos, off) : (U8*)(pos + off)) -#define HOPMAYBE(pos,off) (UTF ? reghopmaybe((U8*)pos, off) : (U8*)(pos + off)) +#define HOP(pos,off) (DO_UTF8(PL_reg_sv) ? reghop((U8*)pos, off) : (U8*)(pos + off)) +#define HOPMAYBE(pos,off) (DO_UTF8(PL_reg_sv) ? reghopmaybe((U8*)pos, off) : (U8*)(pos + off)) #define HOPc(pos,off) ((char*)HOP(pos,off)) #define HOPMAYBEc(pos,off) ((char*)HOPMAYBE(pos,off)) -static void restore_pos(pTHXo_ void *arg); +#define HOPBACK(pos, off) ( \ + (UTF && DO_UTF8(PL_reg_sv)) \ + ? reghopmaybe((U8*)pos, -off) \ + : (pos - off >= PL_bostr) \ + ? (U8*)(pos - off) \ + : (U8*)NULL \ +) +#define HOPBACKc(pos, off) (char*)HOPBACK(pos, off) + +#define reghop3_c(pos,off,lim) ((char*)reghop3((U8*)pos, off, (U8*)lim)) +#define reghopmaybe3_c(pos,off,lim) ((char*)reghopmaybe3((U8*)pos, off, (U8*)lim)) +#define HOP3(pos,off,lim) (DO_UTF8(PL_reg_sv) ? reghop3((U8*)pos, off, (U8*)lim) : (U8*)(pos + off)) +#define HOPMAYBE3(pos,off,lim) (DO_UTF8(PL_reg_sv) ? reghopmaybe3((U8*)pos, off, (U8*)lim) : (U8*)(pos + off)) +#define HOP3c(pos,off,lim) ((char*)HOP3(pos,off,lim)) +#define HOPMAYBE3c(pos,off,lim) ((char*)HOPMAYBE3(pos,off,lim)) +#define LOAD_UTF8_CHARCLASS(a,b) STMT_START { if (!CAT2(PL_utf8_,a)) (void)CAT2(is_utf8_, a)((U8*)b); } STMT_END + +static void restore_pos(pTHXo_ void *arg); STATIC CHECKPOINT S_regcppush(pTHX_ I32 parenfloor) { - dTHR; int retval = PL_savestack_ix; - int i = (PL_regsize - parenfloor) * 4; +#define REGCP_PAREN_ELEMS 4 + int paren_elems_to_push = (PL_regsize - parenfloor) * REGCP_PAREN_ELEMS; int p; - SSCHECK(i + 5); + if (paren_elems_to_push < 0) + Perl_croak(aTHX_ "panic: paren_elems_to_push < 0"); + +#define REGCP_OTHER_ELEMS 5 + SSCHECK(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]); SSPUSHPTR(PL_reg_start_tmp[p]); SSPUSHINT(p); } +/* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */ SSPUSHINT(PL_regsize); SSPUSHINT(*PL_reglastparen); SSPUSHPTR(PL_reginput); - SSPUSHINT(i + 3); - SSPUSHINT(SAVEt_REGCONTEXT); +#define REGCP_FRAME_ELEMS 2 +/* REGCP_FRAME_ELEMS are part of the REGCP_OTHER_ELEMS and + * are needed for the regexp context stack bookkeeping. */ + SSPUSHINT(paren_elems_to_push + REGCP_OTHER_ELEMS - REGCP_FRAME_ELEMS); + SSPUSHINT(SAVEt_REGCONTEXT); /* Magic cookie. */ + return retval; } /* These are needed since we do not localize EVAL nodes: */ -# define REGCP_SET DEBUG_r(PerlIO_printf(Perl_debug_log, \ +# define REGCP_SET(cp) DEBUG_r(PerlIO_printf(Perl_debug_log, \ " Setting an EVAL scope, savestack=%"IVdf"\n", \ - (IV)PL_savestack_ix)); lastcp = PL_savestack_ix + (IV)PL_savestack_ix)); cp = PL_savestack_ix -# define REGCP_UNWIND DEBUG_r(lastcp != PL_savestack_ix ? \ +# define REGCP_UNWIND(cp) DEBUG_r(cp != PL_savestack_ix ? \ PerlIO_printf(Perl_debug_log, \ " Clearing an EVAL scope, savestack=%"IVdf"..%"IVdf"\n", \ - (IV)lastcp, (IV)PL_savestack_ix) : 0); regcpblow(lastcp) + (IV)(cp), (IV)PL_savestack_ix) : 0); regcpblow(cp) STATIC char * S_regcppop(pTHX) { - dTHR; - I32 i = SSPOPINT; + I32 i; U32 paren = 0; char *input; I32 tmps; - assert(i == SAVEt_REGCONTEXT); + + /* Pop REGCP_OTHER_ELEMS before the parentheses loop starts. */ i = SSPOPINT; + assert(i == SAVEt_REGCONTEXT); /* Check that the magic cookie is there. */ + i = SSPOPINT; /* Parentheses elements to pop. */ input = (char *) SSPOPPTR; *PL_reglastparen = SSPOPINT; PL_regsize = SSPOPINT; - for (i -= 3; i > 0; i -= 4) { + + /* Now restore the parentheses context. */ + for (i -= (REGCP_OTHER_ELEMS - REGCP_FRAME_ELEMS); + i > 0; i -= REGCP_PAREN_ELEMS) { paren = (U32)SSPOPINT; PL_reg_start_tmp[paren] = (char *) SSPOPPTR; PL_regstartp[paren] = SSPOPINT; @@ -177,9 +207,9 @@ S_regcppop(pTHX) DEBUG_r( PerlIO_printf(Perl_debug_log, " restoring \\%"UVuf" to %"IVdf"(%"IVdf")..%"IVdf"%s\n", - (UV)paren, (IV)PL_regstartp[paren], + (UV)paren, (IV)PL_regstartp[paren], (IV)(PL_reg_start_tmp[paren] - PL_bostr), - (IV)PL_regendp[paren], + (IV)PL_regendp[paren], (paren > *PL_reglastparen ? "(no)" : "")); ); } @@ -190,18 +220,29 @@ S_regcppop(pTHX) (IV)(*PL_reglastparen + 1), (IV)PL_regnpar); } ); +#if 1 + /* It would seem that the similar code in regtry() + * already takes care of this, and in fact it is in + * a better location to since this code can #if 0-ed out + * but the code in regtry() is needed or otherwise tests + * requiring null fields (pat.t#187 and split.t#{13,14} + * (as of patchlevel 7877) will fail. Then again, + * this code seems to be necessary or otherwise + * building DynaLoader will fail: + * "Error: '*' not in typemap in DynaLoader.xs, line 164" + * --jhi */ for (paren = *PL_reglastparen + 1; paren <= PL_regnpar; paren++) { if (paren > PL_regsize) PL_regstartp[paren] = -1; PL_regendp[paren] = -1; } +#endif return input; } STATIC char * S_regcp_set_to(pTHX_ I32 ss) { - dTHR; I32 tmp = PL_savestack_ix; PL_savestack_ix = ss; @@ -219,7 +260,23 @@ typedef struct re_cc_state regexp *re; } re_cc_state; -#define regcpblow(cp) LEAVE_SCOPE(cp) +#define regcpblow(cp) LEAVE_SCOPE(cp) /* Ignores regcppush()ed data. */ + +#define TRYPAREN(paren, n, input) { \ + if (paren) { \ + if (n) { \ + PL_regstartp[paren] = HOPc(input, -1) - PL_bostr; \ + PL_regendp[paren] = input - PL_bostr; \ + } \ + else \ + PL_regendp[paren] = -1; \ + } \ + if (regmatch(next)) \ + sayYES; \ + if (paren && n) \ + PL_regendp[paren] = -1; \ +} + /* * pregexec and friends @@ -237,24 +294,23 @@ Perl_pregexec(pTHX_ register regexp *prog, char *stringarg, register char *stren /* nosave: For optimizations. */ { return - regexec_flags(prog, stringarg, strend, strbeg, minend, screamer, NULL, + regexec_flags(prog, stringarg, strend, strbeg, minend, screamer, NULL, nosave ? 0 : REXEC_COPY_STR); } STATIC void S_cache_re(pTHX_ regexp *prog) { - dTHR; PL_regprecomp = prog->precomp; /* Needed for FAIL. */ #ifdef DEBUGGING PL_regprogram = prog->program; #endif PL_regnpar = prog->nparens; - PL_regdata = prog->data; - PL_reg_re = prog; + PL_regdata = prog->data; + PL_reg_re = prog; } -/* +/* * Need to implement the following flags for reg_anch: * * USE_INTUIT_NOML - Useful to call re_intuit_start() first @@ -304,16 +360,16 @@ char * Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, char *strend, U32 flags, re_scream_pos_data *data) { - register I32 start_shift; + register I32 start_shift = 0; /* Should be nonnegative! */ - register I32 end_shift; + register I32 end_shift = 0; register char *s; register SV *check; + char *strbeg; char *t; I32 ml_anch; - char *tmp; register char *other_last = Nullch; /* other substr checked before this */ - char *check_at; /* check substr found at this pos */ + char *check_at = Nullch; /* check substr found at this pos */ #ifdef DEBUGGING char *i_strpos = strpos; #endif @@ -331,33 +387,40 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, (strend - strpos > 60 ? "..." : "")) ); - if (prog->minlen > strend - strpos) { + if (prog->reganch & ROPT_UTF8) + PL_reg_flags |= RF_utf8; + + if (prog->minlen > CHR_DIST((U8*)strend, (U8*)strpos)) { DEBUG_r(PerlIO_printf(Perl_debug_log, "String too short...\n")); goto fail; } + strbeg = (sv && SvPOK(sv)) ? strend - SvCUR(sv) : strpos; + PL_regeol = strend; check = prog->check_substr; if (prog->reganch & ROPT_ANCH) { /* Match at beg-of-str or after \n */ ml_anch = !( (prog->reganch & ROPT_ANCH_SINGLE) || ( (prog->reganch & ROPT_ANCH_BOL) && !PL_multiline ) ); /* Check after \n? */ - if ((prog->check_offset_min == prog->check_offset_max) && !ml_anch) { + if (!ml_anch) { + if ( !(prog->reganch & (ROPT_ANCH_GPOS /* Checked by the caller */ + | ROPT_IMPLICIT)) /* not a real BOL */ + /* SvCUR is not set on references: SvRV and SvPVX overlap */ + && sv && !SvROK(sv) + && (strpos != strbeg)) { + DEBUG_r(PerlIO_printf(Perl_debug_log, "Not at start...\n")); + goto fail; + } + if (prog->check_offset_min == prog->check_offset_max && + !(prog->reganch & ROPT_SANY_SEEN)) { /* Substring at constant offset from beg-of-str... */ I32 slen; - if ( !(prog->reganch & ROPT_ANCH_GPOS) /* Checked by the caller */ - /* SvCUR is not set on references: SvRV and SvPVX overlap */ - && sv && !SvROK(sv) - && (strpos + SvCUR(sv) != strend)) { - DEBUG_r(PerlIO_printf(Perl_debug_log, "Not at start...\n")); - goto fail; - } - PL_regeol = strend; /* Used in HOP() */ - s = HOPc(strpos, prog->check_offset_min); + s = HOP3c(strpos, prog->check_offset_min, strend); if (SvTAIL(check)) { slen = SvCUR(check); /* >= 1 */ - if ( strend - s > slen || strend - s < slen - 1 + if ( strend - s > slen || strend - s < slen - 1 || (strend - s == slen && strend[-1] != '\n')) { DEBUG_r(PerlIO_printf(Perl_debug_log, "String too long...\n")); goto fail_finish; @@ -377,6 +440,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, && memNE(SvPVX(check), s, slen))) goto report_neq; goto success_at_start; + } } /* Match is anchored, but substr is not anchored wrt beg-of-str. */ s = strpos; @@ -386,7 +450,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, if (!ml_anch) { I32 end = prog->check_offset_max + CHR_SVLEN(check) - (SvTAIL(check) != 0); - I32 eshift = strend - s - end; + I32 eshift = CHR_DIST((U8*)strend, (U8*)s) - end; if (end_shift < eshift) end_shift = eshift; @@ -410,7 +474,6 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, /* Find a possible match in the region s..strend by looking for the "check" substring in the region corrected by start/end_shift. */ if (flags & REXEC_SCREAM) { - char *strbeg = SvPVX(sv); /* XXXX Assume PV_force() on SCREAM! */ I32 p = -1; /* Internal iterator of scream. */ I32 *pp = data ? data->scream_pos : &p; @@ -418,16 +481,20 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, || ( BmRARE(check) == '\n' && (BmPREVIOUS(check) == SvCUR(check) - 1) && SvTAIL(check) )) - s = screaminstr(sv, check, + s = screaminstr(sv, check, start_shift + (s - strbeg), end_shift, pp, 0); else goto fail_finish; if (data) *data->scream_olds = s; } + else if (prog->reganch & ROPT_SANY_SEEN) + s = fbm_instr((U8*)(s + start_shift), + (U8*)(strend - end_shift), + check, PL_multiline ? FBMrf_MULTILINE : 0); else - s = fbm_instr((unsigned char*)s + start_shift, - (unsigned char*)strend - end_shift, + s = fbm_instr(HOP3(s, start_shift, strend), + HOP3(strend, -end_shift, strbeg), check, PL_multiline ? FBMrf_MULTILINE : 0); /* Update the count-of-usability, remove useless subpatterns, @@ -466,34 +533,33 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, if (check == prog->float_substr) { do_other_anchored: { - char *last = s - start_shift, *last1, *last2; + char *last = HOP3c(s, -start_shift, strbeg), *last1, *last2; char *s1 = s; - tmp = PL_bostr; t = s - prog->check_offset_max; if (s - strpos > prog->check_offset_max /* signed-corrected t > strpos */ && (!(prog->reganch & ROPT_UTF8) - || (PL_bostr = strpos, /* Used in regcopmaybe() */ - (t = reghopmaybe_c(s, -(prog->check_offset_max))) + || ((t = reghopmaybe3_c(s, -(prog->check_offset_max), strpos)) && t > strpos))) /* EMPTY */; else t = strpos; - t += prog->anchored_offset; + t = HOP3c(t, prog->anchored_offset, strend); if (t < other_last) /* These positions already checked */ t = other_last; - PL_bostr = tmp; - last2 = last1 = strend - prog->minlen; + last2 = last1 = HOP3c(strend, -prog->minlen, strbeg); if (last < last1) last1 = last; /* XXXX It is not documented what units *_offsets are in. Assume bytes. */ /* On end-of-str: see comment below. */ s = fbm_instr((unsigned char*)t, - (unsigned char*)last1 + prog->anchored_offset - + SvCUR(prog->anchored_substr) - - (SvTAIL(prog->anchored_substr)!=0), - prog->anchored_substr, PL_multiline ? FBMrf_MULTILINE : 0); - DEBUG_r(PerlIO_printf(Perl_debug_log, "%s anchored substr `%s%.*s%s'%s", + HOP3(HOP3(last1, prog->anchored_offset, strend) + + SvCUR(prog->anchored_substr), + -(SvTAIL(prog->anchored_substr)!=0), strbeg), + prog->anchored_substr, + PL_multiline ? FBMrf_MULTILINE : 0); + DEBUG_r(PerlIO_printf(Perl_debug_log, + "%s anchored substr `%s%.*s%s'%s", (s ? "Found" : "Contradicts"), PL_colors[0], (int)(SvCUR(prog->anchored_substr) @@ -508,17 +574,16 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, } DEBUG_r(PerlIO_printf(Perl_debug_log, ", trying floating at offset %ld...\n", - (long)(s1 + 1 - i_strpos))); - PL_regeol = strend; /* Used in HOP() */ - other_last = last1 + prog->anchored_offset + 1; - s = HOPc(last, 1); + (long)(HOP3c(s1, 1, strend) - i_strpos))); + other_last = HOP3c(last1, prog->anchored_offset+1, strend); + s = HOP3c(last, 1, strend); goto restart; } else { DEBUG_r(PerlIO_printf(Perl_debug_log, " at offset %ld...\n", (long)(s - i_strpos))); - t = s - prog->anchored_offset; - other_last = s + 1; + t = HOP3c(s, -prog->anchored_offset, strbeg); + other_last = HOP3c(s, 1, strend); s = s1; if (t == strpos) goto try_at_start; @@ -530,11 +595,12 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, char *last, *last1; char *s1 = s; - t = s - start_shift; - last1 = last = strend - prog->minlen + prog->float_min_offset; - if (last - t > prog->float_max_offset) - last = t + prog->float_max_offset; - s = t + prog->float_min_offset; + t = HOP3c(s, -start_shift, strbeg); + last1 = last = + HOP3c(strend, -prog->minlen + prog->float_min_offset, strbeg); + if (CHR_DIST((U8*)last, (U8*)t) > prog->float_max_offset) + last = HOP3c(t, prog->float_max_offset, strend); + s = HOP3c(t, prog->float_min_offset, strend); if (s < other_last) s = other_last; /* XXXX It is not documented what units *_offsets are in. Assume bytes. */ @@ -561,15 +627,14 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, DEBUG_r(PerlIO_printf(Perl_debug_log, ", trying anchored starting at offset %ld...\n", (long)(s1 + 1 - i_strpos))); - other_last = last + 1; - PL_regeol = strend; /* Used in HOP() */ - s = HOPc(t, 1); + other_last = last; + s = HOP3c(t, 1, strend); goto restart; } else { DEBUG_r(PerlIO_printf(Perl_debug_log, " at offset %ld...\n", (long)(s - i_strpos))); - other_last = s + 1; + other_last = s; /* Fix this later. --Hugo */ s = s1; if (t == strpos) goto try_at_start; @@ -579,13 +644,10 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, } t = s - prog->check_offset_max; - tmp = PL_bostr; if (s - strpos > prog->check_offset_max /* signed-corrected t > strpos */ && (!(prog->reganch & ROPT_UTF8) - || (PL_bostr = strpos, /* Used in regcopmaybe() */ - ((t = reghopmaybe_c(s, -(prog->check_offset_max))) - && t > strpos)))) { - PL_bostr = tmp; + || ((t = reghopmaybe3_c(s, -prog->check_offset_max, strpos)) + && t > strpos))) { /* Fixed substring is found far enough so that the match cannot start at strpos. */ try_at_offset: @@ -608,7 +670,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, Thus we can arrive here only if check substr is float. Redo checking for "other"=="fixed". */ - strpos = t + 1; + strpos = t + 1; DEBUG_r(PerlIO_printf(Perl_debug_log, "Found /%s^%s/m at offset %ld, rescanning for anchored from offset %ld...\n", PL_colors[0],PL_colors[1], (long)(strpos - i_strpos), (long)(strpos - i_strpos + prog->anchored_offset))); goto do_other_anchored; @@ -625,7 +687,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, than for "\n", so one should lower the limit for t? */ DEBUG_r(PerlIO_printf(Perl_debug_log, "Found /%s^%s/m, restarting lookup for check-string at offset %ld...\n", PL_colors[0],PL_colors[1], (long)(t + 1 - i_strpos))); - strpos = s = t + 1; + other_last = strpos = s = t + 1; goto restart; } t++; @@ -643,7 +705,6 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, ++BmUSEFUL(prog->check_substr); /* hooray/5 */ } else { - PL_bostr = tmp; /* The found string does not prohibit matching at strpos, - no optimization of calling REx engine can be performed, unless it was an MBOL and we are not after MBOL, @@ -652,7 +713,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, /* Even in this situation we may use MBOL flag if strpos is offset wrt the start of the string. */ if (ml_anch && sv && !SvROK(sv) /* See prev comment on SvROK */ - && (strpos + SvCUR(sv) != strend) && strpos[-1] != '\n' + && (strpos != strbeg) && strpos[-1] != '\n' /* May be due to an implicit anchor of m{.*foo} */ && !(prog->reganch & ROPT_IMPLICIT)) { @@ -674,6 +735,7 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, SvREFCNT_dec(prog->check_substr); prog->check_substr = Nullsv; /* disable */ prog->float_substr = Nullsv; /* clear */ + check = Nullsv; /* abort */ s = strpos; /* XXXX This is a remnant of the old implementation. It looks wasteful, since now INTUIT can use many @@ -695,24 +757,27 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, regstclass does not come from lookahead... */ /* If regstclass takes bytelength more than 1: If charlength==1, OK. This leaves EXACTF only, which is dealt with in find_byclass(). */ + U8* str = (U8*)STRING(prog->regstclass); int cl_l = (PL_regkind[(U8)OP(prog->regstclass)] == EXACT - ? STR_LEN(prog->regstclass) + ? CHR_DIST(str+STR_LEN(prog->regstclass), str) : 1); char *endpos = (prog->anchored_substr || ml_anch) - ? s + (prog->minlen? cl_l : 0) - : (prog->float_substr ? check_at - start_shift + cl_l - : strend) ; - char *startpos = sv && SvPOK(sv) ? strend - SvCUR(sv) : s; + ? HOP3c(s, (prog->minlen ? cl_l : 0), strend) + : (prog->float_substr + ? HOP3c(HOP3c(check_at, -start_shift, strbeg), + cl_l, strend) + : strend); + char *startpos = strbeg; t = s; if (prog->reganch & ROPT_UTF8) { - PL_regdata = prog->data; /* Used by REGINCLASS UTF logic */ + PL_regdata = prog->data; PL_bostr = startpos; } s = find_byclass(prog, prog->regstclass, s, endpos, startpos, 1); if (!s) { #ifdef DEBUGGING - char *what; + char *what = 0; #endif if (endpos == strend) { DEBUG_r( PerlIO_printf(Perl_debug_log, @@ -728,14 +793,15 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, if (prog->anchored_substr == check) { DEBUG_r( what = "anchored" ); hop_and_restart: - PL_regeol = strend; /* Used in HOP() */ - s = HOPc(t, 1); + s = HOP3c(t, 1, strend); if (s + start_shift + end_shift > strend) { /* XXXX Should be taken into account earlier? */ DEBUG_r( PerlIO_printf(Perl_debug_log, "Could not match STCLASS...\n") ); goto fail; } + if (!check) + goto giveup; DEBUG_r( PerlIO_printf(Perl_debug_log, "Looking for %s substr starting at offset %ld...\n", what, (long)(s + start_shift - i_strpos)) ); @@ -745,7 +811,9 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, if (t + start_shift >= check_at) /* Contradicts floating=check */ goto retry_floating_check; /* Recheck anchored substring, but not floating... */ - s = check_at; + s = check_at; + if (!check) + goto giveup; DEBUG_r( PerlIO_printf(Perl_debug_log, "Looking for anchored substr starting at offset %ld...\n", (long)(other_last - i_strpos)) ); @@ -755,6 +823,8 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, current position only: */ if (ml_anch) { s = t = t + 1; + if (!check) + goto giveup; DEBUG_r( PerlIO_printf(Perl_debug_log, "Looking for /%s^%s/m starting at offset %ld...\n", PL_colors[0],PL_colors[1], (long)(t - i_strpos)) ); @@ -768,16 +838,22 @@ Perl_re_intuit_start(pTHX_ regexp *prog, SV *sv, char *strpos, DEBUG_r( what = "floating" ); goto hop_and_restart; } - DEBUG_r( if (t != s) - PerlIO_printf(Perl_debug_log, + if (t != s) { + DEBUG_r(PerlIO_printf(Perl_debug_log, "By STCLASS: moving %ld --> %ld\n", - (long)(t - i_strpos), (long)(s - i_strpos)); - else - PerlIO_printf(Perl_debug_log, - "Does not contradict STCLASS...\n") ); + (long)(t - i_strpos), (long)(s - i_strpos)) + ); + } + else { + DEBUG_r(PerlIO_printf(Perl_debug_log, + "Does not contradict STCLASS...\n"); + ); + } } - DEBUG_r(PerlIO_printf(Perl_debug_log, "%sGuessed:%s match at offset %ld\n", - PL_colors[4], PL_colors[5], (long)(s - i_strpos)) ); + giveup: + DEBUG_r(PerlIO_printf(Perl_debug_log, "%s%s:%s match at offset %ld\n", + PL_colors[4], (check ? "Guessed" : "Giving up"), + PL_colors[5], (long)(s - i_strpos)) ); return s; fail_finish: /* Substring not found */ @@ -800,25 +876,13 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta unsigned int c2; char *e; register I32 tmp = 1; /* Scratch variable? */ + register bool do_utf8 = DO_UTF8(PL_reg_sv); /* We know what class it must start with. */ switch (OP(c)) { - case ANYOFUTF8: - while (s < strend) { - if (REGINCLASSUTF8(c, (U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; - else - tmp = doevery; - } - else - tmp = 1; - s += UTF8SKIP(s); - } - break; case ANYOF: while (s < strend) { - if (REGINCLASS(c, *(U8*)s)) { + if (reginclass(c, (U8*)s, do_utf8)) { if (tmp && (norun || regtry(prog, s))) goto got_it; else @@ -826,14 +890,20 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta } else tmp = 1; - s++; + s += do_utf8 ? UTF8SKIP(s) : 1; } break; case EXACTF: m = STRING(c); ln = STR_LEN(c); - c1 = *(U8*)m; - c2 = PL_fold[c1]; + if (UTF) { + c1 = to_utf8_lower((U8*)m); + c2 = to_utf8_upper((U8*)m); + } + else { + c1 = *(U8*)m; + c2 = PL_fold[c1]; + } goto do_exactf; case EXACTFL: m = STRING(c); @@ -845,62 +915,87 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta if (norun && e < s) e = s; /* Due to minlen logic of intuit() */ - /* Here it is NOT UTF! */ - if (c1 == c2) { - while (s <= e) { - if ( *(U8*)s == c1 - && (ln == 1 || !(OP(c) == EXACTF - ? ibcmp(s, m, ln) - : ibcmp_locale(s, m, ln))) - && (norun || regtry(prog, s)) ) - goto got_it; - s++; - } - } else { - while (s <= e) { - if ( (*(U8*)s == c1 || *(U8*)s == c2) - && (ln == 1 || !(OP(c) == EXACTF - ? ibcmp(s, m, ln) - : ibcmp_locale(s, m, ln))) - && (norun || regtry(prog, s)) ) - goto got_it; - s++; - } + + if (do_utf8) { + STRLEN len; + if (c1 == c2) + while (s <= e) { + if ( utf8_to_uvchr((U8*)s, &len) == c1 + && regtry(prog, s) ) + goto got_it; + s += len; + } + else + while (s <= e) { + UV c = utf8_to_uvchr((U8*)s, &len); + if ( (c == c1 || c == c2) && regtry(prog, s) ) + goto got_it; + s += len; + } + } + else { + if (c1 == c2) + while (s <= e) { + if ( *(U8*)s == c1 + && (ln == 1 || !(OP(c) == EXACTF + ? ibcmp(s, m, ln) + : ibcmp_locale(s, m, ln))) + && (norun || regtry(prog, s)) ) + goto got_it; + s++; + } + else + while (s <= e) { + if ( (*(U8*)s == c1 || *(U8*)s == c2) + && (ln == 1 || !(OP(c) == EXACTF + ? ibcmp(s, m, ln) + : ibcmp_locale(s, m, ln))) + && (norun || regtry(prog, s)) ) + goto got_it; + s++; + } } break; case BOUNDL: PL_reg_flags |= RF_tainted; /* FALL THROUGH */ case BOUND: - tmp = (s != startpos) ? UCHARAT(s - 1) : '\n'; - tmp = ((OP(c) == BOUND ? isALNUM(tmp) : isALNUM_LC(tmp)) != 0); - while (s < strend) { - if (tmp == !(OP(c) == BOUND ? isALNUM(*s) : isALNUM_LC(*s))) { - tmp = !tmp; - if ((norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + if (s == PL_bostr) + tmp = '\n'; + else { + U8 *r = reghop3((U8*)s, -1, (U8*)startpos); + + if (s > (char*)r) + tmp = (I32)utf8n_to_uvchr(r, s - (char*)r, 0, 0); + } + tmp = ((OP(c) == BOUND ? + isALNUM_uni(tmp) : isALNUM_LC_uvchr(UNI_TO_NATIVE(tmp))) != 0); + LOAD_UTF8_CHARCLASS(alnum,"a"); + while (s < strend) { + if (tmp == !(OP(c) == BOUND ? + swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8) : + isALNUM_LC_utf8((U8*)s))) + { + tmp = !tmp; + if ((norun || regtry(prog, s))) + goto got_it; + } + s += UTF8SKIP(s); } - s++; } - if ((!prog->minlen && tmp) && (norun || regtry(prog, s))) - goto got_it; - break; - case BOUNDLUTF8: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case BOUNDUTF8: - tmp = (I32)(s != startpos) ? utf8_to_uv(reghop((U8*)s, -1), 0) : '\n'; - tmp = ((OP(c) == BOUNDUTF8 ? isALNUM_uni(tmp) : isALNUM_LC_uni(tmp)) != 0); - while (s < strend) { - if (tmp == !(OP(c) == BOUNDUTF8 ? - swash_fetch(PL_utf8_alnum, (U8*)s) : - isALNUM_LC_utf8((U8*)s))) - { - tmp = !tmp; - if ((norun || regtry(prog, s))) - goto got_it; + else { + tmp = (s != PL_bostr) ? UCHARAT(s - 1) : '\n'; + tmp = ((OP(c) == BOUND ? isALNUM(tmp) : isALNUM_LC(tmp)) != 0); + while (s < strend) { + if (tmp == + !(OP(c) == BOUND ? isALNUM(*s) : isALNUM_LC(*s))) { + tmp = !tmp; + if ((norun || regtry(prog, s))) + goto got_it; + } + s++; } - s += UTF8SKIP(s); } if ((!prog->minlen && tmp) && (norun || regtry(prog, s))) goto got_it; @@ -909,358 +1004,390 @@ S_find_byclass(pTHX_ regexp * prog, regnode *c, char *s, char *strend, char *sta PL_reg_flags |= RF_tainted; /* FALL THROUGH */ case NBOUND: - tmp = (s != startpos) ? UCHARAT(s - 1) : '\n'; - tmp = ((OP(c) == NBOUND ? isALNUM(tmp) : isALNUM_LC(tmp)) != 0); - while (s < strend) { - if (tmp == !(OP(c) == NBOUND ? isALNUM(*s) : isALNUM_LC(*s))) - tmp = !tmp; - else if ((norun || regtry(prog, s))) - goto got_it; - s++; + if (do_utf8) { + if (s == PL_bostr) + tmp = '\n'; + else { + U8 *r = reghop3((U8*)s, -1, (U8*)startpos); + + if (s > (char*)r) + tmp = (I32)utf8n_to_uvchr(r, s - (char*)r, 0, 0); + } + tmp = ((OP(c) == NBOUND ? + isALNUM_uni(tmp) : isALNUM_LC_uvchr(UNI_TO_NATIVE(tmp))) != 0); + LOAD_UTF8_CHARCLASS(alnum,"a"); + while (s < strend) { + if (tmp == !(OP(c) == NBOUND ? + swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8) : + isALNUM_LC_utf8((U8*)s))) + tmp = !tmp; + else if ((norun || regtry(prog, s))) + goto got_it; + s += UTF8SKIP(s); + } } - if ((!prog->minlen && !tmp) && (norun || regtry(prog, s))) - goto got_it; - break; - case NBOUNDLUTF8: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case NBOUNDUTF8: - tmp = (I32)(s != startpos) ? utf8_to_uv(reghop((U8*)s, -1), 0) : '\n'; - tmp = ((OP(c) == NBOUNDUTF8 ? isALNUM_uni(tmp) : isALNUM_LC_uni(tmp)) != 0); - while (s < strend) { - if (tmp == !(OP(c) == NBOUNDUTF8 ? - swash_fetch(PL_utf8_alnum, (U8*)s) : - isALNUM_LC_utf8((U8*)s))) - tmp = !tmp; - else if ((norun || regtry(prog, s))) - goto got_it; - s += UTF8SKIP(s); + else { + tmp = (s != PL_bostr) ? UCHARAT(s - 1) : '\n'; + tmp = ((OP(c) == NBOUND ? + isALNUM(tmp) : isALNUM_LC(tmp)) != 0); + while (s < strend) { + if (tmp == + !(OP(c) == NBOUND ? isALNUM(*s) : isALNUM_LC(*s))) + tmp = !tmp; + else if ((norun || regtry(prog, s))) + goto got_it; + s++; + } } if ((!prog->minlen && !tmp) && (norun || regtry(prog, s))) goto got_it; break; case ALNUM: - while (s < strend) { - if (isALNUM(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + LOAD_UTF8_CHARCLASS(alnum,"a"); + while (s < strend) { + if (swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case ALNUMUTF8: - while (s < strend) { - if (swash_fetch(PL_utf8_alnum, (U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (isALNUM(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case ALNUML: PL_reg_flags |= RF_tainted; - while (s < strend) { - if (isALNUM_LC(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + while (s < strend) { + if (isALNUM_LC_utf8((U8*)s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case ALNUMLUTF8: - PL_reg_flags |= RF_tainted; - while (s < strend) { - if (isALNUM_LC_utf8((U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (isALNUM_LC(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case NALNUM: - while (s < strend) { - if (!isALNUM(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + LOAD_UTF8_CHARCLASS(alnum,"a"); + while (s < strend) { + if (!swash_fetch(PL_utf8_alnum, (U8*)s, do_utf8)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case NALNUMUTF8: - while (s < strend) { - if (!swash_fetch(PL_utf8_alnum, (U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (!isALNUM(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case NALNUML: PL_reg_flags |= RF_tainted; - while (s < strend) { - if (!isALNUM_LC(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + while (s < strend) { + if (!isALNUM_LC_utf8((U8*)s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case NALNUMLUTF8: - PL_reg_flags |= RF_tainted; - while (s < strend) { - if (!isALNUM_LC_utf8((U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (!isALNUM_LC(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case SPACE: - while (s < strend) { - if (isSPACE(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + LOAD_UTF8_CHARCLASS(space," "); + while (s < strend) { + if (*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, do_utf8)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case SPACEUTF8: - while (s < strend) { - if (*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (isSPACE(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case SPACEL: PL_reg_flags |= RF_tainted; - while (s < strend) { - if (isSPACE_LC(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + while (s < strend) { + if (*s == ' ' || isSPACE_LC_utf8((U8*)s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case SPACELUTF8: - PL_reg_flags |= RF_tainted; - while (s < strend) { - if (*s == ' ' || isSPACE_LC_utf8((U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (isSPACE_LC(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case NSPACE: - while (s < strend) { - if (!isSPACE(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + LOAD_UTF8_CHARCLASS(space," "); + while (s < strend) { + if (!(*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, do_utf8))) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case NSPACEUTF8: - while (s < strend) { - if (!(*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s))) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (!isSPACE(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case NSPACEL: PL_reg_flags |= RF_tainted; - while (s < strend) { - if (!isSPACE_LC(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + while (s < strend) { + if (!(*s == ' ' || isSPACE_LC_utf8((U8*)s))) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case NSPACELUTF8: - PL_reg_flags |= RF_tainted; - while (s < strend) { - if (!(*s == ' ' || isSPACE_LC_utf8((U8*)s))) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (!isSPACE_LC(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case DIGIT: - while (s < strend) { - if (isDIGIT(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + LOAD_UTF8_CHARCLASS(digit,"0"); + while (s < strend) { + if (swash_fetch(PL_utf8_digit,(U8*)s, do_utf8)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case DIGITUTF8: - while (s < strend) { - if (swash_fetch(PL_utf8_digit,(U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (isDIGIT(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case DIGITL: PL_reg_flags |= RF_tainted; - while (s < strend) { - if (isDIGIT_LC(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + while (s < strend) { + if (isDIGIT_LC_utf8((U8*)s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case DIGITLUTF8: - PL_reg_flags |= RF_tainted; - while (s < strend) { - if (isDIGIT_LC_utf8((U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (isDIGIT_LC(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case NDIGIT: - while (s < strend) { - if (!isDIGIT(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + LOAD_UTF8_CHARCLASS(digit,"0"); + while (s < strend) { + if (!swash_fetch(PL_utf8_digit,(U8*)s, do_utf8)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case NDIGITUTF8: - while (s < strend) { - if (!swash_fetch(PL_utf8_digit,(U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (!isDIGIT(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; case NDIGITL: PL_reg_flags |= RF_tainted; - while (s < strend) { - if (!isDIGIT_LC(*s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + if (do_utf8) { + while (s < strend) { + if (!isDIGIT_LC_utf8((U8*)s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s += UTF8SKIP(s); } - else - tmp = 1; - s++; } - break; - case NDIGITLUTF8: - PL_reg_flags |= RF_tainted; - while (s < strend) { - if (!isDIGIT_LC_utf8((U8*)s)) { - if (tmp && (norun || regtry(prog, s))) - goto got_it; + else { + while (s < strend) { + if (!isDIGIT_LC(*s)) { + if (tmp && (norun || regtry(prog, s))) + goto got_it; + else + tmp = doevery; + } else - tmp = doevery; + tmp = 1; + s++; } - else - tmp = 1; - s += UTF8SKIP(s); } break; default: @@ -1284,7 +1411,6 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * /* data: May be used for some additional optimizations. */ /* nosave: For optimizations. */ { - dTHR; register char *s; register regnode *c; register char *startpos = stringarg; @@ -1296,12 +1422,13 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * I32 scream_pos = -1; /* Internal iterator of scream. */ char *scream_olds; SV* oreplsv = GvSV(PL_replgv); + bool do_utf8 = DO_UTF8(sv); PL_regcc = 0; cache_re(prog); #ifdef DEBUGGING - PL_regnarrate = PL_debug & 512; + PL_regnarrate = DEBUG_r_TEST; #endif /* Be paranoid... */ @@ -1311,14 +1438,12 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * } minlen = prog->minlen; - if (strend - startpos < minlen) goto phooey; - - if (startpos == strbeg) /* is ^ valid at stringarg? */ - PL_regprev = '\n'; + if (do_utf8) { + if (!(prog->reganch & ROPT_SANY_SEEN)) + if (utf8_distance((U8*)strend, (U8*)startpos) < minlen) goto phooey; + } else { - PL_regprev = (U32)stringarg[-1]; - if (!PL_multiline && PL_regprev == '\n') - PL_regprev = '\0'; /* force ^ to NOT match */ + if (strend - startpos < minlen) goto phooey; } /* Check validity of program. */ @@ -1357,7 +1482,8 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * PL_reg_ganch = startpos; else if (sv && SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv) - && (mg = mg_find(sv, 'g')) && mg->mg_len >= 0) { + && (mg = mg_find(sv, PERL_MAGIC_regex_global)) + && mg->mg_len >= 0) { PL_reg_ganch = strbeg + mg->mg_len; /* Defined pos() */ if (prog->reganch & ROPT_ANCH_GPOS) { if (s > PL_reg_ganch) @@ -1369,7 +1495,8 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * PL_reg_ganch = strbeg; } - if (!(flags & REXEC_CHECKED) && prog->check_substr != Nullsv) { + if (do_utf8 == (UTF!=0) && + !(flags & REXEC_CHECKED) && prog->check_substr != Nullsv) { re_scream_pos_data d; d.scream_olds = &scream_olds; @@ -1404,7 +1531,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * if (minlen) dontbother = minlen - 1; - end = HOPc(strend, -dontbother) - 1; + end = HOP3c(strend, -dontbother, strbeg) - 1; /* for multiline we only have to try after newlines */ if (prog->check_substr) { if (s == startpos) @@ -1442,7 +1569,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * } /* Messy cases: unanchored match. */ - if (prog->anchored_substr && prog->reganch & ROPT_SKIP) { + if (prog->anchored_substr && prog->reganch & ROPT_SKIP) { /* we have /x+whatever/ */ /* it must be a one character string (XXXX Except UTF?) */ char ch = SvPVX(prog->anchored_substr)[0]; @@ -1450,7 +1577,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * int did_match = 0; #endif - if (UTF) { + if (do_utf8) { while (s < strend) { if (*s == ch) { DEBUG_r( did_match = 1 ); @@ -1474,23 +1601,25 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * s++; } } - DEBUG_r(did_match || + DEBUG_r(if (!did_match) PerlIO_printf(Perl_debug_log, - "Did not find anchored character...\n")); + "Did not find anchored character...\n") + ); } /*SUPPRESS 560*/ - else if (prog->anchored_substr != Nullsv - || (prog->float_substr != Nullsv - && prog->float_max_offset < strend - s)) { - SV *must = prog->anchored_substr + else if (do_utf8 == (UTF!=0) && + (prog->anchored_substr != Nullsv + || (prog->float_substr != Nullsv + && prog->float_max_offset < strend - s))) { + SV *must = prog->anchored_substr ? prog->anchored_substr : prog->float_substr; - I32 back_max = + I32 back_max = prog->anchored_substr ? prog->anchored_offset : prog->float_max_offset; - I32 back_min = + I32 back_min = prog->anchored_substr ? prog->anchored_offset : prog->float_min_offset; - char *last = HOPc(strend, /* Cannot start after this */ + char *last = HOP3c(strend, /* Cannot start after this */ -(I32)(CHR_SVLEN(must) - - (SvTAIL(must) != 0) + back_min)); + - (SvTAIL(must) != 0) + back_min), strbeg); char *last1; /* Last position checked before */ #ifdef DEBUGGING int did_match = 0; @@ -1507,11 +1636,11 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * dontbother = end_shift; strend = HOPc(strend, -dontbother); while ( (s <= last) && - ((flags & REXEC_SCREAM) - ? (s = screaminstr(sv, must, HOPc(s, back_min) - strbeg, + ((flags & REXEC_SCREAM) + ? (s = screaminstr(sv, must, HOP3c(s, back_min, strend) - strbeg, end_shift, &scream_pos, 0)) - : (s = fbm_instr((unsigned char*)HOP(s, back_min), - (unsigned char*)strend, must, + : (s = fbm_instr((unsigned char*)HOP3(s, back_min, strend), + (unsigned char*)strend, must, PL_multiline ? FBMrf_MULTILINE : 0))) ) { DEBUG_r( did_match = 1 ); if (HOPc(s, -back_max) > last1) { @@ -1524,7 +1653,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * last1 = HOPc(s, -back_min); s = t; } - if (UTF) { + if (do_utf8) { while (s <= last1) { if (regtry(prog, s)) goto got_it; @@ -1539,20 +1668,27 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * } } } - DEBUG_r(did_match || - PerlIO_printf(Perl_debug_log, "Did not find %s substr `%s%.*s%s'%s...\n", + DEBUG_r(if (!did_match) + PerlIO_printf(Perl_debug_log, + "Did not find %s substr `%s%.*s%s'%s...\n", ((must == prog->anchored_substr) ? "anchored" : "floating"), PL_colors[0], (int)(SvCUR(must) - (SvTAIL(must)!=0)), SvPVX(must), - PL_colors[1], (SvTAIL(must) ? "$" : ""))); + PL_colors[1], (SvTAIL(must) ? "$" : "")) + ); goto phooey; } else if ((c = prog->regstclass)) { if (minlen && PL_regkind[(U8)OP(prog->regstclass)] != EXACT) /* don't bother with what can't match */ strend = HOPc(strend, -(minlen - 1)); + DEBUG_r({ + SV *prop = sv_newmortal(); + regprop(prop, c); + PerlIO_printf(Perl_debug_log, "Matching stclass `%s' against `%s'\n", SvPVX(prop), s); + }); if (find_byclass(prog, c, s, strend, startpos, 0)) goto got_it; DEBUG_r(PerlIO_printf(Perl_debug_log, "Contradicts stclass...\n")); @@ -1566,7 +1702,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * last = screaminstr(sv, prog->float_substr, s - strbeg, end_shift, &scream_pos, 1); /* last one */ if (!last) - last = scream_olds; /* Only one occurence. */ + last = scream_olds; /* Only one occurrence. */ } else { STRLEN len; @@ -1576,13 +1712,13 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * if (memEQ(strend - len + 1, little, len - 1)) last = strend - len + 1; else if (!PL_multiline) - last = memEQ(strend - len, little, len) + last = memEQ(strend - len, little, len) ? strend - len : Nullch; else goto find_last; } else { find_last: - if (len) + if (len) last = rninstr(s, strend, little, little + len); else last = strend; /* matching `$' */ @@ -1600,7 +1736,7 @@ Perl_regexec_flags(pTHX_ register regexp *prog, char *stringarg, register char * dontbother = minlen - 1; strend -= dontbother; /* this one's always in bytes! */ /* We don't know much -- general case. */ - if (UTF) { + if (do_utf8) { for (;;) { if (regtry(prog, s)) goto got_it; @@ -1651,7 +1787,7 @@ got_it: prog->sublen = PL_regeol - strbeg; /* strend may have been modified */ } } - + return 1; phooey: @@ -1668,12 +1804,14 @@ phooey: STATIC I32 /* 0 failure, 1 success */ S_regtry(pTHX_ regexp *prog, char *startpos) { - dTHR; register I32 i; register I32 *sp; register I32 *ep; CHECKPOINT lastcp; +#ifdef DEBUGGING + PL_regindent = 0; /* XXXX Not good when matches are reenterable... */ +#endif if ((prog->reganch & ROPT_EVAL_SEEN) && !PL_reg_eval_set) { MAGIC *mg; @@ -1698,11 +1836,12 @@ S_regtry(pTHX_ regexp *prog, char *startpos) DEFSV = PL_reg_sv; } - if (!(SvTYPE(PL_reg_sv) >= SVt_PVMG && SvMAGIC(PL_reg_sv) - && (mg = mg_find(PL_reg_sv, 'g')))) { + if (!(SvTYPE(PL_reg_sv) >= SVt_PVMG && SvMAGIC(PL_reg_sv) + && (mg = mg_find(PL_reg_sv, PERL_MAGIC_regex_global)))) { /* prepare for quick setting of pos */ - sv_magic(PL_reg_sv, (SV*)0, 'g', Nullch, 0); - mg = mg_find(PL_reg_sv, 'g'); + sv_magic(PL_reg_sv, (SV*)0, + PERL_MAGIC_regex_global, Nullch, 0); + mg = mg_find(PL_reg_sv, PERL_MAGIC_regex_global); mg->mg_len = -1; } PL_reg_magic = mg; @@ -1745,24 +1884,67 @@ S_regtry(pTHX_ regexp *prog, char *startpos) /* XXXX What this code is doing here?!!! There should be no need to do this again and again, PL_reglastparen should take care of - this! */ + this! --ilya*/ + + /* 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 + * above-mentioned test suite tests to succeed. The common theme + * on those tests seems to be returning null fields from matches. + * --jhi */ +#if 1 sp = prog->startp; ep = prog->endp; if (prog->nparens) { - for (i = prog->nparens; i >= 1; i--) { + for (i = prog->nparens; i > *PL_reglastparen; i--) { *++sp = -1; *++ep = -1; } } - REGCP_SET; +#endif + REGCP_SET(lastcp); if (regmatch(prog->program + 1)) { prog->endp[0] = PL_reginput - PL_bostr; return 1; } - REGCP_UNWIND; + REGCP_UNWIND(lastcp); return 0; } +#define RE_UNWIND_BRANCH 1 +#define RE_UNWIND_BRANCHJ 2 + +union re_unwind_t; + +typedef struct { /* XX: makes sense to enlarge it... */ + I32 type; + I32 prev; + CHECKPOINT lastcp; +} re_unwind_generic_t; + +typedef struct { + I32 type; + I32 prev; + CHECKPOINT lastcp; + I32 lastparen; + regnode *next; + char *locinput; + I32 nextchr; +#ifdef DEBUGGING + int regindent; +#endif +} re_unwind_branch_t; + +typedef union re_unwind_t { + I32 type; + re_unwind_generic_t generic; + re_unwind_branch_t branch; +} re_unwind_t; + /* - regmatch - main matching routine * @@ -1780,18 +1962,23 @@ S_regtry(pTHX_ regexp *prog, char *startpos) STATIC I32 /* 0 failure, 1 success */ S_regmatch(pTHX_ regnode *prog) { - dTHR; register regnode *scan; /* Current node. */ regnode *next; /* Next node. */ regnode *inner; /* Next node in internal branch. */ register I32 nextchr; /* renamed nextchr - nextchar colides with function of same name */ register I32 n; /* no or next */ - register I32 ln; /* len or last */ - register char *s; /* operand or save */ + register I32 ln = 0; /* len or last */ + register char *s = Nullch; /* operand or save */ register char *locinput = PL_reginput; - register I32 c1, c2, paren; /* case fold search, parenth */ + register I32 c1 = 0, c2 = 0, paren; /* case fold search, parenth */ int minmod = 0, sw = 0, logical = 0; + I32 unwind = 0; +#if 0 + I32 firstcp = PL_savestack_ix; +#endif + register bool do_utf8 = DO_UTF8(PL_reg_sv); + #ifdef DEBUGGING PL_regindent++; #endif @@ -1801,7 +1988,7 @@ S_regmatch(pTHX_ regnode *prog) scan = prog; while (scan != NULL) { #define sayNO_L (logical ? (logical = 0, sw = 0, goto cont) : sayNO) -#ifdef DEBUGGING +#if 1 # define sayYES goto yes # define sayNO goto no # define sayYES_FINAL goto yes_final @@ -1823,31 +2010,36 @@ S_regmatch(pTHX_ regnode *prog) SV *prop = sv_newmortal(); int docolor = *PL_colors[0]; int taill = (docolor ? 10 : 7); /* 3 chars for "> <" */ - int l = (PL_regeol - locinput > taill ? taill : PL_regeol - locinput); + int l = (PL_regeol - locinput) > taill ? taill : (PL_regeol - locinput); /* The part of the string before starttry has one color (pref0_len chars), between starttry and current position another one (pref_len - pref0_len chars), after the current position the third one. We assume that pref0_len <= pref_len, otherwise we decrease pref0_len. */ - int pref_len = (locinput - PL_bostr > (5 + taill) - l - ? (5 + taill) - l : locinput - PL_bostr); - int pref0_len = pref_len - (locinput - PL_reg_starttry); + int pref_len = (locinput - PL_bostr) > (5 + taill) - l + ? (5 + taill) - l : locinput - PL_bostr; + int pref0_len; + while (UTF8_IS_CONTINUATION(*(U8*)(locinput - pref_len))) + pref_len++; + pref0_len = pref_len - (locinput - PL_reg_starttry); if (l + pref_len < (5 + taill) && l < PL_regeol - locinput) - l = ( PL_regeol - locinput > (5 + taill) - pref_len + l = ( PL_regeol - locinput > (5 + taill) - pref_len ? (5 + taill) - pref_len : PL_regeol - locinput); + while (UTF8_IS_CONTINUATION(*(U8*)(locinput + l))) + l--; if (pref0_len < 0) pref0_len = 0; if (pref0_len > pref_len) pref0_len = pref_len; regprop(prop, scan); - PerlIO_printf(Perl_debug_log, + PerlIO_printf(Perl_debug_log, "%4"IVdf" <%s%.*s%s%s%.*s%s%s%s%.*s%s>%*s|%3"IVdf":%*s%s\n", - (IV)(locinput - PL_bostr), - PL_colors[4], pref0_len, + (IV)(locinput - PL_bostr), + PL_colors[4], pref0_len, locinput - pref_len, PL_colors[5], - PL_colors[2], pref_len - pref0_len, + PL_colors[2], pref_len - pref0_len, locinput - pref_len + pref0_len, PL_colors[3], (docolor ? "" : "> <"), PL_colors[0], l, locinput, PL_colors[1], @@ -1863,19 +2055,16 @@ S_regmatch(pTHX_ regnode *prog) switch (OP(scan)) { case BOL: - if (locinput == PL_bostr - ? PL_regprev == '\n' - : (PL_multiline && - (nextchr || locinput < PL_regeol) && locinput[-1] == '\n') ) + if (locinput == PL_bostr || (PL_multiline && + (nextchr || locinput < PL_regeol) && locinput[-1] == '\n') ) { /* regtill = regbol; */ break; } sayNO; case MBOL: - if (locinput == PL_bostr - ? PL_regprev == '\n' - : ((nextchr || locinput < PL_regeol) && locinput[-1] == '\n') ) + if (locinput == PL_bostr || + ((nextchr || locinput < PL_regeol) && locinput[-1] == '\n')) { break; } @@ -1909,43 +2098,52 @@ S_regmatch(pTHX_ regnode *prog) if (PL_regeol != locinput) sayNO; break; - case SANYUTF8: - if (nextchr & 0x80) { - locinput += PL_utf8skip[nextchr]; - if (locinput > PL_regeol) - sayNO; - nextchr = UCHARAT(locinput); - break; - } - if (!nextchr && locinput >= PL_regeol) - sayNO; - nextchr = UCHARAT(++locinput); - break; case SANY: if (!nextchr && locinput >= PL_regeol) sayNO; nextchr = UCHARAT(++locinput); break; - case ANYUTF8: - if (nextchr & 0x80) { + case REG_ANY: + if ((!nextchr && locinput >= PL_regeol) || nextchr == '\n') + sayNO; + if (do_utf8) { locinput += PL_utf8skip[nextchr]; if (locinput > PL_regeol) sayNO; nextchr = UCHARAT(locinput); - break; } - if ((!nextchr && locinput >= PL_regeol) || nextchr == '\n') - sayNO; - nextchr = UCHARAT(++locinput); - break; - case REG_ANY: - if ((!nextchr && locinput >= PL_regeol) || nextchr == '\n') - sayNO; - nextchr = UCHARAT(++locinput); + else + nextchr = UCHARAT(++locinput); break; case EXACT: s = STRING(scan); ln = STR_LEN(scan); + if (do_utf8 != (UTF!=0)) { + char *l = locinput; + char *e = s + ln; + STRLEN len; + if (do_utf8) + while (s < e) { + if (l >= PL_regeol) + sayNO; + if (*((U8*)s) != utf8_to_uvchr((U8*)l, &len)) + sayNO; + s++; + l += len; + } + else + while (s < e) { + if (l >= PL_regeol) + sayNO; + if (*((U8*)l) != utf8_to_uvchr((U8*)s, &len)) + sayNO; + s += len; + l++; + } + locinput = l; + nextchr = UCHARAT(locinput); + break; + } /* Inline the first character, for speed. */ if (UCHARAT(s) != nextchr) sayNO; @@ -1963,20 +2161,19 @@ S_regmatch(pTHX_ regnode *prog) s = STRING(scan); ln = STR_LEN(scan); - if (UTF) { + if (do_utf8) { char *l = locinput; - char *e = s + ln; + char *e; + e = s + ln; c1 = OP(scan) == EXACTF; while (s < e) { - if (l >= PL_regeol) - sayNO; - if (utf8_to_uv((U8*)s, 0) != (c1 ? - toLOWER_utf8((U8*)l) : - toLOWER_LC_utf8((U8*)l))) - { + if (l >= PL_regeol) { sayNO; } - s += UTF8SKIP(s); + if ((UTF ? utf8n_to_uvchr((U8*)s, e - s, 0, 0) : *((U8*)s)) != + (c1 ? toLOWER_utf8((U8*)l) : toLOWER_LC_utf8((U8*)l))) + sayNO; + s += UTF ? UTF8SKIP(s) : 1; l += UTF8SKIP(l); } locinput = l; @@ -1998,22 +2195,24 @@ S_regmatch(pTHX_ regnode *prog) locinput += ln; nextchr = UCHARAT(locinput); break; - case ANYOFUTF8: - if (!REGINCLASSUTF8(scan, (U8*)locinput)) - sayNO; - if (locinput >= PL_regeol) - sayNO; - locinput += PL_utf8skip[nextchr]; - nextchr = UCHARAT(locinput); - break; case ANYOF: - if (nextchr < 0) + if (do_utf8) { + if (!reginclass(scan, (U8*)locinput, do_utf8)) + sayNO; + if (locinput >= PL_regeol) + sayNO; + locinput += PL_utf8skip[nextchr]; nextchr = UCHARAT(locinput); - if (!REGINCLASS(scan, nextchr)) - sayNO; - if (!nextchr && locinput >= PL_regeol) - sayNO; - nextchr = UCHARAT(++locinput); + } + else { + if (nextchr < 0) + nextchr = UCHARAT(locinput); + if (!reginclass(scan, (U8*)locinput, do_utf8)) + sayNO; + if (!nextchr && locinput >= PL_regeol) + sayNO; + nextchr = UCHARAT(++locinput); + } break; case ALNUML: PL_reg_flags |= RF_tainted; @@ -2021,20 +2220,10 @@ S_regmatch(pTHX_ regnode *prog) case ALNUM: if (!nextchr) sayNO; - if (!(OP(scan) == ALNUM - ? isALNUM(nextchr) : isALNUM_LC(nextchr))) - sayNO; - nextchr = UCHARAT(++locinput); - break; - case ALNUMLUTF8: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case ALNUMUTF8: - if (!nextchr) - sayNO; - if (nextchr & 0x80) { - if (!(OP(scan) == ALNUMUTF8 - ? swash_fetch(PL_utf8_alnum, (U8*)locinput) + if (do_utf8) { + LOAD_UTF8_CHARCLASS(alnum,"a"); + if (!(OP(scan) == ALNUM + ? swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8) : isALNUM_LC_utf8((U8*)locinput))) { sayNO; @@ -2043,7 +2232,7 @@ S_regmatch(pTHX_ regnode *prog) nextchr = UCHARAT(locinput); break; } - if (!(OP(scan) == ALNUMUTF8 + if (!(OP(scan) == ALNUM ? isALNUM(nextchr) : isALNUM_LC(nextchr))) sayNO; nextchr = UCHARAT(++locinput); @@ -2054,20 +2243,10 @@ S_regmatch(pTHX_ regnode *prog) case NALNUM: if (!nextchr && locinput >= PL_regeol) sayNO; - if (OP(scan) == NALNUM - ? isALNUM(nextchr) : isALNUM_LC(nextchr)) - sayNO; - nextchr = UCHARAT(++locinput); - break; - case NALNUMLUTF8: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case NALNUMUTF8: - if (!nextchr && locinput >= PL_regeol) - sayNO; - if (nextchr & 0x80) { - if (OP(scan) == NALNUMUTF8 - ? swash_fetch(PL_utf8_alnum, (U8*)locinput) + if (do_utf8) { + LOAD_UTF8_CHARCLASS(alnum,"a"); + if (OP(scan) == NALNUM + ? swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8) : isALNUM_LC_utf8((U8*)locinput)) { sayNO; @@ -2076,7 +2255,7 @@ S_regmatch(pTHX_ regnode *prog) nextchr = UCHARAT(locinput); break; } - if (OP(scan) == NALNUMUTF8 + if (OP(scan) == NALNUM ? isALNUM(nextchr) : isALNUM_LC(nextchr)) sayNO; nextchr = UCHARAT(++locinput); @@ -2088,37 +2267,39 @@ S_regmatch(pTHX_ regnode *prog) case BOUND: case NBOUND: /* was last char in word? */ - ln = (locinput != PL_regbol) ? UCHARAT(locinput - 1) : PL_regprev; - if (OP(scan) == BOUND || OP(scan) == NBOUND) { - ln = isALNUM(ln); - n = isALNUM(nextchr); - } - else { - ln = isALNUM_LC(ln); - n = isALNUM_LC(nextchr); - } - if (((!ln) == (!n)) == (OP(scan) == BOUND || OP(scan) == BOUNDL)) - sayNO; - break; - case BOUNDLUTF8: - case NBOUNDLUTF8: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case BOUNDUTF8: - case NBOUNDUTF8: - /* was last char in word? */ - ln = (locinput != PL_regbol) - ? utf8_to_uv(reghop((U8*)locinput, -1), 0) : PL_regprev; - if (OP(scan) == BOUNDUTF8 || OP(scan) == NBOUNDUTF8) { - ln = isALNUM_uni(ln); - n = swash_fetch(PL_utf8_alnum, (U8*)locinput); + if (do_utf8) { + if (locinput == PL_bostr) + ln = '\n'; + else { + U8 *r = reghop((U8*)locinput, -1); + + ln = utf8n_to_uvchr(r, s - (char*)r, 0, 0); + } + if (OP(scan) == BOUND || OP(scan) == NBOUND) { + ln = isALNUM_uni(ln); + LOAD_UTF8_CHARCLASS(alnum,"a"); + n = swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8); + } + else { + ln = isALNUM_LC_uvchr(UNI_TO_NATIVE(ln)); + n = isALNUM_LC_utf8((U8*)locinput); + } } else { - ln = isALNUM_LC_uni(ln); - n = isALNUM_LC_utf8((U8*)locinput); + ln = (locinput != PL_bostr) ? + UCHARAT(locinput - 1) : '\n'; + if (OP(scan) == BOUND || OP(scan) == NBOUND) { + ln = isALNUM(ln); + n = isALNUM(nextchr); + } + else { + ln = isALNUM_LC(ln); + n = isALNUM_LC(nextchr); + } } - if (((!ln) == (!n)) == (OP(scan) == BOUNDUTF8 || OP(scan) == BOUNDLUTF8)) - sayNO; + if (((!ln) == (!n)) == (OP(scan) == BOUND || + OP(scan) == BOUNDL)) + sayNO; break; case SPACEL: PL_reg_flags |= RF_tainted; @@ -2126,32 +2307,30 @@ S_regmatch(pTHX_ regnode *prog) case SPACE: if (!nextchr) sayNO; - if (!(OP(scan) == SPACE - ? isSPACE(nextchr) : isSPACE_LC(nextchr))) - sayNO; - nextchr = UCHARAT(++locinput); - break; - case SPACELUTF8: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case SPACEUTF8: - if (!nextchr) - sayNO; - if (nextchr & 0x80) { - if (!(OP(scan) == SPACEUTF8 - ? swash_fetch(PL_utf8_space, (U8*)locinput) - : isSPACE_LC_utf8((U8*)locinput))) - { - sayNO; + if (do_utf8) { + if (UTF8_IS_CONTINUED(nextchr)) { + LOAD_UTF8_CHARCLASS(space," "); + if (!(OP(scan) == SPACE + ? swash_fetch(PL_utf8_space, (U8*)locinput, do_utf8) + : isSPACE_LC_utf8((U8*)locinput))) + { + sayNO; + } + locinput += PL_utf8skip[nextchr]; + nextchr = UCHARAT(locinput); + break; } - locinput += PL_utf8skip[nextchr]; - nextchr = UCHARAT(locinput); - break; + if (!(OP(scan) == SPACE + ? isSPACE(nextchr) : isSPACE_LC(nextchr))) + sayNO; + nextchr = UCHARAT(++locinput); + } + else { + if (!(OP(scan) == SPACE + ? isSPACE(nextchr) : isSPACE_LC(nextchr))) + sayNO; + nextchr = UCHARAT(++locinput); } - if (!(OP(scan) == SPACEUTF8 - ? isSPACE(nextchr) : isSPACE_LC(nextchr))) - sayNO; - nextchr = UCHARAT(++locinput); break; case NSPACEL: PL_reg_flags |= RF_tainted; @@ -2159,20 +2338,10 @@ S_regmatch(pTHX_ regnode *prog) case NSPACE: if (!nextchr && locinput >= PL_regeol) sayNO; - if (OP(scan) == NSPACE - ? isSPACE(nextchr) : isSPACE_LC(nextchr)) - sayNO; - nextchr = UCHARAT(++locinput); - break; - case NSPACELUTF8: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case NSPACEUTF8: - if (!nextchr && locinput >= PL_regeol) - sayNO; - if (nextchr & 0x80) { - if (OP(scan) == NSPACEUTF8 - ? swash_fetch(PL_utf8_space, (U8*)locinput) + if (do_utf8) { + LOAD_UTF8_CHARCLASS(space," "); + if (OP(scan) == NSPACE + ? swash_fetch(PL_utf8_space, (U8*)locinput, do_utf8) : isSPACE_LC_utf8((U8*)locinput)) { sayNO; @@ -2181,7 +2350,7 @@ S_regmatch(pTHX_ regnode *prog) nextchr = UCHARAT(locinput); break; } - if (OP(scan) == NSPACEUTF8 + if (OP(scan) == NSPACE ? isSPACE(nextchr) : isSPACE_LC(nextchr)) sayNO; nextchr = UCHARAT(++locinput); @@ -2192,20 +2361,10 @@ S_regmatch(pTHX_ regnode *prog) case DIGIT: if (!nextchr) sayNO; - if (!(OP(scan) == DIGIT - ? isDIGIT(nextchr) : isDIGIT_LC(nextchr))) - sayNO; - nextchr = UCHARAT(++locinput); - break; - case DIGITLUTF8: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case DIGITUTF8: - if (!nextchr) - sayNO; - if (nextchr & 0x80) { - if (!(OP(scan) == DIGITUTF8 - ? swash_fetch(PL_utf8_digit, (U8*)locinput) + if (do_utf8) { + LOAD_UTF8_CHARCLASS(digit,"0"); + if (!(OP(scan) == DIGIT + ? swash_fetch(PL_utf8_digit, (U8*)locinput, do_utf8) : isDIGIT_LC_utf8((U8*)locinput))) { sayNO; @@ -2214,7 +2373,7 @@ S_regmatch(pTHX_ regnode *prog) nextchr = UCHARAT(locinput); break; } - if (!(OP(scan) == DIGITUTF8 + if (!(OP(scan) == DIGIT ? isDIGIT(nextchr) : isDIGIT_LC(nextchr))) sayNO; nextchr = UCHARAT(++locinput); @@ -2225,20 +2384,10 @@ S_regmatch(pTHX_ regnode *prog) case NDIGIT: if (!nextchr && locinput >= PL_regeol) sayNO; - if (OP(scan) == NDIGIT - ? isDIGIT(nextchr) : isDIGIT_LC(nextchr)) - sayNO; - nextchr = UCHARAT(++locinput); - break; - case NDIGITLUTF8: - PL_reg_flags |= RF_tainted; - /* FALL THROUGH */ - case NDIGITUTF8: - if (!nextchr && locinput >= PL_regeol) - sayNO; - if (nextchr & 0x80) { - if (OP(scan) == NDIGITUTF8 - ? swash_fetch(PL_utf8_digit, (U8*)locinput) + if (do_utf8) { + LOAD_UTF8_CHARCLASS(digit,"0"); + if (OP(scan) == NDIGIT + ? swash_fetch(PL_utf8_digit, (U8*)locinput, do_utf8) : isDIGIT_LC_utf8((U8*)locinput)) { sayNO; @@ -2247,16 +2396,19 @@ S_regmatch(pTHX_ regnode *prog) nextchr = UCHARAT(locinput); break; } - if (OP(scan) == NDIGITUTF8 + if (OP(scan) == NDIGIT ? isDIGIT(nextchr) : isDIGIT_LC(nextchr)) sayNO; nextchr = UCHARAT(++locinput); break; case CLUMP: - if (locinput >= PL_regeol || swash_fetch(PL_utf8_mark,(U8*)locinput)) + LOAD_UTF8_CHARCLASS(mark,"~"); + if (locinput >= PL_regeol || + 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)) + while (locinput < PL_regeol && + swash_fetch(PL_utf8_mark,(U8*)locinput, do_utf8)) locinput += UTF8SKIP(locinput); if (locinput > PL_regeol) sayNO; @@ -2276,7 +2428,7 @@ S_regmatch(pTHX_ regnode *prog) break; s = PL_bostr + ln; - if (UTF && OP(scan) != REF) { /* REF can do byte comparison */ + if (do_utf8 && OP(scan) != REF) { /* REF can do byte comparison */ char *l = locinput; char *e = PL_bostr + PL_regendp[n]; /* @@ -2340,7 +2492,7 @@ S_regmatch(pTHX_ regnode *prog) COP *ocurcop = PL_curcop; SV **ocurpad = PL_curpad; SV *ret; - + n = ARG(scan); PL_op = (OP_4tree*)PL_regdata->data[n]; DEBUG_r( PerlIO_printf(Perl_debug_log, " re_eval 0x%"UVxf"\n", PTR2UV(PL_op)) ); @@ -2351,7 +2503,7 @@ S_regmatch(pTHX_ regnode *prog) SPAGAIN; ret = POPs; PUTBACK; - + PL_op = oop; PL_curpad = ocurpad; PL_curcop = ocurcop; @@ -2366,7 +2518,7 @@ S_regmatch(pTHX_ regnode *prog) SV *sv = SvROK(ret) ? SvRV(ret) : ret; if(SvMAGICAL(sv)) - mg = mg_find(sv, 'r'); + mg = mg_find(sv, PERL_MAGIC_qr); } if (mg) { re = (regexp *)mg->mg_obj; @@ -2380,18 +2532,18 @@ S_regmatch(pTHX_ regnode *prog) I32 osize = PL_regsize; I32 onpar = PL_regnpar; - pm.op_pmflags = 0; - pm.op_pmdynflags = (UTF||DO_UTF8(ret) ? PMdf_UTF8 : 0); + Zero(&pm, 1, PMOP); re = CALLREGCOMP(aTHX_ t, t + len, &pm); - if (!(SvFLAGS(ret) + if (!(SvFLAGS(ret) & (SVs_TEMP | SVs_PADTMP | SVf_READONLY))) - sv_magic(ret,(SV*)ReREFCNT_inc(re),'r',0,0); + sv_magic(ret,(SV*)ReREFCNT_inc(re), + PERL_MAGIC_qr,0,0); PL_regprecomp = oprecomp; PL_regsize = osize; PL_regnpar = onpar; } DEBUG_r( - PerlIO_printf(Perl_debug_log, + PerlIO_printf(Perl_debug_log, "Entering embedded `%s%.60s%s%s'\n", PL_colors[0], re->precomp, @@ -2404,9 +2556,9 @@ S_regmatch(pTHX_ regnode *prog) state.re = PL_reg_re; PL_regcc = 0; - + cp = regcppush(0); /* Save *all* the positions. */ - REGCP_SET; + REGCP_SET(lastcp); cache_re(re); state.ss = PL_savestack_ix; *PL_reglastparen = 0; @@ -2436,7 +2588,7 @@ S_regmatch(pTHX_ regnode *prog) sayYES; } ReREFCNT_dec(re); - REGCP_UNWIND; + REGCP_UNWIND(lastcp); regcppop(); PL_reg_call_cc = state.prev; PL_regcc = state.cc; @@ -2493,7 +2645,7 @@ S_regmatch(pTHX_ regnode *prog) 1) After matching X, regnode for CURLYX is processed; - 2) This regnode creates infoblock on the stack, and calls + 2) This regnode creates infoblock on the stack, and calls regmatch() recursively with the starting point at WHILEM node; 3) Each hit of WHILEM node tries to match A and Z (in the order @@ -2514,7 +2666,7 @@ S_regmatch(pTHX_ regnode *prog) and whatever it mentions via ->next, and additional attached trees corresponding to temporarily unset infoblocks as in "5" above. - In the following picture infoblocks for outer loop of + In the following picture infoblocks for outer loop of (Y(A)*?Z)*?T are denoted O, for inner I. NULL starting block is denoted by x. The matched string is YAAZYAZT. Temporarily postponed infoblocks are drawn below the "reset" infoblock. @@ -2563,12 +2715,18 @@ S_regmatch(pTHX_ regnode *prog) case CURLYX: { CURCUR cc; CHECKPOINT cp = PL_savestack_ix; + /* No need to save/restore up to this paren */ + I32 parenfloor = scan->flags; if (OP(PREVOPER(next)) == NOTHING) /* LONGJMP */ next += ARG(next); cc.oldcc = PL_regcc; PL_regcc = &cc; - cc.parenfloor = *PL_reglastparen; + /* XXXX Probably it is better to teach regpush to support + parenfloor > PL_regsize... */ + if (parenfloor > *PL_reglastparen) + parenfloor = *PL_reglastparen; /* Pessimization... */ + cc.parenfloor = parenfloor; cc.cur = -1; cc.min = ARG1(scan); cc.max = ARG2(scan); @@ -2601,10 +2759,10 @@ S_regmatch(pTHX_ regnode *prog) PL_reginput = locinput; DEBUG_r( - PerlIO_printf(Perl_debug_log, - "%*s %ld out of %ld..%ld cc=%lx\n", + PerlIO_printf(Perl_debug_log, + "%*s %ld out of %ld..%ld cc=%lx\n", REPORT_CODE_OFF+PL_regindent*2, "", - (long)n, (long)cc->min, + (long)n, (long)cc->min, (long)cc->max, (long)cc) ); @@ -2691,19 +2849,19 @@ S_regmatch(pTHX_ regnode *prog) if (PL_regcc) ln = PL_regcc->cur; cp = regcppush(cc->parenfloor); - REGCP_SET; + REGCP_SET(lastcp); if (regmatch(cc->next)) { regcpblow(cp); sayYES; /* All done. */ } - REGCP_UNWIND; + REGCP_UNWIND(lastcp); regcppop(); if (PL_regcc) PL_regcc->cur = ln; PL_regcc = cc; if (n >= cc->max) { /* Maximum greed exceeded? */ - if (ckWARN(WARN_REGEXP) && n >= REG_INFTY + if (ckWARN(WARN_REGEXP) && n >= REG_INFTY && !(PL_reg_flags & RF_warned)) { PL_reg_flags |= RF_warned; Perl_warner(aTHX_ WARN_REGEXP, "%s limit (%d) exceeded", @@ -2723,12 +2881,12 @@ S_regmatch(pTHX_ regnode *prog) cc->cur = n; cc->lastloc = locinput; cp = regcppush(cc->parenfloor); - REGCP_SET; + REGCP_SET(lastcp); if (regmatch(cc->scan)) { regcpblow(cp); sayYES; } - REGCP_UNWIND; + REGCP_UNWIND(lastcp); regcppop(); cc->cur = n - 1; cc->lastloc = lastloc; @@ -2741,12 +2899,12 @@ S_regmatch(pTHX_ regnode *prog) cp = regcppush(cc->parenfloor); cc->cur = n; cc->lastloc = locinput; - REGCP_SET; + REGCP_SET(lastcp); if (regmatch(cc->scan)) { regcpblow(cp); sayYES; } - REGCP_UNWIND; + REGCP_UNWIND(lastcp); regcppop(); /* Restore some previous $s? */ PL_reginput = locinput; DEBUG_r( @@ -2755,7 +2913,7 @@ S_regmatch(pTHX_ regnode *prog) REPORT_CODE_OFF+PL_regindent*2, "") ); } - if (ckWARN(WARN_REGEXP) && n >= REG_INFTY + if (ckWARN(WARN_REGEXP) && n >= REG_INFTY && !(PL_reg_flags & RF_warned)) { PL_reg_flags |= RF_warned; Perl_warner(aTHX_ WARN_REGEXP, "%s limit (%d) exceeded", @@ -2777,45 +2935,44 @@ S_regmatch(pTHX_ regnode *prog) sayNO; } /* NOT REACHED */ - case BRANCHJ: + case BRANCHJ: next = scan + ARG(scan); if (next == scan) next = NULL; inner = NEXTOPER(NEXTOPER(scan)); goto do_branch; - case BRANCH: + case BRANCH: inner = NEXTOPER(scan); do_branch: { - CHECKPOINT lastcp; c1 = OP(scan); if (OP(next) != c1) /* No choice. */ next = inner; /* Avoid recursion. */ else { - int lastparen = *PL_reglastparen; + I32 lastparen = *PL_reglastparen; + I32 unwind1; + re_unwind_branch_t *uw; + + /* Put unwinding data on stack */ + unwind1 = SSNEWt(1,re_unwind_branch_t); + uw = SSPTRt(unwind1,re_unwind_branch_t); + uw->prev = unwind; + unwind = unwind1; + uw->type = ((c1 == BRANCH) + ? RE_UNWIND_BRANCH + : RE_UNWIND_BRANCHJ); + uw->lastparen = lastparen; + uw->next = next; + uw->locinput = locinput; + uw->nextchr = nextchr; +#ifdef DEBUGGING + uw->regindent = ++PL_regindent; +#endif - REGCP_SET; - do { - PL_reginput = locinput; - if (regmatch(inner)) - sayYES; - REGCP_UNWIND; - for (n = *PL_reglastparen; n > lastparen; n--) - PL_regendp[n] = -1; - *PL_reglastparen = n; - scan = next; - /*SUPPRESS 560*/ - if ((n = (c1 == BRANCH ? NEXT_OFF(next) : ARG(next)))) - next += n; - else - next = NULL; - inner = NEXTOPER(scan); - if (c1 == BRANCHJ) { - inner = NEXTOPER(inner); - } - } while (scan != NULL && OP(scan) == c1); - sayNO; - /* NOTREACHED */ + REGCP_SET(uw->lastcp); + + /* Now go into the first branch */ + next = inner; } } break; @@ -2826,7 +2983,7 @@ S_regmatch(pTHX_ regnode *prog) { I32 l = 0; CHECKPOINT lastcp; - + /* We suppose that the next guy does not need backtracking: in particular, it is of constant length, and has no parenths to influence future backrefs. */ @@ -2865,7 +3022,7 @@ S_regmatch(pTHX_ regnode *prog) } else c1 = c2 = -1000; - REGCP_SET; + REGCP_SET(lastcp); /* This may be improved if l == 0. */ while (n >= ln || (n == REG_INFTY && ln > 0 && l)) { /* ln overflow ? */ /* If it could work, try it. */ @@ -2884,7 +3041,7 @@ S_regmatch(pTHX_ regnode *prog) } if (regmatch(next)) sayYES; - REGCP_UNWIND; + REGCP_UNWIND(lastcp); } /* Couldn't or didn't -- move forward. */ PL_reginput = locinput; @@ -2924,7 +3081,7 @@ S_regmatch(pTHX_ regnode *prog) else c1 = c2 = -1000; } - REGCP_SET; + REGCP_SET(lastcp); while (n >= ln) { /* If it could work, try it. */ if (c1 == -1000 || @@ -2946,7 +3103,7 @@ S_regmatch(pTHX_ regnode *prog) } if (regmatch(next)) sayYES; - REGCP_UNWIND; + REGCP_UNWIND(lastcp); } /* Couldn't or didn't -- back up. */ n--; @@ -2990,87 +3147,128 @@ S_regmatch(pTHX_ regnode *prog) * when we know what character comes next. */ if (PL_regkind[(U8)OP(next)] == EXACT) { - c1 = (U8)*STRING(next); - if (OP(next) == EXACTF) - c2 = PL_fold[c1]; - else if (OP(next) == EXACTFL) - c2 = PL_fold_locale[c1]; - else - c2 = c1; + U8 *s = (U8*)STRING(next); + if (!UTF) { + c2 = c1 = *s; + if (OP(next) == EXACTF) + c2 = PL_fold[c1]; + else if (OP(next) == EXACTFL) + c2 = PL_fold_locale[c1]; + } + else { /* UTF */ + if (OP(next) == EXACTF) { + c1 = to_utf8_lower(s); + c2 = to_utf8_upper(s); + } + else { + c2 = c1 = utf8_to_uvchr(s, NULL); + } + } } else c1 = c2 = -1000; PL_reginput = locinput; - if (paren) - PL_regendp[paren] = -1; if (minmod) { CHECKPOINT lastcp; minmod = 0; if (ln && regrepeat(scan, ln) < ln) sayNO; locinput = PL_reginput; - REGCP_SET; + REGCP_SET(lastcp); if (c1 != -1000) { - char *e = locinput + n - ln; /* Should not check after this */ + char *e; /* Should not check after this */ char *old = locinput; - if (e >= PL_regeol || (n == REG_INFTY)) + if (n == REG_INFTY) { e = PL_regeol - 1; + if (do_utf8) + while (UTF8_IS_CONTINUATION(*(U8*)e)) + e--; + } + else if (do_utf8) { + int m = n - ln; + for (e = locinput; + m >0 && e + UTF8SKIP(e) <= PL_regeol; m--) + e += UTF8SKIP(e); + } + else { + e = locinput + n - ln; + if (e >= PL_regeol) + e = PL_regeol - 1; + } while (1) { + int count; /* Find place 'next' could work */ - if (c1 == c2) { - while (locinput <= e && *locinput != c1) - locinput++; - } else { - while (locinput <= e - && *locinput != c1 - && *locinput != c2) - locinput++; + if (!do_utf8) { + if (c1 == c2) { + while (locinput <= e && *locinput != c1) + locinput++; + } else { + while (locinput <= e + && *locinput != c1 + && *locinput != c2) + locinput++; + } + count = locinput - old; + } + else { + STRLEN len; + if (c1 == c2) { + for (count = 0; + locinput <= e && + utf8_to_uvchr((U8*)locinput, &len) != c1; + count++) + locinput += len; + + } else { + for (count = 0; locinput <= e; count++) { + UV c = utf8_to_uvchr((U8*)locinput, &len); + if (c == c1 || c == c2) + break; + locinput += len; + } + } } - if (locinput > e) + if (locinput > e) sayNO; /* PL_reginput == old now */ if (locinput != old) { ln = 1; /* Did some */ - if (regrepeat(scan, locinput - old) < - locinput - old) + if (regrepeat(scan, count) < count) sayNO; } /* PL_reginput == locinput now */ - if (paren) { - if (ln) { - PL_regstartp[paren] = HOPc(locinput, -1) - PL_bostr; - PL_regendp[paren] = locinput - PL_bostr; - } - else - PL_regendp[paren] = -1; - } - if (regmatch(next)) - sayYES; + TRYPAREN(paren, ln, locinput); PL_reginput = locinput; /* Could be reset... */ - REGCP_UNWIND; + REGCP_UNWIND(lastcp); /* Couldn't or didn't -- move forward. */ - old = locinput++; + old = locinput; + if (do_utf8) + locinput += UTF8SKIP(locinput); + else + locinput++; } } else while (n >= ln || (n == REG_INFTY && ln > 0)) { /* ln overflow ? */ + UV c; + if (c1 != -1000) { + if (do_utf8) + c = utf8_to_uvchr((U8*)PL_reginput, NULL); + else + c = UCHARAT(PL_reginput); + /* If it could work, try it. */ + if (c == c1 || c == c2) + { + TRYPAREN(paren, n, PL_reginput); + REGCP_UNWIND(lastcp); + } + } /* If it could work, try it. */ - if (c1 == -1000 || - UCHARAT(PL_reginput) == c1 || - UCHARAT(PL_reginput) == c2) + else if (c1 == -1000) { - if (paren) { - if (n) { - PL_regstartp[paren] = HOPc(PL_reginput, -1) - PL_bostr; - PL_regendp[paren] = PL_reginput - PL_bostr; - } - else - PL_regendp[paren] = -1; - } - if (regmatch(next)) - sayYES; - REGCP_UNWIND; + TRYPAREN(paren, n, PL_reginput); + REGCP_UNWIND(lastcp); } /* Couldn't or didn't -- move forward. */ PL_reginput = locinput; @@ -3095,25 +3293,21 @@ S_regmatch(pTHX_ regnode *prog) if (UCHARAT(PL_reginput - 1) == '\n' && OP(next) != EOS) ln--; } - REGCP_SET; + REGCP_SET(lastcp); if (paren) { + UV c = 0; while (n >= ln) { + if (c1 != -1000) { + if (do_utf8) + c = utf8_to_uvchr((U8*)PL_reginput, NULL); + else + c = UCHARAT(PL_reginput); + } /* If it could work, try it. */ - if (c1 == -1000 || - UCHARAT(PL_reginput) == c1 || - UCHARAT(PL_reginput) == c2) + if (c1 == -1000 || c == c1 || c == c2) { - if (paren && n) { - if (n) { - PL_regstartp[paren] = HOPc(PL_reginput, -1) - PL_bostr; - PL_regendp[paren] = PL_reginput - PL_bostr; - } - else - PL_regendp[paren] = -1; - } - if (regmatch(next)) - sayYES; - REGCP_UNWIND; + TRYPAREN(paren, n, PL_reginput); + REGCP_UNWIND(lastcp); } /* Couldn't or didn't -- back up. */ n--; @@ -3121,15 +3315,19 @@ S_regmatch(pTHX_ regnode *prog) } } else { + UV c = 0; while (n >= ln) { + if (c1 != -1000) { + if (do_utf8) + c = utf8_to_uvchr((U8*)PL_reginput, NULL); + else + c = UCHARAT(PL_reginput); + } /* If it could work, try it. */ - if (c1 == -1000 || - UCHARAT(PL_reginput) == c1 || - UCHARAT(PL_reginput) == c2) + if (c1 == -1000 || c == c1 || c == c2) { - if (regmatch(next)) - sayYES; - REGCP_UNWIND; + TRYPAREN(paren, n, PL_reginput); + REGCP_UNWIND(lastcp); } /* Couldn't or didn't -- back up. */ n--; @@ -3147,7 +3345,7 @@ S_regmatch(pTHX_ regnode *prog) CHECKPOINT cp, lastcp; cp = regcppush(0); /* Save *all* the positions. */ - REGCP_SET; + REGCP_SET(lastcp); regcp_set_to(PL_reg_call_cc->ss); /* Restore parens of the caller. */ PL_reginput = locinput; /* Make position available to @@ -3160,7 +3358,7 @@ S_regmatch(pTHX_ regnode *prog) regcpblow(cp); sayYES; } - REGCP_UNWIND; + REGCP_UNWIND(lastcp); regcppop(); PL_reg_call_cc = cur_call_cc; PL_regcc = cctmp; @@ -3191,24 +3389,14 @@ S_regmatch(pTHX_ regnode *prog) case SUSPEND: n = 1; PL_reginput = locinput; - goto do_ifmatch; + goto do_ifmatch; case UNLESSM: n = 0; if (scan->flags) { - if (UTF) { /* XXXX This is absolutely - broken, we read before - start of string. */ - s = HOPMAYBEc(locinput, -scan->flags); - if (!s) - goto say_yes; - PL_reginput = s; - } - else { - if (locinput < PL_bostr + scan->flags) - goto say_yes; - PL_reginput = locinput - scan->flags; - goto do_ifmatch; - } + s = HOPBACKc(locinput, scan->flags); + if (!s) + goto say_yes; + PL_reginput = s; } else PL_reginput = locinput; @@ -3216,20 +3404,10 @@ S_regmatch(pTHX_ regnode *prog) case IFMATCH: n = 1; if (scan->flags) { - if (UTF) { /* XXXX This is absolutely - broken, we read before - start of string. */ - s = HOPMAYBEc(locinput, -scan->flags); - if (!s || s < PL_bostr) - goto say_no; - PL_reginput = s; - } - else { - if (locinput < PL_bostr + scan->flags) - goto say_no; - PL_reginput = locinput - scan->flags; - goto do_ifmatch; - } + s = HOPBACKc(locinput, scan->flags); + if (!s) + goto say_no; + PL_reginput = s; } else PL_reginput = locinput; @@ -3267,6 +3445,7 @@ S_regmatch(pTHX_ regnode *prog) PTR2UV(scan), OP(scan)); Perl_croak(aTHX_ "regexp memory corruption"); } + reenter: scan = next; } @@ -3292,6 +3471,11 @@ yes: #ifdef DEBUGGING PL_regindent--; #endif + +#if 0 /* Breaks $^R */ + if (unwind) + regcpblow(firstcp); +#endif return 1; no: @@ -3303,6 +3487,55 @@ no: goto do_no; no_final: do_no: + if (unwind) { + re_unwind_t *uw = SSPTRt(unwind,re_unwind_t); + + switch (uw->type) { + case RE_UNWIND_BRANCH: + case RE_UNWIND_BRANCHJ: + { + re_unwind_branch_t *uwb = &(uw->branch); + I32 lastparen = uwb->lastparen; + + REGCP_UNWIND(uwb->lastcp); + for (n = *PL_reglastparen; n > lastparen; n--) + PL_regendp[n] = -1; + *PL_reglastparen = n; + scan = next = uwb->next; + if ( !scan || + OP(scan) != (uwb->type == RE_UNWIND_BRANCH + ? BRANCH : BRANCHJ) ) { /* Failure */ + unwind = uwb->prev; +#ifdef DEBUGGING + PL_regindent--; +#endif + goto do_no; + } + /* Have more choice yet. Reuse the same uwb. */ + /*SUPPRESS 560*/ + if ((n = (uwb->type == RE_UNWIND_BRANCH + ? NEXT_OFF(next) : ARG(next)))) + next += n; + else + next = NULL; /* XXXX Needn't unwinding in this case... */ + uwb->next = next; + next = NEXTOPER(scan); + if (uwb->type == RE_UNWIND_BRANCHJ) + next = NEXTOPER(next); + locinput = uwb->locinput; + nextchr = uwb->nextchr; +#ifdef DEBUGGING + PL_regindent = uwb->regindent; +#endif + + goto reenter; + } + /* NOT REACHED */ + default: + Perl_croak(aTHX_ "regexp unwind memory corruption"); + } + /* NOT REACHED */ + } #ifdef DEBUGGING PL_regindent--; #endif @@ -3320,37 +3553,31 @@ do_no: STATIC I32 S_regrepeat(pTHX_ regnode *p, I32 max) { - dTHR; register char *scan; register I32 c; register char *loceol = PL_regeol; register I32 hardcount = 0; + register bool do_utf8 = DO_UTF8(PL_reg_sv); scan = PL_reginput; if (max != REG_INFTY && max < loceol - scan) loceol = scan + max; switch (OP(p)) { case REG_ANY: - while (scan < loceol && *scan != '\n') - scan++; + if (do_utf8) { + loceol = PL_regeol; + while (scan < loceol && hardcount < max && *scan != '\n') { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && *scan != '\n') + scan++; + } break; case SANY: scan = loceol; break; - case ANYUTF8: - loceol = PL_regeol; - while (scan < loceol && *scan != '\n') { - scan += UTF8SKIP(scan); - hardcount++; - } - break; - case SANYUTF8: - loceol = PL_regeol; - while (scan < loceol) { - scan += UTF8SKIP(scan); - hardcount++; - } - break; case EXACT: /* length of string is 1 */ c = (U8)*STRING(p); while (scan < loceol && UCHARAT(scan) == c) @@ -3369,135 +3596,159 @@ S_regrepeat(pTHX_ regnode *p, I32 max) (UCHARAT(scan) == c || UCHARAT(scan) == PL_fold_locale[c])) scan++; break; - case ANYOFUTF8: - loceol = PL_regeol; - while (scan < loceol && REGINCLASSUTF8(p, (U8*)scan)) { - scan += UTF8SKIP(scan); - hardcount++; - } - break; case ANYOF: - while (scan < loceol && REGINCLASS(p, *scan)) - scan++; + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && + reginclass(p, (U8*)scan, do_utf8)) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && reginclass(p, (U8*)scan, do_utf8)) + scan++; + } break; case ALNUM: - while (scan < loceol && isALNUM(*scan)) - scan++; - break; - case ALNUMUTF8: - loceol = PL_regeol; - while (scan < loceol && swash_fetch(PL_utf8_alnum, (U8*)scan)) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + LOAD_UTF8_CHARCLASS(alnum,"a"); + while (hardcount < max && scan < loceol && + swash_fetch(PL_utf8_alnum, (U8*)scan, do_utf8)) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && isALNUM(*scan)) + scan++; } break; case ALNUML: PL_reg_flags |= RF_tainted; - while (scan < loceol && isALNUM_LC(*scan)) - scan++; - break; - case ALNUMLUTF8: - PL_reg_flags |= RF_tainted; - loceol = PL_regeol; - while (scan < loceol && isALNUM_LC_utf8((U8*)scan)) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && + isALNUM_LC_utf8((U8*)scan)) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && isALNUM_LC(*scan)) + scan++; } break; - break; case NALNUM: - while (scan < loceol && !isALNUM(*scan)) - scan++; - break; - case NALNUMUTF8: - loceol = PL_regeol; - while (scan < loceol && !swash_fetch(PL_utf8_alnum, (U8*)scan)) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + LOAD_UTF8_CHARCLASS(alnum,"a"); + while (hardcount < max && scan < loceol && + !swash_fetch(PL_utf8_alnum, (U8*)scan, do_utf8)) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && !isALNUM(*scan)) + scan++; } break; case NALNUML: PL_reg_flags |= RF_tainted; - while (scan < loceol && !isALNUM_LC(*scan)) - scan++; - break; - case NALNUMLUTF8: - PL_reg_flags |= RF_tainted; - loceol = PL_regeol; - while (scan < loceol && !isALNUM_LC_utf8((U8*)scan)) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && + !isALNUM_LC_utf8((U8*)scan)) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && !isALNUM_LC(*scan)) + scan++; } break; case SPACE: - while (scan < loceol && isSPACE(*scan)) - scan++; - break; - case SPACEUTF8: - loceol = PL_regeol; - while (scan < loceol && (*scan == ' ' || swash_fetch(PL_utf8_space,(U8*)scan))) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + LOAD_UTF8_CHARCLASS(space," "); + while (hardcount < max && scan < loceol && + (*scan == ' ' || + swash_fetch(PL_utf8_space,(U8*)scan, do_utf8))) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && isSPACE(*scan)) + scan++; } break; case SPACEL: PL_reg_flags |= RF_tainted; - while (scan < loceol && isSPACE_LC(*scan)) - scan++; - break; - case SPACELUTF8: - PL_reg_flags |= RF_tainted; - loceol = PL_regeol; - while (scan < loceol && (*scan == ' ' || isSPACE_LC_utf8((U8*)scan))) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && + (*scan == ' ' || isSPACE_LC_utf8((U8*)scan))) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && isSPACE_LC(*scan)) + scan++; } break; case NSPACE: - while (scan < loceol && !isSPACE(*scan)) - scan++; - break; - case NSPACEUTF8: - loceol = PL_regeol; - while (scan < loceol && !(*scan == ' ' || swash_fetch(PL_utf8_space,(U8*)scan))) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + LOAD_UTF8_CHARCLASS(space," "); + while (hardcount < max && scan < loceol && + !(*scan == ' ' || + swash_fetch(PL_utf8_space,(U8*)scan, do_utf8))) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && !isSPACE(*scan)) + scan++; + break; } - break; case NSPACEL: PL_reg_flags |= RF_tainted; - while (scan < loceol && !isSPACE_LC(*scan)) - scan++; - break; - case NSPACELUTF8: - PL_reg_flags |= RF_tainted; - loceol = PL_regeol; - while (scan < loceol && !(*scan == ' ' || isSPACE_LC_utf8((U8*)scan))) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + while (hardcount < max && scan < loceol && + !(*scan == ' ' || isSPACE_LC_utf8((U8*)scan))) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && !isSPACE_LC(*scan)) + scan++; } break; case DIGIT: - while (scan < loceol && isDIGIT(*scan)) - scan++; - break; - case DIGITUTF8: - loceol = PL_regeol; - while (scan < loceol && swash_fetch(PL_utf8_digit,(U8*)scan)) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + LOAD_UTF8_CHARCLASS(digit,"0"); + while (hardcount < max && scan < loceol && + swash_fetch(PL_utf8_digit, (U8*)scan, do_utf8)) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && isDIGIT(*scan)) + scan++; } break; - break; case NDIGIT: - while (scan < loceol && !isDIGIT(*scan)) - scan++; - break; - case NDIGITUTF8: - loceol = PL_regeol; - while (scan < loceol && !swash_fetch(PL_utf8_digit,(U8*)scan)) { - scan += UTF8SKIP(scan); - hardcount++; + if (do_utf8) { + loceol = PL_regeol; + LOAD_UTF8_CHARCLASS(digit,"0"); + while (hardcount < max && scan < loceol && + !swash_fetch(PL_utf8_digit, (U8*)scan, do_utf8)) { + scan += UTF8SKIP(scan); + hardcount++; + } + } else { + while (scan < loceol && !isDIGIT(*scan)) + scan++; } break; default: /* Called on something of 0 width. */ @@ -3510,30 +3761,29 @@ S_regrepeat(pTHX_ regnode *p, I32 max) c = scan - PL_reginput; PL_reginput = scan; - DEBUG_r( + DEBUG_r( { SV *prop = sv_newmortal(); regprop(prop, p); - PerlIO_printf(Perl_debug_log, - "%*s %s can match %"IVdf" times out of %"IVdf"...\n", + PerlIO_printf(Perl_debug_log, + "%*s %s can match %"IVdf" times out of %"IVdf"...\n", REPORT_CODE_OFF+1, "", SvPVX(prop),(IV)c,(IV)max); }); - + return(c); } /* - regrepeat_hard - repeatedly match something, report total lenth and length - * + * * The repeater is supposed to have constant length. */ STATIC I32 S_regrepeat_hard(pTHX_ regnode *p, I32 max, I32 *lp) { - dTHR; - register char *scan; + register char *scan = Nullch; register char *start; register char *loceol = PL_regeol; I32 l = 0; @@ -3543,7 +3793,7 @@ S_regrepeat_hard(pTHX_ regnode *p, I32 max, I32 *lp) return 0; start = PL_reginput; - if (UTF) { + if (DO_UTF8(PL_reg_sv)) { while (PL_reginput < loceol && (scan = PL_reginput, res = regmatch(p))) { if (!count++) { l = 0; @@ -3572,117 +3822,171 @@ S_regrepeat_hard(pTHX_ regnode *p, I32 max, I32 *lp) } if (!res) PL_reginput = scan; - + return count; } /* - - reginclass - determine if a character falls into a character class - */ +- regclass_swash - prepare the utf8 swash +*/ -STATIC bool -S_reginclass(pTHX_ register regnode *p, register I32 c) +SV * +Perl_regclass_swash(pTHX_ register regnode* node, bool doinit, SV** initsvp) { - dTHR; - char flags = ANYOF_FLAGS(p); - bool match = FALSE; + SV *sw = NULL; + SV *si = NULL; - c &= 0xFF; - if (ANYOF_BITMAP_TEST(p, c)) - match = TRUE; - else if (flags & ANYOF_FOLD) { - I32 cf; - if (flags & ANYOF_LOCALE) { - PL_reg_flags |= RF_tainted; - cf = PL_fold_locale[c]; - } - else - cf = PL_fold[c]; - if (ANYOF_BITMAP_TEST(p, cf)) - match = TRUE; - } + if (PL_regdata && PL_regdata->count) { + U32 n = ARG(node); - if (!match && (flags & ANYOF_CLASS)) { - PL_reg_flags |= RF_tainted; - if ( - (ANYOF_CLASS_TEST(p, ANYOF_ALNUM) && isALNUM_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NALNUM) && !isALNUM_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_SPACE) && isSPACE_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NSPACE) && !isSPACE_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_DIGIT) && isDIGIT_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NDIGIT) && !isDIGIT_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_ALNUMC) && isALNUMC_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NALNUMC) && !isALNUMC_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_ALPHA) && isALPHA_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NALPHA) && !isALPHA_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_ASCII) && isASCII(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NASCII) && !isASCII(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_CNTRL) && isCNTRL_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NCNTRL) && !isCNTRL_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_GRAPH) && isGRAPH_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NGRAPH) && !isGRAPH_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_LOWER) && isLOWER_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NLOWER) && !isLOWER_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_PRINT) && isPRINT_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NPRINT) && !isPRINT_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_PUNCT) && isPUNCT_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NPUNCT) && !isPUNCT_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_UPPER) && isUPPER_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NUPPER) && !isUPPER_LC(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_XDIGIT) && isXDIGIT(c)) || - (ANYOF_CLASS_TEST(p, ANYOF_NXDIGIT) && !isXDIGIT(c)) - ) /* How's that for a conditional? */ - { - match = TRUE; + if (PL_regdata->what[n] == 's') { + SV *rv = (SV*)PL_regdata->data[n]; + AV *av = (AV*)SvRV((SV*)rv); + SV **a; + + si = *av_fetch(av, 0, FALSE); + a = av_fetch(av, 1, FALSE); + + if (a) + sw = *a; + else if (si && doinit) { + sw = swash_init("utf8", "", si, 1, 0); + (void)av_store(av, 1, sw); + } } } + + if (initsvp) + *initsvp = si; - return (flags & ANYOF_INVERT) ? !match : match; + return sw; } +/* + - reginclass - determine if a character falls into a character class + */ + STATIC bool -S_reginclassutf8(pTHX_ regnode *f, U8 *p) -{ - dTHR; - char flags = ARG1(f); +S_reginclass(pTHX_ register regnode *n, register U8* p, register bool do_utf8) +{ + char flags = ANYOF_FLAGS(n); bool match = FALSE; - SV *sv = (SV*)PL_regdata->data[ARG2(f)]; + UV c; + STRLEN len = 0; - if (swash_fetch(sv, p)) - match = TRUE; - else if (flags & ANYOF_FOLD) { - U8 tmpbuf[UTF8_MAXLEN]; - if (flags & ANYOF_LOCALE) { - PL_reg_flags |= RF_tainted; - uv_to_utf8(tmpbuf, toLOWER_LC_utf8(p)); + c = do_utf8 ? utf8_to_uvchr(p, &len) : *p; + + if (do_utf8 || (flags & ANYOF_UNICODE)) { + if (do_utf8 && !ANYOF_RUNTIME(n)) { + if (len != (STRLEN)-1 && c < 256 && ANYOF_BITMAP_TEST(n, c)) + match = TRUE; } - else - uv_to_utf8(tmpbuf, toLOWER_utf8(p)); - if (swash_fetch(sv, tmpbuf)) + if (!match && do_utf8 && (flags & ANYOF_UNICODE_ALL) && c >= 256) match = TRUE; + if (!match) { + SV *sw = regclass_swash(n, TRUE, 0); + + if (sw) { + if (swash_fetch(sw, p, do_utf8)) + match = TRUE; + else if (flags & ANYOF_FOLD) { + U8 tmpbuf[UTF8_MAXLEN+1]; + + if (flags & ANYOF_LOCALE) { + PL_reg_flags |= RF_tainted; + uvchr_to_utf8(tmpbuf, toLOWER_LC_utf8(p)); + } + else + uvchr_to_utf8(tmpbuf, toLOWER_utf8(p)); + if (swash_fetch(sw, tmpbuf, do_utf8)) + match = TRUE; + } + } + } } + if (!match && c < 256) { + if (ANYOF_BITMAP_TEST(n, c)) + match = TRUE; + else if (flags & ANYOF_FOLD) { + I32 f; - /* UTF8 combined with ANYOF_CLASS is ill-defined. */ + if (flags & ANYOF_LOCALE) { + PL_reg_flags |= RF_tainted; + f = PL_fold_locale[c]; + } + else + f = PL_fold[c]; + if (f != c && ANYOF_BITMAP_TEST(n, f)) + match = TRUE; + } + + if (!match && (flags & ANYOF_CLASS)) { + PL_reg_flags |= RF_tainted; + if ( + (ANYOF_CLASS_TEST(n, ANYOF_ALNUM) && isALNUM_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NALNUM) && !isALNUM_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_SPACE) && isSPACE_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NSPACE) && !isSPACE_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_DIGIT) && isDIGIT_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NDIGIT) && !isDIGIT_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_ALNUMC) && isALNUMC_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NALNUMC) && !isALNUMC_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_ALPHA) && isALPHA_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NALPHA) && !isALPHA_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_ASCII) && isASCII(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NASCII) && !isASCII(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_CNTRL) && isCNTRL_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NCNTRL) && !isCNTRL_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_GRAPH) && isGRAPH_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NGRAPH) && !isGRAPH_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_LOWER) && isLOWER_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NLOWER) && !isLOWER_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_PRINT) && isPRINT_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NPRINT) && !isPRINT_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_PUNCT) && isPUNCT_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NPUNCT) && !isPUNCT_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_UPPER) && isUPPER_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NUPPER) && !isUPPER_LC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_XDIGIT) && isXDIGIT(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NXDIGIT) && !isXDIGIT(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_PSXSPC) && isPSXSPC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NPSXSPC) && !isPSXSPC(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_BLANK) && isBLANK(c)) || + (ANYOF_CLASS_TEST(n, ANYOF_NBLANK) && !isBLANK(c)) + ) /* How's that for a conditional? */ + { + match = TRUE; + } + } + } return (flags & ANYOF_INVERT) ? !match : match; } STATIC U8 * S_reghop(pTHX_ U8 *s, I32 off) -{ - dTHR; +{ + return S_reghop3(aTHX_ s, off, (U8*)(off >= 0 ? PL_regeol : PL_bostr)); +} + +STATIC U8 * +S_reghop3(pTHX_ U8 *s, I32 off, U8* lim) +{ if (off >= 0) { - while (off-- && s < (U8*)PL_regeol) + while (off-- && s < lim) { + /* XXX could check well-formedness here */ s += UTF8SKIP(s); + } } else { while (off++) { - if (s > (U8*)PL_bostr) { + if (s > lim) { s--; - if (*s & 0x80) { - while (s > (U8*)PL_bostr && (*s & 0xc0) == 0x80) + if (UTF8_IS_CONTINUED(*s)) { + while (s > (U8*)lim && UTF8_IS_CONTINUATION(*s)) s--; - } /* XXX could check well-formedness here */ + } + /* XXX could check well-formedness here */ } } } @@ -3690,23 +3994,31 @@ S_reghop(pTHX_ U8 *s, I32 off) } STATIC U8 * -S_reghopmaybe(pTHX_ U8* s, I32 off) +S_reghopmaybe(pTHX_ U8 *s, I32 off) +{ + return S_reghopmaybe3(aTHX_ s, off, (U8*)(off >= 0 ? PL_regeol : PL_bostr)); +} + +STATIC U8 * +S_reghopmaybe3(pTHX_ U8* s, I32 off, U8* lim) { - dTHR; if (off >= 0) { - while (off-- && s < (U8*)PL_regeol) + while (off-- && s < lim) { + /* XXX could check well-formedness here */ s += UTF8SKIP(s); + } if (off >= 0) return 0; } else { while (off++) { - if (s > (U8*)PL_bostr) { + if (s > lim) { s--; - if (*s & 0x80) { - while (s > (U8*)PL_bostr && (*s & 0xc0) == 0x80) + if (UTF8_IS_CONTINUED(*s)) { + while (s > (U8*)lim && UTF8_IS_CONTINUATION(*s)) s--; - } /* XXX could check well-formedness here */ + } + /* XXX could check well-formedness here */ } else break; @@ -3724,7 +4036,6 @@ S_reghopmaybe(pTHX_ U8* s, I32 off) static void restore_pos(pTHXo_ void *arg) { - dTHR; if (PL_reg_eval_set) { if (PL_reg_oldsaved) { PL_reg_re->subbeg = PL_reg_oldsaved; @@ -3736,4 +4047,3 @@ restore_pos(pTHXo_ void *arg) PL_curpm = PL_reg_oldcurpm; } } -