static void
S_reg_set_capture_string(pTHX_ REGEXP * const rx,
                            char *strbeg,
                            char *strend,
                            SV *sv,
                            U32 flags,
                            bool utf8_target)
{
    struct regexp *const prog = ReANY(rx);

    if (flags & REXEC_COPY_STR) {
#ifdef PERL_ANY_COW
        if (SvCANCOW(sv)) {
            if (DEBUG_C_TEST) {
                PerlIO_printf(Perl_debug_log,
                              "Copy on write: regexp capture, type %d\n",
                              (int) SvTYPE(sv));
            }
            /* Create a new COW SV to share the match string and store
             * in saved_copy, unless the current COW SV in saved_copy
             * is valid and suitable for our purpose */
            if ((   prog->saved_copy
                 && SvIsCOW(prog->saved_copy)
                 && SvPOKp(prog->saved_copy)
                 && SvIsCOW(sv)
                 && SvPOKp(sv)
                 && SvPVX(sv) == SvPVX(prog->saved_copy)))
            {
                /* just reuse saved_copy SV */
                if (RXp_MATCH_COPIED(prog)) {
                    Safefree(prog->subbeg);
                    RXp_MATCH_COPIED_off(prog);
                }
            }
            else {
                /* create new COW SV to share string */
                RX_MATCH_COPY_FREE(rx);
                prog->saved_copy = sv_setsv_cow(prog->saved_copy, sv);
            }
            prog->subbeg = (char *)SvPVX_const(prog->saved_copy);
            assert (SvPOKp(prog->saved_copy));
            prog->sublen  = strend - strbeg;
            prog->suboffset = 0;
            prog->subcoffset = 0;
        } else
#endif
        {
            SSize_t min = 0;
            SSize_t max = strend - strbeg;
            SSize_t sublen;

            if (    (flags & REXEC_COPY_SKIP_POST)
                && !(prog->extflags & RXf_PMf_KEEPCOPY) /* //p */
                && !(PL_sawampersand & SAWAMPERSAND_RIGHT)
            ) { /* don't copy $' part of string */
                U32 n = 0;
                max = -1;
                /* calculate the right-most part of the string covered
                 * by a capture. Due to look-ahead, this may be to
                 * the right of $&, so we have to scan all captures */
                while (n <= prog->lastparen) {
                    if (prog->offs[n].end > max)
                        max = prog->offs[n].end;
                    n++;
                }
                if (max == -1)
                    max = (PL_sawampersand & SAWAMPERSAND_LEFT)
                            ? prog->offs[0].start
                            : 0;
                assert(max >= 0 && max <= strend - strbeg);
            }

            if (    (flags & REXEC_COPY_SKIP_PRE)
                && !(prog->extflags & RXf_PMf_KEEPCOPY) /* //p */
                && !(PL_sawampersand & SAWAMPERSAND_LEFT)
            ) { /* don't copy $` part of string */
                U32 n = 0;
                min = max;
                /* calculate the left-most part of the string covered
                 * by a capture. Due to look-behind, this may be to
                 * the left of $&, so we have to scan all captures */
                while (min && n <= prog->lastparen) {
                    if (   prog->offs[n].start != -1
                        && prog->offs[n].start < min)
                    {
                        min = prog->offs[n].start;
                    }
                    n++;
                }
                if ((PL_sawampersand & SAWAMPERSAND_RIGHT)
                    && min >  prog->offs[0].end
                )
                    min = prog->offs[0].end;

            }

            assert(min >= 0 && min <= max && min <= strend - strbeg);
            sublen = max - min;

            if (RX_MATCH_COPIED(rx)) {
                if (sublen > prog->sublen)
                    prog->subbeg =
                            (char*)saferealloc(prog->subbeg, sublen+1);
            }
            else
                prog->subbeg = (char*)safemalloc(sublen+1);
            Copy(strbeg + min, prog->subbeg, sublen, char);
            prog->subbeg[sublen] = '\0';
            prog->suboffset = min;
            prog->sublen = sublen;
            RX_MATCH_COPIED_on(rx);
        }
        prog->subcoffset = prog->suboffset;
        if (prog->suboffset && utf8_target) {
            /* Convert byte offset to chars.
             * XXX ideally should only compute this if @-/@+
             * has been seen, a la PL_sawampersand ??? */

            /* If there's a direct correspondence between the
             * string which we're matching and the original SV,
             * then we can use the utf8 len cache associated with
             * the SV. In particular, it means that under //g,
             * sv_pos_b2u() will use the previously cached
             * position to speed up working out the new length of
             * subcoffset, rather than counting from the start of
             * the string each time. This stops
             *   $x = "\x{100}" x 1E6; 1 while $x =~ /(.)/g;
             * from going quadratic */
            if (SvPOKp(sv) && SvPVX(sv) == strbeg)
                prog->subcoffset = sv_pos_b2u_flags(sv, prog->subcoffset,
                                                SV_GMAGIC|SV_CONST_RETURN);
            else
                prog->subcoffset = utf8_length((U8*)strbeg,
                                    (U8*)(strbeg+prog->suboffset));
        }
    }
    else {
        RX_MATCH_COPY_FREE(rx);
        prog->subbeg = strbeg;
        prog->suboffset = 0;
        prog->subcoffset = 0;
        prog->sublen = strend - strbeg;
    }