/* At least one required character in the target string is expressible only in
* UTF-8. */
-const char* const non_utf8_target_but_utf8_required
+static const char* const non_utf8_target_but_utf8_required
= "Can't match, because target string needs to be in UTF-8\n";
+#define NON_UTF8_TARGET_BUT_UTF8_REQUIRED(target) STMT_START { \
+ DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "%s", non_utf8_target_but_utf8_required));\
+ goto target; \
+} STMT_END
+
/*
* pregcomp and pregexec -- regsub and regerror are not used in perl
*
#include "unicode_constants.h"
#define RF_tainted 1 /* tainted information used? e.g. locale */
-#define RF_warned 2 /* warned about big count? */
-
-#define RF_utf8 8 /* Pattern contains multibyte chars? */
-
-#define UTF_PATTERN ((PL_reg_flags & RF_utf8) != 0)
#define HAS_NONLATIN1_FOLD_CLOSURE(i) _HAS_NONLATIN1_FOLD_CLOSURE_ONLY_FOR_USE_BY_REGCOMP_DOT_C_AND_REGEXEC_DOT_C(i)
/* Valid for non-utf8 strings: avoids the reginclass
* call if there are no complications: i.e., if everything matchable is
* straight forward in the bitmap */
-#define REGINCLASS(prog,p,c) (ANYOF_FLAGS(p) ? reginclass(prog,p,c,0,0) \
+#define REGINCLASS(prog,p,c) (ANYOF_FLAGS(p) ? reginclass(prog,p,c,0) \
: ANYOF_BITMAP_TEST(p,*(c)))
/*
SET_nextchr
-/* these are unrolled below in the CCC_TRY_XXX defined */
-#define LOAD_UTF8_CHARCLASS(class,str) STMT_START { \
- if (!CAT2(PL_utf8_,class)) { \
- bool ok; \
- ENTER; save_re_context(); \
- ok=CAT2(is_utf8_,class)((const U8*)str); \
- PERL_UNUSED_VAR(ok); \
- assert(ok); assert(CAT2(PL_utf8_,class)); LEAVE; } } STMT_END
-/* Doesn't do an assert to verify that is correct */
-#define LOAD_UTF8_CHARCLASS_NO_CHECK(class) STMT_START { \
- if (!CAT2(PL_utf8_,class)) { \
- bool throw_away PERL_UNUSED_DECL; \
- ENTER; save_re_context(); \
- throw_away = CAT2(is_utf8_,class)((const U8*)" "); \
- LEAVE; } } STMT_END
-
-#define LOAD_UTF8_CHARCLASS_ALNUM() LOAD_UTF8_CHARCLASS(alnum,"a")
-#define LOAD_UTF8_CHARCLASS_DIGIT() LOAD_UTF8_CHARCLASS(digit,"0")
-#define LOAD_UTF8_CHARCLASS_SPACE() LOAD_UTF8_CHARCLASS(space," ")
-
-#define LOAD_UTF8_CHARCLASS_GCB() /* Grapheme cluster boundaries */ \
- /* No asserts are done for some of these, in case called on a */ \
- /* Unicode version in which they map to nothing */ \
- LOAD_UTF8_CHARCLASS(X_regular_begin, HYPHEN_UTF8); \
- LOAD_UTF8_CHARCLASS(X_extend, COMBINING_GRAVE_ACCENT_UTF8); \
+#define LOAD_UTF8_CHARCLASS(swash_ptr, property_name) STMT_START { \
+ if (!swash_ptr) { \
+ U8 flags = _CORE_SWASH_INIT_ACCEPT_INVLIST; \
+ ENTER; save_re_context(); \
+ swash_ptr = _core_swash_init("utf8", property_name, &PL_sv_undef, \
+ 1, 0, NULL, &flags); \
+ assert(swash_ptr); \
+ } \
+ } STMT_END
-#define PLACEHOLDER /* Something for the preprocessor to grab onto */
+/* If in debug mode, we test that a known character properly matches */
+#ifdef DEBUGGING
+# define LOAD_UTF8_CHARCLASS_DEBUG_TEST(swash_ptr, \
+ property_name, \
+ utf8_char_in_property) \
+ LOAD_UTF8_CHARCLASS(swash_ptr, property_name); \
+ assert(swash_fetch(swash_ptr, (U8 *) utf8_char_in_property, TRUE));
+#else
+# define LOAD_UTF8_CHARCLASS_DEBUG_TEST(swash_ptr, \
+ property_name, \
+ utf8_char_in_property) \
+ LOAD_UTF8_CHARCLASS(swash_ptr, property_name)
+#endif
-/* The actual code for CCC_TRY, which uses several variables from the routine
- * it's callable from. It is designed to be the bulk of a case statement.
- * FUNC is the macro or function to call on non-utf8 targets that indicate if
- * nextchr matches the class.
- * UTF8_TEST is the whole test string to use for utf8 targets
- * LOAD is what to use to test, and if not present to load in the swash for the
- * class
- * POS_OR_NEG is either empty or ! to complement the results of FUNC or
- * UTF8_TEST test.
- * The logic is: Fail if we're at the end-of-string; otherwise if the target is
- * utf8 and a variant, load the swash if necessary and test using the utf8
- * test. Advance to the next character if test is ok, otherwise fail; If not
- * utf8 or an invariant under utf8, use the non-utf8 test, and fail if it
- * fails, or advance to the next character */
-
-#define _CCC_TRY_CODE(POS_OR_NEG, FUNC, UTF8_TEST, CLASS, STR) \
- if (NEXTCHR_IS_EOS) { \
- sayNO; \
- } \
- if (utf8_target && UTF8_IS_CONTINUED(nextchr)) { \
- LOAD_UTF8_CHARCLASS(CLASS, STR); \
- if (POS_OR_NEG (UTF8_TEST)) { \
- sayNO; \
- } \
- } \
- else if (POS_OR_NEG (FUNC(nextchr))) { \
- sayNO; \
- } \
- goto increment_locinput;
-
-/* Handle the non-locale cases for a character class and its complement. It
- * calls _CCC_TRY_CODE with a ! to complement the test for the character class.
- * This is because that code fails when the test succeeds, so we want to have
- * the test fail so that the code succeeds. The swash is stored in a
- * predictable PL_ place */
-#define _CCC_TRY_NONLOCALE(NAME, NNAME, FUNC, \
- CLASS, STR) \
- case NAME: \
- _CCC_TRY_CODE( !, FUNC, \
- cBOOL(swash_fetch(CAT2(PL_utf8_,CLASS), \
- (U8*)locinput, TRUE)), \
- CLASS, STR) \
- case NNAME: \
- _CCC_TRY_CODE( PLACEHOLDER , FUNC, \
- cBOOL(swash_fetch(CAT2(PL_utf8_,CLASS), \
- (U8*)locinput, TRUE)), \
- CLASS, STR) \
-
-/* Generate the case statements for both locale and non-locale character
- * classes in regmatch for classes that don't have special unicode semantics.
- * Locales don't use an immediate swash, but an intermediary special locale
- * function that is called on the pointer to the current place in the input
- * string. That function will resolve to needing the same swash. One might
- * think that because we don't know what the locale will match, we shouldn't
- * check with the swash loading function that it loaded properly; ie, that we
- * should use LOAD_UTF8_CHARCLASS_NO_CHECK for those, but what is passed to the
- * regular LOAD_UTF8_CHARCLASS is in non-locale terms, and so locale is
- * irrelevant here */
-#define CCC_TRY(NAME, NNAME, FUNC, \
- NAMEL, NNAMEL, LCFUNC, LCFUNC_utf8, \
- NAMEA, NNAMEA, FUNCA, \
- CLASS, STR) \
- case NAMEL: \
- PL_reg_flags |= RF_tainted; \
- _CCC_TRY_CODE( !, LCFUNC, LCFUNC_utf8((U8*)locinput), CLASS, STR) \
- case NNAMEL: \
- PL_reg_flags |= RF_tainted; \
- _CCC_TRY_CODE( PLACEHOLDER, LCFUNC, LCFUNC_utf8((U8*)locinput), \
- CLASS, STR) \
- case NAMEA: \
- if (NEXTCHR_IS_EOS || ! FUNCA(nextchr)) { \
- sayNO; \
- } \
- /* Matched a utf8-invariant, so don't have to worry about utf8 */ \
- locinput++; \
- break; \
- case NNAMEA: \
- if (NEXTCHR_IS_EOS || FUNCA(nextchr)) { \
- sayNO; \
- } \
- goto increment_locinput; \
- /* Generate the non-locale cases */ \
- _CCC_TRY_NONLOCALE(NAME, NNAME, FUNC, CLASS, STR)
-
-/* This is like CCC_TRY, but has an extra set of parameters for generating case
- * statements to handle separate Unicode semantics nodes */
-#define CCC_TRY_U(NAME, NNAME, FUNC, \
- NAMEL, NNAMEL, LCFUNC, LCFUNC_utf8, \
- NAMEU, NNAMEU, FUNCU, \
- NAMEA, NNAMEA, FUNCA, \
- CLASS, STR) \
- CCC_TRY(NAME, NNAME, FUNC, \
- NAMEL, NNAMEL, LCFUNC, LCFUNC_utf8, \
- NAMEA, NNAMEA, FUNCA, \
- CLASS, STR) \
- _CCC_TRY_NONLOCALE(NAMEU, NNAMEU, FUNCU, CLASS, STR)
+#define LOAD_UTF8_CHARCLASS_ALNUM() LOAD_UTF8_CHARCLASS_DEBUG_TEST( \
+ PL_utf8_swash_ptrs[_CC_WORDCHAR], \
+ swash_property_names[_CC_WORDCHAR], \
+ GREEK_SMALL_LETTER_IOTA_UTF8)
+
+#define LOAD_UTF8_CHARCLASS_GCB() /* Grapheme cluster boundaries */ \
+ STMT_START { \
+ LOAD_UTF8_CHARCLASS_DEBUG_TEST(PL_utf8_X_regular_begin, \
+ "_X_regular_begin", \
+ GREEK_SMALL_LETTER_IOTA_UTF8); \
+ LOAD_UTF8_CHARCLASS_DEBUG_TEST(PL_utf8_X_extend, \
+ "_X_extend", \
+ COMBINING_GRAVE_ACCENT_UTF8); \
+ } STMT_END
+#define PLACEHOLDER /* Something for the preprocessor to grab onto */
/* TODO: Combine JUMPABLE and HAS_TEXT to cache OP(rn) */
/* for use after a quantifier and before an EXACT-like node -- japhy */
} \
} STMT_END
+/* These constants are for finding GCB=LV and GCB=LVT in the CLUMP regnode.
+ * These are for the pre-composed Hangul syllables, which are all in a
+ * contiguous block and arranged there in such a way so as to facilitate
+ * alorithmic determination of their characteristics. As such, they don't need
+ * a swash, but can be determined by simple arithmetic. Almost all are
+ * GCB=LVT, but every 28th one is a GCB=LV */
+#define SBASE 0xAC00 /* Start of block */
+#define SCount 11172 /* Length of block */
+#define TCount 28
static void restore_pos(pTHX_ void *arg);
* are needed for the regexp context stack bookkeeping. */
STATIC CHECKPOINT
-S_regcppush(pTHX_ const regexp *rex, I32 parenfloor)
+S_regcppush(pTHX_ const regexp *rex, I32 parenfloor, U32 maxopenparen)
{
dVAR;
const int retval = PL_savestack_ix;
- const int paren_elems_to_push = (PL_regsize - parenfloor) * REGCP_PAREN_ELEMS;
+ const int paren_elems_to_push =
+ (maxopenparen - parenfloor) * REGCP_PAREN_ELEMS;
const UV total_elems = paren_elems_to_push + REGCP_OTHER_ELEMS;
const UV elems_shifted = total_elems << SAVE_TIGHT_SHIFT;
I32 p;
if ((elems_shifted >> SAVE_TIGHT_SHIFT) != total_elems)
Perl_croak(aTHX_ "panic: paren_elems_to_push offset %"UVuf
" out of range (%lu-%ld)",
- total_elems, (unsigned long)PL_regsize, (long)parenfloor);
+ total_elems,
+ (unsigned long)maxopenparen,
+ (long)parenfloor);
SSGROW(total_elems + REGCP_FRAME_ELEMS);
DEBUG_BUFFERS_r(
- if ((int)PL_regsize > (int)parenfloor)
+ if ((int)maxopenparen > (int)parenfloor)
PerlIO_printf(Perl_debug_log,
"rex=0x%"UVxf" offs=0x%"UVxf": saving capture indices:\n",
PTR2UV(rex),
PTR2UV(rex->offs)
);
);
- for (p = parenfloor+1; p <= (I32)PL_regsize; p++) {
+ for (p = parenfloor+1; p <= (I32)maxopenparen; p++) {
/* REGCP_PARENS_ELEMS are pushed per pairs of parentheses. */
SSPUSHINT(rex->offs[p].end);
SSPUSHINT(rex->offs[p].start);
));
}
/* REGCP_OTHER_ELEMS are pushed in any case, parentheses or no. */
- SSPUSHINT(PL_regsize);
+ SSPUSHINT(maxopenparen);
SSPUSHINT(rex->lastparen);
SSPUSHINT(rex->lastcloseparen);
SSPUSHUV(SAVEt_REGCONTEXT | elems_shifted); /* Magic cookie. */
STATIC void
-S_regcppop(pTHX_ regexp *rex)
+S_regcppop(pTHX_ regexp *rex, U32 *maxopenparen_p)
{
dVAR;
UV i;
i >>= SAVE_TIGHT_SHIFT; /* Parentheses elements to pop. */
rex->lastcloseparen = SSPOPINT;
rex->lastparen = SSPOPINT;
- PL_regsize = SSPOPINT;
+ *maxopenparen_p = SSPOPINT;
i -= REGCP_OTHER_ELEMS;
/* Now restore the parentheses context. */
PTR2UV(rex->offs)
);
);
- paren = PL_regsize;
+ paren = *maxopenparen_p;
for ( ; i > 0; i -= REGCP_PAREN_ELEMS) {
I32 tmps;
rex->offs[paren].start_tmp = SSPOPINT;
* this erroneously leaves $1 defined: "1" =~ /^(?:(\d)x)?\d$/
* --jhi updated by dapm */
for (i = rex->lastparen + 1; i <= rex->nparens; i++) {
- if (i > PL_regsize)
+ if (i > *maxopenparen_p)
rex->offs[i].start = -1;
rex->offs[i].end = -1;
DEBUG_BUFFERS_r( PerlIO_printf(Perl_debug_log,
" \\%"UVuf": %s ..-1 undeffing\n",
(UV)i,
- (i > PL_regsize) ? "-1" : " "
+ (i > *maxopenparen_p) ? "-1" : " "
));
}
#endif
* but without popping the stack */
STATIC void
-S_regcp_restore(pTHX_ regexp *rex, I32 ix)
+S_regcp_restore(pTHX_ regexp *rex, I32 ix, U32 *maxopenparen_p)
{
I32 tmpix = PL_savestack_ix;
PL_savestack_ix = ix;
- regcppop(rex);
+ regcppop(rex, maxopenparen_p);
PL_savestack_ix = tmpix;
}
#define regcpblow(cp) LEAVE_SCOPE(cp) /* Ignores regcppush()ed data. */
+STATIC bool
+S_isFOO_lc(pTHX_ const U8 classnum, const U8 character)
+{
+ /* Returns a boolean as to whether or not 'character' is a member of the
+ * Posix character class given by 'classnum' that should be equivalent to a
+ * value in the typedef '_char_class_number'.
+ *
+ * Ideally this could be replaced by a just an array of function pointers
+ * to the C library functions that implement the macros this calls.
+ * However, to compile, the precise function signatures are required, and
+ * these may vary from platform to to platform. To avoid having to figure
+ * out what those all are on each platform, I (khw) am using this method,
+ * which adds an extra layer of function call overhead (unless the C
+ * optimizer strips it away). But we don't particularly care about
+ * performance with locales anyway. */
+
+ switch ((_char_class_number) classnum) {
+ case _CC_ENUM_ALPHANUMERIC: return isALPHANUMERIC_LC(character);
+ case _CC_ENUM_ALPHA: return isALPHA_LC(character);
+ case _CC_ENUM_DIGIT: return isDIGIT_LC(character);
+ case _CC_ENUM_GRAPH: return isGRAPH_LC(character);
+ case _CC_ENUM_LOWER: return isLOWER_LC(character);
+ case _CC_ENUM_PRINT: return isPRINT_LC(character);
+ case _CC_ENUM_PUNCT: return isPUNCT_LC(character);
+ case _CC_ENUM_UPPER: return isUPPER_LC(character);
+ case _CC_ENUM_WORDCHAR: return isWORDCHAR_LC(character);
+ case _CC_ENUM_SPACE: return isSPACE_LC(character);
+ case _CC_ENUM_BLANK: return isBLANK_LC(character);
+ case _CC_ENUM_XDIGIT: return isXDIGIT_LC(character);
+ case _CC_ENUM_CNTRL: return isCNTRL_LC(character);
+ case _CC_ENUM_PSXSPC: return isPSXSPC_LC(character);
+ case _CC_ENUM_ASCII: return isASCII_LC(character);
+ default: /* VERTSPACE should never occur in locales */
+ Perl_croak(aTHX_ "panic: isFOO_lc() has an unexpected character class '%d'", classnum);
+ }
+
+ assert(0); /* NOTREACHED */
+ return FALSE;
+}
+
+STATIC bool
+S_isFOO_utf8_lc(pTHX_ const U8 classnum, const U8* character)
+{
+ /* Returns a boolean as to whether or not the (well-formed) UTF-8-encoded
+ * 'character' is a member of the Posix character class given by 'classnum'
+ * that should be equivalent to a value in the typedef
+ * '_char_class_number'.
+ *
+ * This just calls isFOO_lc on the code point for the character if it is in
+ * the range 0-255. Outside that range, all characters avoid Unicode
+ * rules, ignoring any locale. So use the Unicode function if this class
+ * requires a swash, and use the Unicode macro otherwise. */
+
+ PERL_ARGS_ASSERT_ISFOO_UTF8_LC;
+
+ if (UTF8_IS_INVARIANT(*character)) {
+ return isFOO_lc(classnum, *character);
+ }
+ else if (UTF8_IS_DOWNGRADEABLE_START(*character)) {
+ return isFOO_lc(classnum,
+ TWO_BYTE_UTF8_TO_UNI(*character, *(character + 1)));
+ }
+
+ if (classnum < _FIRST_NON_SWASH_CC) {
+
+ /* Initialize the swash unless done already */
+ if (! PL_utf8_swash_ptrs[classnum]) {
+ U8 flags = _CORE_SWASH_INIT_ACCEPT_INVLIST;
+ PL_utf8_swash_ptrs[classnum] = _core_swash_init("utf8",
+ swash_property_names[classnum], &PL_sv_undef, 1, 0, NULL, &flags);
+ }
+
+ return swash_fetch(PL_utf8_swash_ptrs[classnum], (U8 *) character, TRUE);
+ }
+
+ switch ((_char_class_number) classnum) {
+ case _CC_ENUM_SPACE:
+ case _CC_ENUM_PSXSPC: return is_XPERLSPACE_high(character);
+
+ case _CC_ENUM_BLANK: return is_HORIZWS_high(character);
+ case _CC_ENUM_XDIGIT: return is_XDIGIT_high(character);
+ case _CC_ENUM_VERTSPACE: return is_VERTWS_high(character);
+ default: return 0; /* Things like CNTRL are always
+ below 256 */
+ }
+
+ assert(0); /* NOTREACHED */
+ return FALSE;
+}
+
/*
* pregexec and friends
*/
- pregexec - match a regexp against a string
*/
I32
-Perl_pregexec(pTHX_ REGEXP * const prog, char* stringarg, register char *strend,
+Perl_pregexec(pTHX_ REGEXP * const prog, char* stringarg, char *strend,
char *strbeg, I32 minend, SV *screamer, U32 nosave)
/* stringarg: the point in the string at which to begin matching */
/* strend: pointer to null at end of string */
/* A failure to find a constant substring means that there is no need to make
an expensive call to REx engine, thus we celebrate a failure. Similarly,
- finding a substring too deep into the string means that less calls to
+ finding a substring too deep into the string means that fewer calls to
regtry() should be needed.
REx compiler's optimizer found 4 possible hints:
char *strend, const U32 flags, re_scream_pos_data *data)
{
dVAR;
- struct regexp *const prog = (struct regexp *)SvANY(rx);
+ struct regexp *const prog = ReANY(rx);
I32 start_shift = 0;
/* Should be nonnegative! */
I32 end_shift = 0;
char *checked_upto = NULL; /* how far into the string we have already checked using find_byclass*/
const I32 multiline = prog->extflags & RXf_PMf_MULTILINE;
RXi_GET_DECL(prog,progi);
+ bool is_utf8_pat;
#ifdef DEBUGGING
const char * const i_strpos = strpos;
#endif
RX_MATCH_UTF8_set(rx,utf8_target);
- if (RX_UTF8(rx)) {
- PL_reg_flags |= RF_utf8;
- }
+ is_utf8_pat = cBOOL(RX_UTF8(rx));
+
DEBUG_EXECUTE_r(
debug_start_match(rx, utf8_target, strpos, strend,
sv ? "Guessing start of match in sv for"
"String too short... [re_intuit_start]\n"));
goto fail;
}
-
+
/* XXX we need to pass strbeg as a separate arg: the following is
* guesswork and can be wrong... */
if (sv && SvPOK(sv)) {
} else {
if (!prog->check_substr && prog->check_utf8) {
if (! to_byte_substr(prog)) {
- DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
- non_utf8_target_but_utf8_required));
- goto fail;
+ NON_UTF8_TARGET_BUT_UTF8_REQUIRED(fail);
}
}
check = prog->check_substr;
DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "Not at start...\n"));
goto fail;
}
- if (prog->check_offset_min == prog->check_offset_max &&
- !(prog->extflags & RXf_CANY_SEEN)) {
+ if (prog->check_offset_min == prog->check_offset_max
+ && !(prog->extflags & RXf_CANY_SEEN)
+ && ! multiline) /* /m can cause \n's to match that aren't
+ accounted for in the string max length.
+ See [perl #115242] */
+ {
/* Substring at constant offset from beg-of-str... */
I32 slen;
(IV)start_shift, (IV)(check_at - strbeg), (IV)(s - strbeg), (IV)(endpos - strbeg), (IV)(checked_upto- strbeg)));
t = s;
- s = find_byclass(prog, progi->regstclass, checked_upto, endpos, NULL);
+ s = find_byclass(prog, progi->regstclass, checked_upto, endpos,
+ NULL, is_utf8_pat);
if (s) {
checked_upto = s;
} else {
#define REXEC_FBC_UTF8_SCAN(CoDe) \
STMT_START { \
- while (s < strend && s + (uskip = UTF8SKIP(s)) <= strend) { \
+ while (s < strend) { \
CoDe \
- s += uskip; \
+ s += UTF8SKIP(s); \
} \
} STMT_END
#define REXEC_FBC_UTF8_CLASS_SCAN(CoNd) \
REXEC_FBC_UTF8_SCAN( \
if (CoNd) { \
- if (tmp && (!reginfo || regtry(reginfo, &s))) \
+ if (tmp && (!reginfo || regtry(reginfo, &s))) \
goto got_it; \
else \
tmp = doevery; \
REXEC_FBC_CLASS_SCAN(CoNd); \
}
-#define REXEC_FBC_CSCAN_PRELOAD(UtFpReLoAd,CoNdUtF8,CoNd) \
- if (utf8_target) { \
- UtFpReLoAd; \
- REXEC_FBC_UTF8_CLASS_SCAN(CoNdUtF8); \
- } \
- else { \
- REXEC_FBC_CLASS_SCAN(CoNd); \
- }
-
-#define REXEC_FBC_CSCAN_TAINT(CoNdUtF8,CoNd) \
- PL_reg_flags |= RF_tainted; \
- if (utf8_target) { \
- REXEC_FBC_UTF8_CLASS_SCAN(CoNdUtF8); \
- } \
- else { \
- REXEC_FBC_CLASS_SCAN(CoNd); \
- }
-
#define DUMP_EXEC_POS(li,s,doutf8) \
dump_exec_pos(li,s,(PL_regeol),(PL_bostr),(PL_reg_starttry),doutf8)
STATIC char *
S_find_byclass(pTHX_ regexp * prog, const regnode *c, char *s,
- const char *strend, regmatch_info *reginfo)
+ const char *strend, regmatch_info *reginfo, bool is_utf8_pat)
{
- dVAR;
- const I32 doevery = (prog->intflags & PREGf_SKIP) == 0;
- char *pat_string; /* The pattern's exactish string */
- char *pat_end; /* ptr to end char of pat_string */
- re_fold_t folder; /* Function for computing non-utf8 folds */
- const U8 *fold_array; /* array for folding ords < 256 */
- STRLEN ln;
- STRLEN lnc;
- STRLEN uskip;
- U8 c1;
- U8 c2;
- char *e;
- I32 tmp = 1; /* Scratch variable? */
- const bool utf8_target = PL_reg_match_utf8;
- UV utf8_fold_flags = 0;
- RXi_GET_DECL(prog,progi);
-
- PERL_ARGS_ASSERT_FIND_BYCLASS;
-
- /* We know what class it must start with. */
- switch (OP(c)) {
- case ANYOF:
- if (utf8_target) {
- STRLEN inclasslen = strend - s;
- REXEC_FBC_UTF8_CLASS_SCAN(
- reginclass(prog, c, (U8*)s, &inclasslen, utf8_target));
- }
- else {
- REXEC_FBC_CLASS_SCAN(REGINCLASS(prog, c, (U8*)s));
- }
- break;
- case CANY:
- REXEC_FBC_SCAN(
- if (tmp && (!reginfo || regtry(reginfo, &s)))
- goto got_it;
- else
- tmp = doevery;
- );
- break;
+ dVAR;
+ const I32 doevery = (prog->intflags & PREGf_SKIP) == 0;
+ char *pat_string; /* The pattern's exactish string */
+ char *pat_end; /* ptr to end char of pat_string */
+ re_fold_t folder; /* Function for computing non-utf8 folds */
+ const U8 *fold_array; /* array for folding ords < 256 */
+ STRLEN ln;
+ STRLEN lnc;
+ U8 c1;
+ U8 c2;
+ char *e;
+ I32 tmp = 1; /* Scratch variable? */
+ const bool utf8_target = PL_reg_match_utf8;
+ UV utf8_fold_flags = 0;
+ bool to_complement = FALSE; /* Invert the result? Taking the xor of this
+ with a result inverts that result, as 0^1 =
+ 1 and 1^1 = 0 */
+ _char_class_number classnum;
- case EXACTFA:
- if (UTF_PATTERN || utf8_target) {
- utf8_fold_flags = FOLDEQ_UTF8_NOMIX_ASCII;
- goto do_exactf_utf8;
- }
- fold_array = PL_fold_latin1; /* Latin1 folds are not affected by */
- folder = foldEQ_latin1; /* /a, except the sharp s one which */
- goto do_exactf_non_utf8; /* isn't dealt with by these */
+ RXi_GET_DECL(prog,progi);
- case EXACTF:
- if (utf8_target) {
+ PERL_ARGS_ASSERT_FIND_BYCLASS;
- /* regcomp.c already folded this if pattern is in UTF-8 */
- utf8_fold_flags = 0;
- goto do_exactf_utf8;
- }
- fold_array = PL_fold;
- folder = foldEQ;
- goto do_exactf_non_utf8;
+ /* We know what class it must start with. */
+ switch (OP(c)) {
+ case ANYOF:
+ if (utf8_target) {
+ REXEC_FBC_UTF8_CLASS_SCAN(
+ reginclass(prog, c, (U8*)s, utf8_target));
+ }
+ else {
+ REXEC_FBC_CLASS_SCAN(REGINCLASS(prog, c, (U8*)s));
+ }
+ break;
+ case CANY:
+ REXEC_FBC_SCAN(
+ if (tmp && (!reginfo || regtry(reginfo, &s)))
+ goto got_it;
+ else
+ tmp = doevery;
+ );
+ break;
- case EXACTFL:
- if (UTF_PATTERN || utf8_target) {
- utf8_fold_flags = FOLDEQ_UTF8_LOCALE;
- goto do_exactf_utf8;
- }
- fold_array = PL_fold_locale;
- folder = foldEQ_locale;
- goto do_exactf_non_utf8;
+ case EXACTFA:
+ if (is_utf8_pat || utf8_target) {
+ utf8_fold_flags = FOLDEQ_UTF8_NOMIX_ASCII;
+ goto do_exactf_utf8;
+ }
+ fold_array = PL_fold_latin1; /* Latin1 folds are not affected by */
+ folder = foldEQ_latin1; /* /a, except the sharp s one which */
+ goto do_exactf_non_utf8; /* isn't dealt with by these */
- case EXACTFU_SS:
- if (UTF_PATTERN) {
- utf8_fold_flags = FOLDEQ_S2_ALREADY_FOLDED;
- }
- goto do_exactf_utf8;
+ case EXACTF:
+ if (utf8_target) {
- case EXACTFU_TRICKYFOLD:
- case EXACTFU:
- if (UTF_PATTERN || utf8_target) {
- utf8_fold_flags = (UTF_PATTERN) ? FOLDEQ_S2_ALREADY_FOLDED : 0;
- goto do_exactf_utf8;
- }
+ /* regcomp.c already folded this if pattern is in UTF-8 */
+ utf8_fold_flags = 0;
+ goto do_exactf_utf8;
+ }
+ fold_array = PL_fold;
+ folder = foldEQ;
+ goto do_exactf_non_utf8;
- /* Any 'ss' in the pattern should have been replaced by regcomp,
- * so we don't have to worry here about this single special case
- * in the Latin1 range */
- fold_array = PL_fold_latin1;
- folder = foldEQ_latin1;
+ case EXACTFL:
+ if (is_utf8_pat || utf8_target) {
+ utf8_fold_flags = FOLDEQ_UTF8_LOCALE;
+ goto do_exactf_utf8;
+ }
+ fold_array = PL_fold_locale;
+ folder = foldEQ_locale;
+ goto do_exactf_non_utf8;
- /* FALL THROUGH */
+ case EXACTFU_SS:
+ if (is_utf8_pat) {
+ utf8_fold_flags = FOLDEQ_S2_ALREADY_FOLDED;
+ }
+ goto do_exactf_utf8;
- do_exactf_non_utf8: /* Neither pattern nor string are UTF8, and there
- are no glitches with fold-length differences
- between the target string and pattern */
-
- /* The idea in the non-utf8 EXACTF* cases is to first find the
- * first character of the EXACTF* node and then, if necessary,
- * case-insensitively compare the full text of the node. c1 is the
- * first character. c2 is its fold. This logic will not work for
- * Unicode semantics and the german sharp ss, which hence should
- * not be compiled into a node that gets here. */
- pat_string = STRING(c);
- ln = STR_LEN(c); /* length to match in octets/bytes */
-
- /* We know that we have to match at least 'ln' bytes (which is the
- * same as characters, since not utf8). If we have to match 3
- * characters, and there are only 2 availabe, we know without
- * trying that it will fail; so don't start a match past the
- * required minimum number from the far end */
- e = HOP3c(strend, -((I32)ln), s);
-
- if (!reginfo && e < s) {
- e = s; /* Due to minlen logic of intuit() */
- }
+ case EXACTFU_TRICKYFOLD:
+ case EXACTFU:
+ if (is_utf8_pat || utf8_target) {
+ utf8_fold_flags = is_utf8_pat ? FOLDEQ_S2_ALREADY_FOLDED : 0;
+ goto do_exactf_utf8;
+ }
- c1 = *pat_string;
- c2 = fold_array[c1];
- if (c1 == c2) { /* If char and fold are the same */
- REXEC_FBC_EXACTISH_SCAN(*(U8*)s == c1);
- }
- else {
- REXEC_FBC_EXACTISH_SCAN(*(U8*)s == c1 || *(U8*)s == c2);
- }
- break;
+ /* Any 'ss' in the pattern should have been replaced by regcomp,
+ * so we don't have to worry here about this single special case
+ * in the Latin1 range */
+ fold_array = PL_fold_latin1;
+ folder = foldEQ_latin1;
+
+ /* FALL THROUGH */
+
+ do_exactf_non_utf8: /* Neither pattern nor string are UTF8, and there
+ are no glitches with fold-length differences
+ between the target string and pattern */
+
+ /* The idea in the non-utf8 EXACTF* cases is to first find the
+ * first character of the EXACTF* node and then, if necessary,
+ * case-insensitively compare the full text of the node. c1 is the
+ * first character. c2 is its fold. This logic will not work for
+ * Unicode semantics and the german sharp ss, which hence should
+ * not be compiled into a node that gets here. */
+ pat_string = STRING(c);
+ ln = STR_LEN(c); /* length to match in octets/bytes */
+
+ /* We know that we have to match at least 'ln' bytes (which is the
+ * same as characters, since not utf8). If we have to match 3
+ * characters, and there are only 2 availabe, we know without
+ * trying that it will fail; so don't start a match past the
+ * required minimum number from the far end */
+ e = HOP3c(strend, -((I32)ln), s);
+
+ if (!reginfo && e < s) {
+ e = s; /* Due to minlen logic of intuit() */
+ }
- do_exactf_utf8:
- {
- unsigned expansion;
-
-
- /* If one of the operands is in utf8, we can't use the simpler
- * folding above, due to the fact that many different characters
- * can have the same fold, or portion of a fold, or different-
- * length fold */
- pat_string = STRING(c);
- ln = STR_LEN(c); /* length to match in octets/bytes */
- pat_end = pat_string + ln;
- lnc = (UTF_PATTERN) /* length to match in characters */
- ? utf8_length((U8 *) pat_string, (U8 *) pat_end)
- : ln;
-
- /* We have 'lnc' characters to match in the pattern, but because of
- * multi-character folding, each character in the target can match
- * up to 3 characters (Unicode guarantees it will never exceed
- * this) if it is utf8-encoded; and up to 2 if not (based on the
- * fact that the Latin 1 folds are already determined, and the
- * only multi-char fold in that range is the sharp-s folding to
- * 'ss'. Thus, a pattern character can match as little as 1/3 of a
- * string character. Adjust lnc accordingly, rounding up, so that
- * if we need to match at least 4+1/3 chars, that really is 5. */
- expansion = (utf8_target) ? UTF8_MAX_FOLD_CHAR_EXPAND : 2;
- lnc = (lnc + expansion - 1) / expansion;
-
- /* As in the non-UTF8 case, if we have to match 3 characters, and
- * only 2 are left, it's guaranteed to fail, so don't start a
- * match that would require us to go beyond the end of the string
- */
- e = HOP3c(strend, -((I32)lnc), s);
+ c1 = *pat_string;
+ c2 = fold_array[c1];
+ if (c1 == c2) { /* If char and fold are the same */
+ REXEC_FBC_EXACTISH_SCAN(*(U8*)s == c1);
+ }
+ else {
+ REXEC_FBC_EXACTISH_SCAN(*(U8*)s == c1 || *(U8*)s == c2);
+ }
+ break;
- if (!reginfo && e < s) {
- e = s; /* Due to minlen logic of intuit() */
- }
+ do_exactf_utf8:
+ {
+ unsigned expansion;
+
+ /* If one of the operands is in utf8, we can't use the simpler folding
+ * above, due to the fact that many different characters can have the
+ * same fold, or portion of a fold, or different- length fold */
+ pat_string = STRING(c);
+ ln = STR_LEN(c); /* length to match in octets/bytes */
+ pat_end = pat_string + ln;
+ lnc = is_utf8_pat /* length to match in characters */
+ ? utf8_length((U8 *) pat_string, (U8 *) pat_end)
+ : ln;
+
+ /* We have 'lnc' characters to match in the pattern, but because of
+ * multi-character folding, each character in the target can match
+ * up to 3 characters (Unicode guarantees it will never exceed
+ * this) if it is utf8-encoded; and up to 2 if not (based on the
+ * fact that the Latin 1 folds are already determined, and the
+ * only multi-char fold in that range is the sharp-s folding to
+ * 'ss'. Thus, a pattern character can match as little as 1/3 of a
+ * string character. Adjust lnc accordingly, rounding up, so that
+ * if we need to match at least 4+1/3 chars, that really is 5. */
+ expansion = (utf8_target) ? UTF8_MAX_FOLD_CHAR_EXPAND : 2;
+ lnc = (lnc + expansion - 1) / expansion;
+
+ /* As in the non-UTF8 case, if we have to match 3 characters, and
+ * only 2 are left, it's guaranteed to fail, so don't start a
+ * match that would require us to go beyond the end of the string
+ */
+ e = HOP3c(strend, -((I32)lnc), s);
+
+ if (!reginfo && e < s) {
+ e = s; /* Due to minlen logic of intuit() */
+ }
- /* XXX Note that we could recalculate e to stop the loop earlier,
- * as the worst case expansion above will rarely be met, and as we
- * go along we would usually find that e moves further to the left.
- * This would happen only after we reached the point in the loop
- * where if there were no expansion we should fail. Unclear if
- * worth the expense */
-
- while (s <= e) {
- char *my_strend= (char *)strend;
- if (foldEQ_utf8_flags(s, &my_strend, 0, utf8_target,
- pat_string, NULL, ln, cBOOL(UTF_PATTERN), utf8_fold_flags)
- && (!reginfo || regtry(reginfo, &s)) )
- {
- goto got_it;
- }
- s += (utf8_target) ? UTF8SKIP(s) : 1;
- }
- break;
- }
- case BOUNDL:
- PL_reg_flags |= RF_tainted;
- FBC_BOUND(isALNUM_LC,
- isALNUM_LC_uvchr(UNI_TO_NATIVE(tmp)),
- isALNUM_LC_utf8((U8*)s));
- break;
- case NBOUNDL:
- PL_reg_flags |= RF_tainted;
- FBC_NBOUND(isALNUM_LC,
- isALNUM_LC_uvchr(UNI_TO_NATIVE(tmp)),
- isALNUM_LC_utf8((U8*)s));
- break;
- case BOUND:
- FBC_BOUND(isWORDCHAR,
- isALNUM_uni(tmp),
- cBOOL(swash_fetch(PL_utf8_alnum, (U8*)s, utf8_target)));
- break;
- case BOUNDA:
- FBC_BOUND_NOLOAD(isWORDCHAR_A,
- isWORDCHAR_A(tmp),
- isWORDCHAR_A((U8*)s));
- break;
- case NBOUND:
- FBC_NBOUND(isWORDCHAR,
- isALNUM_uni(tmp),
- cBOOL(swash_fetch(PL_utf8_alnum, (U8*)s, utf8_target)));
- break;
- case NBOUNDA:
- FBC_NBOUND_NOLOAD(isWORDCHAR_A,
- isWORDCHAR_A(tmp),
- isWORDCHAR_A((U8*)s));
- break;
- case BOUNDU:
- FBC_BOUND(isWORDCHAR_L1,
- isALNUM_uni(tmp),
- cBOOL(swash_fetch(PL_utf8_alnum, (U8*)s, utf8_target)));
- break;
- case NBOUNDU:
- FBC_NBOUND(isWORDCHAR_L1,
- isALNUM_uni(tmp),
- cBOOL(swash_fetch(PL_utf8_alnum, (U8*)s, utf8_target)));
- break;
- case ALNUML:
- REXEC_FBC_CSCAN_TAINT(
- isALNUM_LC_utf8((U8*)s),
- isALNUM_LC(*s)
- );
- break;
- case ALNUMU:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_ALNUM(),
- swash_fetch(PL_utf8_alnum,(U8*)s, utf8_target),
- isWORDCHAR_L1((U8) *s)
- );
- break;
- case ALNUM:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_ALNUM(),
- swash_fetch(PL_utf8_alnum,(U8*)s, utf8_target),
- isWORDCHAR((U8) *s)
- );
- break;
- case ALNUMA:
- /* Don't need to worry about utf8, as it can match only a single
- * byte invariant character */
- REXEC_FBC_CLASS_SCAN( isWORDCHAR_A(*s));
- break;
- case NALNUMU:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_ALNUM(),
- !swash_fetch(PL_utf8_alnum,(U8*)s, utf8_target),
- ! isWORDCHAR_L1((U8) *s)
- );
- break;
- case NALNUM:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_ALNUM(),
- !swash_fetch(PL_utf8_alnum, (U8*)s, utf8_target),
- ! isALNUM(*s)
- );
- break;
- case NALNUMA:
- REXEC_FBC_CSCAN(
- !isWORDCHAR_A(*s),
- !isWORDCHAR_A(*s)
- );
- break;
- case NALNUML:
- REXEC_FBC_CSCAN_TAINT(
- !isALNUM_LC_utf8((U8*)s),
- !isALNUM_LC(*s)
- );
- break;
- case SPACEU:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_SPACE(),
- *s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, utf8_target),
- isSPACE_L1((U8) *s)
- );
- break;
- case SPACE:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_SPACE(),
- *s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, utf8_target),
- isSPACE((U8) *s)
- );
- break;
- case SPACEA:
- /* Don't need to worry about utf8, as it can match only a single
- * byte invariant character */
- REXEC_FBC_CLASS_SCAN( isSPACE_A(*s));
- break;
- case SPACEL:
- REXEC_FBC_CSCAN_TAINT(
- isSPACE_LC_utf8((U8*)s),
- isSPACE_LC(*s)
- );
- break;
- case NSPACEU:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_SPACE(),
- !( *s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, utf8_target)),
- ! isSPACE_L1((U8) *s)
- );
- break;
- case NSPACE:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_SPACE(),
- !(*s == ' ' || swash_fetch(PL_utf8_space,(U8*)s, utf8_target)),
- ! isSPACE((U8) *s)
- );
- break;
- case NSPACEA:
- REXEC_FBC_CSCAN(
- !isSPACE_A(*s),
- !isSPACE_A(*s)
- );
- break;
- case NSPACEL:
- REXEC_FBC_CSCAN_TAINT(
- !isSPACE_LC_utf8((U8*)s),
- !isSPACE_LC(*s)
- );
- break;
- case DIGIT:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_DIGIT(),
- swash_fetch(PL_utf8_digit,(U8*)s, utf8_target),
- isDIGIT(*s)
- );
- break;
- case DIGITA:
- /* Don't need to worry about utf8, as it can match only a single
- * byte invariant character */
- REXEC_FBC_CLASS_SCAN( isDIGIT_A(*s));
- break;
- case DIGITL:
- REXEC_FBC_CSCAN_TAINT(
- isDIGIT_LC_utf8((U8*)s),
- isDIGIT_LC(*s)
- );
- break;
- case NDIGIT:
- REXEC_FBC_CSCAN_PRELOAD(
- LOAD_UTF8_CHARCLASS_DIGIT(),
- !swash_fetch(PL_utf8_digit,(U8*)s, utf8_target),
- !isDIGIT(*s)
- );
- break;
- case NDIGITA:
- REXEC_FBC_CSCAN(
- !isDIGIT_A(*s),
- !isDIGIT_A(*s)
- );
- break;
- case NDIGITL:
- REXEC_FBC_CSCAN_TAINT(
- !isDIGIT_LC_utf8((U8*)s),
- !isDIGIT_LC(*s)
- );
- break;
- case LNBREAK:
- REXEC_FBC_CSCAN(
- is_LNBREAK_utf8_safe(s, strend),
- is_LNBREAK_latin1_safe(s, strend)
- );
- break;
- case VERTWS:
- REXEC_FBC_CSCAN(
- is_VERTWS_utf8_safe(s, strend),
- is_VERTWS_latin1_safe(s, strend)
- );
- break;
- case NVERTWS:
- REXEC_FBC_CSCAN(
- !is_VERTWS_utf8_safe(s, strend),
- !is_VERTWS_latin1_safe(s, strend)
- );
- break;
- case HORIZWS:
- REXEC_FBC_CSCAN(
- is_HORIZWS_utf8_safe(s, strend),
- is_HORIZWS_latin1_safe(s, strend)
- );
- break;
- case NHORIZWS:
- REXEC_FBC_CSCAN(
- !is_HORIZWS_utf8_safe(s, strend),
- !is_HORIZWS_latin1_safe(s, strend)
- );
- break;
- case POSIXA:
- /* Don't need to worry about utf8, as it can match only a single
- * byte invariant character. The flag in this node type is the
- * class number to pass to _generic_isCC() to build a mask for
- * searching in PL_charclass[] */
- REXEC_FBC_CLASS_SCAN( _generic_isCC_A(*s, FLAGS(c)));
- break;
- case NPOSIXA:
- REXEC_FBC_CSCAN(
- !_generic_isCC_A(*s, FLAGS(c)),
- !_generic_isCC_A(*s, FLAGS(c))
- );
- break;
+ /* XXX Note that we could recalculate e to stop the loop earlier,
+ * as the worst case expansion above will rarely be met, and as we
+ * go along we would usually find that e moves further to the left.
+ * This would happen only after we reached the point in the loop
+ * where if there were no expansion we should fail. Unclear if
+ * worth the expense */
+
+ while (s <= e) {
+ char *my_strend= (char *)strend;
+ if (foldEQ_utf8_flags(s, &my_strend, 0, utf8_target,
+ pat_string, NULL, ln, is_utf8_pat, utf8_fold_flags)
+ && (!reginfo || regtry(reginfo, &s)) )
+ {
+ goto got_it;
+ }
+ s += (utf8_target) ? UTF8SKIP(s) : 1;
+ }
+ break;
+ }
+ case BOUNDL:
+ PL_reg_flags |= RF_tainted;
+ FBC_BOUND(isALNUM_LC,
+ isALNUM_LC_uvchr(UNI_TO_NATIVE(tmp)),
+ isALNUM_LC_utf8((U8*)s));
+ break;
+ case NBOUNDL:
+ PL_reg_flags |= RF_tainted;
+ FBC_NBOUND(isALNUM_LC,
+ isALNUM_LC_uvchr(UNI_TO_NATIVE(tmp)),
+ isALNUM_LC_utf8((U8*)s));
+ break;
+ case BOUND:
+ FBC_BOUND(isWORDCHAR,
+ isALNUM_uni(tmp),
+ cBOOL(swash_fetch(PL_utf8_swash_ptrs[_CC_WORDCHAR], (U8*)s, utf8_target)));
+ break;
+ case BOUNDA:
+ FBC_BOUND_NOLOAD(isWORDCHAR_A,
+ isWORDCHAR_A(tmp),
+ isWORDCHAR_A((U8*)s));
+ break;
+ case NBOUND:
+ FBC_NBOUND(isWORDCHAR,
+ isALNUM_uni(tmp),
+ cBOOL(swash_fetch(PL_utf8_swash_ptrs[_CC_WORDCHAR], (U8*)s, utf8_target)));
+ break;
+ case NBOUNDA:
+ FBC_NBOUND_NOLOAD(isWORDCHAR_A,
+ isWORDCHAR_A(tmp),
+ isWORDCHAR_A((U8*)s));
+ break;
+ case BOUNDU:
+ FBC_BOUND(isWORDCHAR_L1,
+ isALNUM_uni(tmp),
+ cBOOL(swash_fetch(PL_utf8_swash_ptrs[_CC_WORDCHAR], (U8*)s, utf8_target)));
+ break;
+ case NBOUNDU:
+ FBC_NBOUND(isWORDCHAR_L1,
+ isALNUM_uni(tmp),
+ cBOOL(swash_fetch(PL_utf8_swash_ptrs[_CC_WORDCHAR], (U8*)s, utf8_target)));
+ break;
+ case LNBREAK:
+ REXEC_FBC_CSCAN(is_LNBREAK_utf8_safe(s, strend),
+ is_LNBREAK_latin1_safe(s, strend)
+ );
+ break;
- case AHOCORASICKC:
- case AHOCORASICK:
- {
- DECL_TRIE_TYPE(c);
- /* what trie are we using right now */
- reg_ac_data *aho
- = (reg_ac_data*)progi->data->data[ ARG( c ) ];
- reg_trie_data *trie
- = (reg_trie_data*)progi->data->data[ aho->trie ];
- HV *widecharmap = MUTABLE_HV(progi->data->data[ aho->trie + 1 ]);
+ /* The argument to all the POSIX node types is the class number to pass to
+ * _generic_isCC() to build a mask for searching in PL_charclass[] */
- const char *last_start = strend - trie->minlen;
-#ifdef DEBUGGING
- const char *real_start = s;
-#endif
- STRLEN maxlen = trie->maxlen;
- SV *sv_points;
- U8 **points; /* map of where we were in the input string
- when reading a given char. For ASCII this
- is unnecessary overhead as the relationship
- is always 1:1, but for Unicode, especially
- case folded Unicode this is not true. */
- U8 foldbuf[ UTF8_MAXBYTES_CASE + 1 ];
- U8 *bitmap=NULL;
-
-
- GET_RE_DEBUG_FLAGS_DECL;
-
- /* We can't just allocate points here. We need to wrap it in
- * an SV so it gets freed properly if there is a croak while
- * running the match */
- ENTER;
- SAVETMPS;
- sv_points=newSV(maxlen * sizeof(U8 *));
- SvCUR_set(sv_points,
- maxlen * sizeof(U8 *));
- SvPOK_on(sv_points);
- sv_2mortal(sv_points);
- points=(U8**)SvPV_nolen(sv_points );
- if ( trie_type != trie_utf8_fold
- && (trie->bitmap || OP(c)==AHOCORASICKC) )
- {
- if (trie->bitmap)
- bitmap=(U8*)trie->bitmap;
- else
- bitmap=(U8*)ANYOF_BITMAP(c);
- }
- /* this is the Aho-Corasick algorithm modified a touch
- to include special handling for long "unknown char"
- sequences. The basic idea being that we use AC as long
- as we are dealing with a possible matching char, when
- we encounter an unknown char (and we have not encountered
- an accepting state) we scan forward until we find a legal
- starting char.
- AC matching is basically that of trie matching, except
- that when we encounter a failing transition, we fall back
- to the current states "fail state", and try the current char
- again, a process we repeat until we reach the root state,
- state 1, or a legal transition. If we fail on the root state
- then we can either terminate if we have reached an accepting
- state previously, or restart the entire process from the beginning
- if we have not.
+ case NPOSIXL:
+ to_complement = 1;
+ /* FALLTHROUGH */
- */
- while (s <= last_start) {
- const U32 uniflags = UTF8_ALLOW_DEFAULT;
- U8 *uc = (U8*)s;
- U16 charid = 0;
- U32 base = 1;
- U32 state = 1;
- UV uvc = 0;
- STRLEN len = 0;
- STRLEN foldlen = 0;
- U8 *uscan = (U8*)NULL;
- U8 *leftmost = NULL;
-#ifdef DEBUGGING
- U32 accepted_word= 0;
-#endif
- U32 pointpos = 0;
+ case POSIXL:
+ PL_reg_flags |= RF_tainted;
+ REXEC_FBC_CSCAN(to_complement ^ cBOOL(isFOO_utf8_lc(FLAGS(c), (U8 *) s)),
+ to_complement ^ cBOOL(isFOO_lc(FLAGS(c), *s)));
+ break;
- while ( state && uc <= (U8*)strend ) {
- int failed=0;
- U32 word = aho->states[ state ].wordnum;
+ case NPOSIXD:
+ to_complement = 1;
+ /* FALLTHROUGH */
- if( state==1 ) {
- if ( bitmap ) {
- DEBUG_TRIE_EXECUTE_r(
- if ( uc <= (U8*)last_start && !BITMAP_TEST(bitmap,*uc) ) {
- dump_exec_pos( (char *)uc, c, strend, real_start,
- (char *)uc, utf8_target );
- PerlIO_printf( Perl_debug_log,
- " Scanning for legal start char...\n");
- }
- );
- if (utf8_target) {
- while ( uc <= (U8*)last_start && !BITMAP_TEST(bitmap,*uc) ) {
- uc += UTF8SKIP(uc);
- }
- } else {
- while ( uc <= (U8*)last_start && !BITMAP_TEST(bitmap,*uc) ) {
- uc++;
- }
- }
- s= (char *)uc;
- }
- if (uc >(U8*)last_start) break;
- }
-
- if ( word ) {
- U8 *lpos= points[ (pointpos - trie->wordinfo[word].len) % maxlen ];
- if (!leftmost || lpos < leftmost) {
- DEBUG_r(accepted_word=word);
- leftmost= lpos;
- }
- if (base==0) break;
-
- }
- points[pointpos++ % maxlen]= uc;
- if (foldlen || uc < (U8*)strend) {
- REXEC_TRIE_READ_CHAR(trie_type, trie,
- widecharmap, uc,
- uscan, len, uvc, charid, foldlen,
- foldbuf, uniflags);
- DEBUG_TRIE_EXECUTE_r({
- dump_exec_pos( (char *)uc, c, strend,
- real_start, s, utf8_target);
- PerlIO_printf(Perl_debug_log,
- " Charid:%3u CP:%4"UVxf" ",
- charid, uvc);
- });
- }
+ case POSIXD:
+ if (utf8_target) {
+ goto posix_utf8;
+ }
+ goto posixa;
+
+ case NPOSIXA:
+ if (utf8_target) {
+ /* The complement of something that matches only ASCII matches all
+ * UTF-8 variant code points, plus everything in ASCII that isn't
+ * in the class */
+ REXEC_FBC_UTF8_CLASS_SCAN(! UTF8_IS_INVARIANT(*s)
+ || ! _generic_isCC_A(*s, FLAGS(c)));
+ break;
+ }
+
+ to_complement = 1;
+ /* FALLTHROUGH */
+
+ case POSIXA:
+ posixa:
+ /* Don't need to worry about utf8, as it can match only a single
+ * byte invariant character. */
+ REXEC_FBC_CLASS_SCAN(
+ to_complement ^ cBOOL(_generic_isCC_A(*s, FLAGS(c))));
+ break;
+
+ case NPOSIXU:
+ to_complement = 1;
+ /* FALLTHROUGH */
+
+ case POSIXU:
+ if (! utf8_target) {
+ REXEC_FBC_CLASS_SCAN(to_complement ^ cBOOL(_generic_isCC(*s,
+ FLAGS(c))));
+ }
+ else {
+
+ posix_utf8:
+ classnum = (_char_class_number) FLAGS(c);
+ if (classnum < _FIRST_NON_SWASH_CC) {
+ while (s < strend) {
+
+ /* We avoid loading in the swash as long as possible, but
+ * should we have to, we jump to a separate loop. This
+ * extra 'if' statement is what keeps this code from being
+ * just a call to REXEC_FBC_UTF8_CLASS_SCAN() */
+ if (UTF8_IS_ABOVE_LATIN1(*s)) {
+ goto found_above_latin1;
+ }
+ if ((UTF8_IS_INVARIANT(*s)
+ && to_complement ^ cBOOL(_generic_isCC((U8) *s,
+ classnum)))
+ || (UTF8_IS_DOWNGRADEABLE_START(*s)
+ && to_complement ^ cBOOL(
+ _generic_isCC(TWO_BYTE_UTF8_TO_UNI(*s, *(s + 1)),
+ classnum))))
+ {
+ if (tmp && (!reginfo || regtry(reginfo, &s)))
+ goto got_it;
else {
- len = 0;
- charid = 0;
+ tmp = doevery;
}
+ }
+ else {
+ tmp = 1;
+ }
+ s += UTF8SKIP(s);
+ }
+ }
+ else switch (classnum) { /* These classes are implemented as
+ macros */
+ case _CC_ENUM_SPACE: /* XXX would require separate code if we
+ revert the change of \v matching this */
+ /* FALL THROUGH */
+
+ case _CC_ENUM_PSXSPC:
+ REXEC_FBC_UTF8_CLASS_SCAN(
+ to_complement ^ cBOOL(isSPACE_utf8(s)));
+ break;
+
+ case _CC_ENUM_BLANK:
+ REXEC_FBC_UTF8_CLASS_SCAN(
+ to_complement ^ cBOOL(isBLANK_utf8(s)));
+ break;
+
+ case _CC_ENUM_XDIGIT:
+ REXEC_FBC_UTF8_CLASS_SCAN(
+ to_complement ^ cBOOL(isXDIGIT_utf8(s)));
+ break;
+
+ case _CC_ENUM_VERTSPACE:
+ REXEC_FBC_UTF8_CLASS_SCAN(
+ to_complement ^ cBOOL(isVERTWS_utf8(s)));
+ break;
+ case _CC_ENUM_CNTRL:
+ REXEC_FBC_UTF8_CLASS_SCAN(
+ to_complement ^ cBOOL(isCNTRL_utf8(s)));
+ break;
+
+ default:
+ Perl_croak(aTHX_ "panic: find_byclass() node %d='%s' has an unexpected character class '%d'", OP(c), PL_reg_name[OP(c)], classnum);
+ assert(0); /* NOTREACHED */
+ }
+ }
+ break;
+
+ found_above_latin1: /* Here we have to load a swash to get the result
+ for the current code point */
+ if (! PL_utf8_swash_ptrs[classnum]) {
+ U8 flags = _CORE_SWASH_INIT_ACCEPT_INVLIST;
+ PL_utf8_swash_ptrs[classnum] =
+ _core_swash_init("utf8", swash_property_names[classnum],
+ &PL_sv_undef, 1, 0, NULL, &flags);
+ }
+
+ /* This is a copy of the loop above for swash classes, though using the
+ * FBC macro instead of being expanded out. Since we've loaded the
+ * swash, we don't have to check for that each time through the loop */
+ REXEC_FBC_UTF8_CLASS_SCAN(
+ to_complement ^ cBOOL(_generic_utf8(
+ classnum,
+ s,
+ swash_fetch(PL_utf8_swash_ptrs[classnum],
+ (U8 *) s, TRUE))));
+ break;
+
+ case AHOCORASICKC:
+ case AHOCORASICK:
+ {
+ DECL_TRIE_TYPE(c);
+ /* what trie are we using right now */
+ reg_ac_data *aho = (reg_ac_data*)progi->data->data[ ARG( c ) ];
+ reg_trie_data *trie = (reg_trie_data*)progi->data->data[ aho->trie ];
+ HV *widecharmap = MUTABLE_HV(progi->data->data[ aho->trie + 1 ]);
- do {
+ const char *last_start = strend - trie->minlen;
#ifdef DEBUGGING
- word = aho->states[ state ].wordnum;
+ const char *real_start = s;
#endif
- base = aho->states[ state ].trans.base;
-
- DEBUG_TRIE_EXECUTE_r({
- if (failed)
- dump_exec_pos( (char *)uc, c, strend, real_start,
- s, utf8_target );
- PerlIO_printf( Perl_debug_log,
- "%sState: %4"UVxf", word=%"UVxf,
- failed ? " Fail transition to " : "",
- (UV)state, (UV)word);
- });
- if ( base ) {
- U32 tmp;
- I32 offset;
- if (charid &&
- ( ((offset = base + charid
- - 1 - trie->uniquecharcount)) >= 0)
- && ((U32)offset < trie->lasttrans)
- && trie->trans[offset].check == state
- && (tmp=trie->trans[offset].next))
- {
- DEBUG_TRIE_EXECUTE_r(
- PerlIO_printf( Perl_debug_log," - legal\n"));
- state = tmp;
- break;
+ STRLEN maxlen = trie->maxlen;
+ SV *sv_points;
+ U8 **points; /* map of where we were in the input string
+ when reading a given char. For ASCII this
+ is unnecessary overhead as the relationship
+ is always 1:1, but for Unicode, especially
+ case folded Unicode this is not true. */
+ U8 foldbuf[ UTF8_MAXBYTES_CASE + 1 ];
+ U8 *bitmap=NULL;
+
+
+ GET_RE_DEBUG_FLAGS_DECL;
+
+ /* We can't just allocate points here. We need to wrap it in
+ * an SV so it gets freed properly if there is a croak while
+ * running the match */
+ ENTER;
+ SAVETMPS;
+ sv_points=newSV(maxlen * sizeof(U8 *));
+ SvCUR_set(sv_points,
+ maxlen * sizeof(U8 *));
+ SvPOK_on(sv_points);
+ sv_2mortal(sv_points);
+ points=(U8**)SvPV_nolen(sv_points );
+ if ( trie_type != trie_utf8_fold
+ && (trie->bitmap || OP(c)==AHOCORASICKC) )
+ {
+ if (trie->bitmap)
+ bitmap=(U8*)trie->bitmap;
+ else
+ bitmap=(U8*)ANYOF_BITMAP(c);
+ }
+ /* this is the Aho-Corasick algorithm modified a touch
+ to include special handling for long "unknown char" sequences.
+ The basic idea being that we use AC as long as we are dealing
+ with a possible matching char, when we encounter an unknown char
+ (and we have not encountered an accepting state) we scan forward
+ until we find a legal starting char.
+ AC matching is basically that of trie matching, except that when
+ we encounter a failing transition, we fall back to the current
+ states "fail state", and try the current char again, a process
+ we repeat until we reach the root state, state 1, or a legal
+ transition. If we fail on the root state then we can either
+ terminate if we have reached an accepting state previously, or
+ restart the entire process from the beginning if we have not.
+
+ */
+ while (s <= last_start) {
+ const U32 uniflags = UTF8_ALLOW_DEFAULT;
+ U8 *uc = (U8*)s;
+ U16 charid = 0;
+ U32 base = 1;
+ U32 state = 1;
+ UV uvc = 0;
+ STRLEN len = 0;
+ STRLEN foldlen = 0;
+ U8 *uscan = (U8*)NULL;
+ U8 *leftmost = NULL;
+#ifdef DEBUGGING
+ U32 accepted_word= 0;
+#endif
+ U32 pointpos = 0;
+
+ while ( state && uc <= (U8*)strend ) {
+ int failed=0;
+ U32 word = aho->states[ state ].wordnum;
+
+ if( state==1 ) {
+ if ( bitmap ) {
+ DEBUG_TRIE_EXECUTE_r(
+ if ( uc <= (U8*)last_start && !BITMAP_TEST(bitmap,*uc) ) {
+ dump_exec_pos( (char *)uc, c, strend, real_start,
+ (char *)uc, utf8_target );
+ PerlIO_printf( Perl_debug_log,
+ " Scanning for legal start char...\n");
}
- else {
- DEBUG_TRIE_EXECUTE_r(
- PerlIO_printf( Perl_debug_log," - fail\n"));
- failed = 1;
- state = aho->fail[state];
+ );
+ if (utf8_target) {
+ while ( uc <= (U8*)last_start && !BITMAP_TEST(bitmap,*uc) ) {
+ uc += UTF8SKIP(uc);
+ }
+ } else {
+ while ( uc <= (U8*)last_start && !BITMAP_TEST(bitmap,*uc) ) {
+ uc++;
}
}
- else {
- /* we must be accepting here */
- DEBUG_TRIE_EXECUTE_r(
- PerlIO_printf( Perl_debug_log," - accepting\n"));
- failed = 1;
- break;
- }
- } while(state);
- uc += len;
- if (failed) {
- if (leftmost)
- break;
- if (!state) state = 1;
+ s= (char *)uc;
}
+ if (uc >(U8*)last_start) break;
}
- if ( aho->states[ state ].wordnum ) {
- U8 *lpos = points[ (pointpos - trie->wordinfo[aho->states[ state ].wordnum].len) % maxlen ];
+
+ if ( word ) {
+ U8 *lpos= points[ (pointpos - trie->wordinfo[word].len) % maxlen ];
if (!leftmost || lpos < leftmost) {
- DEBUG_r(accepted_word=aho->states[ state ].wordnum);
- leftmost = lpos;
+ DEBUG_r(accepted_word=word);
+ leftmost= lpos;
}
+ if (base==0) break;
+
}
- if (leftmost) {
- s = (char*)leftmost;
+ points[pointpos++ % maxlen]= uc;
+ if (foldlen || uc < (U8*)strend) {
+ REXEC_TRIE_READ_CHAR(trie_type, trie,
+ widecharmap, uc,
+ uscan, len, uvc, charid, foldlen,
+ foldbuf, uniflags);
DEBUG_TRIE_EXECUTE_r({
- PerlIO_printf(
- Perl_debug_log,"Matches word #%"UVxf" at position %"IVdf". Trying full pattern...\n",
- (UV)accepted_word, (IV)(s - real_start)
- );
+ dump_exec_pos( (char *)uc, c, strend,
+ real_start, s, utf8_target);
+ PerlIO_printf(Perl_debug_log,
+ " Charid:%3u CP:%4"UVxf" ",
+ charid, uvc);
});
- if (!reginfo || regtry(reginfo, &s)) {
- FREETMPS;
- LEAVE;
- goto got_it;
- }
- s = HOPc(s,1);
+ }
+ else {
+ len = 0;
+ charid = 0;
+ }
+
+
+ do {
+#ifdef DEBUGGING
+ word = aho->states[ state ].wordnum;
+#endif
+ base = aho->states[ state ].trans.base;
+
DEBUG_TRIE_EXECUTE_r({
- PerlIO_printf( Perl_debug_log,"Pattern failed. Looking for new start point...\n");
+ if (failed)
+ dump_exec_pos( (char *)uc, c, strend, real_start,
+ s, utf8_target );
+ PerlIO_printf( Perl_debug_log,
+ "%sState: %4"UVxf", word=%"UVxf,
+ failed ? " Fail transition to " : "",
+ (UV)state, (UV)word);
});
- } else {
- DEBUG_TRIE_EXECUTE_r(
- PerlIO_printf( Perl_debug_log,"No match.\n"));
- break;
+ if ( base ) {
+ U32 tmp;
+ I32 offset;
+ if (charid &&
+ ( ((offset = base + charid
+ - 1 - trie->uniquecharcount)) >= 0)
+ && ((U32)offset < trie->lasttrans)
+ && trie->trans[offset].check == state
+ && (tmp=trie->trans[offset].next))
+ {
+ DEBUG_TRIE_EXECUTE_r(
+ PerlIO_printf( Perl_debug_log," - legal\n"));
+ state = tmp;
+ break;
+ }
+ else {
+ DEBUG_TRIE_EXECUTE_r(
+ PerlIO_printf( Perl_debug_log," - fail\n"));
+ failed = 1;
+ state = aho->fail[state];
+ }
+ }
+ else {
+ /* we must be accepting here */
+ DEBUG_TRIE_EXECUTE_r(
+ PerlIO_printf( Perl_debug_log," - accepting\n"));
+ failed = 1;
+ break;
+ }
+ } while(state);
+ uc += len;
+ if (failed) {
+ if (leftmost)
+ break;
+ if (!state) state = 1;
}
}
- FREETMPS;
- LEAVE;
- }
- break;
- default:
- Perl_croak(aTHX_ "panic: unknown regstclass %d", (int)OP(c));
- break;
- }
- return 0;
- got_it:
- return s;
+ if ( aho->states[ state ].wordnum ) {
+ U8 *lpos = points[ (pointpos - trie->wordinfo[aho->states[ state ].wordnum].len) % maxlen ];
+ if (!leftmost || lpos < leftmost) {
+ DEBUG_r(accepted_word=aho->states[ state ].wordnum);
+ leftmost = lpos;
+ }
+ }
+ if (leftmost) {
+ s = (char*)leftmost;
+ DEBUG_TRIE_EXECUTE_r({
+ PerlIO_printf(
+ Perl_debug_log,"Matches word #%"UVxf" at position %"IVdf". Trying full pattern...\n",
+ (UV)accepted_word, (IV)(s - real_start)
+ );
+ });
+ if (!reginfo || regtry(reginfo, &s)) {
+ FREETMPS;
+ LEAVE;
+ goto got_it;
+ }
+ s = HOPc(s,1);
+ DEBUG_TRIE_EXECUTE_r({
+ PerlIO_printf( Perl_debug_log,"Pattern failed. Looking for new start point...\n");
+ });
+ } else {
+ DEBUG_TRIE_EXECUTE_r(
+ PerlIO_printf( Perl_debug_log,"No match.\n"));
+ break;
+ }
+ }
+ FREETMPS;
+ LEAVE;
+ }
+ break;
+ default:
+ Perl_croak(aTHX_ "panic: unknown regstclass %d", (int)OP(c));
+ break;
+ }
+ return 0;
+ got_it:
+ return s;
}
- regexec_flags - match a regexp against a string
*/
I32
-Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, register char *strend,
+Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, char *strend,
char *strbeg, I32 minend, SV *sv, void *data, U32 flags)
/* stringarg: the point in the string at which to begin matching */
/* strend: pointer to null at end of string */
{
dVAR;
- struct regexp *const prog = (struct regexp *)SvANY(rx);
- /*register*/ char *s;
+ struct regexp *const prog = ReANY(rx);
+ char *s;
regnode *c;
- /*register*/ char *startpos = stringarg;
+ char *startpos = stringarg;
I32 minlen; /* must match at least this many chars */
I32 dontbother = 0; /* how many characters not to try at end */
I32 end_shift = 0; /* Same for the end. */ /* CC */
PL_reg_state.re_state_eval_setup_done = FALSE;
PL_reg_maxiter = 0;
- if (RX_UTF8(rx))
- PL_reg_flags |= RF_utf8;
-
+ reginfo.is_utf8_pat = cBOOL(RX_UTF8(rx));
+ reginfo.warned = FALSE;
/* Mark beginning of line for ^ and lookbehind. */
reginfo.bol = startpos; /* XXX not used ??? */
PL_bostr = strbeg;
was from this regex we don't want a subsequent partially
successful match to clobber the old results.
So when we detect this possibility we add a swap buffer
- to the re, and switch the buffer each match. If we fail
- we switch it back, otherwise we leave it swapped.
+ to the re, and switch the buffer each match. If we fail,
+ we switch it back; otherwise we leave it swapped.
*/
swap = prog->offs;
/* do we need a save destructor here for eval dies? */
/* Messy cases: unanchored match. */
if ((prog->anchored_substr || prog->anchored_utf8) && prog->intflags & PREGf_SKIP) {
/* we have /x+whatever/ */
- /* it must be a one character string (XXXX Except UTF_PATTERN?) */
+ /* it must be a one character string (XXXX Except is_utf8_pat?) */
char ch;
#ifdef DEBUGGING
int did_match = 0;
else {
if (! prog->anchored_substr) {
if (! to_byte_substr(prog)) {
- DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
- non_utf8_target_but_utf8_required));
- goto phooey;
+ NON_UTF8_TARGET_BUT_UTF8_REQUIRED(phooey);
}
}
ch = SvPVX_const(prog->anchored_substr)[0];
else {
if (! prog->anchored_substr) {
if (! to_byte_substr(prog)) {
- DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
- non_utf8_target_but_utf8_required));
- goto phooey;
+ NON_UTF8_TARGET_BUT_UTF8_REQUIRED(phooey);
}
}
must = prog->anchored_substr;
else {
if (! prog->float_substr) {
if (! to_byte_substr(prog)) {
- DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
- non_utf8_target_but_utf8_required));
- goto phooey;
+ NON_UTF8_TARGET_BUT_UTF8_REQUIRED(phooey);
}
}
must = prog->float_substr;
quoted, (int)(strend - s));
}
});
- if (find_byclass(prog, c, s, strend, ®info))
+ if (find_byclass(prog, c, s, strend, ®info, reginfo.is_utf8_pat))
goto got_it;
DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log, "Contradicts stclass... [regexec_flags]\n"));
}
else {
if (! prog->float_substr) {
if (! to_byte_substr(prog)) {
- DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
- non_utf8_target_but_utf8_required));
- goto phooey;
+ NON_UTF8_TARGET_BUT_UTF8_REQUIRED(phooey);
}
}
float_real = prog->float_substr;
/* make sure $`, $&, $', and $digit will work later */
if ( !(flags & REXEC_NOT_FIRST) ) {
if (flags & REXEC_COPY_STR) {
-#ifdef PERL_OLD_COPY_ON_WRITE
- if ((SvIsCOW(sv)
- || (SvFLAGS(sv) & CAN_COW_MASK) == CAN_COW_FLAGS)) {
+#ifdef PERL_ANY_COW
+ if (SvCANCOW(sv)) {
if (DEBUG_C_TEST) {
PerlIO_printf(Perl_debug_log,
"Copy on write: regexp capture, type %d\n",
dVAR;
CHECKPOINT lastcp;
REGEXP *const rx = reginfo->prog;
- regexp *const prog = (struct regexp *)SvANY(rx);
+ regexp *const prog = ReANY(rx);
I32 result;
RXi_GET_DECL(prog,progi);
GET_RE_DEBUG_FLAGS_DECL;
PL_reg_oldsavedlen = prog->sublen;
PL_reg_oldsavedoffset = prog->suboffset;
PL_reg_oldsavedcoffset = prog->suboffset;
-#ifdef PERL_OLD_COPY_ON_WRITE
+#ifdef PERL_ANY_COW
PL_nrs = prog->saved_copy;
#endif
RXp_MATCH_COPIED_off(prog);
prog->offs[0].start = *startposp - PL_bostr;
prog->lastparen = 0;
prog->lastcloseparen = 0;
- PL_regsize = 0;
/* XXXX What this code is doing here?!!! There should be no need
to do this again and again, prog->lastparen should take care of
#define CHRTEST_UNINIT -1001 /* c1/c2 haven't been calculated yet */
#define CHRTEST_VOID -1000 /* the c1/c2 "next char" test should be skipped */
+#define CHRTEST_NOT_A_CP_1 -999
+#define CHRTEST_NOT_A_CP_2 -998
#define SLAB_FIRST(s) (&(s)->states[0])
#define SLAB_LAST(s) (&(s)->states[PERL_REGMATCH_SLAB_SLOTS-1])
}
}
static bool
-S_setup_EXACTISH_ST_c1_c2(pTHX_ regnode *text_node, I32 *c1, I32 *c2)
+S_setup_EXACTISH_ST_c1_c2(pTHX_ const regnode * const text_node, int *c1p,
+ U8* c1_utf8, int *c2p, U8* c2_utf8, bool is_utf8_pat)
{
- /* This sets up a relatively quick check for the initial part of what must
- * match after a CURLY-type operation condition (the "B" in A*B), where B
- * starts with an EXACTish node, <text_node>. If this check is not met,
- * the caller knows that it should continue with the loop. If the check is
- * met, the caller must see if all of B is met, before making the decision.
+ /* This function determines if there are one or two characters that match
+ * the first character of the passed-in EXACTish node <text_node>, and if
+ * so, returns them in the passed-in pointers.
+ *
+ * If it determines that no possible character in the target string can
+ * match, it returns FALSE; otherwise TRUE. (The FALSE situation occurs if
+ * the first character in <text_node> requires UTF-8 to represent, and the
+ * target string isn't in UTF-8.)
+ *
+ * If there are more than two characters that could match the beginning of
+ * <text_node>, or if more context is required to determine a match or not,
+ * it sets both *<c1p> and *<c2p> to CHRTEST_VOID.
*
- * This function sets *<c1> and *<c2> to be the first code point of B. If
- * there are two possible such code points (as when the text_node is
- * folded), *<c2> is set to the second. If there are more than two (which
- * happens for some folds), or there is some other complication, these
- * parameters are set to CHRTEST_VOID, to indicate not to do a quick check:
- * just try all of B after every time through the loop.
+ * The motiviation behind this function is to allow the caller to set up
+ * tight loops for matching. If <text_node> is of type EXACT, there is
+ * only one possible character that can match its first character, and so
+ * the situation is quite simple. But things get much more complicated if
+ * folding is involved. It may be that the first character of an EXACTFish
+ * node doesn't participate in any possible fold, e.g., punctuation, so it
+ * can be matched only by itself. The vast majority of characters that are
+ * in folds match just two things, their lower and upper-case equivalents.
+ * But not all are like that; some have multiple possible matches, or match
+ * sequences of more than one character. This function sorts all that out.
*
- * If the routine determines that there is no possible way for there to be
- * a match, it returns FALSE.
- * */
+ * Consider the patterns A*B or A*?B where A and B are arbitrary. In a
+ * loop of trying to match A*, we know we can't exit where the thing
+ * following it isn't a B. And something can't be a B unless it is the
+ * beginning of B. By putting a quick test for that beginning in a tight
+ * loop, we can rule out things that can't possibly be B without having to
+ * break out of the loop, thus avoiding work. Similarly, if A is a single
+ * character, we can make a tight loop matching A*, using the outputs of
+ * this function.
+ *
+ * If the target string to match isn't in UTF-8, and there aren't
+ * complications which require CHRTEST_VOID, *<c1p> and *<c2p> are set to
+ * the one or two possible octets (which are characters in this situation)
+ * that can match. In all cases, if there is only one character that can
+ * match, *<c1p> and *<c2p> will be identical.
+ *
+ * If the target string is in UTF-8, the buffers pointed to by <c1_utf8>
+ * and <c2_utf8> will contain the one or two UTF-8 sequences of bytes that
+ * can match the beginning of <text_node>. They should be declared with at
+ * least length UTF8_MAXBYTES+1. (If the target string isn't in UTF-8, it is
+ * undefined what these contain.) If one or both of the buffers are
+ * invariant under UTF-8, *<c1p>, and *<c2p> will also be set to the
+ * corresponding invariant. If variant, the corresponding *<c1p> and/or
+ * *<c2p> will be set to a negative number(s) that shouldn't match any code
+ * point (unless inappropriately coerced to unsigned). *<c1p> will equal
+ * *<c2p> if and only if <c1_utf8> and <c2_utf8> are the same. */
const bool utf8_target = PL_reg_match_utf8;
- const U32 uniflags = UTF8_ALLOW_DEFAULT;
+
+ UV c1 = CHRTEST_NOT_A_CP_1;
+ UV c2 = CHRTEST_NOT_A_CP_2;
+ bool use_chrtest_void = FALSE;
+
+ /* Used when we have both utf8 input and utf8 output, to avoid converting
+ * to/from code points */
+ bool utf8_has_been_setup = FALSE;
+
dVAR;
- /* First byte from the EXACTish node */
- U8 *pat_byte = (U8*)STRING(text_node);
+ U8 *pat = (U8*)STRING(text_node);
+
+ if (OP(text_node) == EXACT) {
+
+ /* In an exact node, only one thing can be matched, that first
+ * character. If both the pat and the target are UTF-8, we can just
+ * copy the input to the output, avoiding finding the code point of
+ * that character */
+ if (!is_utf8_pat) {
+ c2 = c1 = *pat;
+ }
+ else if (utf8_target) {
+ Copy(pat, c1_utf8, UTF8SKIP(pat), U8);
+ Copy(pat, c2_utf8, UTF8SKIP(pat), U8);
+ utf8_has_been_setup = TRUE;
+ }
+ else {
+ c2 = c1 = valid_utf8_to_uvchr(pat, NULL);
+ }
+ }
+ else /* an EXACTFish node */
+ if ((is_utf8_pat
+ && is_MULTI_CHAR_FOLD_utf8_safe(pat,
+ pat + STR_LEN(text_node)))
+ || (!is_utf8_pat
+ && is_MULTI_CHAR_FOLD_latin1_safe(pat,
+ pat + STR_LEN(text_node))))
+ {
+ /* Multi-character folds require more context to sort out. Also
+ * PL_utf8_foldclosures used below doesn't handle them, so have to be
+ * handled outside this routine */
+ use_chrtest_void = TRUE;
+ }
+ else { /* an EXACTFish node which doesn't begin with a multi-char fold */
+ c1 = is_utf8_pat ? valid_utf8_to_uvchr(pat, NULL) : *pat;
+ if (c1 > 256) {
+ /* Load the folds hash, if not already done */
+ SV** listp;
+ if (! PL_utf8_foldclosures) {
+ if (! PL_utf8_tofold) {
+ U8 dummy[UTF8_MAXBYTES+1];
+
+ /* Force loading this by folding an above-Latin1 char */
+ to_utf8_fold((U8*) HYPHEN_UTF8, dummy, NULL);
+ assert(PL_utf8_tofold); /* Verify that worked */
+ }
+ PL_utf8_foldclosures = _swash_inversion_hash(PL_utf8_tofold);
+ }
+
+ /* The fold closures data structure is a hash with the keys being
+ * the UTF-8 of every character that is folded to, like 'k', and
+ * the values each an array of all code points that fold to its
+ * key. e.g. [ 'k', 'K', KELVIN_SIGN ]. Multi-character folds are
+ * not included */
+ if ((! (listp = hv_fetch(PL_utf8_foldclosures,
+ (char *) pat,
+ UTF8SKIP(pat),
+ FALSE))))
+ {
+ /* Not found in the hash, therefore there are no folds
+ * containing it, so there is only a single character that
+ * could match */
+ c2 = c1;
+ }
+ else { /* Does participate in folds */
+ AV* list = (AV*) *listp;
+ if (av_len(list) != 1) {
- if (! UTF_PATTERN) { /* Not UTF-8: the code point is the byte */
- *c1 = *pat_byte;
- if (OP(text_node) == EXACT) {
- *c2 = *c1;
+ /* If there aren't exactly two folds to this, it is outside
+ * the scope of this function */
+ use_chrtest_void = TRUE;
+ }
+ else { /* There are two. Get them */
+ SV** c_p = av_fetch(list, 0, FALSE);
+ if (c_p == NULL) {
+ Perl_croak(aTHX_ "panic: invalid PL_utf8_foldclosures structure");
+ }
+ c1 = SvUV(*c_p);
+
+ c_p = av_fetch(list, 1, FALSE);
+ if (c_p == NULL) {
+ Perl_croak(aTHX_ "panic: invalid PL_utf8_foldclosures structure");
+ }
+ c2 = SvUV(*c_p);
+
+ /* Folds that cross the 255/256 boundary are forbidden if
+ * EXACTFL, or EXACTFA and one is ASCIII. Since the
+ * pattern character is above 256, and its only other match
+ * is below 256, the only legal match will be to itself.
+ * We have thrown away the original, so have to compute
+ * which is the one above 255 */
+ if ((c1 < 256) != (c2 < 256)) {
+ if (OP(text_node) == EXACTFL
+ || (OP(text_node) == EXACTFA
+ && (isASCII(c1) || isASCII(c2))))
+ {
+ if (c1 < 256) {
+ c1 = c2;
+ }
+ else {
+ c2 = c1;
+ }
+ }
+ }
+ }
+ }
}
- else if (utf8_target
- && HAS_NONLATIN1_FOLD_CLOSURE(*c1)
- && (OP(text_node) != EXACTFA || ! isASCII(*c1)))
+ else /* Here, c1 is < 255 */
+ if (utf8_target
+ && HAS_NONLATIN1_FOLD_CLOSURE(c1)
+ && OP(text_node) != EXACTFL
+ && (OP(text_node) != EXACTFA || ! isASCII(c1)))
{
/* Here, there could be something above Latin1 in the target which
- * folds to this character in the pattern, which means there are
- * more than two possible beginnings of B. */
- *c1 = *c2 = CHRTEST_VOID;
+ * folds to this character in the pattern. All such cases except
+ * LATIN SMALL LETTER Y WITH DIAERESIS have more than two characters
+ * involved in their folds, so are outside the scope of this
+ * function */
+ if (UNLIKELY(c1 == LATIN_SMALL_LETTER_Y_WITH_DIAERESIS)) {
+ c2 = LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS;
+ }
+ else {
+ use_chrtest_void = TRUE;
+ }
}
else { /* Here nothing above Latin1 can fold to the pattern character */
switch (OP(text_node)) {
case EXACTFL: /* /l rules */
- *c2 = PL_fold_locale[*c1];
- break;
-
- case EXACTFU_SS: /* This requires special handling: Don't
- shortcut */
- *c1 = *c2 = CHRTEST_VOID;
+ c2 = PL_fold_locale[c1];
break;
case EXACTF:
if (! utf8_target) { /* /d rules */
- *c2 = PL_fold[*c1];
+ c2 = PL_fold[c1];
break;
}
/* FALLTHROUGH */
/* /u rules for all these. This happens to work for
- * EXACTFA in the ASCII range as nothing in Latin1 folds to
- * ASCII */
+ * EXACTFA as nothing in Latin1 folds to ASCII */
case EXACTFA:
case EXACTFU_TRICKYFOLD:
+ case EXACTFU_SS:
case EXACTFU:
- *c2 = PL_fold_latin1[*c1];
+ c2 = PL_fold_latin1[c1];
break;
- default: Perl_croak(aTHX_ "panic: Unexpected op %u", OP(text_node));
+ default:
+ Perl_croak(aTHX_ "panic: Unexpected op %u", OP(text_node));
+ assert(0); /* NOTREACHED */
}
}
}
- else { /* UTF_PATTERN */
- if (OP(text_node) == EXACT) {
- *c2 = *c1 = utf8n_to_uvchr(pat_byte, UTF8_MAXBYTES, 0, uniflags);
- if (*c1 < 0) { /* Overflowed what we can handle */
- *c1 = *c2 = CHRTEST_VOID;
- }
- else if (*c1 > 255 && ! utf8_target) {
- return FALSE; /* Can't possibly match */
- }
+
+ /* Here have figured things out. Set up the returns */
+ if (use_chrtest_void) {
+ *c2p = *c1p = CHRTEST_VOID;
+ }
+ else if (utf8_target) {
+ if (! utf8_has_been_setup) { /* Don't have the utf8; must get it */
+ uvchr_to_utf8(c1_utf8, c1);
+ uvchr_to_utf8(c2_utf8, c2);
}
- else {
- if (UTF8_IS_ABOVE_LATIN1(*pat_byte)) {
- /* A multi-character fold is complicated, probably has more
- * than two possibilities */
- if (is_MULTI_CHAR_FOLD_utf8_safe((char*) pat_byte,
- (char*) pat_byte + STR_LEN(text_node)))
- {
- *c1 = *c2 = CHRTEST_VOID;
- }
- else { /* Not a multi-char fold */
-
- /* Load the folds hash, if not already done */
- SV** listp;
- if (! PL_utf8_foldclosures) {
- if (! PL_utf8_tofold) {
- U8 dummy[UTF8_MAXBYTES+1];
- STRLEN dummy_len;
-
- /* Force loading this by folding an above-Latin1
- * char */
- to_utf8_fold((U8*) HYPHEN_UTF8, dummy, &dummy_len);
- assert(PL_utf8_tofold); /* Verify that worked */
- }
- PL_utf8_foldclosures =
- _swash_inversion_hash(PL_utf8_tofold);
- }
+ /* Invariants are stored in both the utf8 and byte outputs; Use
+ * negative numbers otherwise for the byte ones. Make sure that the
+ * byte ones are the same iff the utf8 ones are the same */
+ *c1p = (UTF8_IS_INVARIANT(*c1_utf8)) ? *c1_utf8 : CHRTEST_NOT_A_CP_1;
+ *c2p = (UTF8_IS_INVARIANT(*c2_utf8))
+ ? *c2_utf8
+ : (c1 == c2)
+ ? CHRTEST_NOT_A_CP_1
+ : CHRTEST_NOT_A_CP_2;
+ }
+ else if (c1 > 255) {
+ if (c2 > 255) { /* both possibilities are above what a non-utf8 string
+ can represent */
+ return FALSE;
+ }
- /* The fold closures data structure is a hash with the keys
- * being every character that is folded to, like 'k', and
- * the values each an array of everything that folds to its
- * key. e.g. [ 'k', 'K', KELVIN_SIGN ] */
- if ((! (listp = hv_fetch(PL_utf8_foldclosures,
- (char *) pat_byte,
- UTF8SKIP(pat_byte),
- FALSE))))
- {
- /* Not found in the hash, therefore there are no folds
- * containing it, so there is only a single char
- * possible for beginning B */
- *c2 = *c1 = utf8n_to_uvchr(pat_byte, STR_LEN(text_node),
- 0, uniflags);
- if (*c1 < 0) { /* Overflowed what we can handle */
- *c1 = *c2 = CHRTEST_VOID;
- }
- }
- else {
- AV* list = (AV*) *listp;
- if (av_len(list) != 1) { /* If there aren't exactly
- two folds to this, have
- to test B completely */
- *c1 = *c2 = CHRTEST_VOID;
- }
- else { /* There are two. Set *c1 and *c2 to them */
- SV** c_p = av_fetch(list, 0, FALSE);
- if (c_p == NULL) {
- Perl_croak(aTHX_ "panic: invalid PL_utf8_foldclosures structure");
- }
- *c1 = SvUV(*c_p);
- c_p = av_fetch(list, 1, FALSE);
- if (c_p == NULL) {
- Perl_croak(aTHX_ "panic: invalid PL_utf8_foldclosures structure");
- }
- *c2 = SvUV(*c_p);
- }
- }
- }
- }
- else {
- /* Get the character represented by the UTF-8-encoded byte */
- U8 c = (UTF8_IS_INVARIANT(*pat_byte))
- ? *pat_byte
- : TWO_BYTE_UTF8_TO_UNI(*pat_byte, *(pat_byte+1));
-
- if (HAS_NONLATIN1_FOLD_CLOSURE(c)
- && (OP(text_node) != EXACTFA || ! isASCII(c)))
- { /* Something above Latin1 folds to this; hence there are
- more than 2 possibilities for B to begin with */
- *c1 = *c2 = CHRTEST_VOID;
- }
- else {
- *c1 = c;
- *c2 = (OP(text_node) == EXACTFL)
- ? PL_fold_locale[*c1]
- : PL_fold_latin1[*c1];
- }
- }
- }
+ *c1p = *c2p = c2; /* c2 is the only representable value */
+ }
+ else { /* c1 is representable; see about c2 */
+ *c1p = c1;
+ *c2p = (c2 < 256) ? c2 : c1;
}
return TRUE;
const bool utf8_target = PL_reg_match_utf8;
const U32 uniflags = UTF8_ALLOW_DEFAULT;
REGEXP *rex_sv = reginfo->prog;
- regexp *rex = (struct regexp *)SvANY(rex_sv);
+ regexp *rex = ReANY(rex_sv);
RXi_GET_DECL(rex,rexi);
I32 oldsave;
/* the current state. This is a cached copy of PL_regmatch_state */
CV *caller_cv = NULL; /* who called us */
CV *last_pushed_cv = NULL; /* most recently called (?{}) CV */
CHECKPOINT runops_cp; /* savestack position before executing EVAL */
+ U32 maxopenparen = 0; /* max '(' index seen so far */
+ int to_complement; /* Invert the result? */
+ _char_class_number classnum;
+ bool is_utf8_pat = reginfo->is_utf8_pat;
#ifdef DEBUGGING
GET_RE_DEBUG_FLAGS_DECL;
state_num = OP(scan);
reenter_switch:
+ to_complement = 0;
SET_nextchr;
+ assert(nextchr < 256 && (nextchr >= 0 || nextchr == NEXTCHR_EOS));
switch (state_num) {
case BOL: /* /^../ */
st->u.keeper.val = rex->offs[0].start;
rex->offs[0].start = locinput - PL_bostr;
PUSH_STATE_GOTO(KEEPS_next, next, locinput);
- /*NOT-REACHED*/
+ assert(0); /*NOTREACHED*/
case KEEPS_next_fail:
/* rollback the start point change */
rex->offs[0].start = st->u.keeper.val;
sayNO_SILENT;
- /*NOT-REACHED*/
+ assert(0); /*NOTREACHED*/
case EOL: /* /..$/ */
goto seol;
case EXACT: { /* /abc/ */
char *s = STRING(scan);
ln = STR_LEN(scan);
- if (utf8_target != UTF_PATTERN) {
+ if (utf8_target != is_utf8_pat) {
/* The target and the pattern have differing utf8ness. */
char *l = locinput;
const char * const e = s + ln;
* is an invariant, but there are tests in the test suite
* dealing with (??{...}) which violate this) */
while (s < e) {
- if (l >= PL_regeol)
- sayNO;
- if (UTF8_IS_ABOVE_LATIN1(* (U8*) l)) {
+ if (l >= PL_regeol || UTF8_IS_ABOVE_LATIN1(* (U8*) l)) {
sayNO;
}
if (UTF8_IS_INVARIANT(*(U8*)l)) {
}
}
locinput = l;
- break;
}
- /* The target and the pattern have the same utf8ness. */
- /* Inline the first character, for speed. */
- if (UCHARAT(s) != nextchr)
- sayNO;
- if (PL_regeol - locinput < ln)
- sayNO;
- if (ln > 1 && memNE(s, locinput, ln))
- sayNO;
- locinput += ln;
+ else {
+ /* The target and the pattern have the same utf8ness. */
+ /* Inline the first character, for speed. */
+ if (PL_regeol - locinput < ln
+ || UCHARAT(s) != nextchr
+ || (ln > 1 && memNE(s, locinput, ln)))
+ {
+ sayNO;
+ }
+ locinput += ln;
+ }
break;
}
U32 fold_utf8_flags;
PL_reg_flags |= RF_tainted;
- folder = foldEQ_locale;
- fold_array = PL_fold_locale;
+ folder = foldEQ_locale;
+ fold_array = PL_fold_locale;
fold_utf8_flags = FOLDEQ_UTF8_LOCALE;
goto do_exactf;
case EXACTFU: /* /abc/iu */
folder = foldEQ_latin1;
fold_array = PL_fold_latin1;
- fold_utf8_flags = (UTF_PATTERN) ? FOLDEQ_S1_ALREADY_FOLDED : 0;
+ fold_utf8_flags = is_utf8_pat ? FOLDEQ_S1_ALREADY_FOLDED : 0;
goto do_exactf;
case EXACTFA: /* /abc/iaa */
s = STRING(scan);
ln = STR_LEN(scan);
- if (utf8_target || UTF_PATTERN || state_num == EXACTFU_SS) {
+ if (utf8_target || is_utf8_pat || state_num == EXACTFU_SS) {
/* Either target or the pattern are utf8, or has the issue where
* the fold lengths may differ. */
const char * const l = locinput;
char *e = PL_regeol;
- if (! foldEQ_utf8_flags(s, 0, ln, cBOOL(UTF_PATTERN),
+ if (! foldEQ_utf8_flags(s, 0, ln, is_utf8_pat,
l, &e, 0, utf8_target, fold_utf8_flags))
{
sayNO;
}
/* Neither the target nor the pattern are utf8 */
- if (UCHARAT(s) != nextchr &&
- UCHARAT(s) != fold_array[nextchr])
+ if (UCHARAT(s) != nextchr
+ && !NEXTCHR_IS_EOS
+ && UCHARAT(s) != fold_array[nextchr])
{
sayNO;
}
n = 0;
else {
LOAD_UTF8_CHARCLASS_ALNUM();
- n = swash_fetch(PL_utf8_alnum, (U8*)locinput,
+ n = swash_fetch(PL_utf8_swash_ptrs[_CC_WORDCHAR], (U8*)locinput,
utf8_target);
}
}
if (NEXTCHR_IS_EOS)
sayNO;
if (utf8_target) {
- STRLEN inclasslen = PL_regeol - locinput;
- if (!reginclass(rex, scan, (U8*)locinput, &inclasslen, utf8_target))
+ if (!reginclass(rex, scan, (U8*)locinput, utf8_target))
sayNO;
- locinput += inclasslen;
- break;
+ locinput += UTF8SKIP(locinput);
}
else {
if (!REGINCLASS(rex, scan, (U8*)locinput))
sayNO;
locinput++;
- break;
}
break;
- /* Special char classes: \d, \w etc.
- * The defines start on line 166 or so */
- CCC_TRY_U(ALNUM, NALNUM, isWORDCHAR,
- ALNUML, NALNUML, isALNUM_LC, isALNUM_LC_utf8,
- ALNUMU, NALNUMU, isWORDCHAR_L1,
- ALNUMA, NALNUMA, isWORDCHAR_A,
- alnum, "a");
-
- CCC_TRY_U(SPACE, NSPACE, isSPACE,
- SPACEL, NSPACEL, isSPACE_LC, isSPACE_LC_utf8,
- SPACEU, NSPACEU, isSPACE_L1,
- SPACEA, NSPACEA, isSPACE_A,
- space, " ");
-
- CCC_TRY(DIGIT, NDIGIT, isDIGIT,
- DIGITL, NDIGITL, isDIGIT_LC, isDIGIT_LC_utf8,
- DIGITA, NDIGITA, isDIGIT_A,
- digit, "0");
-
- case POSIXA: /* /[[:ascii:]]/ etc */
- if (NEXTCHR_IS_EOS || ! _generic_isCC_A(nextchr, FLAGS(scan))) {
+ /* The argument (FLAGS) to all the POSIX node types is the class number
+ * */
+
+ case NPOSIXL: /* \W or [:^punct:] etc. under /l */
+ to_complement = 1;
+ /* FALLTHROUGH */
+
+ case POSIXL: /* \w or [:punct:] etc. under /l */
+ if (NEXTCHR_IS_EOS)
+ sayNO;
+
+ /* The locale hasn't influenced the outcome before this, so defer
+ * tainting until now */
+ PL_reg_flags |= RF_tainted;
+
+ /* Use isFOO_lc() for characters within Latin1. (Note that
+ * UTF8_IS_INVARIANT works even on non-UTF-8 strings, or else
+ * wouldn't be invariant) */
+ if (UTF8_IS_INVARIANT(nextchr) || ! utf8_target) {
+ if (! (to_complement ^ cBOOL(isFOO_lc(FLAGS(scan), nextchr)))) {
+ sayNO;
+ }
+ }
+ else if (UTF8_IS_DOWNGRADEABLE_START(nextchr)) {
+ if (! (to_complement ^ cBOOL(isFOO_lc(FLAGS(scan),
+ TWO_BYTE_UTF8_TO_UNI(nextchr,
+ *(locinput + 1))))))
+ {
+ sayNO;
+ }
+ }
+ else { /* Here, must be an above Latin-1 code point */
+ goto utf8_posix_not_eos;
+ }
+
+ /* Here, must be utf8 */
+ locinput += UTF8SKIP(locinput);
+ break;
+
+ case NPOSIXD: /* \W or [:^punct:] etc. under /d */
+ to_complement = 1;
+ /* FALLTHROUGH */
+
+ case POSIXD: /* \w or [:punct:] etc. under /d */
+ if (utf8_target) {
+ goto utf8_posix;
+ }
+ goto posixa;
+
+ case NPOSIXA: /* \W or [:^punct:] etc. under /a */
+
+ if (NEXTCHR_IS_EOS) {
+ sayNO;
+ }
+
+ /* All UTF-8 variants match */
+ if (! UTF8_IS_INVARIANT(nextchr)) {
+ goto increment_locinput;
+ }
+
+ to_complement = 1;
+ /* FALLTHROUGH */
+
+ case POSIXA: /* \w or [:punct:] etc. under /a */
+
+ posixa:
+ /* We get here through POSIXD, NPOSIXD, and NPOSIXA when not in
+ * UTF-8, and also from NPOSIXA even in UTF-8 when the current
+ * character is a single byte */
+
+ if (NEXTCHR_IS_EOS
+ || ! (to_complement ^ cBOOL(_generic_isCC_A(nextchr,
+ FLAGS(scan)))))
+ {
sayNO;
}
- /* Matched a utf8-invariant, so don't have to worry about utf8 */
+
+ /* Here we are either not in utf8, or we matched a utf8-invariant,
+ * so the next char is the next byte */
locinput++;
break;
- case NPOSIXA: /* /[^[:ascii:]]/ etc */
- if (NEXTCHR_IS_EOS || _generic_isCC_A(nextchr, FLAGS(scan))) {
+ case NPOSIXU: /* \W or [:^punct:] etc. under /u */
+ to_complement = 1;
+ /* FALLTHROUGH */
+
+ case POSIXU: /* \w or [:punct:] etc. under /u */
+ utf8_posix:
+ if (NEXTCHR_IS_EOS) {
sayNO;
}
- goto increment_locinput;
+ utf8_posix_not_eos:
+
+ /* Use _generic_isCC() for characters within Latin1. (Note that
+ * UTF8_IS_INVARIANT works even on non-UTF-8 strings, or else
+ * wouldn't be invariant) */
+ if (UTF8_IS_INVARIANT(nextchr) || ! utf8_target) {
+ if (! (to_complement ^ cBOOL(_generic_isCC(nextchr,
+ FLAGS(scan)))))
+ {
+ sayNO;
+ }
+ locinput++;
+ }
+ else if (UTF8_IS_DOWNGRADEABLE_START(nextchr)) {
+ if (! (to_complement
+ ^ cBOOL(_generic_isCC(TWO_BYTE_UTF8_TO_UNI(nextchr,
+ *(locinput + 1)),
+ FLAGS(scan)))))
+ {
+ sayNO;
+ }
+ locinput += 2;
+ }
+ else { /* Handle above Latin-1 code points */
+ classnum = (_char_class_number) FLAGS(scan);
+ if (classnum < _FIRST_NON_SWASH_CC) {
+
+ /* Here, uses a swash to find such code points. Load if if
+ * not done already */
+ if (! PL_utf8_swash_ptrs[classnum]) {
+ U8 flags = _CORE_SWASH_INIT_ACCEPT_INVLIST;
+ PL_utf8_swash_ptrs[classnum]
+ = _core_swash_init("utf8",
+ swash_property_names[classnum],
+ &PL_sv_undef, 1, 0, NULL, &flags);
+ }
+ if (! (to_complement
+ ^ cBOOL(swash_fetch(PL_utf8_swash_ptrs[classnum],
+ (U8 *) locinput, TRUE))))
+ {
+ sayNO;
+ }
+ }
+ else { /* Here, uses macros to find above Latin-1 code points */
+ switch (classnum) {
+ case _CC_ENUM_SPACE: /* XXX would require separate
+ code if we revert the change
+ of \v matching this */
+ case _CC_ENUM_PSXSPC:
+ if (! (to_complement
+ ^ cBOOL(is_XPERLSPACE_high(locinput))))
+ {
+ sayNO;
+ }
+ break;
+ case _CC_ENUM_BLANK:
+ if (! (to_complement
+ ^ cBOOL(is_HORIZWS_high(locinput))))
+ {
+ sayNO;
+ }
+ break;
+ case _CC_ENUM_XDIGIT:
+ if (! (to_complement
+ ^ cBOOL(is_XDIGIT_high(locinput))))
+ {
+ sayNO;
+ }
+ break;
+ case _CC_ENUM_VERTSPACE:
+ if (! (to_complement
+ ^ cBOOL(is_VERTWS_high(locinput))))
+ {
+ sayNO;
+ }
+ break;
+ default: /* The rest, e.g. [:cntrl:], can't match
+ above Latin1 */
+ if (! to_complement) {
+ sayNO;
+ }
+ break;
+ }
+ }
+ locinput += UTF8SKIP(locinput);
+ }
+ break;
case CLUMP: /* Match \X: logical Unicode character. This is defined as
a Unicode extended Grapheme Cluster */
/* From http://www.unicode.org/reports/tr29 (5.2 version). An
extended Grapheme Cluster is:
- CR LF
- | Prepend* Begin Extend*
- | .
+ CR LF
+ | Prepend* Begin Extend*
+ | .
- Begin is: ( Special_Begin | ! Control )
- Special_Begin is: ( Regional-Indicator+ | Hangul-syllable )
- Extend is: ( Grapheme_Extend | Spacing_Mark )
- Control is: [ GCB_Control CR LF ]
- Hangul-syllable is: ( T+ | ( L* ( L | ( LVT | ( V | LV ) V* ) T* ) ))
+ Begin is: ( Special_Begin | ! Control )
+ Special_Begin is: ( Regional-Indicator+ | Hangul-syllable )
+ Extend is: ( Grapheme_Extend | Spacing_Mark )
+ Control is: [ GCB_Control | CR | LF ]
+ Hangul-syllable is: ( T+ | ( L* ( L | ( LVT | ( V | LV ) V* ) T* ) ))
If we create a 'Regular_Begin' = Begin - Special_Begin, then
we can rewrite
if (nextchr == '\r' /* And if it was CR, and the next is LF,
match the LF */
&& locinput < PL_regeol
- && UCHARAT(locinput) == '\n') locinput++;
+ && UCHARAT(locinput) == '\n')
+ {
+ locinput++;
+ }
}
else {
/* Utf8: See if is ( CR LF ); already know that locinput <
* PL_regeol, so locinput+1 is in bounds */
if ( nextchr == '\r' && locinput+1 < PL_regeol
- && UCHARAT(locinput + 1) == '\n')
+ && UCHARAT(locinput + 1) == '\n')
{
locinput += 2;
}
char *starting = locinput;
/* In case have to backtrack the last prepend */
- char *previous_prepend = 0;
+ char *previous_prepend = NULL;
LOAD_UTF8_CHARCLASS_GCB();
&& (locinput >= PL_regeol
|| (! swash_fetch(PL_utf8_X_regular_begin,
(U8*)locinput, utf8_target)
- && ! is_GCB_SPECIAL_BEGIN_utf8(locinput)))
+ && ! is_GCB_SPECIAL_BEGIN_START_utf8(locinput)))
)
{
locinput = previous_prepend;
(U8*)locinput, utf8_target)) {
locinput += UTF8SKIP(locinput);
}
- else if (! is_GCB_SPECIAL_BEGIN_utf8(locinput)) {
+ else if (! is_GCB_SPECIAL_BEGIN_START_utf8(locinput)) {
/* Here did not match the required 'Begin' in the
* second term. So just match the very first
if (locinput < PL_regeol
&& is_GCB_LV_LVT_V_utf8(locinput))
{
-
/* Otherwise keep going. Must be LV, LVT or V.
- * See if LVT */
- if (is_utf8_X_LVT((U8*)locinput)) {
+ * See if LVT, by first ruling out V, then LV */
+ if (! is_GCB_V_utf8(locinput)
+ /* All but every TCount one is LV */
+ && (valid_utf8_to_uvchr((U8 *) locinput,
+ NULL)
+ - SBASE)
+ % TCount != 0)
+ {
locinput += UTF8SKIP(locinput);
} else {
/* This call case insensitively compares the entire buffer
* at s, with the current input starting at locinput, but
* not going off the end given by PL_regeol, and returns in
- * limit upon success, how much of the current input was
+ * <limit> upon success, how much of the current input was
* matched */
if (! foldEQ_utf8_flags(s, NULL, rex->offs[n].end - ln, utf8_target,
locinput, &limit, 0, utf8_target, utf8_fold_flags))
/* execute the code in the {...} */
dSP;
- SV ** before;
+ IV before;
OP * const oop = PL_op;
COP * const ocurcop = PL_curcop;
OP *nop;
CV *newcv;
/* save *all* paren positions */
- regcppush(rex, 0);
+ regcppush(rex, 0, maxopenparen);
REGCP_SET(runops_cp);
/* To not corrupt the existing regex state while executing the
n = ARG(scan);
if (rexi->data->what[n] == 'r') { /* code from an external qr */
- newcv = ((struct regexp *)SvANY(
+ newcv = (ReANY(
(REGEXP*)(rexi->data->data[n])
))->qr_anoncv
;
}
last_pushed_cv = newcv;
}
+ else {
+ /* these assignments are just to silence compiler
+ * warnings */
+ multicall_cop = NULL;
+ newsp = NULL;
+ }
last_pad = PL_comppad;
/* the initial nextstate you would normally execute
/* we don't use MULTICALL here as we want to call the
* first op of the block of interest, rather than the
* first op of the sub */
- before = SP;
+ before = (IV)(SP-PL_stack_base);
PL_op = nop;
CALLRUNOPS(aTHX); /* Scalar context. */
SPAGAIN;
- if (SP == before)
+ if ((IV)(SP-PL_stack_base) == before)
ret = &PL_sv_undef; /* protect against empty (?{}) blocks. */
else {
ret = POPs;
PL_op = oop;
PL_curcop = ocurcop;
PL_regeol = saved_regeol;
- S_regcp_restore(aTHX_ rex, runops_cp);
+ S_regcp_restore(aTHX_ rex, runops_cp, &maxopenparen);
if (logical != 2)
break;
}
else {
U32 pm_flags = 0;
- const I32 osize = PL_regsize;
if (SvUTF8(ret) && IN_BYTES) {
/* In use 'bytes': make a copy of the octet
scalar. */
sv_magic(ret, MUTABLE_SV(re_sv), PERL_MAGIC_qr, 0, 0);
}
- PL_regsize = osize;
/* safe to do now that any $1 etc has been
* interpolated into the new pattern string and
* compiled */
- S_regcp_restore(aTHX_ rex, runops_cp);
+ S_regcp_restore(aTHX_ rex, runops_cp, &maxopenparen);
}
- re = (struct regexp *)SvANY(re_sv);
+ SAVEFREESV(re_sv);
+ re = ReANY(re_sv);
}
RXp_MATCH_COPIED_off(re);
re->subbeg = rex->subbeg;
eval_recurse_doit: /* Share code with GOSUB below this line */
/* run the pattern returned from (??{...}) */
- ST.cp = regcppush(rex, 0); /* Save *all* the positions. */
+
+ /* Save *all* the positions. */
+ ST.cp = regcppush(rex, 0, maxopenparen);
REGCP_SET(ST.lastcp);
re->lastparen = 0;
re->lastcloseparen = 0;
- PL_regsize = 0;
+ maxopenparen = 0;
/* XXXX This is too dramatic a measure... */
PL_reg_maxiter = 0;
- ST.toggle_reg_flags = PL_reg_flags;
- if (RX_UTF8(re_sv))
- PL_reg_flags |= RF_utf8;
- else
- PL_reg_flags &= ~RF_utf8;
- ST.toggle_reg_flags ^= PL_reg_flags; /* diff of old and new */
+ ST.saved_utf8_pat = is_utf8_pat;
+ is_utf8_pat = cBOOL(RX_UTF8(re_sv));
ST.prev_rex = rex_sv;
ST.prev_curlyx = cur_curlyx;
case EVAL_AB: /* cleanup after a successful (??{A})B */
/* note: this is called twice; first after popping B, then A */
- PL_reg_flags ^= ST.toggle_reg_flags;
+ is_utf8_pat = ST.saved_utf8_pat;
rex_sv = ST.prev_rex;
SET_reg_curpm(rex_sv);
- rex = (struct regexp *)SvANY(rex_sv);
+ rex = ReANY(rex_sv);
rexi = RXi_GET(rex);
regcpblow(ST.cp);
cur_eval = ST.prev_eval;
case EVAL_AB_fail: /* unsuccessfully ran A or B in (??{A})B */
/* note: this is called twice; first after popping B, then A */
- PL_reg_flags ^= ST.toggle_reg_flags;
+ is_utf8_pat = ST.saved_utf8_pat;
rex_sv = ST.prev_rex;
SET_reg_curpm(rex_sv);
- rex = (struct regexp *)SvANY(rex_sv);
+ rex = ReANY(rex_sv);
rexi = RXi_GET(rex);
REGCP_UNWIND(ST.lastcp);
- regcppop(rex);
+ regcppop(rex, &maxopenparen);
cur_eval = ST.prev_eval;
cur_curlyx = ST.prev_curlyx;
/* XXXX This is too dramatic a measure... */
case OPEN: /* ( */
n = ARG(scan); /* which paren pair */
rex->offs[n].start_tmp = locinput - PL_bostr;
- if (n > PL_regsize)
- PL_regsize = n;
+ if (n > maxopenparen)
+ maxopenparen = n;
DEBUG_BUFFERS_r(PerlIO_printf(Perl_debug_log,
- "rex=0x%"UVxf" offs=0x%"UVxf": \\%"UVuf": set %"IVdf" tmp; regsize=%"UVuf"\n",
+ "rex=0x%"UVxf" offs=0x%"UVxf": \\%"UVuf": set %"IVdf" tmp; maxopenparen=%"UVuf"\n",
PTR2UV(rex),
PTR2UV(rex->offs),
(UV)n,
(IV)rex->offs[n].start_tmp,
- (UV)PL_regsize
+ (UV)maxopenparen
));
lastopen = n;
break;
case CLOSE: /* ) */
n = ARG(scan); /* which paren pair */
CLOSE_CAPTURE;
- /*if (n > PL_regsize)
- PL_regsize = n;*/
if (n > rex->lastparen)
rex->lastparen = n;
rex->lastcloseparen = n;
n = ARG(cursor);
if ( n <= lastopen ) {
CLOSE_CAPTURE;
- /*if (n > PL_regsize)
- PL_regsize = n;*/
if (n > rex->lastparen)
rex->lastparen = n;
rex->lastcloseparen = n;
next += ARG(next);
/* XXXX Probably it is better to teach regpush to support
- parenfloor > PL_regsize... */
+ parenfloor > maxopenparen ... */
if (parenfloor > (I32)rex->lastparen)
parenfloor = rex->lastparen; /* Pessimization... */
/* First just match a string of min A's. */
if (n < min) {
- ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
+ ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor,
+ maxopenparen);
cur_curlyx->u.curlyx.lastloc = locinput;
REGCP_SET(ST.lastcp);
if (cur_curlyx->u.curlyx.minmod) {
ST.save_curlyx = cur_curlyx;
cur_curlyx = cur_curlyx->u.curlyx.prev_curlyx;
- ST.cp = regcppush(rex, ST.save_curlyx->u.curlyx.parenfloor);
+ ST.cp = regcppush(rex, ST.save_curlyx->u.curlyx.parenfloor,
+ maxopenparen);
REGCP_SET(ST.lastcp);
PUSH_YES_STATE_GOTO(WHILEM_B_min, ST.save_curlyx->u.curlyx.B,
locinput);
/* Prefer A over B for maximal matching. */
if (n < max) { /* More greed allowed? */
- ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
+ ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor,
+ maxopenparen);
cur_curlyx->u.curlyx.lastloc = locinput;
REGCP_SET(ST.lastcp);
PUSH_STATE_GOTO(WHILEM_A_max, A, locinput);
/* FALL THROUGH */
case WHILEM_A_pre_fail: /* just failed to match even minimal A */
REGCP_UNWIND(ST.lastcp);
- regcppop(rex);
+ regcppop(rex, &maxopenparen);
cur_curlyx->u.curlyx.lastloc = ST.save_lastloc;
cur_curlyx->u.curlyx.count--;
CACHEsayNO;
case WHILEM_A_max_fail: /* just failed to match A in a maximal match */
REGCP_UNWIND(ST.lastcp);
- regcppop(rex); /* Restore some previous $<digit>s? */
+ regcppop(rex, &maxopenparen); /* Restore some previous $<digit>s? */
DEBUG_EXECUTE_r(PerlIO_printf(Perl_debug_log,
"%*s whilem: failed, trying continuation...\n",
REPORT_CODE_OFF+depth*2, "")
do_whilem_B_max:
if (cur_curlyx->u.curlyx.count >= REG_INFTY
&& ckWARN(WARN_REGEXP)
- && !(PL_reg_flags & RF_warned))
+ && !reginfo->warned)
{
- PL_reg_flags |= RF_warned;
+ reginfo->warned = TRUE;
Perl_warner(aTHX_ packWARN(WARN_REGEXP),
"Complex regular subexpression recursion limit (%d) "
"exceeded",
case WHILEM_B_min_fail: /* just failed to match B in a minimal match */
cur_curlyx = ST.save_curlyx;
REGCP_UNWIND(ST.lastcp);
- regcppop(rex);
+ regcppop(rex, &maxopenparen);
if (cur_curlyx->u.curlyx.count >= /*max*/ARG2(cur_curlyx->u.curlyx.me)) {
/* Maximum greed exceeded */
if (cur_curlyx->u.curlyx.count >= REG_INFTY
&& ckWARN(WARN_REGEXP)
- && !(PL_reg_flags & RF_warned))
+ && !reginfo->warned)
{
- PL_reg_flags |= RF_warned;
+ reginfo->warned = TRUE;
Perl_warner(aTHX_ packWARN(WARN_REGEXP),
"Complex regular subexpression recursion "
"limit (%d) exceeded",
);
/* Try grabbing another A and see if it helps. */
cur_curlyx->u.curlyx.lastloc = locinput;
- ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor);
+ ST.cp = regcppush(rex, cur_curlyx->u.curlyx.parenfloor,
+ maxopenparen);
REGCP_SET(ST.lastcp);
PUSH_STATE_GOTO(WHILEM_A_min,
/*A*/ NEXTOPER(ST.save_curlyx->u.curlyx.me) + EXTRA_STEP_2ARGS,
/* if paren positive, emulate an OPEN/CLOSE around A */
if (ST.me->flags) {
U32 paren = ST.me->flags;
- if (paren > PL_regsize)
- PL_regsize = paren;
+ if (paren > maxopenparen)
+ maxopenparen = paren;
scan += NEXT_OFF(scan); /* Skip former OPEN. */
}
ST.A = scan;
IS_TEXT and friends need to change.
*/
if (PL_regkind[OP(text_node)] == EXACT) {
- if (! S_setup_EXACTISH_ST_c1_c2(aTHX_ text_node,
- &ST.c1, &ST.c2))
+ if (! S_setup_EXACTISH_ST_c1_c2(aTHX_
+ text_node, &ST.c1, ST.c1_utf8, &ST.c2, ST.c2_utf8,
+ is_utf8_pat))
{
sayNO;
}
"", (IV)ST.count)
);
if (! NEXTCHR_IS_EOS && ST.c1 != CHRTEST_VOID) {
- const UV c = (utf8_target)
- ? utf8n_to_uvchr((U8*)locinput,
- UTF8_MAXBYTES, NULL,
- uniflags)
- : nextchr;
- if (c != (UV) ST.c1 && c != (UV) ST.c2) {
+ if (! UTF8_IS_INVARIANT(nextchr) && utf8_target) {
+ if (memNE(locinput, ST.c1_utf8, UTF8SKIP(locinput))
+ && memNE(locinput, ST.c2_utf8, UTF8SKIP(locinput)))
+ {
+ /* simulate B failing */
+ DEBUG_OPTIMISE_r(
+ PerlIO_printf(Perl_debug_log,
+ "%*s CURLYM Fast bail next target=U+%"UVXf" c1=U+%"UVXf" c2=U+%"UVXf"\n",
+ (int)(REPORT_CODE_OFF+(depth*2)),"",
+ valid_utf8_to_uvchr((U8 *) locinput, NULL),
+ valid_utf8_to_uvchr(ST.c1_utf8, NULL),
+ valid_utf8_to_uvchr(ST.c2_utf8, NULL))
+ );
+ state_num = CURLYM_B_fail;
+ goto reenter_switch;
+ }
+ }
+ else if (nextchr != ST.c1 && nextchr != ST.c2) {
/* simulate B failing */
DEBUG_OPTIMISE_r(
PerlIO_printf(Perl_debug_log,
- "%*s CURLYM Fast bail c1=%"IVdf" c2=%"IVdf"\n",
+ "%*s CURLYM Fast bail next target=U+%X c1=U+%X c2=U+%X\n",
(int)(REPORT_CODE_OFF+(depth*2)),"",
- (IV)ST.c1,(IV)ST.c2
- ));
+ (int) nextchr, ST.c1, ST.c2)
+ );
state_num = CURLYM_B_fail;
goto reenter_switch;
}
ST.paren = scan->flags; /* Which paren to set */
ST.lastparen = rex->lastparen;
ST.lastcloseparen = rex->lastcloseparen;
- if (ST.paren > PL_regsize)
- PL_regsize = ST.paren;
+ if (ST.paren > maxopenparen)
+ maxopenparen = ST.paren;
ST.min = ARG1(scan); /* min to match */
ST.max = ARG2(scan); /* max to match */
if (cur_eval && cur_eval->u.eval.close_paren &&
if this changes back then the macro for IS_TEXT and
friends need to change. */
- if (! S_setup_EXACTISH_ST_c1_c2(aTHX_ text_node,
- &ST.c1, &ST.c2))
+ if (! S_setup_EXACTISH_ST_c1_c2(aTHX_
+ text_node, &ST.c1, ST.c1_utf8, &ST.c2, ST.c2_utf8,
+ is_utf8_pat))
{
sayNO;
}
if (minmod) {
char *li = locinput;
minmod = 0;
- if (ST.min && regrepeat(rex, &li, ST.A, ST.min, depth) < ST.min)
+ if (ST.min &&
+ regrepeat(rex, &li, ST.A, ST.min, depth, is_utf8_pat)
+ < ST.min)
sayNO;
SET_locinput(li);
ST.count = ST.min;
else if (utf8_target) {
int m = ST.max - ST.min;
for (ST.maxpos = locinput;
- m >0 && ST.maxpos + UTF8SKIP(ST.maxpos) <= PL_regeol; m--)
+ m >0 && ST.maxpos < PL_regeol; m--)
ST.maxpos += UTF8SKIP(ST.maxpos);
}
else {
/* avoid taking address of locinput, so it can remain
* a register var */
char *li = locinput;
- ST.count = regrepeat(rex, &li, ST.A, ST.max, depth);
+ ST.count = regrepeat(rex, &li, ST.A, ST.max, depth,
+ is_utf8_pat);
if (ST.count < ST.min)
sayNO;
SET_locinput(li);
if (utf8_target) {
n = (ST.oldloc == locinput) ? 0 : 1;
if (ST.c1 == ST.c2) {
- STRLEN len;
/* set n to utf8_distance(oldloc, locinput) */
- while (locinput <= ST.maxpos &&
- utf8n_to_uvchr((U8*)locinput,
- UTF8_MAXBYTES, &len,
- uniflags) != (UV)ST.c1) {
- locinput += len;
+ while (locinput <= ST.maxpos
+ && memNE(locinput, ST.c1_utf8, UTF8SKIP(locinput)))
+ {
+ locinput += UTF8SKIP(locinput);
n++;
}
}
else {
/* set n to utf8_distance(oldloc, locinput) */
- while (locinput <= ST.maxpos) {
- STRLEN len;
- const UV c = utf8n_to_uvchr((U8*)locinput,
- UTF8_MAXBYTES, &len,
- uniflags);
- if (c == (UV)ST.c1 || c == (UV)ST.c2)
- break;
- locinput += len;
+ while (locinput <= ST.maxpos
+ && memNE(locinput, ST.c1_utf8, UTF8SKIP(locinput))
+ && memNE(locinput, ST.c2_utf8, UTF8SKIP(locinput)))
+ {
+ locinput += UTF8SKIP(locinput);
n++;
}
}
* locinput matches */
char *li = ST.oldloc;
ST.count += n;
- if (regrepeat(rex, &li, ST.A, n, depth) < n)
+ if (regrepeat(rex, &li, ST.A, n, depth, is_utf8_pat) < n)
sayNO;
assert(n == REG_INFTY || locinput == li);
}
/* failed -- move forward one */
{
char *li = locinput;
- if (!regrepeat(rex, &li, ST.A, 1, depth)) {
+ if (!regrepeat(rex, &li, ST.A, 1, depth, is_utf8_pat)) {
sayNO;
}
locinput = li;
goto fake_end;
}
{
- UV c = 0;
- if (ST.c1 != CHRTEST_VOID && locinput < PL_regeol)
- c = utf8_target ? utf8n_to_uvchr((U8*)locinput,
- UTF8_MAXBYTES, 0, uniflags)
- : (UV) UCHARAT(locinput);
+ bool could_match = locinput < PL_regeol;
+
/* If it could work, try it. */
- if (ST.c1 == CHRTEST_VOID
- || (locinput < PL_regeol &&
- (c == (UV)ST.c1 || c == (UV)ST.c2)))
- {
+ if (ST.c1 != CHRTEST_VOID && could_match) {
+ if (! UTF8_IS_INVARIANT(UCHARAT(locinput)) && utf8_target)
+ {
+ could_match = memEQ(locinput,
+ ST.c1_utf8,
+ UTF8SKIP(locinput))
+ || memEQ(locinput,
+ ST.c2_utf8,
+ UTF8SKIP(locinput));
+ }
+ else {
+ could_match = UCHARAT(locinput) == ST.c1
+ || UCHARAT(locinput) == ST.c2;
+ }
+ }
+ if (ST.c1 == CHRTEST_VOID || could_match) {
CURLY_SETPAREN(ST.paren, ST.count);
PUSH_STATE_GOTO(CURLY_B_max, ST.B, locinput);
assert(0); /* NOTREACHED */
fake_end:
if (cur_eval) {
/* we've just finished A in /(??{A})B/; now continue with B */
- st->u.eval.toggle_reg_flags
- = cur_eval->u.eval.toggle_reg_flags;
- PL_reg_flags ^= st->u.eval.toggle_reg_flags;
+ st->u.eval.saved_utf8_pat = is_utf8_pat;
+ is_utf8_pat = cur_eval->u.eval.saved_utf8_pat;
st->u.eval.prev_rex = rex_sv; /* inner */
- st->u.eval.cp = regcppush(rex, 0); /* Save *all* the positions. */
+
+ /* Save *all* the positions. */
+ st->u.eval.cp = regcppush(rex, 0, maxopenparen);
rex_sv = cur_eval->u.eval.prev_rex;
SET_reg_curpm(rex_sv);
- rex = (struct regexp *)SvANY(rex_sv);
+ rex = ReANY(rex_sv);
rexi = RXi_GET(rex);
cur_curlyx = cur_eval->u.eval.prev_curlyx;
/* Restore parens of the outer rex without popping the
* savestack */
- S_regcp_restore(aTHX_ rex, cur_eval->u.eval.lastcp);
+ S_regcp_restore(aTHX_ rex, cur_eval->u.eval.lastcp,
+ &maxopenparen);
st->u.eval.prev_eval = cur_eval;
cur_eval = cur_eval->u.eval.prev_eval;
sayNO;
break;
-#define CASE_CLASS(nAmE) \
- case nAmE: \
- if (NEXTCHR_IS_EOS) \
- sayNO; \
- if ((n=is_##nAmE(locinput,utf8_target))) { \
- locinput += n; \
- } else \
- sayNO; \
- break; \
- case N##nAmE: \
- if (NEXTCHR_IS_EOS) \
- sayNO; \
- if ((n=is_##nAmE(locinput,utf8_target))) { \
- sayNO; \
- } else { \
- locinput += UTF8SKIP(locinput); \
- } \
- break
-
- CASE_CLASS(VERTWS); /* \v \V */
- CASE_CLASS(HORIZWS); /* \h \H */
-#undef CASE_CLASS
-
default:
PerlIO_printf(Perl_error_log, "%"UVxf" %d\n",
PTR2UV(scan), OP(scan));
/* this is a point to jump to in order to increment
* locinput by one character */
increment_locinput:
+ assert(!NEXTCHR_IS_EOS);
if (utf8_target) {
locinput += PL_utf8skip[nextchr];
/* locinput is allowed to go 1 char off the end, but not 2+ */
/*
- regrepeat - repeatedly match something simple, report how many
*
+ * What 'simple' means is a node which can be the operand of a quantifier like
+ * '+', or {1,3}
+ *
* startposp - pointer a pointer to the start position. This is updated
* to point to the byte following the highest successful
* match.
* p - the regnode to be repeatedly matched against.
- * max - maximum number of characters to match.
+ * max - maximum number of things to match.
* depth - (for debugging) backtracking depth.
*/
STATIC I32
-S_regrepeat(pTHX_ const regexp *prog, char **startposp, const regnode *p, I32 max, int depth)
+S_regrepeat(pTHX_ const regexp *prog, char **startposp, const regnode *p,
+ I32 max, int depth, bool is_utf8_pat)
{
dVAR;
- char *scan;
+ char *scan; /* Pointer to current position in target string */
I32 c;
- char *loceol = PL_regeol;
- I32 hardcount = 0;
+ char *loceol = PL_regeol; /* local version */
+ I32 hardcount = 0; /* How many matches so far */
bool utf8_target = PL_reg_match_utf8;
+ int to_complement = 0; /* Invert the result? */
UV utf8_flags;
+ _char_class_number classnum;
#ifndef DEBUGGING
PERL_UNUSED_ARG(depth);
#endif
scan = *startposp;
if (max == REG_INFTY)
max = I32_MAX;
- else if (max < loceol - scan)
+ else if (! utf8_target && scan + max < loceol)
loceol = scan + max;
+
+ /* Here, for the case of a non-UTF-8 target we have adjusted <loceol> down
+ * to the maximum of how far we should go in it (leaving it set to the real
+ * end, if the maximum permissible would take us beyond that). This allows
+ * us to make the loop exit condition that we haven't gone past <loceol> to
+ * also mean that we haven't exceeded the max permissible count, saving a
+ * test each time through the loop. But it assumes that the OP matches a
+ * single byte, which is true for most of the OPs below when applied to a
+ * non-UTF-8 target. Those relatively few OPs that don't have this
+ * characteristic will have to compensate.
+ *
+ * There is no adjustment for UTF-8 targets, as the number of bytes per
+ * character varies. OPs will have to test both that the count is less
+ * than the max permissible (using <hardcount> to keep track), and that we
+ * are still within the bounds of the string (using <loceol>. A few OPs
+ * match a single byte no matter what the encoding. They can omit the max
+ * test if, for the UTF-8 case, they do the adjustment that was skipped
+ * above.
+ *
+ * Thus, the code above sets things up for the common case; and exceptional
+ * cases need extra work; the common case is to make sure <scan> doesn't
+ * go past <loceol>, and for UTF-8 to also use <hardcount> to make sure the
+ * count doesn't exceed the maximum permissible */
+
switch (OP(p)) {
case REG_ANY:
if (utf8_target) {
- loceol = PL_regeol;
while (scan < loceol && hardcount < max && *scan != '\n') {
scan += UTF8SKIP(scan);
hardcount++;
break;
case SANY:
if (utf8_target) {
- loceol = PL_regeol;
while (scan < loceol && hardcount < max) {
scan += UTF8SKIP(scan);
hardcount++;
else
scan = loceol;
break;
- case CANY:
- scan = loceol;
+ case CANY: /* Move <scan> forward <max> bytes, unless goes off end */
+ if (utf8_target && scan + max < loceol) {
+
+ /* <loceol> hadn't been adjusted in the UTF-8 case */
+ scan += max;
+ }
+ else {
+ scan = loceol;
+ }
break;
case EXACT:
+ assert(STR_LEN(p) == is_utf8_pat ? UTF8SKIP(STRING(p)) : 1);
+
c = (U8)*STRING(p);
/* Can use a simple loop if the pattern char to match on is invariant
* under UTF-8, or both target and pattern aren't UTF-8. Note that we
* can use UTF8_IS_INVARIANT() even if the pattern isn't UTF-8, as it's
* true iff it doesn't matter if the argument is in UTF-8 or not */
- if (UTF8_IS_INVARIANT(c) || (! utf8_target && ! UTF_PATTERN)) {
+ if (UTF8_IS_INVARIANT(c) || (! utf8_target && ! is_utf8_pat)) {
+ if (utf8_target && scan + max < loceol) {
+ /* We didn't adjust <loceol> because is UTF-8, but ok to do so,
+ * since here, to match at all, 1 char == 1 byte */
+ loceol = scan + max;
+ }
while (scan < loceol && UCHARAT(scan) == c) {
scan++;
}
}
- else if (UTF_PATTERN) {
+ else if (is_utf8_pat) {
if (utf8_target) {
STRLEN scan_char_len;
- loceol = PL_regeol;
- /* When both target and pattern are UTF-8, we have to do s
+ /* When both target and pattern are UTF-8, we have to do
* string EQ */
while (hardcount < max
- && scan + (scan_char_len = UTF8SKIP(scan)) <= loceol
- && scan_char_len <= STR_LEN(p)
+ && scan < loceol
+ && (scan_char_len = UTF8SKIP(scan)) <= STR_LEN(p)
&& memEQ(scan, STRING(p), scan_char_len))
{
scan += scan_char_len;
* then look for those in sequence in the utf8 string */
U8 high = UTF8_TWO_BYTE_HI(c);
U8 low = UTF8_TWO_BYTE_LO(c);
- loceol = PL_regeol;
while (hardcount < max
&& scan + 1 < loceol
case EXACTFU_SS:
case EXACTFU_TRICKYFOLD:
case EXACTFU:
- utf8_flags = (UTF_PATTERN) ? FOLDEQ_S2_ALREADY_FOLDED : 0;
+ utf8_flags = is_utf8_pat ? FOLDEQ_S2_ALREADY_FOLDED : 0;
- do_exactf:
- c = (U8)*STRING(p);
+ do_exactf: {
+ int c1, c2;
+ U8 c1_utf8[UTF8_MAXBYTES+1], c2_utf8[UTF8_MAXBYTES+1];
- if (utf8_target
- || OP(p) == EXACTFU_SS
- || (UTF_PATTERN && ! UTF8_IS_INVARIANT(c)))
- {
- /* Use full Unicode fold matching */
- char *tmpeol = loceol;
- STRLEN pat_len = (UTF_PATTERN) ? UTF8SKIP(STRING(p)) : 1;
- while (hardcount < max
- && foldEQ_utf8_flags(scan, &tmpeol, 0, utf8_target,
- STRING(p), NULL, pat_len, cBOOL(UTF_PATTERN), utf8_flags))
- {
- scan = tmpeol;
- tmpeol = loceol;
- hardcount++;
- }
+ assert(STR_LEN(p) == is_utf8_pat ? UTF8SKIP(STRING(p)) : 1);
- /* XXX Note that the above handles properly the German sharp s in
- * the pattern matching ss in the string. But it doesn't handle
- * properly cases where the string contains say 'LIGATURE ff' and
- * the pattern is 'f+'. This would require, say, a new function or
- * revised interface to foldEQ_utf8(), in which the maximum number
- * of characters to match could be passed and it would return how
- * many actually did. This is just one of many cases where
- * multi-char folds don't work properly, and so the fix is being
- * deferred */
- }
- else {
- U8 folded;
-
- /* Here, the string isn't utf8; and either the pattern isn't utf8
- * or c is an invariant, so its utf8ness doesn't affect c. Can
- * just do simple comparisons for exact or fold matching. */
- switch (OP(p)) {
- case EXACTF: folded = PL_fold[c]; break;
- case EXACTFA:
- case EXACTFU_TRICKYFOLD:
- case EXACTFU: folded = PL_fold_latin1[c]; break;
- case EXACTFL: folded = PL_fold_locale[c]; break;
- default: Perl_croak(aTHX_ "panic: Unexpected op %u", OP(p));
- }
- while (scan < loceol &&
- (UCHARAT(scan) == c || UCHARAT(scan) == folded))
- {
- scan++;
- }
+ if (S_setup_EXACTISH_ST_c1_c2(aTHX_ p, &c1, c1_utf8, &c2, c2_utf8,
+ is_utf8_pat))
+ {
+ if (c1 == CHRTEST_VOID) {
+ /* Use full Unicode fold matching */
+ char *tmpeol = PL_regeol;
+ STRLEN pat_len = is_utf8_pat ? UTF8SKIP(STRING(p)) : 1;
+ while (hardcount < max
+ && foldEQ_utf8_flags(scan, &tmpeol, 0, utf8_target,
+ STRING(p), NULL, pat_len,
+ is_utf8_pat, utf8_flags))
+ {
+ scan = tmpeol;
+ tmpeol = PL_regeol;
+ hardcount++;
+ }
+ }
+ else if (utf8_target) {
+ if (c1 == c2) {
+ while (scan < loceol
+ && hardcount < max
+ && memEQ(scan, c1_utf8, UTF8SKIP(scan)))
+ {
+ scan += UTF8SKIP(scan);
+ hardcount++;
+ }
+ }
+ else {
+ while (scan < loceol
+ && hardcount < max
+ && (memEQ(scan, c1_utf8, UTF8SKIP(scan))
+ || memEQ(scan, c2_utf8, UTF8SKIP(scan))))
+ {
+ scan += UTF8SKIP(scan);
+ hardcount++;
+ }
+ }
+ }
+ else if (c1 == c2) {
+ while (scan < loceol && UCHARAT(scan) == c1) {
+ scan++;
+ }
+ }
+ else {
+ while (scan < loceol &&
+ (UCHARAT(scan) == c1 || UCHARAT(scan) == c2))
+ {
+ scan++;
+ }
+ }
}
break;
+ }
case ANYOF:
if (utf8_target) {
- STRLEN inclasslen;
- loceol = PL_regeol;
- inclasslen = loceol - scan;
while (hardcount < max
- && ((inclasslen = loceol - scan) > 0)
- && reginclass(prog, p, (U8*)scan, &inclasslen, utf8_target))
+ && scan < loceol
+ && reginclass(prog, p, (U8*)scan, utf8_target))
{
- scan += inclasslen;
+ scan += UTF8SKIP(scan);
hardcount++;
}
} else {
scan++;
}
break;
- case ALNUMU:
- if (utf8_target) {
- utf8_wordchar:
- loceol = PL_regeol;
- LOAD_UTF8_CHARCLASS_ALNUM();
- while (hardcount < max && scan < loceol &&
- swash_fetch(PL_utf8_alnum, (U8*)scan, utf8_target))
+
+ /* The argument (FLAGS) to all the POSIX node types is the class number */
+
+ case NPOSIXL:
+ to_complement = 1;
+ /* FALLTHROUGH */
+
+ case POSIXL:
+ PL_reg_flags |= RF_tainted;
+ if (! utf8_target) {
+ while (scan < loceol && to_complement ^ cBOOL(isFOO_lc(FLAGS(p),
+ *scan)))
{
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && isWORDCHAR_L1((U8) *scan)) {
- scan++;
+ scan++;
}
- }
- break;
- case ALNUM:
- if (utf8_target)
- goto utf8_wordchar;
- while (scan < loceol && isALNUM((U8) *scan)) {
- scan++;
- }
- break;
- case ALNUMA:
- while (scan < loceol && isWORDCHAR_A((U8) *scan)) {
- scan++;
- }
- break;
- case ALNUML:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- 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 NALNUMU:
- if (utf8_target) {
-
- utf8_Nwordchar:
-
- loceol = PL_regeol;
- LOAD_UTF8_CHARCLASS_ALNUM();
- while (hardcount < max && scan < loceol &&
- ! swash_fetch(PL_utf8_alnum, (U8*)scan, utf8_target))
+ while (hardcount < max && scan < loceol
+ && to_complement ^ cBOOL(isFOO_utf8_lc(FLAGS(p),
+ (U8 *) scan)))
{
- scan += UTF8SKIP(scan);
+ scan += UTF8SKIP(scan);
hardcount++;
}
- } else {
- while (scan < loceol && ! isWORDCHAR_L1((U8) *scan)) {
- scan++;
- }
- }
- break;
- case NALNUM:
- if (utf8_target)
- goto utf8_Nwordchar;
- while (scan < loceol && ! isALNUM((U8) *scan)) {
- scan++;
}
break;
+ case POSIXD:
+ if (utf8_target) {
+ goto utf8_posix;
+ }
+ /* FALLTHROUGH */
+
case POSIXA:
- while (scan < loceol && _generic_isCC_A((U8) *scan, FLAGS(p))) {
+ if (utf8_target && scan + max < loceol) {
+
+ /* We didn't adjust <loceol> at the beginning of this routine
+ * because is UTF-8, but it is actually ok to do so, since here, to
+ * match, 1 char == 1 byte. */
+ loceol = scan + max;
+ }
+ while (scan < loceol && _generic_isCC_A((U8) *scan, FLAGS(p))) {
scan++;
}
break;
- case NPOSIXA:
- if (utf8_target) {
- while (scan < loceol && ! _generic_isCC_A((U8) *scan, FLAGS(p))) {
- scan += UTF8SKIP(scan);
- }
- }
- else {
- while (scan < loceol && ! _generic_isCC_A((U8) *scan, FLAGS(p))) {
- scan++;
- }
- }
- break;
- case NALNUMA:
- if (utf8_target) {
- while (scan < loceol && ! isWORDCHAR_A((U8) *scan)) {
- scan += UTF8SKIP(scan);
- }
- }
- else {
- while (scan < loceol && ! isWORDCHAR_A((U8) *scan)) {
- scan++;
- }
- }
- break;
- case NALNUML:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- 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 SPACEU:
- if (utf8_target) {
- utf8_space:
+ case NPOSIXD:
+ if (utf8_target) {
+ to_complement = 1;
+ goto utf8_posix;
+ }
+ /* FALL THROUGH */
- loceol = PL_regeol;
- LOAD_UTF8_CHARCLASS_SPACE();
- while (hardcount < max && scan < loceol &&
- (*scan == ' ' ||
- swash_fetch(PL_utf8_space,(U8*)scan, utf8_target)))
- {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- break;
- }
- else {
- while (scan < loceol && isSPACE_L1((U8) *scan)) {
+ case NPOSIXA:
+ if (! utf8_target) {
+ while (scan < loceol && ! _generic_isCC_A((U8) *scan, FLAGS(p))) {
scan++;
}
- break;
- }
- case SPACE:
- if (utf8_target)
- goto utf8_space;
+ }
+ else {
- while (scan < loceol && isSPACE((U8) *scan)) {
- scan++;
- }
- break;
- case SPACEA:
- while (scan < loceol && isSPACE_A((U8) *scan)) {
- scan++;
- }
- break;
- case SPACEL:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- loceol = PL_regeol;
- while (hardcount < max && scan < loceol &&
- isSPACE_LC_utf8((U8*)scan)) {
- scan += UTF8SKIP(scan);
+ /* The complement of something that matches only ASCII matches all
+ * UTF-8 variant code points, plus everything in ASCII that isn't
+ * in the class. */
+ while (hardcount < max && scan < loceol
+ && (! UTF8_IS_INVARIANT(*scan)
+ || ! _generic_isCC_A((U8) *scan, FLAGS(p))))
+ {
+ scan += UTF8SKIP(scan);
hardcount++;
}
- } else {
- while (scan < loceol && isSPACE_LC(*scan))
- scan++;
- }
- break;
- case NSPACEU:
- if (utf8_target) {
+ }
+ break;
- utf8_Nspace:
+ case NPOSIXU:
+ to_complement = 1;
+ /* FALLTHROUGH */
- loceol = PL_regeol;
- LOAD_UTF8_CHARCLASS_SPACE();
- while (hardcount < max && scan < loceol &&
- ! (*scan == ' ' ||
- swash_fetch(PL_utf8_space,(U8*)scan, utf8_target)))
+ case POSIXU:
+ if (! utf8_target) {
+ while (scan < loceol && to_complement
+ ^ cBOOL(_generic_isCC((U8) *scan, FLAGS(p))))
{
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- break;
- }
- else {
- while (scan < loceol && ! isSPACE_L1((U8) *scan)) {
scan++;
}
}
- break;
- case NSPACE:
- if (utf8_target)
- goto utf8_Nspace;
-
- while (scan < loceol && ! isSPACE((U8) *scan)) {
- scan++;
- }
- break;
- case NSPACEA:
- if (utf8_target) {
- while (scan < loceol && ! isSPACE_A((U8) *scan)) {
- scan += UTF8SKIP(scan);
- }
- }
- else {
- while (scan < loceol && ! isSPACE_A((U8) *scan)) {
- scan++;
- }
- }
- break;
- case NSPACEL:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- loceol = PL_regeol;
- while (hardcount < max && scan < loceol &&
- !isSPACE_LC_utf8((U8*)scan)) {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && !isSPACE_LC(*scan))
- scan++;
- }
- break;
- case DIGIT:
- if (utf8_target) {
- loceol = PL_regeol;
- LOAD_UTF8_CHARCLASS_DIGIT();
- while (hardcount < max && scan < loceol &&
- swash_fetch(PL_utf8_digit, (U8*)scan, utf8_target)) {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && isDIGIT(*scan))
- scan++;
- }
- break;
- case DIGITA:
- while (scan < loceol && isDIGIT_A((U8) *scan)) {
- scan++;
- }
- break;
- case DIGITL:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- loceol = PL_regeol;
- while (hardcount < max && scan < loceol &&
- isDIGIT_LC_utf8((U8*)scan)) {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && isDIGIT_LC(*scan))
- scan++;
- }
- break;
- case NDIGIT:
- if (utf8_target) {
- loceol = PL_regeol;
- LOAD_UTF8_CHARCLASS_DIGIT();
- while (hardcount < max && scan < loceol &&
- !swash_fetch(PL_utf8_digit, (U8*)scan, utf8_target)) {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && !isDIGIT(*scan))
- scan++;
- }
- break;
- case NDIGITA:
- if (utf8_target) {
- while (scan < loceol && ! isDIGIT_A((U8) *scan)) {
- scan += UTF8SKIP(scan);
- }
- }
else {
- while (scan < loceol && ! isDIGIT_A((U8) *scan)) {
- scan++;
- }
- }
- break;
- case NDIGITL:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- loceol = PL_regeol;
- while (hardcount < max && scan < loceol &&
- !isDIGIT_LC_utf8((U8*)scan)) {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && !isDIGIT_LC(*scan))
- scan++;
+ utf8_posix:
+ classnum = (_char_class_number) FLAGS(p);
+ if (classnum < _FIRST_NON_SWASH_CC) {
+
+ /* Here, a swash is needed for above-Latin1 code points.
+ * Process as many Latin1 code points using the built-in rules.
+ * Go to another loop to finish processing upon encountering
+ * the first Latin1 code point. We could do that in this loop
+ * as well, but the other way saves having to test if the swash
+ * has been loaded every time through the loop: extra space to
+ * save a test. */
+ while (hardcount < max && scan < loceol) {
+ if (UTF8_IS_INVARIANT(*scan)) {
+ if (! (to_complement ^ cBOOL(_generic_isCC((U8) *scan,
+ classnum))))
+ {
+ break;
+ }
+ scan++;
+ }
+ else if (UTF8_IS_DOWNGRADEABLE_START(*scan)) {
+ if (! (to_complement
+ ^ cBOOL(_generic_isCC(TWO_BYTE_UTF8_TO_UNI(*scan,
+ *(scan + 1)),
+ classnum))))
+ {
+ break;
+ }
+ scan += 2;
+ }
+ else {
+ goto found_above_latin1;
+ }
+
+ hardcount++;
+ }
+ }
+ else {
+ /* For these character classes, the knowledge of how to handle
+ * every code point is compiled in to Perl via a macro. This
+ * code is written for making the loops as tight as possible.
+ * It could be refactored to save space instead */
+ switch (classnum) {
+ case _CC_ENUM_SPACE: /* XXX would require separate code
+ if we revert the change of \v
+ matching this */
+ /* FALL THROUGH */
+ case _CC_ENUM_PSXSPC:
+ while (hardcount < max
+ && scan < loceol
+ && (to_complement ^ cBOOL(isSPACE_utf8(scan))))
+ {
+ scan += UTF8SKIP(scan);
+ hardcount++;
+ }
+ break;
+ case _CC_ENUM_BLANK:
+ while (hardcount < max
+ && scan < loceol
+ && (to_complement ^ cBOOL(isBLANK_utf8(scan))))
+ {
+ scan += UTF8SKIP(scan);
+ hardcount++;
+ }
+ break;
+ case _CC_ENUM_XDIGIT:
+ while (hardcount < max
+ && scan < loceol
+ && (to_complement ^ cBOOL(isXDIGIT_utf8(scan))))
+ {
+ scan += UTF8SKIP(scan);
+ hardcount++;
+ }
+ break;
+ case _CC_ENUM_VERTSPACE:
+ while (hardcount < max
+ && scan < loceol
+ && (to_complement ^ cBOOL(isVERTWS_utf8(scan))))
+ {
+ scan += UTF8SKIP(scan);
+ hardcount++;
+ }
+ break;
+ case _CC_ENUM_CNTRL:
+ while (hardcount < max
+ && scan < loceol
+ && (to_complement ^ cBOOL(isCNTRL_utf8(scan))))
+ {
+ scan += UTF8SKIP(scan);
+ hardcount++;
+ }
+ break;
+ default:
+ Perl_croak(aTHX_ "panic: regrepeat() node %d='%s' has an unexpected character class '%d'", OP(p), PL_reg_name[OP(p)], classnum);
+ }
+ }
}
- break;
+ break;
+
+ found_above_latin1: /* Continuation of POSIXU and NPOSIXU */
+
+ /* Load the swash if not already present */
+ if (! PL_utf8_swash_ptrs[classnum]) {
+ U8 flags = _CORE_SWASH_INIT_ACCEPT_INVLIST;
+ PL_utf8_swash_ptrs[classnum] = _core_swash_init(
+ "utf8", swash_property_names[classnum],
+ &PL_sv_undef, 1, 0, NULL, &flags);
+ }
+
+ while (hardcount < max && scan < loceol
+ && to_complement ^ cBOOL(_generic_utf8(
+ classnum,
+ scan,
+ swash_fetch(PL_utf8_swash_ptrs[classnum],
+ (U8 *) scan,
+ TRUE))))
+ {
+ scan += UTF8SKIP(scan);
+ hardcount++;
+ }
+ break;
+
case LNBREAK:
if (utf8_target) {
- loceol = PL_regeol;
while (hardcount < max && scan < loceol &&
(c=is_LNBREAK_utf8_safe(scan, loceol))) {
scan += c;
hardcount++;
}
} else {
- /*
- LNBREAK can match two latin chars, which is ok,
- because we have a null terminated string, but we
- have to use hardcount in this situation
- */
+ /* LNBREAK can match one or two latin chars, which is ok, but we
+ * have to use hardcount in this situation, and throw away the
+ * adjustment to <loceol> done before the switch statement */
+ loceol = PL_regeol;
while (scan < loceol && (c=is_LNBREAK_latin1_safe(scan, loceol))) {
scan+=c;
hardcount++;
}
- }
- break;
- case HORIZWS:
- if (utf8_target) {
- loceol = PL_regeol;
- while (hardcount < max && scan < loceol &&
- (c=is_HORIZWS_utf8_safe(scan, loceol)))
- {
- scan += c;
- hardcount++;
- }
- } else {
- while (scan < loceol && is_HORIZWS_latin1_safe(scan, loceol))
- scan++;
- }
- break;
- case NHORIZWS:
- if (utf8_target) {
- loceol = PL_regeol;
- while (hardcount < max && scan < loceol &&
- !is_HORIZWS_utf8_safe(scan, loceol))
- {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && !is_HORIZWS_latin1_safe(scan, loceol))
- scan++;
-
- }
+ }
break;
- case VERTWS:
- if (utf8_target) {
- loceol = PL_regeol;
- while (hardcount < max && scan < loceol &&
- (c=is_VERTWS_utf8_safe(scan, loceol)))
- {
- scan += c;
- hardcount++;
- }
- } else {
- while (scan < loceol && is_VERTWS_latin1_safe(scan, loceol))
- scan++;
- }
- break;
- case NVERTWS:
- if (utf8_target) {
- loceol = PL_regeol;
- while (hardcount < max && scan < loceol &&
- !is_VERTWS_utf8_safe(scan, loceol))
- {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && !is_VERTWS_latin1_safe(scan, loceol))
- scan++;
-
- }
- break;
+ case BOUND:
+ case BOUNDA:
+ case BOUNDL:
+ case BOUNDU:
+ case EOS:
+ case GPOS:
+ case KEEPS:
+ case NBOUND:
+ case NBOUNDA:
+ case NBOUNDL:
+ case NBOUNDU:
+ case OPFAIL:
+ case SBOL:
+ case SEOL:
+ /* These are all 0 width, so match right here or not at all. */
+ break;
+
+ default:
+ Perl_croak(aTHX_ "panic: regrepeat() called with unrecognized node type %d='%s'", OP(p), PL_reg_name[OP(p)]);
+ assert(0); /* NOTREACHED */
- default: /* Called on something of 0 width. */
- break; /* So match right here or not at all. */
}
if (hardcount)
If <altsvp> is non-null, will return NULL in it, for back-compat.
*/
SV *
-Perl_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bool doinit, SV** listsvp, SV **altsvp)
+Perl_regclass_swash(pTHX_ const regexp *prog, const regnode* node, bool doinit, SV** listsvp, SV **altsvp)
{
PERL_ARGS_ASSERT_REGCLASS_SWASH;
#endif
STATIC SV *
-S_core_regclass_swash(pTHX_ const regexp *prog, register const regnode* node, bool doinit, SV** listsvp)
+S_core_regclass_swash(pTHX_ const regexp *prog, const regnode* node, bool doinit, SV** listsvp)
{
/* Returns the swash for the input 'node' in the regex 'prog'.
* If <doinit> is true, will attempt to create the swash if not already
n is the ANYOF regnode
p is the target string
- lenp is pointer to the maximum number of bytes of how far to go in p
- (This is assumed wthout checking to always be at least the current
- character's size)
utf8_target tells whether p is in UTF-8.
- Returns true if matched; false otherwise. If lenp is not NULL, on return
- from a successful match, the value it points to will be updated to how many
- bytes in p were matched. If there was no match, the value is undefined,
- possibly changed from the input.
+ Returns true if matched; false otherwise.
Note that this can be a synthetic start class, a combination of various
nodes, so things you think might be mutually exclusive, such as locale,
*/
STATIC bool
-S_reginclass(pTHX_ const regexp * const prog, register const regnode * const n, register const U8* const p, STRLEN* lenp, register const bool utf8_target)
+S_reginclass(pTHX_ const regexp * const prog, const regnode * const n, const U8* const p, const bool utf8_target)
{
dVAR;
const char flags = ANYOF_FLAGS(n);
bool match = FALSE;
UV c = *p;
- STRLEN c_len = 0;
- STRLEN maxlen;
PERL_ARGS_ASSERT_REGINCLASS;
- /* If c is not already the code point, get it */
- if (utf8_target && !UTF8_IS_INVARIANT(c)) {
+ /* If c is not already the code point, get it. Note that
+ * UTF8_IS_INVARIANT() works even if not in UTF-8 */
+ if (! UTF8_IS_INVARIANT(c) && utf8_target) {
+ STRLEN c_len = 0;
c = utf8n_to_uvchr(p, UTF8_MAXBYTES, &c_len,
(UTF8_ALLOW_DEFAULT & UTF8_ALLOW_ANYUV)
| UTF8_ALLOW_FFFF | UTF8_CHECK_ONLY);
if (c_len == (STRLEN)-1)
Perl_croak(aTHX_ "Malformed UTF-8 character (fatal)");
}
- else {
- c_len = 1;
- }
-
- /* Use passed in max length, or one character if none passed in or less
- * than one character. And assume will match just one character. This is
- * overwritten later if matched more. */
- if (lenp) {
- maxlen = (*lenp > c_len) ? *lenp : c_len;
- *lenp = c_len;
-
- }
- else {
- maxlen = c_len;
- }
/* If this character is potentially in the bitmap, check it */
if (c < 256) {
{
match = TRUE;
}
- else if (ANYOF_CLASS_TEST_ANY_SET(n) &&
- ((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_LC(c)) ||
- (ANYOF_CLASS_TEST(n, ANYOF_NASCII) && !isASCII_LC(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_LC(c)) ||
- (ANYOF_CLASS_TEST(n, ANYOF_NBLANK) && !isBLANK_LC(c))
- ) /* How's that for a conditional? */
- ) {
- match = TRUE;
+ else if (ANYOF_CLASS_TEST_ANY_SET(n)) {
+
+ /* The data structure is arranged so bits 0, 2, 4, ... are set
+ * if the class includes the Posix character class given by
+ * bit/2; and 1, 3, 5, ... are set if the class includes the
+ * complemented Posix class given by int(bit/2). So we loop
+ * through the bits, each time changing whether we complement
+ * the result or not. Suppose for the sake of illustration
+ * that bits 0-3 mean respectively, \w, \W, \s, \S. If bit 0
+ * is set, it means there is a match for this ANYOF node if the
+ * character is in the class given by the expression (0 / 2 = 0
+ * = \w). If it is in that class, isFOO_lc() will return 1,
+ * and since 'to_complement' is 0, the result will stay TRUE,
+ * and we exit the loop. Suppose instead that bit 0 is 0, but
+ * bit 1 is 1. That means there is a match if the character
+ * matches \W. We won't bother to call isFOO_lc() on bit 0,
+ * but will on bit 1. On the second iteration 'to_complement'
+ * will be 1, so the exclusive or will reverse things, so we
+ * are testing for \W. On the third iteration, 'to_complement'
+ * will be 0, and we would be testing for \s; the fourth
+ * iteration would test for \S, etc. */
+
+ int count = 0;
+ int to_complement = 0;
+ while (count < ANYOF_MAX) {
+ if (ANYOF_CLASS_TEST(n, count)
+ && to_complement ^ cBOOL(isFOO_lc(count/2, (U8) c)))
+ {
+ match = TRUE;
+ break;
+ }
+ count++;
+ to_complement ^= 1;
+ }
}
}
}
rex->sublen = PL_reg_oldsavedlen;
rex->suboffset = PL_reg_oldsavedoffset;
rex->subcoffset = PL_reg_oldsavedcoffset;
-#ifdef PERL_OLD_COPY_ON_WRITE
+#ifdef PERL_ANY_COW
rex->saved_copy = PL_nrs;
#endif
RXp_MATCH_COPIED_on(rex);
}
STATIC void
-S_to_utf8_substr(pTHX_ register regexp *prog)
+S_to_utf8_substr(pTHX_ regexp *prog)
{
/* Converts substr fields in prog from bytes to UTF-8, calling fbm_compile
* on the converted value */
}
STATIC bool
-S_to_byte_substr(pTHX_ register regexp *prog)
+S_to_byte_substr(pTHX_ regexp *prog)
{
/* Converts substr fields in prog from UTF-8 to bytes, calling fbm_compile
* on the converted value; returns FALSE if can't be converted. */
return TRUE;
}
-/* These constants are for finding GCB=LV and GCB=LVT. These are for the
- * pre-composed Hangul syllables, which are all in a contiguous block and
- * arranged there in such a way so as to facilitate alorithmic determination of
- * their characteristics. As such, they don't need a swash, but can be
- * determined by simple arithmetic. Almost all are GCB=LVT, but every 28th one
- * is a GCB=LV */
-#define SBASE 0xAC00 /* Start of block */
-#define SCount 11172 /* Length of block */
-#define TCount 28
-
-#if 0 /* This routine is not currently used */
-PERL_STATIC_INLINE bool
-S_is_utf8_X_LV(pTHX_ const U8 *p)
-{
- /* Unlike most other similarly named routines here, this does not create a
- * swash, so swash_fetch() cannot be used on PL_utf8_X_LV. */
-
- dVAR;
-
- UV cp = valid_utf8_to_uvchr(p, NULL);
-
- PERL_ARGS_ASSERT_IS_UTF8_X_LV;
-
- /* The earliest Unicode releases did not have these precomposed Hangul
- * syllables. Set to point to undef in that case, so will return false on
- * every call */
- if (! PL_utf8_X_LV) { /* Set up if this is the first time called */
- PL_utf8_X_LV = swash_init("utf8", "_X_GCB_LV", &PL_sv_undef, 1, 0);
- if (_invlist_len(_get_swash_invlist(PL_utf8_X_LV)) == 0) {
- SvREFCNT_dec(PL_utf8_X_LV);
- PL_utf8_X_LV = &PL_sv_undef;
- }
- }
-
- return (PL_utf8_X_LV != &PL_sv_undef
- && cp >= SBASE && cp < SBASE + SCount
- && (cp - SBASE) % TCount == 0); /* Only every TCount one is LV */
-}
-#endif
-
-PERL_STATIC_INLINE bool
-S_is_utf8_X_LVT(pTHX_ const U8 *p)
-{
- /* Unlike most other similarly named routines here, this does not create a
- * swash, so swash_fetch() cannot be used on PL_utf8_X_LVT. */
-
- dVAR;
-
- UV cp = valid_utf8_to_uvchr(p, NULL);
-
- PERL_ARGS_ASSERT_IS_UTF8_X_LVT;
-
- /* The earliest Unicode releases did not have these precomposed Hangul
- * syllables. Set to point to undef in that case, so will return false on
- * every call */
- if (! PL_utf8_X_LVT) { /* Set up if this is the first time called */
- PL_utf8_X_LVT = swash_init("utf8", "_X_GCB_LVT", &PL_sv_undef, 1, 0);
- if (_invlist_len(_get_swash_invlist(PL_utf8_X_LVT)) == 0) {
- SvREFCNT_dec(PL_utf8_X_LVT);
- PL_utf8_X_LVT = &PL_sv_undef;
- }
- }
-
- return (PL_utf8_X_LVT != &PL_sv_undef
- && cp >= SBASE && cp < SBASE + SCount
- && (cp - SBASE) % TCount != 0); /* All but every TCount one is LV */
-}
-
/*
* Local variables:
* c-indentation-style: bsd