#include "inline_invlist.c"
#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)
#ifndef STATIC
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*)" "); \
- PERL_UNUSED_VAR(throw_away); \
- 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_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; \
+ 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_ASCII: return isASCII_LC(character);
+ case _CC_ENUM_BLANK: return isBLANK_LC(character);
+ case _CC_ENUM_CASED: return isLOWER_LC(character)
+ || isUPPER_LC(character);
+ case _CC_ENUM_CNTRL: return isCNTRL_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_PSXSPC: return isPSXSPC_LC(character);
+ case _CC_ENUM_PUNCT: return isPUNCT_LC(character);
+ case _CC_ENUM_SPACE: return isSPACE_LC(character);
+ case _CC_ENUM_UPPER: return isUPPER_LC(character);
+ case _CC_ENUM_WORDCHAR: return isWORDCHAR_LC(character);
+ case _CC_ENUM_XDIGIT: return isXDIGIT_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 cBOOL(swash_fetch(PL_utf8_swash_ptrs[classnum], (U8 *)
+ character,
+ TRUE /* is UTF */ ));
+ }
+
+ 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
*/
/* 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 *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)) {
(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 {
? (utf8_target ? trie_utf8 : trie_plain) \
: (utf8_target ? trie_utf8_fold : trie_latin_utf8_fold))
-#define REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc, uscan, len, \
-uvc, charid, foldlen, foldbuf, uniflags) STMT_START { \
+#define REXEC_TRIE_READ_CHAR(trie_type, trie, widecharmap, uc, uscan, len, uvc, charid, foldlen, foldbuf, uniflags) \
+STMT_START { \
STRLEN skiplen; \
switch (trie_type) { \
case trie_utf8_fold: \
#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) {
- 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;
+ 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:
+ case ANYOF_SYNTHETIC:
+ case ANYOF_WARN_SUPER:
+ 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(
- is_XPERLSPACE_utf8(s),
- isSPACE_L1((U8) *s)
- );
- break;
- case SPACE:
- REXEC_FBC_CSCAN(
- is_XPERLSPACE_utf8(s),
- 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(
- ! is_XPERLSPACE_utf8(s),
- ! isSPACE_L1((U8) *s)
- );
- break;
- case NSPACE:
- REXEC_FBC_CSCAN(
- ! is_XPERLSPACE_utf8(s),
- ! 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:
+ RXp_MATCH_TAINTED_on(prog);
+ FBC_BOUND(isWORDCHAR_LC,
+ isWORDCHAR_LC_uvchr(UNI_TO_NATIVE(tmp)),
+ isWORDCHAR_LC_utf8((U8*)s));
+ break;
+ case NBOUNDL:
+ RXp_MATCH_TAINTED_on(prog);
+ FBC_NBOUND(isWORDCHAR_LC,
+ isWORDCHAR_LC_uvchr(UNI_TO_NATIVE(tmp)),
+ isWORDCHAR_LC_utf8((U8*)s));
+ break;
+ case BOUND:
+ FBC_BOUND(isWORDCHAR,
+ isWORDCHAR_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,
+ isWORDCHAR_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,
+ isWORDCHAR_uni(tmp),
+ cBOOL(swash_fetch(PL_utf8_swash_ptrs[_CC_WORDCHAR], (U8*)s, utf8_target)));
+ break;
+ case NBOUNDU:
+ FBC_NBOUND(isWORDCHAR_L1,
+ isWORDCHAR_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:
+ RXp_MATCH_TAINTED_on(prog);
+ 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;
- do {
+ 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 ]);
+
+ 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;
}
Perl_croak(aTHX_ "corrupted regexp program");
}
- PL_reg_flags = 0;
+ RX_MATCH_TAINTED_off(rx);
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;
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"));
}
);
);
Safefree(swap);
- RX_MATCH_TAINTED_set(rx, PL_reg_flags & RF_tainted);
if (PL_reg_state.re_state_eval_setup_done)
restore_pos(aTHX_ 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
}
}
static bool
-S_setup_EXACTISH_ST_c1_c2(pTHX_ const regnode * const text_node, int *c1p, U8* c1_utf8, int *c2p, U8* c2_utf8)
+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 function determines if there are one or two characters that match
* the first character of the passed-in EXACTish node <text_node>, and if
* 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 (! UTF_PATTERN) {
+ if (!is_utf8_pat) {
c2 = c1 = *pat;
}
else if (utf8_target) {
}
}
else /* an EXACTFish node */
- if ((UTF_PATTERN
+ if ((is_utf8_pat
&& is_MULTI_CHAR_FOLD_utf8_safe(pat,
pat + STR_LEN(text_node)))
- || (! UTF_PATTERN
+ || (!is_utf8_pat
&& is_MULTI_CHAR_FOLD_latin1_safe(pat,
pat + STR_LEN(text_node))))
{
use_chrtest_void = TRUE;
}
else { /* an EXACTFish node which doesn't begin with a multi-char fold */
- c1 = (UTF_PATTERN) ? valid_utf8_to_uvchr(pat, NULL) : *pat;
+ c1 = is_utf8_pat ? valid_utf8_to_uvchr(pat, NULL) : *pat;
if (c1 > 256) {
/* Load the folds hash, if not already done */
SV** listp;
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));
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;
}
const char * s;
U32 fold_utf8_flags;
- PL_reg_flags |= RF_tainted;
- folder = foldEQ_locale;
- fold_array = PL_fold_locale;
+ RX_MATCH_TAINTED_on(reginfo->prog);
+ 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;
* have to set the FLAGS fields of these */
case BOUNDL: /* /\b/l */
case NBOUNDL: /* /\B/l */
- PL_reg_flags |= RF_tainted;
+ RX_MATCH_TAINTED_on(reginfo->prog);
/* FALL THROUGH */
case BOUND: /* /\b/ */
case BOUNDU: /* /\b/u */
ln = utf8n_to_uvchr(r, UTF8SKIP(r), 0, uniflags);
}
if (FLAGS(scan) != REGEX_LOCALE_CHARSET) {
- ln = isALNUM_uni(ln);
+ ln = isWORDCHAR_uni(ln);
if (NEXTCHR_IS_EOS)
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);
}
}
else {
- ln = isALNUM_LC_uvchr(UNI_TO_NATIVE(ln));
- n = NEXTCHR_IS_EOS ? 0 : isALNUM_LC_utf8((U8*)locinput);
+ ln = isWORDCHAR_LC_uvchr(UNI_TO_NATIVE(ln));
+ n = NEXTCHR_IS_EOS ? 0 : isWORDCHAR_LC_utf8((U8*)locinput);
}
}
else {
n = NEXTCHR_IS_EOS ? 0 : isWORDCHAR_L1(nextchr);
break;
case REGEX_LOCALE_CHARSET:
- ln = isALNUM_LC(ln);
- n = NEXTCHR_IS_EOS ? 0 : isALNUM_LC(nextchr);
+ ln = isWORDCHAR_LC(ln);
+ n = NEXTCHR_IS_EOS ? 0 : isWORDCHAR_LC(nextchr);
break;
case REGEX_DEPENDS_CHARSET:
- ln = isALNUM(ln);
- n = NEXTCHR_IS_EOS ? 0 : isALNUM(nextchr);
+ ln = isWORDCHAR(ln);
+ n = NEXTCHR_IS_EOS ? 0 : isWORDCHAR(nextchr);
break;
case REGEX_ASCII_RESTRICTED_CHARSET:
case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
break;
case ANYOF: /* /[abc]/ */
+ case ANYOF_WARN_SUPER:
if (NEXTCHR_IS_EOS)
sayNO;
if (utf8_target) {
if (!reginclass(rex, scan, (U8*)locinput, utf8_target))
sayNO;
locinput += UTF8SKIP(locinput);
- break;
}
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");
+ /* The argument (FLAGS) to all the POSIX node types is the class number
+ * */
- case SPACEL:
- PL_reg_flags |= RF_tainted;
- if (NEXTCHR_IS_EOS) {
+ 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;
- }
- if (utf8_target && UTF8_IS_CONTINUED(nextchr)) {
- if (! isSPACE_LC_utf8((U8 *) locinput)) {
+
+ /* The locale hasn't influenced the outcome before this, so defer
+ * tainting until now */
+ RX_MATCH_TAINTED_on(reginfo->prog);
+
+ /* 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), (U8) nextchr)))) {
sayNO;
}
}
- else if (! isSPACE_LC((U8) nextchr)) {
- sayNO;
- }
- goto increment_locinput;
-
- case NSPACEL:
- PL_reg_flags |= RF_tainted;
- if (NEXTCHR_IS_EOS) {
- sayNO;
- }
- if (utf8_target && UTF8_IS_CONTINUED(nextchr)) {
- if (isSPACE_LC_utf8((U8 *) locinput)) {
+ else if (UTF8_IS_DOWNGRADEABLE_START(nextchr)) {
+ if (! (to_complement ^ cBOOL(isFOO_lc(FLAGS(scan),
+ (U8) TWO_BYTE_UTF8_TO_UNI(nextchr,
+ *(locinput + 1))))))
+ {
sayNO;
}
}
- else if (isSPACE_LC(nextchr)) {
- sayNO;
+ else { /* Here, must be an above Latin-1 code point */
+ goto utf8_posix_not_eos;
}
- goto increment_locinput;
- case SPACE:
- if (utf8_target) {
- goto utf8_space;
- }
- /* FALL THROUGH */
- case SPACEA:
- if (NEXTCHR_IS_EOS || ! isSPACE_A(nextchr)) {
- sayNO;
- }
- /* Matched a utf8-invariant, so don't have to worry about utf8 */
- locinput++;
+ /* Here, must be utf8 */
+ locinput += UTF8SKIP(locinput);
break;
- case NSPACE:
+ 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_nspace;
+ goto utf8_posix;
}
- /* FALL THROUGH */
- case NSPACEA:
- if (NEXTCHR_IS_EOS || isSPACE_A(nextchr)) {
- sayNO;
- }
- goto increment_locinput;
+ goto posixa;
- case SPACEU:
- utf8_space:
- if (NEXTCHR_IS_EOS || ! is_XPERLSPACE(locinput, utf8_target)) {
+ case NPOSIXA: /* \W or [:^punct:] etc. under /a */
+
+ if (NEXTCHR_IS_EOS) {
sayNO;
}
- goto increment_locinput;
- case NSPACEU:
- utf8_nspace:
- if (NEXTCHR_IS_EOS || is_XPERLSPACE(locinput, utf8_target)) {
- sayNO;
+ /* All UTF-8 variants match */
+ if (! UTF8_IS_INVARIANT(nextchr)) {
+ goto increment_locinput;
}
- goto increment_locinput;
- CCC_TRY(DIGIT, NDIGIT, isDIGIT,
- DIGITL, NDIGITL, isDIGIT_LC, isDIGIT_LC_utf8,
- DIGITA, NDIGITA, isDIGIT_A,
- digit, "0");
+ to_complement = 1;
+ /* FALLTHROUGH */
+
+ case POSIXA: /* \w or [:punct:] etc. under /a */
- case POSIXA: /* /[[:ascii:]]/ etc */
- if (NEXTCHR_IS_EOS || ! _generic_isCC_A(nextchr, FLAGS(scan))) {
+ 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 {
const U8 *fold_array;
UV utf8_fold_flags;
- PL_reg_flags |= RF_tainted;
+ RX_MATCH_TAINTED_on(reginfo->prog);
folder = foldEQ_locale;
fold_array = PL_fold_locale;
type = REFFL;
goto do_nref_ref_common;
case REFFL: /* /\1/il */
- PL_reg_flags |= RF_tainted;
+ RX_MATCH_TAINTED_on(reginfo->prog);
folder = foldEQ_locale;
fold_array = PL_fold_locale;
utf8_fold_flags = FOLDEQ_UTF8_LOCALE;
/* execute the code in the {...} */
dSP;
- PADOFFSET 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
*/
Copy(&PL_reg_state, &saved_state, 1, struct re_save_state);
- PL_reg_state.re_reparsing = FALSE;
-
if (!caller_cv)
caller_cv = find_runcv(NULL);
* points to newcv's pad. */
if (newcv != last_pushed_cv || PL_comppad != last_pad)
{
- I32 depth = (newcv == caller_cv) ? 0 : 1;
+ U8 flags = (CXp_SUB_RE |
+ ((newcv == caller_cv) ? CXp_SUB_RE_FAKE : 0));
if (last_pushed_cv) {
- CHANGE_MULTICALL_WITHDEPTH(newcv, depth);
+ CHANGE_MULTICALL_FLAGS(newcv, flags);
}
else {
- PUSH_MULTICALL_WITHDEPTH(newcv, depth);
+ PUSH_MULTICALL_FLAGS(newcv, flags);
}
last_pushed_cv = newcv;
}
/* 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-PL_stack_base;
+ before = (IV)(SP-PL_stack_base);
PL_op = nop;
CALLRUNOPS(aTHX); /* Scalar context. */
SPAGAIN;
- if (SP-PL_stack_base == 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);
}
SAVEFREESV(re_sv);
re = ReANY(re_sv);
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 = ReANY(rex_sv);
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 = 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;
*/
if (PL_regkind[OP(text_node)] == EXACT) {
if (! S_setup_EXACTISH_ST_c1_c2(aTHX_
- text_node, &ST.c1, ST.c1_utf8, &ST.c2, ST.c2_utf8))
+ text_node, &ST.c1, ST.c1_utf8, &ST.c2, ST.c2_utf8,
+ is_utf8_pat))
{
sayNO;
}
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.c1_utf8, &ST.c2, ST.c2_utf8))
+ 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);
* 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;
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 = ReANY(rex_sv);
/* 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));
* 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_ regexp *prog, char **startposp, const regnode *p,
+ I32 max, int depth, bool is_utf8_pat)
{
dVAR;
char *scan; /* Pointer to current position in target string */
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
}
break;
case EXACT:
- assert(STR_LEN(p) == (UTF_PATTERN) ? UTF8SKIP(STRING(p)) : 1);
+ assert(STR_LEN(p) == is_utf8_pat ? UTF8SKIP(STRING(p)) : 1);
c = (U8)*STRING(p);
* 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 */
scan++;
}
}
- else if (UTF_PATTERN) {
+ else if (is_utf8_pat) {
if (utf8_target) {
STRLEN scan_char_len;
/* 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;
goto do_exactf;
case EXACTFL:
- PL_reg_flags |= RF_tainted;
+ RXp_MATCH_TAINTED_on(prog);
utf8_flags = FOLDEQ_UTF8_LOCALE;
goto do_exactf;
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: {
int c1, c2;
U8 c1_utf8[UTF8_MAXBYTES+1], c2_utf8[UTF8_MAXBYTES+1];
- assert(STR_LEN(p) == (UTF_PATTERN) ? UTF8SKIP(STRING(p)) : 1);
+ assert(STR_LEN(p) == is_utf8_pat ? UTF8SKIP(STRING(p)) : 1);
- if (S_setup_EXACTISH_ST_c1_c2(aTHX_ p, &c1, c1_utf8, &c2, c2_utf8)) {
+ 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 = (UTF_PATTERN) ? UTF8SKIP(STRING(p)) : 1;
+ 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,
- cBOOL(UTF_PATTERN), utf8_flags))
+ is_utf8_pat, utf8_flags))
{
scan = tmpeol;
tmpeol = PL_regeol;
break;
}
case ANYOF:
+ case ANYOF_WARN_SUPER:
if (utf8_target) {
- STRLEN inclasslen;
while (hardcount < max
- && scan + (inclasslen = UTF8SKIP(scan)) <= loceol
+ && 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:
- LOAD_UTF8_CHARCLASS_ALNUM();
- while (hardcount < max && scan < loceol &&
- swash_fetch(PL_utf8_alnum, (U8*)scan, utf8_target))
- {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && isWORDCHAR_L1((U8) *scan)) {
- scan++;
- }
- }
- break;
- case ALNUM:
- if (utf8_target)
- goto utf8_wordchar;
- while (scan < loceol && isALNUM((U8) *scan)) {
- scan++;
- }
- break;
- case ALNUMA:
- if (utf8_target && scan + max < loceol) {
- /* We didn't adjust <loceol> because is UTF-8, but ok to do so,
- * since here, to match, 1 char == 1 byte */
- loceol = scan + max;
- }
- while (scan < loceol && isWORDCHAR_A((U8) *scan)) {
- scan++;
- }
- break;
- case ALNUML:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- 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) {
+ /* The argument (FLAGS) to all the POSIX node types is the class number */
- utf8_Nwordchar:
+ case NPOSIXL:
+ to_complement = 1;
+ /* FALLTHROUGH */
- LOAD_UTF8_CHARCLASS_ALNUM();
- while (hardcount < max && scan < loceol &&
- ! swash_fetch(PL_utf8_alnum, (U8*)scan, utf8_target))
+ case POSIXL:
+ RXp_MATCH_TAINTED_on(prog);
+ if (! utf8_target) {
+ while (scan < loceol && to_complement ^ cBOOL(isFOO_lc(FLAGS(p),
+ *scan)))
{
- scan += UTF8SKIP(scan);
+ scan++;
+ }
+ } else {
+ while (hardcount < max && scan < loceol
+ && to_complement ^ cBOOL(isFOO_utf8_lc(FLAGS(p),
+ (U8 *) 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:
if (utf8_target && scan + max < loceol) {
- /* We didn't adjust <loceol> because is UTF-8, but ok to do so,
- * since here, to match, 1 char == 1 byte */
+ /* 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 && hardcount < max
- && ! _generic_isCC_A((U8) *scan, FLAGS(p)))
- {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- }
- else {
- while (scan < loceol && ! _generic_isCC_A((U8) *scan, FLAGS(p))) {
- scan++;
- }
- }
- break;
- case NALNUMA:
- if (utf8_target) {
- while (scan < loceol && hardcount < max
- && ! isWORDCHAR_A((U8) *scan))
- {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- }
- else {
- while (scan < loceol && ! isWORDCHAR_A((U8) *scan)) {
- scan++;
- }
- }
- break;
- case NALNUML:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- 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 */
- while (hardcount < max && scan < loceol
- && is_XPERLSPACE_utf8((U8*)scan))
- {
- 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;
-
- while (scan < loceol && isSPACE((U8) *scan)) {
- scan++;
- }
- break;
- case SPACEA:
- if (utf8_target && scan + max < loceol) {
-
- /* We didn't adjust <loceol> because is UTF-8, but ok to do so,
- * since here, to match, 1 char == 1 byte */
- loceol = scan + max;
}
- while (scan < loceol && isSPACE_A((U8) *scan)) {
- scan++;
- }
- break;
- case SPACEL:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- while (hardcount < max && scan < loceol &&
- isSPACE_LC_utf8((U8*)scan)) {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && isSPACE_LC(*scan))
- scan++;
- }
- break;
- case NSPACEU:
- if (utf8_target) {
-
- utf8_Nspace:
+ else {
+ /* 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
- && ! is_XPERLSPACE_utf8((U8*)scan))
+ && (! UTF8_IS_INVARIANT(*scan)
+ || ! _generic_isCC_A((U8) *scan, FLAGS(p))))
{
- scan += UTF8SKIP(scan);
+ scan += UTF8SKIP(scan);
hardcount++;
}
- break;
- }
- else {
- while (scan < loceol && ! isSPACE_L1((U8) *scan)) {
- scan++;
- }
- }
- break;
- case NSPACE:
- if (utf8_target)
- goto utf8_Nspace;
+ }
+ break;
- while (scan < loceol && ! isSPACE((U8) *scan)) {
- scan++;
- }
- break;
- case NSPACEA:
- if (utf8_target) {
- while (hardcount < max && scan < loceol
- && ! isSPACE_A((U8) *scan))
+ case NPOSIXU:
+ to_complement = 1;
+ /* FALLTHROUGH */
+
+ case POSIXU:
+ if (! utf8_target) {
+ while (scan < loceol && to_complement
+ ^ cBOOL(_generic_isCC((U8) *scan, FLAGS(p))))
{
- scan += UTF8SKIP(scan);
- hardcount++;
- }
+ scan++;
+ }
}
else {
- while (scan < loceol && ! isSPACE_A((U8) *scan)) {
- scan++;
- }
- }
- break;
- case NSPACEL:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- 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) {
- 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++;
+ 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;
- case DIGITA:
- if (utf8_target && scan + max < loceol) {
+ break;
- /* We didn't adjust <loceol> because is UTF-8, but ok to do so,
- * since here, to match, 1 char == 1 byte */
- loceol = scan + max;
+ 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 (scan < loceol && isDIGIT_A((U8) *scan)) {
- scan++;
- }
- break;
- case DIGITL:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- 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) {
- 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 (hardcount < max && scan < loceol
- && ! isDIGIT_A((U8) *scan)) {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- }
- else {
- while (scan < loceol && ! isDIGIT_A((U8) *scan)) {
- scan++;
- }
- }
- break;
- case NDIGITL:
- PL_reg_flags |= RF_tainted;
- if (utf8_target) {
- while (hardcount < max && scan < loceol &&
- !isDIGIT_LC_utf8((U8*)scan)) {
- scan += UTF8SKIP(scan);
- hardcount++;
- }
- } else {
- while (scan < loceol && !isDIGIT_LC(*scan))
- scan++;
- }
- break;
+
+ 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) {
while (hardcount < max && scan < loceol &&
}
}
break;
- case HORIZWS:
- if (utf8_target) {
- 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) {
- 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) {
- 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) {
- 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:
*/
STATIC bool
-S_reginclass(pTHX_ const regexp * const prog, const regnode * const n, const U8* const p, const bool utf8_target)
+S_reginclass(pTHX_ regexp * const prog, const regnode * const n, const U8* const p, const bool utf8_target)
{
dVAR;
const char flags = ANYOF_FLAGS(n);
match = TRUE;
}
else if (flags & ANYOF_LOCALE) {
- PL_reg_flags |= RF_tainted;
+ RXp_MATCH_TAINTED_on(prog);
if ((flags & ANYOF_LOC_FOLD)
&& ANYOF_BITMAP_TEST(n, PL_fold_locale[c]))
{
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.
+ *
+ * Note that this code assumes that all the classes are closed
+ * under folding. For example, if a character matches \w, then
+ * its fold does too; and vice versa. This should be true for
+ * any well-behaved locale for all the currently defined Posix
+ * classes, except for :lower: and :upper:, which are handled
+ * by the pseudo-class :cased: which matches if either of the
+ * other two does. To get rid of this assumption, an outer
+ * loop could be used below to iterate over both the source
+ * character, and its fold (if different) */
+
+ 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;
+ }
}
}
}
|| (utf8_target
&& (c >=256
|| (! (flags & ANYOF_LOCALE))
- || (flags & ANYOF_IS_SYNTHETIC)))))
+ || OP(n) == ANYOF_SYNTHETIC))))
{
SV * const sw = core_regclass_swash(prog, n, TRUE, 0);
if (sw) {
}
if (UNICODE_IS_SUPER(c)
- && (flags & ANYOF_WARN_SUPER)
+ && OP(n) == ANYOF_WARN_SUPER
&& ckWARN_d(WARN_NON_UNICODE))
{
Perl_warner(aTHX_ packWARN(WARN_NON_UNICODE),
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