STATIC bool
S_isSB(pTHX_ SB_enum before,
             SB_enum after,
             const U8 * const strbeg,
             const U8 * const curpos,
             const U8 * const strend,
             const bool utf8_target)
{
    /* returns a boolean indicating if there is a Sentence Boundary Break
     * between the inputs.  See http://www.unicode.org/reports/tr29/ */

    U8 * lpos = (U8 *) curpos;
    U8 * temp_pos;
    SB_enum backup;

    PERL_ARGS_ASSERT_ISSB;

    /* Break at the start and end of text.
        SB1.  sot  ÷
        SB2.  ÷  eot */
    if (before == SB_EDGE || after == SB_EDGE) {
        return TRUE;
    }

    /* SB 3: Do not break within CRLF. */
    if (before == SB_CR && after == SB_LF) {
        return FALSE;
    }

    /* Break after paragraph separators.  (though why CR and LF are considered
     * so is beyond me (khw)
       SB4.  Sep | CR | LF  ÷ */
    if (before == SB_Sep || before == SB_CR || before == SB_LF) {
        return TRUE;
    }

    /* Ignore Format and Extend characters, except after sot, Sep, CR, or LF.
     * (See Section 6.2, Replacing Ignore Rules.)
        SB5.  X (Extend | Format)*  →  X */
    if (after == SB_Extend || after == SB_Format) {
        return FALSE;
    }

    if (before == SB_Extend || before == SB_Format) {
        before = backup_one_SB(strbeg, &lpos, utf8_target);
    }

    /* Do not break after ambiguous terminators like period, if they are
     * immediately followed by a number or lowercase letter, if they are
     * between uppercase letters, if the first following letter (optionally
     * after certain punctuation) is lowercase, or if they are followed by
     * "continuation" punctuation such as comma, colon, or semicolon. For
     * example, a period may be an abbreviation or numeric period, and thus may
     * not mark the end of a sentence.

     * SB6. ATerm  ×  Numeric */
    if (before == SB_ATerm && after == SB_Numeric) {
        return FALSE;
    }

    /* SB7.  (Upper | Lower) ATerm  ×  Upper */
    if (before == SB_ATerm && after == SB_Upper) {
        temp_pos = lpos;
        backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
        if (backup == SB_Upper || backup == SB_Lower) {
            return FALSE;
        }
    }

    /* SB8a.  (STerm | ATerm) Close* Sp*  ×  (SContinue | STerm | ATerm)
     * SB10.  (STerm | ATerm) Close* Sp*  ×  ( Sp | Sep | CR | LF )      */
    backup = before;
    temp_pos = lpos;
    while (backup == SB_Sp) {
        backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
    }
    while (backup == SB_Close) {
        backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
    }
    if ((backup == SB_STerm || backup == SB_ATerm)
        && (   after == SB_SContinue
            || after == SB_STerm
            || after == SB_ATerm
            || after == SB_Sp
            || after == SB_Sep
            || after == SB_CR
            || after == SB_LF))
    {
        return FALSE;
    }

    /* SB8.  ATerm Close* Sp*  ×  ( ¬(OLetter | Upper | Lower | Sep | CR | LF |
     *                                              STerm | ATerm) )* Lower */
    if (backup == SB_ATerm) {
        U8 * rpos = (U8 *) curpos;
        SB_enum later = after;

        while (    later != SB_OLetter
                && later != SB_Upper
                && later != SB_Lower
                && later != SB_Sep
                && later != SB_CR
                && later != SB_LF
                && later != SB_STerm
                && later != SB_ATerm
                && later != SB_EDGE)
        {
            later = advance_one_SB(&rpos, strend, utf8_target);
        }
        if (later == SB_Lower) {
            return FALSE;
        }
    }

    /* Break after sentence terminators, but include closing punctuation,
     * trailing spaces, and a paragraph separator (if present). [See note
     * below.]
     * SB9.  ( STerm | ATerm ) Close*  ×  ( Close | Sp | Sep | CR | LF ) */
    backup = before;
    temp_pos = lpos;
    while (backup == SB_Close) {
        backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
    }
    if ((backup == SB_STerm || backup == SB_ATerm)
        && (   after == SB_Close
            || after == SB_Sp
            || after == SB_Sep
            || after == SB_CR
            || after == SB_LF))
    {
        return FALSE;
    }


    /* SB11.  ( STerm | ATerm ) Close* Sp* ( Sep | CR | LF )?  ÷ */
    temp_pos = lpos;
    backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
    if (   backup == SB_Sep
        || backup == SB_CR
        || backup == SB_LF)
    {
        lpos = temp_pos;
    }
    else {
        backup = before;
    }
    while (backup == SB_Sp) {
        backup = backup_one_SB(strbeg, &lpos, utf8_target);
    }
    while (backup == SB_Close) {
        backup = backup_one_SB(strbeg, &lpos, utf8_target);
    }
    if (backup == SB_STerm || backup == SB_ATerm) {
        return TRUE;
    }

    /* Otherwise, do not break.
    SB12.  Any  ×  Any */

    return FALSE;
STATIC bool
S_isSB(pTHX_ SB_enum before,
             SB_enum after,
             const U8 * const strbeg,
             const U8 * const curpos,
             const U8 * const strend,
             const bool utf8_target)
{
     

    U8 * lpos = (U8 *) curpos;
    U8 * temp_pos;
    SB_enum backup;

    PERL_ARGS_ASSERT_ISSB;

     
    if (before == SB_EDGE || after == SB_EDGE) {
        return TRUE;
    }

     
    if (before == SB_CR && after == SB_LF) {
        return FALSE;
    }

     
    if (before == SB_Sep || before == SB_CR || before == SB_LF) {
        return TRUE;
    }

     
    if (after == SB_Extend || after == SB_Format) {
        return FALSE;
    }

    if (before == SB_Extend || before == SB_Format) {
        before = backup_one_SB(strbeg, &lpos, utf8_target);
    }

     
    if (before == SB_ATerm && after == SB_Numeric) {
        return FALSE;
    }

     
    if (before == SB_ATerm && after == SB_Upper) {
        temp_pos = lpos;
        backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
        if (backup == SB_Upper || backup == SB_Lower) {
            return FALSE;
        }
    }

     
    backup = before;
    temp_pos = lpos;
    while (backup == SB_Sp) {
        backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
    }
    while (backup == SB_Close) {
        backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
    }
    if ((backup == SB_STerm || backup == SB_ATerm)
        && (   after == SB_SContinue
            || after == SB_STerm
            || after == SB_ATerm
            || after == SB_Sp
            || after == SB_Sep
            || after == SB_CR
            || after == SB_LF))
    {
        return FALSE;
    }

     
    if (backup == SB_ATerm) {
        U8 * rpos = (U8 *) curpos;
        SB_enum later = after;

        while (    later != SB_OLetter
                && later != SB_Upper
                && later != SB_Lower
                && later != SB_Sep
                && later != SB_CR
                && later != SB_LF
                && later != SB_STerm
                && later != SB_ATerm
                && later != SB_EDGE)
        {
            later = advance_one_SB(&rpos, strend, utf8_target);
        }
        if (later == SB_Lower) {
            return FALSE;
        }
    }

     
    backup = before;
    temp_pos = lpos;
    while (backup == SB_Close) {
        backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
    }
    if ((backup == SB_STerm || backup == SB_ATerm)
        && (   after == SB_Close
            || after == SB_Sp
            || after == SB_Sep
            || after == SB_CR
            || after == SB_LF))
    {
        return FALSE;
    }


     
    temp_pos = lpos;
    backup = backup_one_SB(strbeg, &temp_pos, utf8_target);
    if (   backup == SB_Sep
        || backup == SB_CR
        || backup == SB_LF)
    {
        lpos = temp_pos;
    }
    else {
        backup = before;
    }
    while (backup == SB_Sp) {
        backup = backup_one_SB(strbeg, &lpos, utf8_target);
    }
    while (backup == SB_Close) {
        backup = backup_one_SB(strbeg, &lpos, utf8_target);
    }
    if (backup == SB_STerm || backup == SB_ATerm) {
        return TRUE;
    }

     

    return FALSE;