- case EXACT: {
- char *s = STRING(scan);
- ln = STR_LEN(scan);
- if (utf8_target != UTF_PATTERN) {
- /* The target and the pattern have differing utf8ness. */
- char *l = locinput;
- const char * const e = s + ln;
-
- if (utf8_target) {
- /* The target is utf8, the pattern is not utf8. */
- while (s < e) {
- STRLEN ulen;
- if (l >= PL_regeol)
- sayNO;
- if (NATIVE_TO_UNI(*(U8*)s) !=
- utf8n_to_uvuni((U8*)l, UTF8_MAXBYTES, &ulen,
- uniflags))
- sayNO;
- l += ulen;
- s ++;
- }
- }
- else {
- /* The target is not utf8, the pattern is utf8. */
- while (s < e) {
- STRLEN ulen;
- if (l >= PL_regeol)
- sayNO;
- if (NATIVE_TO_UNI(*((U8*)l)) !=
- utf8n_to_uvuni((U8*)s, UTF8_MAXBYTES, &ulen,
- uniflags))
- sayNO;
- s += ulen;
- l ++;
- }
- }
- locinput = l;
- nextchr = UCHARAT(locinput);
- 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;
- nextchr = UCHARAT(locinput);
- break;
- }
- case EXACTFL: {
- re_fold_t folder;
- const U8 * fold_array;
- const char * s;
- U32 fold_utf8_flags;
-
- PL_reg_flags |= RF_tainted;
- folder = foldEQ_locale;
- fold_array = PL_fold_locale;
- fold_utf8_flags = FOLDEQ_UTF8_LOCALE;
- goto do_exactf;
-
- case EXACTFU:
- folder = foldEQ_latin1;
- fold_array = PL_fold_latin1;
- fold_utf8_flags = 0;
- goto do_exactf;
-
- case EXACTFA:
- folder = foldEQ_latin1;
- fold_array = PL_fold_latin1;
- fold_utf8_flags = FOLDEQ_UTF8_NOMIX_ASCII;
- goto do_exactf;
-
- case EXACTF:
- folder = foldEQ;
- fold_array = PL_fold;
- fold_utf8_flags = 0;
-
- do_exactf:
- s = STRING(scan);
- ln = STR_LEN(scan);
-
- if (utf8_target || UTF_PATTERN) {
- /* Either target or the pattern are utf8. */
- const char * const l = locinput;
- char *e = PL_regeol;
-
- if (! foldEQ_utf8_flags(s, 0, ln, cBOOL(UTF_PATTERN),
- l, &e, 0, utf8_target, fold_utf8_flags))
- {
- sayNO;
- }
- locinput = e;
- nextchr = UCHARAT(locinput);
- break;
- }
-
- /* Neither the target nor the pattern are utf8 */
- if (UCHARAT(s) != nextchr &&
- UCHARAT(s) != fold_array[nextchr])
- {
- sayNO;
- }
- if (PL_regeol - locinput < ln)
- sayNO;
- if (ln > 1 && ! folder(s, locinput, ln))
- sayNO;
- locinput += ln;
- nextchr = UCHARAT(locinput);
- break;
- }
-
- /* XXX Could improve efficiency by separating these all out using a
- * macro or in-line function. At that point regcomp.c would no longer
- * have to set the FLAGS fields of these */
- case BOUNDL:
- case NBOUNDL:
- PL_reg_flags |= RF_tainted;
- /* FALL THROUGH */
- case BOUND:
- case BOUNDU:
- case BOUNDA:
- case NBOUND:
- case NBOUNDU:
- case NBOUNDA:
- /* was last char in word? */
- if (utf8_target
- && FLAGS(scan) != REGEX_ASCII_RESTRICTED_CHARSET
- && FLAGS(scan) != REGEX_ASCII_MORE_RESTRICTED_CHARSET)
- {
- if (locinput == PL_bostr)
- ln = '\n';
- else {
- const U8 * const r = reghop3((U8*)locinput, -1, (U8*)PL_bostr);
-
- ln = utf8n_to_uvchr(r, UTF8SKIP(r), 0, uniflags);
- }
- if (FLAGS(scan) != REGEX_LOCALE_CHARSET) {
- ln = isALNUM_uni(ln);
- LOAD_UTF8_CHARCLASS_ALNUM();
- n = swash_fetch(PL_utf8_alnum, (U8*)locinput, utf8_target);
- }
- else {
- ln = isALNUM_LC_uvchr(UNI_TO_NATIVE(ln));
- n = isALNUM_LC_utf8((U8*)locinput);
- }
- }
- else {
-
- /* Here the string isn't utf8, or is utf8 and only ascii
- * characters are to match \w. In the latter case looking at
- * the byte just prior to the current one may be just the final
- * byte of a multi-byte character. This is ok. There are two
- * cases:
- * 1) it is a single byte character, and then the test is doing
- * just what it's supposed to.
- * 2) it is a multi-byte character, in which case the final
- * byte is never mistakable for ASCII, and so the test
- * will say it is not a word character, which is the
- * correct answer. */
- ln = (locinput != PL_bostr) ?
- UCHARAT(locinput - 1) : '\n';
- switch (FLAGS(scan)) {
- case REGEX_UNICODE_CHARSET:
- ln = isWORDCHAR_L1(ln);
- n = isWORDCHAR_L1(nextchr);
- break;
- case REGEX_LOCALE_CHARSET:
- ln = isALNUM_LC(ln);
- n = isALNUM_LC(nextchr);
- break;
- case REGEX_DEPENDS_CHARSET:
- ln = isALNUM(ln);
- n = isALNUM(nextchr);
- break;
- case REGEX_ASCII_RESTRICTED_CHARSET:
- case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
- ln = isWORDCHAR_A(ln);
- n = isWORDCHAR_A(nextchr);
- break;
- default:
- Perl_croak(aTHX_ "panic: Unexpected FLAGS %u in op %u", FLAGS(scan), OP(scan));
- break;
- }
- }
- /* Note requires that all BOUNDs be lower than all NBOUNDs in
- * regcomp.sym */
- if (((!ln) == (!n)) == (OP(scan) < NBOUND))
- sayNO;
- break;
- case ANYOFV:
- case ANYOF:
- if (utf8_target || state_num == ANYOFV) {
- STRLEN inclasslen = PL_regeol - locinput;
- if (locinput >= PL_regeol)
- sayNO;
-
- if (!reginclass(rex, scan, (U8*)locinput, &inclasslen, utf8_target))
- sayNO;
- locinput += inclasslen;
- nextchr = UCHARAT(locinput);
- break;
- }
- else {
- if (nextchr < 0)
- nextchr = UCHARAT(locinput);
- if (!nextchr && locinput >= PL_regeol)
- sayNO;
- if (!REGINCLASS(rex, scan, (U8*)locinput))
- sayNO;
- nextchr = UCHARAT(++locinput);
- break;
- }
- break;
- /* Special char classes - The defines start on line 129 or so */
- CCC_TRY_U(ALNUM, NALNUM, isWORDCHAR,
- ALNUML, NALNUML, isALNUM_LC, isALNUM_LC_utf8,
- ALNUMU, NALNUMU, isWORDCHAR_L1,
- ALNUMA, NALNUMA, isWORDCHAR_A,
- alnum, "a");
-
- CCC_TRY_U(SPACE, NSPACE, isSPACE,
- SPACEL, NSPACEL, isSPACE_LC, isSPACE_LC_utf8,
- SPACEU, NSPACEU, isSPACE_L1,
- SPACEA, NSPACEA, isSPACE_A,
- space, " ");
-
- CCC_TRY(DIGIT, NDIGIT, isDIGIT,
- DIGITL, NDIGITL, isDIGIT_LC, isDIGIT_LC_utf8,
- DIGITA, NDIGITA, isDIGIT_A,
- digit, "0");
-
- case CLUMP: /* Match \X: logical Unicode character. This is defined as
- a Unicode extended Grapheme Cluster */
- /* From http://www.unicode.org/reports/tr29 (5.2 version). An
- extended Grapheme Cluster is:
-
- CR LF
- | Prepend* Begin Extend*
- | .
-
- Begin is (Hangul-syllable | ! Control)
- Extend is (Grapheme_Extend | Spacing_Mark)
- Control is [ GCB_Control CR LF ]
-
- The discussion below shows how the code for CLUMP is derived
- from this regex. Note that most of these concepts are from
- property values of the Grapheme Cluster Boundary (GCB) property.
- No code point can have multiple property values for a given
- property. Thus a code point in Prepend can't be in Control, but
- it must be in !Control. This is why Control above includes
- GCB_Control plus CR plus LF. The latter two are used in the GCB
- property separately, and so can't be in GCB_Control, even though
- they logically are controls. Control is not the same as gc=cc,
- but includes format and other characters as well.
-
- The Unicode definition of Hangul-syllable is:
- L+
- | (L* ( ( V | LV ) V* | LVT ) T*)
- | T+
- )
- Each of these is a value for the GCB property, and hence must be
- disjoint, so the order they are tested is immaterial, so the
- above can safely be changed to
- T+
- | L+
- | (L* ( LVT | ( V | LV ) V*) T*)
-
- The last two terms can be combined like this:
- L* ( L
- | (( LVT | ( V | LV ) V*) T*))
-
- And refactored into this:
- L* (L | LVT T* | V V* T* | LV V* T*)
-
- That means that if we have seen any L's at all we can quit
- there, but if the next character is a LVT, a V or and LV we
- should keep going.
-
- There is a subtlety with Prepend* which showed up in testing.
- Note that the Begin, and only the Begin is required in:
- | Prepend* Begin Extend*
- Also, Begin contains '! Control'. A Prepend must be a '!
- Control', which means it must be a Begin. What it comes down to
- is that if we match Prepend* and then find no suitable Begin
- afterwards, that if we backtrack the last Prepend, that one will
- be a suitable Begin.
- */
-
- if (locinput >= PL_regeol)
- sayNO;
- if (! utf8_target) {
-
- /* Match either CR LF or '.', as all the other possibilities
- * require utf8 */
- locinput++; /* Match the . or CR */
- if (nextchr == '\r'
- && locinput < PL_regeol
- && UCHARAT(locinput) == '\n') locinput++;
- }
- else {
-
- /* Utf8: See if is ( CR LF ); already know that locinput <
- * PL_regeol, so locinput+1 is in bounds */
- if (nextchr == '\r' && UCHARAT(locinput + 1) == '\n') {
- locinput += 2;
- }
- else {
- /* In case have to backtrack to beginning, then match '.' */
- char *starting = locinput;
-
- /* In case have to backtrack the last prepend */
- char *previous_prepend = 0;
-
- LOAD_UTF8_CHARCLASS_GCB();
-
- /* Match (prepend)* */
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_prepend,
- (U8*)locinput, utf8_target))
- {
- previous_prepend = locinput;
- locinput += UTF8SKIP(locinput);
- }
-
- /* As noted above, if we matched a prepend character, but
- * the next thing won't match, back off the last prepend we
- * matched, as it is guaranteed to match the begin */
- if (previous_prepend
- && (locinput >= PL_regeol
- || ! swash_fetch(PL_utf8_X_begin,
- (U8*)locinput, utf8_target)))
- {
- locinput = previous_prepend;
- }
-
- /* Note that here we know PL_regeol > locinput, as we
- * tested that upon input to this switch case, and if we
- * moved locinput forward, we tested the result just above
- * and it either passed, or we backed off so that it will
- * now pass */
- if (! swash_fetch(PL_utf8_X_begin, (U8*)locinput, utf8_target)) {
-
- /* Here did not match the required 'Begin' in the
- * second term. So just match the very first
- * character, the '.' of the final term of the regex */
- locinput = starting + UTF8SKIP(starting);
- } else {
-
- /* Here is the beginning of a character that can have
- * an extender. It is either a hangul syllable, or a
- * non-control */
- if (swash_fetch(PL_utf8_X_non_hangul,
- (U8*)locinput, utf8_target))
- {
-
- /* Here not a Hangul syllable, must be a
- * ('! * Control') */
- locinput += UTF8SKIP(locinput);
- } else {
-
- /* Here is a Hangul syllable. It can be composed
- * of several individual characters. One
- * possibility is T+ */
- if (swash_fetch(PL_utf8_X_T,
- (U8*)locinput, utf8_target))
- {
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_T,
- (U8*)locinput, utf8_target))
- {
- locinput += UTF8SKIP(locinput);
- }
- } else {
-
- /* Here, not T+, but is a Hangul. That means
- * it is one of the others: L, LV, LVT or V,
- * and matches:
- * L* (L | LVT T* | V V* T* | LV V* T*) */
-
- /* Match L* */
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_L,
- (U8*)locinput, utf8_target))
- {
- locinput += UTF8SKIP(locinput);
- }
-
- /* Here, have exhausted L*. If the next
- * character is not an LV, LVT nor V, it means
- * we had to have at least one L, so matches L+
- * in the original equation, we have a complete
- * hangul syllable. Are done. */
-
- if (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_LV_LVT_V,
- (U8*)locinput, utf8_target))
- {
-
- /* Otherwise keep going. Must be LV, LVT
- * or V. See if LVT */
- if (swash_fetch(PL_utf8_X_LVT,
- (U8*)locinput, utf8_target))
- {
- locinput += UTF8SKIP(locinput);
- } else {
-
- /* Must be V or LV. Take it, then
- * match V* */
- locinput += UTF8SKIP(locinput);
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_V,
- (U8*)locinput, utf8_target))
- {
- locinput += UTF8SKIP(locinput);
- }
- }
-
- /* And any of LV, LVT, or V can be followed
- * by T* */
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_T,
- (U8*)locinput,
- utf8_target))
- {
- locinput += UTF8SKIP(locinput);
- }
- }
- }
- }
-
- /* Match any extender */
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_extend,
- (U8*)locinput, utf8_target))
- {
- locinput += UTF8SKIP(locinput);
- }
- }
- }
- if (locinput > PL_regeol) sayNO;
- }
- nextchr = UCHARAT(locinput);
- break;
-
- case NREFFL:
- { /* The capture buffer cases. The ones beginning with N for the
- named buffers just convert to the equivalent numbered and
- pretend they were called as the corresponding numbered buffer
- op. */
- /* don't initialize these in the declaration, it makes C++
- unhappy */
- char *s;
- char type;
- re_fold_t folder;
- const U8 *fold_array;
- UV utf8_fold_flags;
-
- PL_reg_flags |= RF_tainted;
- folder = foldEQ_locale;
- fold_array = PL_fold_locale;
- type = REFFL;
- utf8_fold_flags = FOLDEQ_UTF8_LOCALE;
- goto do_nref;
-
- case NREFFA:
- folder = foldEQ_latin1;
- fold_array = PL_fold_latin1;
- type = REFFA;
- utf8_fold_flags = FOLDEQ_UTF8_NOMIX_ASCII;
- goto do_nref;
-
- case NREFFU:
- folder = foldEQ_latin1;
- fold_array = PL_fold_latin1;
- type = REFFU;
- utf8_fold_flags = 0;
- goto do_nref;
-
- case NREFF:
- folder = foldEQ;
- fold_array = PL_fold;
- type = REFF;
- utf8_fold_flags = 0;
- goto do_nref;
-
- case NREF:
- type = REF;
- folder = NULL;
- fold_array = NULL;
- utf8_fold_flags = 0;
- do_nref:
-
- /* For the named back references, find the corresponding buffer
- * number */
- n = reg_check_named_buff_matched(rex,scan);
-
- if ( ! n ) {
- sayNO;
- }
- goto do_nref_ref_common;
-
- case REFFL:
- PL_reg_flags |= RF_tainted;
- folder = foldEQ_locale;
- fold_array = PL_fold_locale;
- utf8_fold_flags = FOLDEQ_UTF8_LOCALE;
- goto do_ref;
-
- case REFFA:
- folder = foldEQ_latin1;
- fold_array = PL_fold_latin1;
- utf8_fold_flags = FOLDEQ_UTF8_NOMIX_ASCII;
- goto do_ref;
-
- case REFFU:
- folder = foldEQ_latin1;
- fold_array = PL_fold_latin1;
- utf8_fold_flags = 0;
- goto do_ref;
-
- case REFF:
- folder = foldEQ;
- fold_array = PL_fold;
- utf8_fold_flags = 0;
- goto do_ref;
-
- case REF:
- folder = NULL;
- fold_array = NULL;
- utf8_fold_flags = 0;
-
- do_ref:
- type = OP(scan);
- n = ARG(scan); /* which paren pair */
-
- do_nref_ref_common:
- ln = PL_regoffs[n].start;
- PL_reg_leftiter = PL_reg_maxiter; /* Void cache */
- if (*PL_reglastparen < n || ln == -1)
- sayNO; /* Do not match unless seen CLOSEn. */
- if (ln == PL_regoffs[n].end)
- break;
-
- s = PL_bostr + ln;
- if (type != REF /* REF can do byte comparison */
- && (utf8_target || type == REFFU))
- { /* XXX handle REFFL better */
- char * limit = PL_regeol;
-
- /* This call case insensitively compares the entire buffer
- * at s, with the current input starting at locinput, but
- * not going off the end given by PL_regeol, and returns in
- * limit upon success, how much of the current input was
- * matched */
- if (! foldEQ_utf8_flags(s, NULL, PL_regoffs[n].end - ln, utf8_target,
- locinput, &limit, 0, utf8_target, utf8_fold_flags))
- {
- sayNO;
- }
- locinput = limit;
- nextchr = UCHARAT(locinput);
- break;
- }
-
- /* Not utf8: Inline the first character, for speed. */
- if (UCHARAT(s) != nextchr &&
- (type == REF ||
- UCHARAT(s) != fold_array[nextchr]))
- sayNO;
- ln = PL_regoffs[n].end - ln;
- if (locinput + ln > PL_regeol)
- sayNO;
- if (ln > 1 && (type == REF
- ? memNE(s, locinput, ln)
- : ! folder(s, locinput, ln)))
- sayNO;
- locinput += ln;
- nextchr = UCHARAT(locinput);
- break;
- }
- case NOTHING:
- case TAIL:
- break;
- case BACK:
- break;
+ ln = utf8n_to_uvchr(r, UTF8SKIP(r), 0, uniflags);
+ }
+ if (FLAGS(scan) != REGEX_LOCALE_CHARSET) {
+ ln = isALNUM_uni(ln);
+ LOAD_UTF8_CHARCLASS_ALNUM();
+ n = swash_fetch(PL_utf8_alnum, (U8*)locinput, utf8_target);
+ }
+ else {
+ ln = isALNUM_LC_uvchr(UNI_TO_NATIVE(ln));
+ n = isALNUM_LC_utf8((U8*)locinput);
+ }
+ }
+ else {
+
+ /* Here the string isn't utf8, or is utf8 and only ascii
+ * characters are to match \w. In the latter case looking at
+ * the byte just prior to the current one may be just the final
+ * byte of a multi-byte character. This is ok. There are two
+ * cases:
+ * 1) it is a single byte character, and then the test is doing
+ * just what it's supposed to.
+ * 2) it is a multi-byte character, in which case the final
+ * byte is never mistakable for ASCII, and so the test
+ * will say it is not a word character, which is the
+ * correct answer. */
+ ln = (locinput != PL_bostr) ?
+ UCHARAT(locinput - 1) : '\n';
+ switch (FLAGS(scan)) {
+ case REGEX_UNICODE_CHARSET:
+ ln = isWORDCHAR_L1(ln);
+ n = isWORDCHAR_L1(nextchr);
+ break;
+ case REGEX_LOCALE_CHARSET:
+ ln = isALNUM_LC(ln);
+ n = isALNUM_LC(nextchr);
+ break;
+ case REGEX_DEPENDS_CHARSET:
+ ln = isALNUM(ln);
+ n = isALNUM(nextchr);
+ break;
+ case REGEX_ASCII_RESTRICTED_CHARSET:
+ case REGEX_ASCII_MORE_RESTRICTED_CHARSET:
+ ln = isWORDCHAR_A(ln);
+ n = isWORDCHAR_A(nextchr);
+ break;
+ default:
+ Perl_croak(aTHX_ "panic: Unexpected FLAGS %u in op %u", FLAGS(scan), OP(scan));
+ break;
+ }
+ }
+ /* Note requires that all BOUNDs be lower than all NBOUNDs in
+ * regcomp.sym */
+ if (((!ln) == (!n)) == (OP(scan) < NBOUND))
+ sayNO;
+ break;
+ case ANYOFV:
+ case ANYOF:
+ if (utf8_target || state_num == ANYOFV) {
+ STRLEN inclasslen = PL_regeol - locinput;
+ if (locinput >= PL_regeol)
+ sayNO;
+
+ if (!reginclass(rex, scan, (U8*)locinput, &inclasslen, utf8_target))
+ sayNO;
+ locinput += inclasslen;
+ nextchr = UCHARAT(locinput);
+ break;
+ }
+ else {
+ if (nextchr < 0)
+ nextchr = UCHARAT(locinput);
+ if (!nextchr && locinput >= PL_regeol)
+ sayNO;
+ if (!REGINCLASS(rex, scan, (U8*)locinput))
+ sayNO;
+ nextchr = UCHARAT(++locinput);
+ break;
+ }
+ break;
+ /* Special char classes - The defines start on line 129 or so */
+ CCC_TRY_U(ALNUM, NALNUM, isWORDCHAR,
+ ALNUML, NALNUML, isALNUM_LC, isALNUM_LC_utf8,
+ ALNUMU, NALNUMU, isWORDCHAR_L1,
+ ALNUMA, NALNUMA, isWORDCHAR_A,
+ alnum, "a");
+
+ CCC_TRY_U(SPACE, NSPACE, isSPACE,
+ SPACEL, NSPACEL, isSPACE_LC, isSPACE_LC_utf8,
+ SPACEU, NSPACEU, isSPACE_L1,
+ SPACEA, NSPACEA, isSPACE_A,
+ space, " ");
+
+ CCC_TRY(DIGIT, NDIGIT, isDIGIT,
+ DIGITL, NDIGITL, isDIGIT_LC, isDIGIT_LC_utf8,
+ DIGITA, NDIGITA, isDIGIT_A,
+ digit, "0");
+
+ case CLUMP: /* Match \X: logical Unicode character. This is defined as
+ a Unicode extended Grapheme Cluster */
+ /* From http://www.unicode.org/reports/tr29 (5.2 version). An
+ extended Grapheme Cluster is:
+
+ CR LF
+ | Prepend* Begin Extend*
+ | .
+
+ Begin is (Hangul-syllable | ! Control)
+ Extend is (Grapheme_Extend | Spacing_Mark)
+ Control is [ GCB_Control CR LF ]
+
+ The discussion below shows how the code for CLUMP is derived
+ from this regex. Note that most of these concepts are from
+ property values of the Grapheme Cluster Boundary (GCB) property.
+ No code point can have multiple property values for a given
+ property. Thus a code point in Prepend can't be in Control, but
+ it must be in !Control. This is why Control above includes
+ GCB_Control plus CR plus LF. The latter two are used in the GCB
+ property separately, and so can't be in GCB_Control, even though
+ they logically are controls. Control is not the same as gc=cc,
+ but includes format and other characters as well.
+
+ The Unicode definition of Hangul-syllable is:
+ L+
+ | (L* ( ( V | LV ) V* | LVT ) T*)
+ | T+
+ )
+ Each of these is a value for the GCB property, and hence must be
+ disjoint, so the order they are tested is immaterial, so the
+ above can safely be changed to
+ T+
+ | L+
+ | (L* ( LVT | ( V | LV ) V*) T*)
+
+ The last two terms can be combined like this:
+ L* ( L
+ | (( LVT | ( V | LV ) V*) T*))
+
+ And refactored into this:
+ L* (L | LVT T* | V V* T* | LV V* T*)
+
+ That means that if we have seen any L's at all we can quit
+ there, but if the next character is a LVT, a V or and LV we
+ should keep going.
+
+ There is a subtlety with Prepend* which showed up in testing.
+ Note that the Begin, and only the Begin is required in:
+ | Prepend* Begin Extend*
+ Also, Begin contains '! Control'. A Prepend must be a '!
+ Control', which means it must be a Begin. What it comes down to
+ is that if we match Prepend* and then find no suitable Begin
+ afterwards, that if we backtrack the last Prepend, that one will
+ be a suitable Begin.
+ */
+
+ if (locinput >= PL_regeol)
+ sayNO;
+ if (! utf8_target) {
+
+ /* Match either CR LF or '.', as all the other possibilities
+ * require utf8 */
+ locinput++; /* Match the . or CR */
+ if (nextchr == '\r'
+ && locinput < PL_regeol
+ && UCHARAT(locinput) == '\n') locinput++;
+ }
+ else {
+
+ /* Utf8: See if is ( CR LF ); already know that locinput <
+ * PL_regeol, so locinput+1 is in bounds */
+ if (nextchr == '\r' && UCHARAT(locinput + 1) == '\n') {
+ locinput += 2;
+ }
+ else {
+ /* In case have to backtrack to beginning, then match '.' */
+ char *starting = locinput;
+
+ /* In case have to backtrack the last prepend */
+ char *previous_prepend = 0;
+
+ LOAD_UTF8_CHARCLASS_GCB();
+
+ /* Match (prepend)* */
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_prepend,
+ (U8*)locinput, utf8_target))
+ {
+ previous_prepend = locinput;
+ locinput += UTF8SKIP(locinput);
+ }
+
+ /* As noted above, if we matched a prepend character, but
+ * the next thing won't match, back off the last prepend we
+ * matched, as it is guaranteed to match the begin */
+ if (previous_prepend
+ && (locinput >= PL_regeol
+ || ! swash_fetch(PL_utf8_X_begin,
+ (U8*)locinput, utf8_target)))
+ {
+ locinput = previous_prepend;
+ }
+
+ /* Note that here we know PL_regeol > locinput, as we
+ * tested that upon input to this switch case, and if we
+ * moved locinput forward, we tested the result just above
+ * and it either passed, or we backed off so that it will
+ * now pass */
+ if (! swash_fetch(PL_utf8_X_begin, (U8*)locinput, utf8_target)) {
+
+ /* Here did not match the required 'Begin' in the
+ * second term. So just match the very first
+ * character, the '.' of the final term of the regex */
+ locinput = starting + UTF8SKIP(starting);
+ } else {
+
+ /* Here is the beginning of a character that can have
+ * an extender. It is either a hangul syllable, or a
+ * non-control */
+ if (swash_fetch(PL_utf8_X_non_hangul,
+ (U8*)locinput, utf8_target))
+ {
+
+ /* Here not a Hangul syllable, must be a
+ * ('! * Control') */
+ locinput += UTF8SKIP(locinput);
+ } else {
+
+ /* Here is a Hangul syllable. It can be composed
+ * of several individual characters. One
+ * possibility is T+ */
+ if (swash_fetch(PL_utf8_X_T,
+ (U8*)locinput, utf8_target))
+ {
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_T,
+ (U8*)locinput, utf8_target))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+ } else {
+
+ /* Here, not T+, but is a Hangul. That means
+ * it is one of the others: L, LV, LVT or V,
+ * and matches:
+ * L* (L | LVT T* | V V* T* | LV V* T*) */
+
+ /* Match L* */
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_L,
+ (U8*)locinput, utf8_target))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+
+ /* Here, have exhausted L*. If the next
+ * character is not an LV, LVT nor V, it means
+ * we had to have at least one L, so matches L+
+ * in the original equation, we have a complete
+ * hangul syllable. Are done. */
+
+ if (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_LV_LVT_V,
+ (U8*)locinput, utf8_target))
+ {
+
+ /* Otherwise keep going. Must be LV, LVT
+ * or V. See if LVT */
+ if (swash_fetch(PL_utf8_X_LVT,
+ (U8*)locinput, utf8_target))
+ {
+ locinput += UTF8SKIP(locinput);
+ } else {
+
+ /* Must be V or LV. Take it, then
+ * match V* */
+ locinput += UTF8SKIP(locinput);
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_V,
+ (U8*)locinput, utf8_target))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+ }
+
+ /* And any of LV, LVT, or V can be followed
+ * by T* */
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_T,
+ (U8*)locinput,
+ utf8_target))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+ }
+ }
+ }
+
+ /* Match any extender */
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_extend,
+ (U8*)locinput, utf8_target))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+ }
+ }
+ if (locinput > PL_regeol) sayNO;
+ }
+ nextchr = UCHARAT(locinput);
+ break;
+
+ case NREFFL:
+ { /* The capture buffer cases. The ones beginning with N for the
+ named buffers just convert to the equivalent numbered and
+ pretend they were called as the corresponding numbered buffer
+ op. */
+ /* don't initialize these in the declaration, it makes C++
+ unhappy */
+ char *s;
+ char type;
+ re_fold_t folder;
+ const U8 *fold_array;
+ UV utf8_fold_flags;
+
+ PL_reg_flags |= RF_tainted;
+ folder = foldEQ_locale;
+ fold_array = PL_fold_locale;
+ type = REFFL;
+ utf8_fold_flags = FOLDEQ_UTF8_LOCALE;
+ goto do_nref;
+
+ case NREFFA:
+ folder = foldEQ_latin1;
+ fold_array = PL_fold_latin1;
+ type = REFFA;
+ utf8_fold_flags = FOLDEQ_UTF8_NOMIX_ASCII;
+ goto do_nref;
+
+ case NREFFU:
+ folder = foldEQ_latin1;
+ fold_array = PL_fold_latin1;
+ type = REFFU;
+ utf8_fold_flags = 0;
+ goto do_nref;
+
+ case NREFF:
+ folder = foldEQ;
+ fold_array = PL_fold;
+ type = REFF;
+ utf8_fold_flags = 0;
+ goto do_nref;
+
+ case NREF:
+ type = REF;
+ folder = NULL;
+ fold_array = NULL;
+ utf8_fold_flags = 0;
+ do_nref:
+
+ /* For the named back references, find the corresponding buffer
+ * number */
+ n = reg_check_named_buff_matched(rex,scan);
+
+ if ( ! n ) {
+ sayNO;
+ }
+ goto do_nref_ref_common;
+
+ case REFFL:
+ PL_reg_flags |= RF_tainted;
+ folder = foldEQ_locale;
+ fold_array = PL_fold_locale;
+ utf8_fold_flags = FOLDEQ_UTF8_LOCALE;
+ goto do_ref;
+
+ case REFFA:
+ folder = foldEQ_latin1;
+ fold_array = PL_fold_latin1;
+ utf8_fold_flags = FOLDEQ_UTF8_NOMIX_ASCII;
+ goto do_ref;
+
+ case REFFU:
+ folder = foldEQ_latin1;
+ fold_array = PL_fold_latin1;
+ utf8_fold_flags = 0;
+ goto do_ref;
+
+ case REFF:
+ folder = foldEQ;
+ fold_array = PL_fold;
+ utf8_fold_flags = 0;
+ goto do_ref;
+
+ case REF:
+ folder = NULL;
+ fold_array = NULL;
+ utf8_fold_flags = 0;
+
+ do_ref:
+ type = OP(scan);
+ n = ARG(scan); /* which paren pair */
+
+ do_nref_ref_common:
+ ln = PL_regoffs[n].start;
+ PL_reg_leftiter = PL_reg_maxiter; /* Void cache */
+ if (*PL_reglastparen < n || ln == -1)
+ sayNO; /* Do not match unless seen CLOSEn. */
+ if (ln == PL_regoffs[n].end)
+ break;
+
+ s = PL_bostr + ln;
+ if (type != REF /* REF can do byte comparison */
+ && (utf8_target || type == REFFU))
+ { /* XXX handle REFFL better */
+ char * limit = PL_regeol;
+
+ /* This call case insensitively compares the entire buffer
+ * at s, with the current input starting at locinput, but
+ * not going off the end given by PL_regeol, and returns in
+ * limit upon success, how much of the current input was
+ * matched */
+ if (! foldEQ_utf8_flags(s, NULL, PL_regoffs[n].end - ln, utf8_target,
+ locinput, &limit, 0, utf8_target, utf8_fold_flags))
+ {
+ sayNO;
+ }
+ locinput = limit;
+ nextchr = UCHARAT(locinput);
+ break;
+ }
+
+ /* Not utf8: Inline the first character, for speed. */
+ if (UCHARAT(s) != nextchr &&
+ (type == REF ||
+ UCHARAT(s) != fold_array[nextchr]))
+ sayNO;
+ ln = PL_regoffs[n].end - ln;
+ if (locinput + ln > PL_regeol)
+ sayNO;
+ if (ln > 1 && (type == REF
+ ? memNE(s, locinput, ln)
+ : ! folder(s, locinput, ln)))
+ sayNO;
+ locinput += ln;
+ nextchr = UCHARAT(locinput);
+ break;
+ }
+ case NOTHING:
+ case TAIL:
+ break;
+ case BACK:
+ break;