static bool
S_setup_EXACTISH_ST_c1_c2(pTHX_ const regnode * const text_node, int *c1p,
        U8* c1_utf8, int *c2p, U8* c2_utf8, regmatch_info *reginfo)
{
    /* This function determines if there are one or two characters that match
     * the first character of the passed-in EXACTish node <text_node>, and if
     * so, returns them in the passed-in pointers.
     *
     * If it determines that no possible character in the target string can
     * match, it returns FALSE; otherwise TRUE.  (The FALSE situation occurs if
     * the first character in <text_node> requires UTF-8 to represent, and the
     * target string isn't in UTF-8.)
     *
     * If there are more than two characters that could match the beginning of
     * <text_node>, or if more context is required to determine a match or not,
     * it sets both *<c1p> and *<c2p> to CHRTEST_VOID.
     *
     * The motiviation behind this function is to allow the caller to set up
     * tight loops for matching.  If <text_node> is of type EXACT, there is
     * only one possible character that can match its first character, and so
     * the situation is quite simple.  But things get much more complicated if
     * folding is involved.  It may be that the first character of an EXACTFish
     * node doesn't participate in any possible fold, e.g., punctuation, so it
     * can be matched only by itself.  The vast majority of characters that are
     * in folds match just two things, their lower and upper-case equivalents.
     * But not all are like that; some have multiple possible matches, or match
     * sequences of more than one character.  This function sorts all that out.
     *
     * Consider the patterns A*B or A*?B where A and B are arbitrary.  In a
     * loop of trying to match A*, we know we can't exit where the thing
     * following it isn't a B.  And something can't be a B unless it is the
     * beginning of B.  By putting a quick test for that beginning in a tight
     * loop, we can rule out things that can't possibly be B without having to
     * break out of the loop, thus avoiding work.  Similarly, if A is a single
     * character, we can make a tight loop matching A*, using the outputs of
     * this function.
     *
     * If the target string to match isn't in UTF-8, and there aren't
     * complications which require CHRTEST_VOID, *<c1p> and *<c2p> are set to
     * the one or two possible octets (which are characters in this situation)
     * that can match.  In all cases, if there is only one character that can
     * match, *<c1p> and *<c2p> will be identical.
     *
     * If the target string is in UTF-8, the buffers pointed to by <c1_utf8>
     * and <c2_utf8> will contain the one or two UTF-8 sequences of bytes that
     * can match the beginning of <text_node>.  They should be declared with at
     * least length UTF8_MAXBYTES+1.  (If the target string isn't in UTF-8, it is
     * undefined what these contain.)  If one or both of the buffers are
     * invariant under UTF-8, *<c1p>, and *<c2p> will also be set to the
     * corresponding invariant.  If variant, the corresponding *<c1p> and/or
     * *<c2p> will be set to a negative number(s) that shouldn't match any code
     * point (unless inappropriately coerced to unsigned).   *<c1p> will equal
     * *<c2p> if and only if <c1_utf8> and <c2_utf8> are the same. */

    const bool utf8_target = reginfo->is_utf8_target;

    UV c1 = (UV)CHRTEST_NOT_A_CP_1;
    UV c2 = (UV)CHRTEST_NOT_A_CP_2;
    bool use_chrtest_void = FALSE;
    const bool is_utf8_pat = reginfo->is_utf8_pat;

    /* Used when we have both utf8 input and utf8 output, to avoid converting
     * to/from code points */
    bool utf8_has_been_setup = FALSE;

    dVAR;

    U8 *pat = (U8*)STRING(text_node);
    U8 folded[UTF8_MAX_FOLD_CHAR_EXPAND * UTF8_MAXBYTES_CASE + 1] = { '\0' };

    if (OP(text_node) == EXACT || OP(text_node) == EXACTL) {

        /* In an exact node, only one thing can be matched, that first
         * character.  If both the pat and the target are UTF-8, we can just
         * copy the input to the output, avoiding finding the code point of
         * that character */
        if (!is_utf8_pat) {
            c2 = c1 = *pat;
        }
        else if (utf8_target) {
            Copy(pat, c1_utf8, UTF8SKIP(pat), U8);
            Copy(pat, c2_utf8, UTF8SKIP(pat), U8);
            utf8_has_been_setup = TRUE;
        }
        else {
            c2 = c1 = valid_utf8_to_uvchr(pat, NULL);
        }
    }
    else { /* an EXACTFish node */
        U8 *pat_end = pat + STR_LEN(text_node);

        /* An EXACTFL node has at least some characters unfolded, because what
         * they match is not known until now.  So, now is the time to fold
         * the first few of them, as many as are needed to determine 'c1' and
         * 'c2' later in the routine.  If the pattern isn't UTF-8, we only need
         * to fold if in a UTF-8 locale, and then only the Sharp S; everything
         * else is 1-1 and isn't assumed to be folded.  In a UTF-8 pattern, we
         * need to fold as many characters as a single character can fold to,
         * so that later we can check if the first ones are such a multi-char
         * fold.  But, in such a pattern only locale-problematic characters
         * aren't folded, so we can skip this completely if the first character
         * in the node isn't one of the tricky ones */
        if (OP(text_node) == EXACTFL) {

            if (! is_utf8_pat) {
                if (IN_UTF8_CTYPE_LOCALE && *pat == LATIN_SMALL_LETTER_SHARP_S)
                {
                    folded[0] = folded[1] = 's';
                    pat = folded;
                    pat_end = folded + 2;
                }
            }
            else if (is_PROBLEMATIC_LOCALE_FOLDEDS_START_utf8(pat)) {
                U8 *s = pat;
                U8 *d = folded;
                int i;

                for (i = 0; i < UTF8_MAX_FOLD_CHAR_EXPAND && s < pat_end; i++) {
                    if (isASCII(*s)) {
                        *(d++) = (U8) toFOLD_LC(*s);
                        s++;
                    }
                    else {
                        STRLEN len;
                        _to_utf8_fold_flags(s,
                                            d,
                                            &len,
                                            FOLD_FLAGS_FULL | FOLD_FLAGS_LOCALE);
                        d += len;
                        s += UTF8SKIP(s);
                    }
                }

                pat = folded;
                pat_end = d;
            }
        }

        if ((is_utf8_pat && is_MULTI_CHAR_FOLD_utf8_safe(pat, pat_end))
             || (!is_utf8_pat && is_MULTI_CHAR_FOLD_latin1_safe(pat, pat_end)))
        {
            /* Multi-character folds require more context to sort out.  Also
             * PL_utf8_foldclosures used below doesn't handle them, so have to
             * be handled outside this routine */
            use_chrtest_void = TRUE;
        }
        else { /* an EXACTFish node which doesn't begin with a multi-char fold */
            c1 = is_utf8_pat ? valid_utf8_to_uvchr(pat, NULL) : *pat;
            if (c1 > 255) {
                /* Load the folds hash, if not already done */
                SV** listp;
                if (! PL_utf8_foldclosures) {
                    _load_PL_utf8_foldclosures();
                }

                /* The fold closures data structure is a hash with the keys
                 * being the UTF-8 of every character that is folded to, like
                 * 'k', and the values each an array of all code points that
                 * fold to its key.  e.g. [ 'k', 'K', KELVIN_SIGN ].
                 * Multi-character folds are not included */
                if ((! (listp = hv_fetch(PL_utf8_foldclosures,
                                        (char *) pat,
                                        UTF8SKIP(pat),
                                        FALSE))))
                {
                    /* Not found in the hash, therefore there are no folds
                    * containing it, so there is only a single character that
                    * could match */
                    c2 = c1;
                }
                else {  /* Does participate in folds */
                    AV* list = (AV*) *listp;
                    if (av_tindex(list) != 1) {

                        /* If there aren't exactly two folds to this, it is
                         * outside the scope of this function */
                        use_chrtest_void = TRUE;
                    }
                    else {  /* There are two.  Get them */
                        SV** c_p = av_fetch(list, 0, FALSE);
                        if (c_p == NULL) {
                            Perl_croak(aTHX_ "panic: invalid PL_utf8_foldclosures structure");
                        }
                        c1 = SvUV(*c_p);

                        c_p = av_fetch(list, 1, FALSE);
                        if (c_p == NULL) {
                            Perl_croak(aTHX_ "panic: invalid PL_utf8_foldclosures structure");
                        }
                        c2 = SvUV(*c_p);

                        /* Folds that cross the 255/256 boundary are forbidden
                         * if EXACTFL (and isnt a UTF8 locale), or EXACTFA and
                         * one is ASCIII.  Since the pattern character is above
                         * 255, and its only other match is below 256, the only
                         * legal match will be to itself.  We have thrown away
                         * the original, so have to compute which is the one
                         * above 255. */
                        if ((c1 < 256) != (c2 < 256)) {
                            if ((OP(text_node) == EXACTFL
                                 && ! IN_UTF8_CTYPE_LOCALE)
                                || ((OP(text_node) == EXACTFA
                                    || OP(text_node) == EXACTFA_NO_TRIE)
                                    && (isASCII(c1) || isASCII(c2))))
                            {
                                if (c1 < 256) {
                                    c1 = c2;
                                }
                                else {
                                    c2 = c1;
                                }
                            }
                        }
                    }
                }
            }
            else /* Here, c1 is <= 255 */
                if (utf8_target
                    && HAS_NONLATIN1_FOLD_CLOSURE(c1)
                    && ( ! (OP(text_node) == EXACTFL && ! IN_UTF8_CTYPE_LOCALE))
                    && ((OP(text_node) != EXACTFA
                        && OP(text_node) != EXACTFA_NO_TRIE)
                        || ! isASCII(c1)))
            {
                /* Here, there could be something above Latin1 in the target
                 * which folds to this character in the pattern.  All such
                 * cases except LATIN SMALL LETTER Y WITH DIAERESIS have more
                 * than two characters involved in their folds, so are outside
                 * the scope of this function */
                if (UNLIKELY(c1 == LATIN_SMALL_LETTER_Y_WITH_DIAERESIS)) {
                    c2 = LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS;
                }
                else {
                    use_chrtest_void = TRUE;
                }
            }
            else { /* Here nothing above Latin1 can fold to the pattern
                      character */
                switch (OP(text_node)) {

                    case EXACTFL:   /* /l rules */
                        c2 = PL_fold_locale[c1];
                        break;

                    case EXACTF:   /* This node only generated for non-utf8
                                    patterns */
                        assert(! is_utf8_pat);
                        if (! utf8_target) {    /* /d rules */
                            c2 = PL_fold[c1];
                            break;
                        }
                        /* FALLTHROUGH */
                        /* /u rules for all these.  This happens to work for
                        * EXACTFA as nothing in Latin1 folds to ASCII */
                    case EXACTFA_NO_TRIE:   /* This node only generated for
                                            non-utf8 patterns */
                        assert(! is_utf8_pat);
                        /* FALLTHROUGH */
                    case EXACTFA:
                    case EXACTFU_SS:
                    case EXACTFU:
                        c2 = PL_fold_latin1[c1];
                        break;

                    default:
                        Perl_croak(aTHX_ "panic: Unexpected op %u", OP(text_node));
                        NOT_REACHED; /* NOTREACHED */
                }
            }
        }
    }

    /* Here have figured things out.  Set up the returns */
    if (use_chrtest_void) {
        *c2p = *c1p = CHRTEST_VOID;
    }
    else if (utf8_target) {
        if (! utf8_has_been_setup) {    /* Don't have the utf8; must get it */
            uvchr_to_utf8(c1_utf8, c1);
            uvchr_to_utf8(c2_utf8, c2);
        }

        /* Invariants are stored in both the utf8 and byte outputs; Use
         * negative numbers otherwise for the byte ones.  Make sure that the
         * byte ones are the same iff the utf8 ones are the same */
        *c1p = (UTF8_IS_INVARIANT(*c1_utf8)) ? *c1_utf8 : CHRTEST_NOT_A_CP_1;
        *c2p = (UTF8_IS_INVARIANT(*c2_utf8))
                ? *c2_utf8
                : (c1 == c2)
                  ? CHRTEST_NOT_A_CP_1
                  : CHRTEST_NOT_A_CP_2;
    }
    else if (c1 > 255) {
       if (c2 > 255) {  /* both possibilities are above what a non-utf8 string
                           can represent */
           return FALSE;
       }

       *c1p = *c2p = c2;    /* c2 is the only representable value */
    }
    else {  /* c1 is representable; see about c2 */
       *c1p = c1;
       *c2p = (c2 < 256) ? c2 : c1;
    }

    return TRUE;
static bool
S_setup_EXACTISH_ST_c1_c2(pTHX_ const regnode * const text_node, int *c1p,
        U8* c1_utf8, int *c2p, U8* c2_utf8, regmatch_info *reginfo)
{
     

    const bool utf8_target = reginfo->is_utf8_target;

    UV c1 = (UV)CHRTEST_NOT_A_CP_1;
    UV c2 = (UV)CHRTEST_NOT_A_CP_2;
    bool use_chrtest_void = FALSE;
    const bool is_utf8_pat = reginfo->is_utf8_pat;

     
    bool utf8_has_been_setup = FALSE;

    dVAR;

    U8 *pat = (U8*)STRING(text_node);
    U8 folded[UTF8_MAX_FOLD_CHAR_EXPAND * UTF8_MAXBYTES_CASE + 1] = { '\0' };

    if (OP(text_node) == EXACT || OP(text_node) == EXACTL) {

         
        if (!is_utf8_pat) {
            c2 = c1 = *pat;
        }
        else if (utf8_target) {
            Copy(pat, c1_utf8, UTF8SKIP(pat), U8);
            Copy(pat, c2_utf8, UTF8SKIP(pat), U8);
            utf8_has_been_setup = TRUE;
        }
        else {
            c2 = c1 = valid_utf8_to_uvchr(pat, NULL);
        }
    }
    else {  
        U8 *pat_end = pat + STR_LEN(text_node);

         
        if (OP(text_node) == EXACTFL) {

            if (! is_utf8_pat) {
                if (IN_UTF8_CTYPE_LOCALE && *pat == LATIN_SMALL_LETTER_SHARP_S)
                {
                    folded[0] = folded[1] = 's';
                    pat = folded;
                    pat_end = folded + 2;
                }
            }
            else if (is_PROBLEMATIC_LOCALE_FOLDEDS_START_utf8(pat)) {
                U8 *s = pat;
                U8 *d = folded;
                int i;

                for (i = 0; i < UTF8_MAX_FOLD_CHAR_EXPAND && s < pat_end; i++) {
                    if (isASCII(*s)) {
                        *(d++) = (U8) toFOLD_LC(*s);
                        s++;
                    }
                    else {
                        STRLEN len;
                        _to_utf8_fold_flags(s,
                                            d,
                                            &len,
                                            FOLD_FLAGS_FULL | FOLD_FLAGS_LOCALE);
                        d += len;
                        s += UTF8SKIP(s);
                    }
                }

                pat = folded;
                pat_end = d;
            }
        }

        if ((is_utf8_pat && is_MULTI_CHAR_FOLD_utf8_safe(pat, pat_end))
             || (!is_utf8_pat && is_MULTI_CHAR_FOLD_latin1_safe(pat, pat_end)))
        {
             
            use_chrtest_void = TRUE;
        }
        else {  
            c1 = is_utf8_pat ? valid_utf8_to_uvchr(pat, NULL) : *pat;
            if (c1 > 255) {
                 
                SV** listp;
                if (! PL_utf8_foldclosures) {
                    _load_PL_utf8_foldclosures();
                }

                 
                if ((! (listp = hv_fetch(PL_utf8_foldclosures,
                                        (char *) pat,
                                        UTF8SKIP(pat),
                                        FALSE))))
                {
                     
                    c2 = c1;
                }
                else {   
                    AV* list = (AV*) *listp;
                    if (av_tindex(list) != 1) {

                         
                        use_chrtest_void = TRUE;
                    }
                    else {   
                        SV** c_p = av_fetch(list, 0, FALSE);
                        if (c_p == NULL) {
                            Perl_croak(aTHX_ "panic: invalid PL_utf8_foldclosures structure");
                        }
                        c1 = SvUV(*c_p);

                        c_p = av_fetch(list, 1, FALSE);
                        if (c_p == NULL) {
                            Perl_croak(aTHX_ "panic: invalid PL_utf8_foldclosures structure");
                        }
                        c2 = SvUV(*c_p);

                         
                        if ((c1 < 256) != (c2 < 256)) {
                            if ((OP(text_node) == EXACTFL
                                 && ! IN_UTF8_CTYPE_LOCALE)
                                || ((OP(text_node) == EXACTFA
                                    || OP(text_node) == EXACTFA_NO_TRIE)
                                    && (isASCII(c1) || isASCII(c2))))
                            {
                                if (c1 < 256) {
                                    c1 = c2;
                                }
                                else {
                                    c2 = c1;
                                }
                            }
                        }
                    }
                }
            }
            else  
                if (utf8_target
                    && HAS_NONLATIN1_FOLD_CLOSURE(c1)
                    && ( ! (OP(text_node) == EXACTFL && ! IN_UTF8_CTYPE_LOCALE))
                    && ((OP(text_node) != EXACTFA
                        && OP(text_node) != EXACTFA_NO_TRIE)
                        || ! isASCII(c1)))
            {
                 
                if (UNLIKELY(c1 == LATIN_SMALL_LETTER_Y_WITH_DIAERESIS)) {
                    c2 = LATIN_CAPITAL_LETTER_Y_WITH_DIAERESIS;
                }
                else {
                    use_chrtest_void = TRUE;
                }
            }
            else {  
                switch (OP(text_node)) {

                    case EXACTFL:    
                        c2 = PL_fold_locale[c1];
                        break;

                    case EXACTF:    
                        assert(! is_utf8_pat);
                        if (! utf8_target) {     
                            c2 = PL_fold[c1];
                            break;
                        }
                         
                         
                    case EXACTFA_NO_TRIE:    
                        assert(! is_utf8_pat);
                         
                    case EXACTFA:
                    case EXACTFU_SS:
                    case EXACTFU:
                        c2 = PL_fold_latin1[c1];
                        break;

                    default:
                        Perl_croak(aTHX_ "panic: Unexpected op %u", OP(text_node));
                        NOT_REACHED;  
                }
            }
        }
    }

     
    if (use_chrtest_void) {
        *c2p = *c1p = CHRTEST_VOID;
    }
    else if (utf8_target) {
        if (! utf8_has_been_setup) {     
            uvchr_to_utf8(c1_utf8, c1);
            uvchr_to_utf8(c2_utf8, c2);
        }

         
        *c1p = (UTF8_IS_INVARIANT(*c1_utf8)) ? *c1_utf8 : CHRTEST_NOT_A_CP_1;
        *c2p = (UTF8_IS_INVARIANT(*c2_utf8))
                ? *c2_utf8
                : (c1 == c2)
                  ? CHRTEST_NOT_A_CP_1
                  : CHRTEST_NOT_A_CP_2;
    }
    else if (c1 > 255) {
       if (c2 > 255) {   
           return FALSE;
       }

       *c1p = *c2p = c2;     
    }
    else {   
       *c1p = c1;
       *c2p = (c2 < 256) ? c2 : c1;
    }

    return TRUE;