- case EXACT: {
- char *s = STRING(scan);
- ln = STR_LEN(scan);
- if (do_utf8 != UTF) {
- /* The target and the pattern have differing utf8ness. */
- char *l = locinput;
- const char * const e = s + ln;
-
- if (do_utf8) {
- /* 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:
- PL_reg_flags |= RF_tainted;
- /* FALL THROUGH */
- case EXACTF: {
- char * const s = STRING(scan);
- ln = STR_LEN(scan);
-
- if (do_utf8 || UTF) {
- /* Either target or the pattern are utf8. */
- const char * const l = locinput;
- char *e = PL_regeol;
-
- if (ibcmp_utf8(s, 0, ln, (bool)UTF,
- l, &e, 0, do_utf8)) {
- /* One more case for the sharp s:
- * pack("U0U*", 0xDF) =~ /ss/i,
- * the 0xC3 0x9F are the UTF-8
- * byte sequence for the U+00DF. */
-
- if (!(do_utf8 &&
- toLOWER(s[0]) == 's' &&
- ln >= 2 &&
- toLOWER(s[1]) == 's' &&
- (U8)l[0] == 0xC3 &&
- e - l >= 2 &&
- (U8)l[1] == 0x9F))
- sayNO;
- }
- locinput = e;
- nextchr = UCHARAT(locinput);
- break;
- }
-
- /* Neither the target and the pattern are utf8. */
-
- /* Inline the first character, for speed. */
- if (UCHARAT(s) != nextchr &&
- UCHARAT(s) != ((OP(scan) == EXACTF)
- ? PL_fold : PL_fold_locale)[nextchr])
- sayNO;
- if (PL_regeol - locinput < ln)
- sayNO;
- if (ln > 1 && (OP(scan) == EXACTF
- ? ibcmp(s, locinput, ln)
- : ibcmp_locale(s, locinput, ln)))
- sayNO;
- locinput += ln;
- nextchr = UCHARAT(locinput);
- break;
- }
- case BOUNDL:
- case NBOUNDL:
- PL_reg_flags |= RF_tainted;
- /* FALL THROUGH */
- case BOUND:
- case NBOUND:
- /* was last char in word? */
- if (do_utf8) {
- 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 (OP(scan) == BOUND || OP(scan) == NBOUND) {
- ln = isALNUM_uni(ln);
- LOAD_UTF8_CHARCLASS_ALNUM();
- n = swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8);
- }
- else {
- ln = isALNUM_LC_uvchr(UNI_TO_NATIVE(ln));
- n = isALNUM_LC_utf8((U8*)locinput);
- }
- }
- else {
- ln = (locinput != PL_bostr) ?
- UCHARAT(locinput - 1) : '\n';
- if (OP(scan) == BOUND || OP(scan) == NBOUND) {
- ln = isALNUM(ln);
- n = isALNUM(nextchr);
- }
- else {
- ln = isALNUM_LC(ln);
- n = isALNUM_LC(nextchr);
- }
- }
- if (((!ln) == (!n)) == (OP(scan) == BOUND ||
- OP(scan) == BOUNDL))
- sayNO;
- break;
- case ANYOF:
- if (do_utf8) {
- STRLEN inclasslen = PL_regeol - locinput;
-
- if (!reginclass(rex, scan, (U8*)locinput, &inclasslen, do_utf8))
- goto anyof_fail;
- if (locinput >= PL_regeol)
- sayNO;
- locinput += inclasslen ? inclasslen : UTF8SKIP(locinput);
- nextchr = UCHARAT(locinput);
- break;
- }
- else {
- if (nextchr < 0)
- nextchr = UCHARAT(locinput);
- if (!REGINCLASS(rex, scan, (U8*)locinput))
- goto anyof_fail;
- if (!nextchr && locinput >= PL_regeol)
- sayNO;
- nextchr = UCHARAT(++locinput);
- break;
- }
- anyof_fail:
- /* If we might have the case of the German sharp s
- * in a casefolding Unicode character class. */
-
- if (ANYOF_FOLD_SHARP_S(scan, locinput, PL_regeol)) {
- locinput += SHARP_S_SKIP;
- nextchr = UCHARAT(locinput);
- }
- else
- sayNO;
- break;
- /* Special char classes - The defines start on line 129 or so */
- CCC_TRY_AFF( ALNUM, ALNUML, perl_word, "a", isALNUM_LC_utf8, isALNUM, isALNUM_LC);
- CCC_TRY_NEG(NALNUM, NALNUML, perl_word, "a", isALNUM_LC_utf8, isALNUM, isALNUM_LC);
-
- CCC_TRY_AFF( SPACE, SPACEL, perl_space, " ", isSPACE_LC_utf8, isSPACE, isSPACE_LC);
- CCC_TRY_NEG(NSPACE, NSPACEL, perl_space, " ", isSPACE_LC_utf8, isSPACE, isSPACE_LC);
-
- CCC_TRY_AFF( DIGIT, DIGITL, posix_digit, "0", isDIGIT_LC_utf8, isDIGIT, isDIGIT_LC);
- CCC_TRY_NEG(NDIGIT, NDIGITL, posix_digit, "0", isDIGIT_LC_utf8, isDIGIT, isDIGIT_LC);
-
- case CLUMP: /* Match \X: logical Unicode character. This is defined as
- a Unicode extended Grapheme Cluster */
- /* From http://www.unicode.org/reports/tr29 (5.2 version). An
- extended Grapheme Cluster is:
-
- CR LF
- | Prepend* Begin Extend*
- | .
-
- Begin is (Hangul-syllable | ! Control)
- Extend is (Grapheme_Extend | Spacing_Mark)
- Control is [ GCB_Control CR LF ]
-
- The discussion below shows how the code for CLUMP is derived
- from this regex. Note that most of these concepts are from
- property values of the Grapheme Cluster Boundary (GCB) property.
- No code point can have multiple property values for a given
- property. Thus a code point in Prepend can't be in Control, but
- it must be in !Control. This is why Control above includes
- GCB_Control plus CR plus LF. The latter two are used in the GCB
- property separately, and so can't be in GCB_Control, even though
- they logically are controls. Control is not the same as gc=cc,
- but includes format and other characters as well.
-
- The Unicode definition of Hangul-syllable is:
- L+
- | (L* ( ( V | LV ) V* | LVT ) T*)
- | T+
- )
- Each of these is a value for the GCB property, and hence must be
- disjoint, so the order they are tested is immaterial, so the
- above can safely be changed to
- T+
- | L+
- | (L* ( LVT | ( V | LV ) V*) T*)
-
- The last two terms can be combined like this:
- L* ( L
- | (( LVT | ( V | LV ) V*) T*))
-
- And refactored into this:
- L* (L | LVT T* | V V* T* | LV V* T*)
-
- That means that if we have seen any L's at all we can quit
- there, but if the next character is a LVT, a V or and LV we
- should keep going.
-
- There is a subtlety with Prepend* which showed up in testing.
- Note that the Begin, and only the Begin is required in:
- | Prepend* Begin Extend*
- Also, Begin contains '! Control'. A Prepend must be a '!
- Control', which means it must be a Begin. What it comes down to
- is that if we match Prepend* and then find no suitable Begin
- afterwards, that if we backtrack the last Prepend, that one will
- be a suitable Begin.
- */
-
- if (locinput >= PL_regeol)
- sayNO;
- if (! do_utf8) {
-
- /* 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, do_utf8))
- {
- previous_prepend = locinput;
- locinput += UTF8SKIP(locinput);
- }
-
- /* As noted above, if we matched a prepend character, but
- * the next thing won't match, back off the last prepend we
- * matched, as it is guaranteed to match the begin */
- if (previous_prepend
- && (locinput >= PL_regeol
- || ! swash_fetch(PL_utf8_X_begin,
- (U8*)locinput, do_utf8)))
- {
- locinput = previous_prepend;
- }
-
- /* Note that here we know PL_regeol > locinput, as we
- * tested that upon input to this switch case, and if we
- * moved locinput forward, we tested the result just above
- * and it either passed, or we backed off so that it will
- * now pass */
- if (! swash_fetch(PL_utf8_X_begin, (U8*)locinput, do_utf8)) {
-
- /* Here did not match the required 'Begin' in the
- * second term. So just match the very first
- * character, the '.' of the final term of the regex */
- locinput = starting + UTF8SKIP(starting);
- } else {
-
- /* Here is the beginning of a character that can have
- * an extender. It is either a hangul syllable, or a
- * non-control */
- if (swash_fetch(PL_utf8_X_non_hangul,
- (U8*)locinput, do_utf8))
- {
-
- /* Here not a Hangul syllable, must be a
- * ('! * Control') */
- locinput += UTF8SKIP(locinput);
- } else {
-
- /* Here is a Hangul syllable. It can be composed
- * of several individual characters. One
- * possibility is T+ */
- if (swash_fetch(PL_utf8_X_T,
- (U8*)locinput, do_utf8))
- {
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_T,
- (U8*)locinput, do_utf8))
- {
- locinput += UTF8SKIP(locinput);
- }
- } else {
-
- /* Here, not T+, but is a Hangul. That means
- * it is one of the others: L, LV, LVT or V,
- * and matches:
- * L* (L | LVT T* | V V* T* | LV V* T*) */
-
- /* Match L* */
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_L,
- (U8*)locinput, do_utf8))
- {
- locinput += UTF8SKIP(locinput);
- }
-
- /* Here, have exhausted L*. If the next
- * character is not an LV, LVT nor V, it means
- * we had to have at least one L, so matches L+
- * in the original equation, we have a complete
- * hangul syllable. Are done. */
-
- if (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_LV_LVT_V,
- (U8*)locinput, do_utf8))
- {
-
- /* Otherwise keep going. Must be LV, LVT
- * or V. See if LVT */
- if (swash_fetch(PL_utf8_X_LVT,
- (U8*)locinput, do_utf8))
- {
- locinput += UTF8SKIP(locinput);
- } else {
-
- /* Must be V or LV. Take it, then
- * match V* */
- locinput += UTF8SKIP(locinput);
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_V,
- (U8*)locinput, do_utf8))
- {
- locinput += UTF8SKIP(locinput);
- }
- }
-
- /* And any of LV, LVT, or V can be followed
- * by T* */
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_T,
- (U8*)locinput,
- do_utf8))
- {
- locinput += UTF8SKIP(locinput);
- }
- }
- }
- }
-
- /* Match any extender */
- while (locinput < PL_regeol
- && swash_fetch(PL_utf8_X_extend,
- (U8*)locinput, do_utf8))
- {
- locinput += UTF8SKIP(locinput);
- }
- }
- }
- if (locinput > PL_regeol) sayNO;
- }
- nextchr = UCHARAT(locinput);
- break;
-
- case NREFFL:
- {
- char *s;
- char type;
- PL_reg_flags |= RF_tainted;
- /* FALL THROUGH */
- case NREF:
- case NREFF:
- type = OP(scan);
- n = reg_check_named_buff_matched(rex,scan);
-
- if ( n ) {
- type = REF + ( type - NREF );
- goto do_ref;
- } else {
- sayNO;
- }
- /* unreached */
- case REFFL:
- PL_reg_flags |= RF_tainted;
- /* FALL THROUGH */
- case REF:
- case REFF:
- n = ARG(scan); /* which paren pair */
- type = OP(scan);
- do_ref:
- 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 (do_utf8 && type != REF) { /* REF can do byte comparison */
- char *l = locinput;
- const char *e = PL_bostr + PL_regoffs[n].end;
- /*
- * Note that we can't do the "other character" lookup trick as
- * in the 8-bit case (no pun intended) because in Unicode we
- * have to map both upper and title case to lower case.
- */
- if (type == REFF) {
- while (s < e) {
- STRLEN ulen1, ulen2;
- U8 tmpbuf1[UTF8_MAXBYTES_CASE+1];
- U8 tmpbuf2[UTF8_MAXBYTES_CASE+1];
-
- if (l >= PL_regeol)
- sayNO;
- toLOWER_utf8((U8*)s, tmpbuf1, &ulen1);
- toLOWER_utf8((U8*)l, tmpbuf2, &ulen2);
- if (ulen1 != ulen2 || memNE((char *)tmpbuf1, (char *)tmpbuf2, ulen1))
- sayNO;
- s += ulen1;
- l += ulen2;
- }
- }
- locinput = l;
- nextchr = UCHARAT(locinput);
- break;
- }
-
- /* Inline the first character, for speed. */
- if (UCHARAT(s) != nextchr &&
- (type == REF ||
- (UCHARAT(s) != (type == REFF
- ? PL_fold : PL_fold_locale)[nextchr])))
- sayNO;
- ln = PL_regoffs[n].end - ln;
- if (locinput + ln > PL_regeol)
- sayNO;
- if (ln > 1 && (type == REF
- ? memNE(s, locinput, ln)
- : (type == REFF
- ? ibcmp(s, locinput, ln)
- : ibcmp_locale(s, locinput, ln))))
- sayNO;
- locinput += ln;
- nextchr = UCHARAT(locinput);
- break;
- }
- case NOTHING:
- case TAIL:
- break;
- case BACK:
- break;
+ case EXACT: {
+ char *s = STRING(scan);
+ ln = STR_LEN(scan);
+ if (do_utf8 != UTF) {
+ /* The target and the pattern have differing utf8ness. */
+ char *l = locinput;
+ const char * const e = s + ln;
+
+ if (do_utf8) {
+ /* 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:
+ PL_reg_flags |= RF_tainted;
+ /* FALL THROUGH */
+ case EXACTF: {
+ char * const s = STRING(scan);
+ ln = STR_LEN(scan);
+
+ if (do_utf8 || UTF) {
+ /* Either target or the pattern are utf8. */
+ const char * const l = locinput;
+ char *e = PL_regeol;
+
+ if (ibcmp_utf8(s, 0, ln, (bool)UTF,
+ l, &e, 0, do_utf8)) {
+ /* One more case for the sharp s:
+ * pack("U0U*", 0xDF) =~ /ss/i,
+ * the 0xC3 0x9F are the UTF-8
+ * byte sequence for the U+00DF. */
+
+ if (!(do_utf8 &&
+ toLOWER(s[0]) == 's' &&
+ ln >= 2 &&
+ toLOWER(s[1]) == 's' &&
+ (U8)l[0] == 0xC3 &&
+ e - l >= 2 &&
+ (U8)l[1] == 0x9F))
+ sayNO;
+ }
+ locinput = e;
+ nextchr = UCHARAT(locinput);
+ break;
+ }
+
+ /* Neither the target and the pattern are utf8. */
+
+ /* Inline the first character, for speed. */
+ if (UCHARAT(s) != nextchr &&
+ UCHARAT(s) != ((OP(scan) == EXACTF)
+ ? PL_fold : PL_fold_locale)[nextchr])
+ sayNO;
+ if (PL_regeol - locinput < ln)
+ sayNO;
+ if (ln > 1 && (OP(scan) == EXACTF
+ ? ibcmp(s, locinput, ln)
+ : ibcmp_locale(s, locinput, ln)))
+ sayNO;
+ locinput += ln;
+ nextchr = UCHARAT(locinput);
+ break;
+ }
+ case BOUNDL:
+ case NBOUNDL:
+ PL_reg_flags |= RF_tainted;
+ /* FALL THROUGH */
+ case BOUND:
+ case NBOUND:
+ /* was last char in word? */
+ if (do_utf8) {
+ 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 (OP(scan) == BOUND || OP(scan) == NBOUND) {
+ ln = isALNUM_uni(ln);
+ LOAD_UTF8_CHARCLASS_ALNUM();
+ n = swash_fetch(PL_utf8_alnum, (U8*)locinput, do_utf8);
+ }
+ else {
+ ln = isALNUM_LC_uvchr(UNI_TO_NATIVE(ln));
+ n = isALNUM_LC_utf8((U8*)locinput);
+ }
+ }
+ else {
+ ln = (locinput != PL_bostr) ?
+ UCHARAT(locinput - 1) : '\n';
+ if (OP(scan) == BOUND || OP(scan) == NBOUND) {
+ ln = isALNUM(ln);
+ n = isALNUM(nextchr);
+ }
+ else {
+ ln = isALNUM_LC(ln);
+ n = isALNUM_LC(nextchr);
+ }
+ }
+ if (((!ln) == (!n)) == (OP(scan) == BOUND ||
+ OP(scan) == BOUNDL))
+ sayNO;
+ break;
+ case ANYOF:
+ if (do_utf8) {
+ STRLEN inclasslen = PL_regeol - locinput;
+
+ if (!reginclass(rex, scan, (U8*)locinput, &inclasslen, do_utf8))
+ goto anyof_fail;
+ if (locinput >= PL_regeol)
+ sayNO;
+ locinput += inclasslen ? inclasslen : UTF8SKIP(locinput);
+ nextchr = UCHARAT(locinput);
+ break;
+ }
+ else {
+ if (nextchr < 0)
+ nextchr = UCHARAT(locinput);
+ if (!REGINCLASS(rex, scan, (U8*)locinput))
+ goto anyof_fail;
+ if (!nextchr && locinput >= PL_regeol)
+ sayNO;
+ nextchr = UCHARAT(++locinput);
+ break;
+ }
+ anyof_fail:
+ /* If we might have the case of the German sharp s
+ * in a casefolding Unicode character class. */
+
+ if (ANYOF_FOLD_SHARP_S(scan, locinput, PL_regeol)) {
+ locinput += SHARP_S_SKIP;
+ nextchr = UCHARAT(locinput);
+ }
+ else
+ sayNO;
+ break;
+ /* Special char classes - The defines start on line 129 or so */
+ CCC_TRY_AFF( ALNUM, ALNUML, perl_word, "a", isALNUM_LC_utf8, isALNUM, isALNUM_LC);
+ CCC_TRY_NEG(NALNUM, NALNUML, perl_word, "a", isALNUM_LC_utf8, isALNUM, isALNUM_LC);
+
+ CCC_TRY_AFF( SPACE, SPACEL, perl_space, " ", isSPACE_LC_utf8, isSPACE, isSPACE_LC);
+ CCC_TRY_NEG(NSPACE, NSPACEL, perl_space, " ", isSPACE_LC_utf8, isSPACE, isSPACE_LC);
+
+ CCC_TRY_AFF( DIGIT, DIGITL, posix_digit, "0", isDIGIT_LC_utf8, isDIGIT, isDIGIT_LC);
+ CCC_TRY_NEG(NDIGIT, NDIGITL, posix_digit, "0", isDIGIT_LC_utf8, isDIGIT, isDIGIT_LC);
+
+ case CLUMP: /* Match \X: logical Unicode character. This is defined as
+ a Unicode extended Grapheme Cluster */
+ /* From http://www.unicode.org/reports/tr29 (5.2 version). An
+ extended Grapheme Cluster is:
+
+ CR LF
+ | Prepend* Begin Extend*
+ | .
+
+ Begin is (Hangul-syllable | ! Control)
+ Extend is (Grapheme_Extend | Spacing_Mark)
+ Control is [ GCB_Control CR LF ]
+
+ The discussion below shows how the code for CLUMP is derived
+ from this regex. Note that most of these concepts are from
+ property values of the Grapheme Cluster Boundary (GCB) property.
+ No code point can have multiple property values for a given
+ property. Thus a code point in Prepend can't be in Control, but
+ it must be in !Control. This is why Control above includes
+ GCB_Control plus CR plus LF. The latter two are used in the GCB
+ property separately, and so can't be in GCB_Control, even though
+ they logically are controls. Control is not the same as gc=cc,
+ but includes format and other characters as well.
+
+ The Unicode definition of Hangul-syllable is:
+ L+
+ | (L* ( ( V | LV ) V* | LVT ) T*)
+ | T+
+ )
+ Each of these is a value for the GCB property, and hence must be
+ disjoint, so the order they are tested is immaterial, so the
+ above can safely be changed to
+ T+
+ | L+
+ | (L* ( LVT | ( V | LV ) V*) T*)
+
+ The last two terms can be combined like this:
+ L* ( L
+ | (( LVT | ( V | LV ) V*) T*))
+
+ And refactored into this:
+ L* (L | LVT T* | V V* T* | LV V* T*)
+
+ That means that if we have seen any L's at all we can quit
+ there, but if the next character is a LVT, a V or and LV we
+ should keep going.
+
+ There is a subtlety with Prepend* which showed up in testing.
+ Note that the Begin, and only the Begin is required in:
+ | Prepend* Begin Extend*
+ Also, Begin contains '! Control'. A Prepend must be a '!
+ Control', which means it must be a Begin. What it comes down to
+ is that if we match Prepend* and then find no suitable Begin
+ afterwards, that if we backtrack the last Prepend, that one will
+ be a suitable Begin.
+ */
+
+ if (locinput >= PL_regeol)
+ sayNO;
+ if (! do_utf8) {
+
+ /* 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, do_utf8))
+ {
+ previous_prepend = locinput;
+ locinput += UTF8SKIP(locinput);
+ }
+
+ /* As noted above, if we matched a prepend character, but
+ * the next thing won't match, back off the last prepend we
+ * matched, as it is guaranteed to match the begin */
+ if (previous_prepend
+ && (locinput >= PL_regeol
+ || ! swash_fetch(PL_utf8_X_begin,
+ (U8*)locinput, do_utf8)))
+ {
+ locinput = previous_prepend;
+ }
+
+ /* Note that here we know PL_regeol > locinput, as we
+ * tested that upon input to this switch case, and if we
+ * moved locinput forward, we tested the result just above
+ * and it either passed, or we backed off so that it will
+ * now pass */
+ if (! swash_fetch(PL_utf8_X_begin, (U8*)locinput, do_utf8)) {
+
+ /* Here did not match the required 'Begin' in the
+ * second term. So just match the very first
+ * character, the '.' of the final term of the regex */
+ locinput = starting + UTF8SKIP(starting);
+ } else {
+
+ /* Here is the beginning of a character that can have
+ * an extender. It is either a hangul syllable, or a
+ * non-control */
+ if (swash_fetch(PL_utf8_X_non_hangul,
+ (U8*)locinput, do_utf8))
+ {
+
+ /* Here not a Hangul syllable, must be a
+ * ('! * Control') */
+ locinput += UTF8SKIP(locinput);
+ } else {
+
+ /* Here is a Hangul syllable. It can be composed
+ * of several individual characters. One
+ * possibility is T+ */
+ if (swash_fetch(PL_utf8_X_T,
+ (U8*)locinput, do_utf8))
+ {
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_T,
+ (U8*)locinput, do_utf8))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+ } else {
+
+ /* Here, not T+, but is a Hangul. That means
+ * it is one of the others: L, LV, LVT or V,
+ * and matches:
+ * L* (L | LVT T* | V V* T* | LV V* T*) */
+
+ /* Match L* */
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_L,
+ (U8*)locinput, do_utf8))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+
+ /* Here, have exhausted L*. If the next
+ * character is not an LV, LVT nor V, it means
+ * we had to have at least one L, so matches L+
+ * in the original equation, we have a complete
+ * hangul syllable. Are done. */
+
+ if (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_LV_LVT_V,
+ (U8*)locinput, do_utf8))
+ {
+
+ /* Otherwise keep going. Must be LV, LVT
+ * or V. See if LVT */
+ if (swash_fetch(PL_utf8_X_LVT,
+ (U8*)locinput, do_utf8))
+ {
+ locinput += UTF8SKIP(locinput);
+ } else {
+
+ /* Must be V or LV. Take it, then
+ * match V* */
+ locinput += UTF8SKIP(locinput);
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_V,
+ (U8*)locinput, do_utf8))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+ }
+
+ /* And any of LV, LVT, or V can be followed
+ * by T* */
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_T,
+ (U8*)locinput,
+ do_utf8))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+ }
+ }
+ }
+
+ /* Match any extender */
+ while (locinput < PL_regeol
+ && swash_fetch(PL_utf8_X_extend,
+ (U8*)locinput, do_utf8))
+ {
+ locinput += UTF8SKIP(locinput);
+ }
+ }
+ }
+ if (locinput > PL_regeol) sayNO;
+ }
+ nextchr = UCHARAT(locinput);
+ break;
+
+ case NREFFL:
+ {
+ char *s;
+ char type;
+ PL_reg_flags |= RF_tainted;
+ /* FALL THROUGH */
+ case NREF:
+ case NREFF:
+ type = OP(scan);
+ n = reg_check_named_buff_matched(rex,scan);
+
+ if ( n ) {
+ type = REF + ( type - NREF );
+ goto do_ref;
+ } else {
+ sayNO;
+ }
+ /* unreached */
+ case REFFL:
+ PL_reg_flags |= RF_tainted;
+ /* FALL THROUGH */
+ case REF:
+ case REFF:
+ n = ARG(scan); /* which paren pair */
+ type = OP(scan);
+ do_ref:
+ 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 (do_utf8 && type != REF) { /* REF can do byte comparison */
+ char *l = locinput;
+ const char *e = PL_bostr + PL_regoffs[n].end;
+ /*
+ * Note that we can't do the "other character" lookup trick as
+ * in the 8-bit case (no pun intended) because in Unicode we
+ * have to map both upper and title case to lower case.
+ */
+ if (type == REFF) {
+ while (s < e) {
+ STRLEN ulen1, ulen2;
+ U8 tmpbuf1[UTF8_MAXBYTES_CASE+1];
+ U8 tmpbuf2[UTF8_MAXBYTES_CASE+1];
+
+ if (l >= PL_regeol)
+ sayNO;
+ toLOWER_utf8((U8*)s, tmpbuf1, &ulen1);
+ toLOWER_utf8((U8*)l, tmpbuf2, &ulen2);
+ if (ulen1 != ulen2 || memNE((char *)tmpbuf1, (char *)tmpbuf2, ulen1))
+ sayNO;
+ s += ulen1;
+ l += ulen2;
+ }
+ }
+ locinput = l;
+ nextchr = UCHARAT(locinput);
+ break;
+ }
+
+ /* Inline the first character, for speed. */
+ if (UCHARAT(s) != nextchr &&
+ (type == REF ||
+ (UCHARAT(s) != (type == REFF
+ ? PL_fold : PL_fold_locale)[nextchr])))
+ sayNO;
+ ln = PL_regoffs[n].end - ln;
+ if (locinput + ln > PL_regeol)
+ sayNO;
+ if (ln > 1 && (type == REF
+ ? memNE(s, locinput, ln)
+ : (type == REFF
+ ? ibcmp(s, locinput, ln)
+ : ibcmp_locale(s, locinput, ln))))
+ sayNO;
+ locinput += ln;
+ nextchr = UCHARAT(locinput);
+ break;
+ }
+ case NOTHING:
+ case TAIL:
+ break;
+ case BACK:
+ break;