17db96d56Sopenharmony_ci#define PY_SSIZE_T_CLEAN
27db96d56Sopenharmony_ci#include "Python.h"
37db96d56Sopenharmony_ci#include "pycore_abstract.h"   // _PyIndex_Check()
47db96d56Sopenharmony_ci#include "pycore_bytes_methods.h"
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_isspace__doc__,
77db96d56Sopenharmony_ci"B.isspace() -> bool\n\
87db96d56Sopenharmony_ci\n\
97db96d56Sopenharmony_ciReturn True if all characters in B are whitespace\n\
107db96d56Sopenharmony_ciand there is at least one character in B, False otherwise.");
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ciPyObject*
137db96d56Sopenharmony_ci_Py_bytes_isspace(const char *cptr, Py_ssize_t len)
147db96d56Sopenharmony_ci{
157db96d56Sopenharmony_ci    const unsigned char *p
167db96d56Sopenharmony_ci        = (const unsigned char *) cptr;
177db96d56Sopenharmony_ci    const unsigned char *e;
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci    /* Shortcut for single character strings */
207db96d56Sopenharmony_ci    if (len == 1 && Py_ISSPACE(*p))
217db96d56Sopenharmony_ci        Py_RETURN_TRUE;
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ci    /* Special case for empty strings */
247db96d56Sopenharmony_ci    if (len == 0)
257db96d56Sopenharmony_ci        Py_RETURN_FALSE;
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci    e = p + len;
287db96d56Sopenharmony_ci    for (; p < e; p++) {
297db96d56Sopenharmony_ci        if (!Py_ISSPACE(*p))
307db96d56Sopenharmony_ci            Py_RETURN_FALSE;
317db96d56Sopenharmony_ci    }
327db96d56Sopenharmony_ci    Py_RETURN_TRUE;
337db96d56Sopenharmony_ci}
347db96d56Sopenharmony_ci
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_isalpha__doc__,
377db96d56Sopenharmony_ci"B.isalpha() -> bool\n\
387db96d56Sopenharmony_ci\n\
397db96d56Sopenharmony_ciReturn True if all characters in B are alphabetic\n\
407db96d56Sopenharmony_ciand there is at least one character in B, False otherwise.");
417db96d56Sopenharmony_ci
427db96d56Sopenharmony_ciPyObject*
437db96d56Sopenharmony_ci_Py_bytes_isalpha(const char *cptr, Py_ssize_t len)
447db96d56Sopenharmony_ci{
457db96d56Sopenharmony_ci    const unsigned char *p
467db96d56Sopenharmony_ci        = (const unsigned char *) cptr;
477db96d56Sopenharmony_ci    const unsigned char *e;
487db96d56Sopenharmony_ci
497db96d56Sopenharmony_ci    /* Shortcut for single character strings */
507db96d56Sopenharmony_ci    if (len == 1 && Py_ISALPHA(*p))
517db96d56Sopenharmony_ci        Py_RETURN_TRUE;
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ci    /* Special case for empty strings */
547db96d56Sopenharmony_ci    if (len == 0)
557db96d56Sopenharmony_ci        Py_RETURN_FALSE;
567db96d56Sopenharmony_ci
577db96d56Sopenharmony_ci    e = p + len;
587db96d56Sopenharmony_ci    for (; p < e; p++) {
597db96d56Sopenharmony_ci        if (!Py_ISALPHA(*p))
607db96d56Sopenharmony_ci            Py_RETURN_FALSE;
617db96d56Sopenharmony_ci    }
627db96d56Sopenharmony_ci    Py_RETURN_TRUE;
637db96d56Sopenharmony_ci}
647db96d56Sopenharmony_ci
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_isalnum__doc__,
677db96d56Sopenharmony_ci"B.isalnum() -> bool\n\
687db96d56Sopenharmony_ci\n\
697db96d56Sopenharmony_ciReturn True if all characters in B are alphanumeric\n\
707db96d56Sopenharmony_ciand there is at least one character in B, False otherwise.");
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ciPyObject*
737db96d56Sopenharmony_ci_Py_bytes_isalnum(const char *cptr, Py_ssize_t len)
747db96d56Sopenharmony_ci{
757db96d56Sopenharmony_ci    const unsigned char *p
767db96d56Sopenharmony_ci        = (const unsigned char *) cptr;
777db96d56Sopenharmony_ci    const unsigned char *e;
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci    /* Shortcut for single character strings */
807db96d56Sopenharmony_ci    if (len == 1 && Py_ISALNUM(*p))
817db96d56Sopenharmony_ci        Py_RETURN_TRUE;
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_ci    /* Special case for empty strings */
847db96d56Sopenharmony_ci    if (len == 0)
857db96d56Sopenharmony_ci        Py_RETURN_FALSE;
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_ci    e = p + len;
887db96d56Sopenharmony_ci    for (; p < e; p++) {
897db96d56Sopenharmony_ci        if (!Py_ISALNUM(*p))
907db96d56Sopenharmony_ci            Py_RETURN_FALSE;
917db96d56Sopenharmony_ci    }
927db96d56Sopenharmony_ci    Py_RETURN_TRUE;
937db96d56Sopenharmony_ci}
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_ci
967db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_isascii__doc__,
977db96d56Sopenharmony_ci"B.isascii() -> bool\n\
987db96d56Sopenharmony_ci\n\
997db96d56Sopenharmony_ciReturn True if B is empty or all characters in B are ASCII,\n\
1007db96d56Sopenharmony_ciFalse otherwise.");
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci// Optimization is copied from ascii_decode in unicodeobject.c
1037db96d56Sopenharmony_ci/* Mask to quickly check whether a C 'size_t' contains a
1047db96d56Sopenharmony_ci   non-ASCII, UTF8-encoded char. */
1057db96d56Sopenharmony_ci#if (SIZEOF_SIZE_T == 8)
1067db96d56Sopenharmony_ci# define ASCII_CHAR_MASK 0x8080808080808080ULL
1077db96d56Sopenharmony_ci#elif (SIZEOF_SIZE_T == 4)
1087db96d56Sopenharmony_ci# define ASCII_CHAR_MASK 0x80808080U
1097db96d56Sopenharmony_ci#else
1107db96d56Sopenharmony_ci# error C 'size_t' size should be either 4 or 8!
1117db96d56Sopenharmony_ci#endif
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ciPyObject*
1147db96d56Sopenharmony_ci_Py_bytes_isascii(const char *cptr, Py_ssize_t len)
1157db96d56Sopenharmony_ci{
1167db96d56Sopenharmony_ci    const char *p = cptr;
1177db96d56Sopenharmony_ci    const char *end = p + len;
1187db96d56Sopenharmony_ci
1197db96d56Sopenharmony_ci    while (p < end) {
1207db96d56Sopenharmony_ci        /* Fast path, see in STRINGLIB(utf8_decode) in stringlib/codecs.h
1217db96d56Sopenharmony_ci           for an explanation. */
1227db96d56Sopenharmony_ci        if (_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) {
1237db96d56Sopenharmony_ci            /* Help allocation */
1247db96d56Sopenharmony_ci            const char *_p = p;
1257db96d56Sopenharmony_ci            while (_p + SIZEOF_SIZE_T <= end) {
1267db96d56Sopenharmony_ci                size_t value = *(const size_t *) _p;
1277db96d56Sopenharmony_ci                if (value & ASCII_CHAR_MASK) {
1287db96d56Sopenharmony_ci                    Py_RETURN_FALSE;
1297db96d56Sopenharmony_ci                }
1307db96d56Sopenharmony_ci                _p += SIZEOF_SIZE_T;
1317db96d56Sopenharmony_ci            }
1327db96d56Sopenharmony_ci            p = _p;
1337db96d56Sopenharmony_ci            if (_p == end)
1347db96d56Sopenharmony_ci                break;
1357db96d56Sopenharmony_ci        }
1367db96d56Sopenharmony_ci        if ((unsigned char)*p & 0x80) {
1377db96d56Sopenharmony_ci            Py_RETURN_FALSE;
1387db96d56Sopenharmony_ci        }
1397db96d56Sopenharmony_ci        p++;
1407db96d56Sopenharmony_ci    }
1417db96d56Sopenharmony_ci    Py_RETURN_TRUE;
1427db96d56Sopenharmony_ci}
1437db96d56Sopenharmony_ci
1447db96d56Sopenharmony_ci#undef ASCII_CHAR_MASK
1457db96d56Sopenharmony_ci
1467db96d56Sopenharmony_ci
1477db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_isdigit__doc__,
1487db96d56Sopenharmony_ci"B.isdigit() -> bool\n\
1497db96d56Sopenharmony_ci\n\
1507db96d56Sopenharmony_ciReturn True if all characters in B are digits\n\
1517db96d56Sopenharmony_ciand there is at least one character in B, False otherwise.");
1527db96d56Sopenharmony_ci
1537db96d56Sopenharmony_ciPyObject*
1547db96d56Sopenharmony_ci_Py_bytes_isdigit(const char *cptr, Py_ssize_t len)
1557db96d56Sopenharmony_ci{
1567db96d56Sopenharmony_ci    const unsigned char *p
1577db96d56Sopenharmony_ci        = (const unsigned char *) cptr;
1587db96d56Sopenharmony_ci    const unsigned char *e;
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_ci    /* Shortcut for single character strings */
1617db96d56Sopenharmony_ci    if (len == 1 && Py_ISDIGIT(*p))
1627db96d56Sopenharmony_ci        Py_RETURN_TRUE;
1637db96d56Sopenharmony_ci
1647db96d56Sopenharmony_ci    /* Special case for empty strings */
1657db96d56Sopenharmony_ci    if (len == 0)
1667db96d56Sopenharmony_ci        Py_RETURN_FALSE;
1677db96d56Sopenharmony_ci
1687db96d56Sopenharmony_ci    e = p + len;
1697db96d56Sopenharmony_ci    for (; p < e; p++) {
1707db96d56Sopenharmony_ci        if (!Py_ISDIGIT(*p))
1717db96d56Sopenharmony_ci            Py_RETURN_FALSE;
1727db96d56Sopenharmony_ci    }
1737db96d56Sopenharmony_ci    Py_RETURN_TRUE;
1747db96d56Sopenharmony_ci}
1757db96d56Sopenharmony_ci
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_islower__doc__,
1787db96d56Sopenharmony_ci"B.islower() -> bool\n\
1797db96d56Sopenharmony_ci\n\
1807db96d56Sopenharmony_ciReturn True if all cased characters in B are lowercase and there is\n\
1817db96d56Sopenharmony_ciat least one cased character in B, False otherwise.");
1827db96d56Sopenharmony_ci
1837db96d56Sopenharmony_ciPyObject*
1847db96d56Sopenharmony_ci_Py_bytes_islower(const char *cptr, Py_ssize_t len)
1857db96d56Sopenharmony_ci{
1867db96d56Sopenharmony_ci    const unsigned char *p
1877db96d56Sopenharmony_ci        = (const unsigned char *) cptr;
1887db96d56Sopenharmony_ci    const unsigned char *e;
1897db96d56Sopenharmony_ci    int cased;
1907db96d56Sopenharmony_ci
1917db96d56Sopenharmony_ci    /* Shortcut for single character strings */
1927db96d56Sopenharmony_ci    if (len == 1)
1937db96d56Sopenharmony_ci        return PyBool_FromLong(Py_ISLOWER(*p));
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci    /* Special case for empty strings */
1967db96d56Sopenharmony_ci    if (len == 0)
1977db96d56Sopenharmony_ci        Py_RETURN_FALSE;
1987db96d56Sopenharmony_ci
1997db96d56Sopenharmony_ci    e = p + len;
2007db96d56Sopenharmony_ci    cased = 0;
2017db96d56Sopenharmony_ci    for (; p < e; p++) {
2027db96d56Sopenharmony_ci        if (Py_ISUPPER(*p))
2037db96d56Sopenharmony_ci            Py_RETURN_FALSE;
2047db96d56Sopenharmony_ci        else if (!cased && Py_ISLOWER(*p))
2057db96d56Sopenharmony_ci            cased = 1;
2067db96d56Sopenharmony_ci    }
2077db96d56Sopenharmony_ci    return PyBool_FromLong(cased);
2087db96d56Sopenharmony_ci}
2097db96d56Sopenharmony_ci
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_isupper__doc__,
2127db96d56Sopenharmony_ci"B.isupper() -> bool\n\
2137db96d56Sopenharmony_ci\n\
2147db96d56Sopenharmony_ciReturn True if all cased characters in B are uppercase and there is\n\
2157db96d56Sopenharmony_ciat least one cased character in B, False otherwise.");
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ciPyObject*
2187db96d56Sopenharmony_ci_Py_bytes_isupper(const char *cptr, Py_ssize_t len)
2197db96d56Sopenharmony_ci{
2207db96d56Sopenharmony_ci    const unsigned char *p
2217db96d56Sopenharmony_ci        = (const unsigned char *) cptr;
2227db96d56Sopenharmony_ci    const unsigned char *e;
2237db96d56Sopenharmony_ci    int cased;
2247db96d56Sopenharmony_ci
2257db96d56Sopenharmony_ci    /* Shortcut for single character strings */
2267db96d56Sopenharmony_ci    if (len == 1)
2277db96d56Sopenharmony_ci        return PyBool_FromLong(Py_ISUPPER(*p));
2287db96d56Sopenharmony_ci
2297db96d56Sopenharmony_ci    /* Special case for empty strings */
2307db96d56Sopenharmony_ci    if (len == 0)
2317db96d56Sopenharmony_ci        Py_RETURN_FALSE;
2327db96d56Sopenharmony_ci
2337db96d56Sopenharmony_ci    e = p + len;
2347db96d56Sopenharmony_ci    cased = 0;
2357db96d56Sopenharmony_ci    for (; p < e; p++) {
2367db96d56Sopenharmony_ci        if (Py_ISLOWER(*p))
2377db96d56Sopenharmony_ci            Py_RETURN_FALSE;
2387db96d56Sopenharmony_ci        else if (!cased && Py_ISUPPER(*p))
2397db96d56Sopenharmony_ci            cased = 1;
2407db96d56Sopenharmony_ci    }
2417db96d56Sopenharmony_ci    return PyBool_FromLong(cased);
2427db96d56Sopenharmony_ci}
2437db96d56Sopenharmony_ci
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_istitle__doc__,
2467db96d56Sopenharmony_ci"B.istitle() -> bool\n\
2477db96d56Sopenharmony_ci\n\
2487db96d56Sopenharmony_ciReturn True if B is a titlecased string and there is at least one\n\
2497db96d56Sopenharmony_cicharacter in B, i.e. uppercase characters may only follow uncased\n\
2507db96d56Sopenharmony_cicharacters and lowercase characters only cased ones. Return False\n\
2517db96d56Sopenharmony_ciotherwise.");
2527db96d56Sopenharmony_ci
2537db96d56Sopenharmony_ciPyObject*
2547db96d56Sopenharmony_ci_Py_bytes_istitle(const char *cptr, Py_ssize_t len)
2557db96d56Sopenharmony_ci{
2567db96d56Sopenharmony_ci    const unsigned char *p
2577db96d56Sopenharmony_ci        = (const unsigned char *) cptr;
2587db96d56Sopenharmony_ci    const unsigned char *e;
2597db96d56Sopenharmony_ci    int cased, previous_is_cased;
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci    /* Shortcut for single character strings */
2627db96d56Sopenharmony_ci    if (len == 1)
2637db96d56Sopenharmony_ci        return PyBool_FromLong(Py_ISUPPER(*p));
2647db96d56Sopenharmony_ci
2657db96d56Sopenharmony_ci    /* Special case for empty strings */
2667db96d56Sopenharmony_ci    if (len == 0)
2677db96d56Sopenharmony_ci        Py_RETURN_FALSE;
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ci    e = p + len;
2707db96d56Sopenharmony_ci    cased = 0;
2717db96d56Sopenharmony_ci    previous_is_cased = 0;
2727db96d56Sopenharmony_ci    for (; p < e; p++) {
2737db96d56Sopenharmony_ci        const unsigned char ch = *p;
2747db96d56Sopenharmony_ci
2757db96d56Sopenharmony_ci        if (Py_ISUPPER(ch)) {
2767db96d56Sopenharmony_ci            if (previous_is_cased)
2777db96d56Sopenharmony_ci                Py_RETURN_FALSE;
2787db96d56Sopenharmony_ci            previous_is_cased = 1;
2797db96d56Sopenharmony_ci            cased = 1;
2807db96d56Sopenharmony_ci        }
2817db96d56Sopenharmony_ci        else if (Py_ISLOWER(ch)) {
2827db96d56Sopenharmony_ci            if (!previous_is_cased)
2837db96d56Sopenharmony_ci                Py_RETURN_FALSE;
2847db96d56Sopenharmony_ci            previous_is_cased = 1;
2857db96d56Sopenharmony_ci            cased = 1;
2867db96d56Sopenharmony_ci        }
2877db96d56Sopenharmony_ci        else
2887db96d56Sopenharmony_ci            previous_is_cased = 0;
2897db96d56Sopenharmony_ci    }
2907db96d56Sopenharmony_ci    return PyBool_FromLong(cased);
2917db96d56Sopenharmony_ci}
2927db96d56Sopenharmony_ci
2937db96d56Sopenharmony_ci
2947db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_lower__doc__,
2957db96d56Sopenharmony_ci"B.lower() -> copy of B\n\
2967db96d56Sopenharmony_ci\n\
2977db96d56Sopenharmony_ciReturn a copy of B with all ASCII characters converted to lowercase.");
2987db96d56Sopenharmony_ci
2997db96d56Sopenharmony_civoid
3007db96d56Sopenharmony_ci_Py_bytes_lower(char *result, const char *cptr, Py_ssize_t len)
3017db96d56Sopenharmony_ci{
3027db96d56Sopenharmony_ci    Py_ssize_t i;
3037db96d56Sopenharmony_ci
3047db96d56Sopenharmony_ci    for (i = 0; i < len; i++) {
3057db96d56Sopenharmony_ci        result[i] = Py_TOLOWER((unsigned char) cptr[i]);
3067db96d56Sopenharmony_ci    }
3077db96d56Sopenharmony_ci}
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_ci
3107db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_upper__doc__,
3117db96d56Sopenharmony_ci"B.upper() -> copy of B\n\
3127db96d56Sopenharmony_ci\n\
3137db96d56Sopenharmony_ciReturn a copy of B with all ASCII characters converted to uppercase.");
3147db96d56Sopenharmony_ci
3157db96d56Sopenharmony_civoid
3167db96d56Sopenharmony_ci_Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len)
3177db96d56Sopenharmony_ci{
3187db96d56Sopenharmony_ci    Py_ssize_t i;
3197db96d56Sopenharmony_ci
3207db96d56Sopenharmony_ci    for (i = 0; i < len; i++) {
3217db96d56Sopenharmony_ci        result[i] = Py_TOUPPER((unsigned char) cptr[i]);
3227db96d56Sopenharmony_ci    }
3237db96d56Sopenharmony_ci}
3247db96d56Sopenharmony_ci
3257db96d56Sopenharmony_ci
3267db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_title__doc__,
3277db96d56Sopenharmony_ci"B.title() -> copy of B\n\
3287db96d56Sopenharmony_ci\n\
3297db96d56Sopenharmony_ciReturn a titlecased version of B, i.e. ASCII words start with uppercase\n\
3307db96d56Sopenharmony_cicharacters, all remaining cased characters have lowercase.");
3317db96d56Sopenharmony_ci
3327db96d56Sopenharmony_civoid
3337db96d56Sopenharmony_ci_Py_bytes_title(char *result, const char *s, Py_ssize_t len)
3347db96d56Sopenharmony_ci{
3357db96d56Sopenharmony_ci    Py_ssize_t i;
3367db96d56Sopenharmony_ci    int previous_is_cased = 0;
3377db96d56Sopenharmony_ci
3387db96d56Sopenharmony_ci    for (i = 0; i < len; i++) {
3397db96d56Sopenharmony_ci        int c = Py_CHARMASK(*s++);
3407db96d56Sopenharmony_ci        if (Py_ISLOWER(c)) {
3417db96d56Sopenharmony_ci            if (!previous_is_cased)
3427db96d56Sopenharmony_ci                c = Py_TOUPPER(c);
3437db96d56Sopenharmony_ci            previous_is_cased = 1;
3447db96d56Sopenharmony_ci        } else if (Py_ISUPPER(c)) {
3457db96d56Sopenharmony_ci            if (previous_is_cased)
3467db96d56Sopenharmony_ci                c = Py_TOLOWER(c);
3477db96d56Sopenharmony_ci            previous_is_cased = 1;
3487db96d56Sopenharmony_ci        } else
3497db96d56Sopenharmony_ci            previous_is_cased = 0;
3507db96d56Sopenharmony_ci        *result++ = c;
3517db96d56Sopenharmony_ci    }
3527db96d56Sopenharmony_ci}
3537db96d56Sopenharmony_ci
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_capitalize__doc__,
3567db96d56Sopenharmony_ci"B.capitalize() -> copy of B\n\
3577db96d56Sopenharmony_ci\n\
3587db96d56Sopenharmony_ciReturn a copy of B with only its first character capitalized (ASCII)\n\
3597db96d56Sopenharmony_ciand the rest lower-cased.");
3607db96d56Sopenharmony_ci
3617db96d56Sopenharmony_civoid
3627db96d56Sopenharmony_ci_Py_bytes_capitalize(char *result, const char *s, Py_ssize_t len)
3637db96d56Sopenharmony_ci{
3647db96d56Sopenharmony_ci    if (len > 0) {
3657db96d56Sopenharmony_ci        *result = Py_TOUPPER(*s);
3667db96d56Sopenharmony_ci        _Py_bytes_lower(result + 1, s + 1, len - 1);
3677db96d56Sopenharmony_ci    }
3687db96d56Sopenharmony_ci}
3697db96d56Sopenharmony_ci
3707db96d56Sopenharmony_ci
3717db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_swapcase__doc__,
3727db96d56Sopenharmony_ci"B.swapcase() -> copy of B\n\
3737db96d56Sopenharmony_ci\n\
3747db96d56Sopenharmony_ciReturn a copy of B with uppercase ASCII characters converted\n\
3757db96d56Sopenharmony_cito lowercase ASCII and vice versa.");
3767db96d56Sopenharmony_ci
3777db96d56Sopenharmony_civoid
3787db96d56Sopenharmony_ci_Py_bytes_swapcase(char *result, const char *s, Py_ssize_t len)
3797db96d56Sopenharmony_ci{
3807db96d56Sopenharmony_ci    Py_ssize_t i;
3817db96d56Sopenharmony_ci
3827db96d56Sopenharmony_ci    for (i = 0; i < len; i++) {
3837db96d56Sopenharmony_ci        int c = Py_CHARMASK(*s++);
3847db96d56Sopenharmony_ci        if (Py_ISLOWER(c)) {
3857db96d56Sopenharmony_ci            *result = Py_TOUPPER(c);
3867db96d56Sopenharmony_ci        }
3877db96d56Sopenharmony_ci        else if (Py_ISUPPER(c)) {
3887db96d56Sopenharmony_ci            *result = Py_TOLOWER(c);
3897db96d56Sopenharmony_ci        }
3907db96d56Sopenharmony_ci        else
3917db96d56Sopenharmony_ci            *result = c;
3927db96d56Sopenharmony_ci        result++;
3937db96d56Sopenharmony_ci    }
3947db96d56Sopenharmony_ci}
3957db96d56Sopenharmony_ci
3967db96d56Sopenharmony_ci
3977db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_maketrans__doc__,
3987db96d56Sopenharmony_ci"B.maketrans(frm, to) -> translation table\n\
3997db96d56Sopenharmony_ci\n\
4007db96d56Sopenharmony_ciReturn a translation table (a bytes object of length 256) suitable\n\
4017db96d56Sopenharmony_cifor use in the bytes or bytearray translate method where each byte\n\
4027db96d56Sopenharmony_ciin frm is mapped to the byte at the same position in to.\n\
4037db96d56Sopenharmony_ciThe bytes objects frm and to must be of the same length.");
4047db96d56Sopenharmony_ci
4057db96d56Sopenharmony_ciPyObject *
4067db96d56Sopenharmony_ci_Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to)
4077db96d56Sopenharmony_ci{
4087db96d56Sopenharmony_ci    PyObject *res = NULL;
4097db96d56Sopenharmony_ci    Py_ssize_t i;
4107db96d56Sopenharmony_ci    char *p;
4117db96d56Sopenharmony_ci
4127db96d56Sopenharmony_ci    if (frm->len != to->len) {
4137db96d56Sopenharmony_ci        PyErr_Format(PyExc_ValueError,
4147db96d56Sopenharmony_ci                     "maketrans arguments must have same length");
4157db96d56Sopenharmony_ci        return NULL;
4167db96d56Sopenharmony_ci    }
4177db96d56Sopenharmony_ci    res = PyBytes_FromStringAndSize(NULL, 256);
4187db96d56Sopenharmony_ci    if (!res)
4197db96d56Sopenharmony_ci        return NULL;
4207db96d56Sopenharmony_ci    p = PyBytes_AS_STRING(res);
4217db96d56Sopenharmony_ci    for (i = 0; i < 256; i++)
4227db96d56Sopenharmony_ci        p[i] = (char) i;
4237db96d56Sopenharmony_ci    for (i = 0; i < frm->len; i++) {
4247db96d56Sopenharmony_ci        p[((unsigned char *)frm->buf)[i]] = ((char *)to->buf)[i];
4257db96d56Sopenharmony_ci    }
4267db96d56Sopenharmony_ci
4277db96d56Sopenharmony_ci    return res;
4287db96d56Sopenharmony_ci}
4297db96d56Sopenharmony_ci
4307db96d56Sopenharmony_ci#define FASTSEARCH fastsearch
4317db96d56Sopenharmony_ci#define STRINGLIB(F) stringlib_##F
4327db96d56Sopenharmony_ci#define STRINGLIB_CHAR char
4337db96d56Sopenharmony_ci#define STRINGLIB_SIZEOF_CHAR 1
4347db96d56Sopenharmony_ci
4357db96d56Sopenharmony_ci#include "stringlib/fastsearch.h"
4367db96d56Sopenharmony_ci#include "stringlib/count.h"
4377db96d56Sopenharmony_ci#include "stringlib/find.h"
4387db96d56Sopenharmony_ci
4397db96d56Sopenharmony_ci/*
4407db96d56Sopenharmony_ciWraps stringlib_parse_args_finds() and additionally checks the first
4417db96d56Sopenharmony_ciargument type.
4427db96d56Sopenharmony_ci
4437db96d56Sopenharmony_ciIn case the first argument is a bytes-like object, sets it to subobj,
4447db96d56Sopenharmony_ciand doesn't touch the byte parameter.
4457db96d56Sopenharmony_ciIn case it is an integer in range(0, 256), writes the integer value
4467db96d56Sopenharmony_cito byte, and sets subobj to NULL.
4477db96d56Sopenharmony_ci
4487db96d56Sopenharmony_ciThe other parameters are similar to those of
4497db96d56Sopenharmony_cistringlib_parse_args_finds().
4507db96d56Sopenharmony_ci*/
4517db96d56Sopenharmony_ci
4527db96d56Sopenharmony_ciPy_LOCAL_INLINE(int)
4537db96d56Sopenharmony_ciparse_args_finds_byte(const char *function_name, PyObject *args,
4547db96d56Sopenharmony_ci                      PyObject **subobj, char *byte,
4557db96d56Sopenharmony_ci                      Py_ssize_t *start, Py_ssize_t *end)
4567db96d56Sopenharmony_ci{
4577db96d56Sopenharmony_ci    PyObject *tmp_subobj;
4587db96d56Sopenharmony_ci    Py_ssize_t ival;
4597db96d56Sopenharmony_ci
4607db96d56Sopenharmony_ci    if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj,
4617db96d56Sopenharmony_ci                                   start, end))
4627db96d56Sopenharmony_ci        return 0;
4637db96d56Sopenharmony_ci
4647db96d56Sopenharmony_ci    if (PyObject_CheckBuffer(tmp_subobj)) {
4657db96d56Sopenharmony_ci        *subobj = tmp_subobj;
4667db96d56Sopenharmony_ci        return 1;
4677db96d56Sopenharmony_ci    }
4687db96d56Sopenharmony_ci
4697db96d56Sopenharmony_ci    if (!_PyIndex_Check(tmp_subobj)) {
4707db96d56Sopenharmony_ci        PyErr_Format(PyExc_TypeError,
4717db96d56Sopenharmony_ci                     "argument should be integer or bytes-like object, "
4727db96d56Sopenharmony_ci                     "not '%.200s'",
4737db96d56Sopenharmony_ci                     Py_TYPE(tmp_subobj)->tp_name);
4747db96d56Sopenharmony_ci        return 0;
4757db96d56Sopenharmony_ci    }
4767db96d56Sopenharmony_ci
4777db96d56Sopenharmony_ci    ival = PyNumber_AsSsize_t(tmp_subobj, NULL);
4787db96d56Sopenharmony_ci    if (ival == -1 && PyErr_Occurred()) {
4797db96d56Sopenharmony_ci        return 0;
4807db96d56Sopenharmony_ci    }
4817db96d56Sopenharmony_ci    if (ival < 0 || ival > 255) {
4827db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
4837db96d56Sopenharmony_ci        return 0;
4847db96d56Sopenharmony_ci    }
4857db96d56Sopenharmony_ci
4867db96d56Sopenharmony_ci    *subobj = NULL;
4877db96d56Sopenharmony_ci    *byte = (char)ival;
4887db96d56Sopenharmony_ci    return 1;
4897db96d56Sopenharmony_ci}
4907db96d56Sopenharmony_ci
4917db96d56Sopenharmony_ci/* helper macro to fixup start/end slice values */
4927db96d56Sopenharmony_ci#define ADJUST_INDICES(start, end, len)         \
4937db96d56Sopenharmony_ci    if (end > len)                          \
4947db96d56Sopenharmony_ci        end = len;                          \
4957db96d56Sopenharmony_ci    else if (end < 0) {                     \
4967db96d56Sopenharmony_ci        end += len;                         \
4977db96d56Sopenharmony_ci        if (end < 0)                        \
4987db96d56Sopenharmony_ci        end = 0;                        \
4997db96d56Sopenharmony_ci    }                                       \
5007db96d56Sopenharmony_ci    if (start < 0) {                        \
5017db96d56Sopenharmony_ci        start += len;                       \
5027db96d56Sopenharmony_ci        if (start < 0)                      \
5037db96d56Sopenharmony_ci        start = 0;                      \
5047db96d56Sopenharmony_ci    }
5057db96d56Sopenharmony_ci
5067db96d56Sopenharmony_ciPy_LOCAL_INLINE(Py_ssize_t)
5077db96d56Sopenharmony_cifind_internal(const char *str, Py_ssize_t len,
5087db96d56Sopenharmony_ci              const char *function_name, PyObject *args, int dir)
5097db96d56Sopenharmony_ci{
5107db96d56Sopenharmony_ci    PyObject *subobj;
5117db96d56Sopenharmony_ci    char byte;
5127db96d56Sopenharmony_ci    Py_buffer subbuf;
5137db96d56Sopenharmony_ci    const char *sub;
5147db96d56Sopenharmony_ci    Py_ssize_t sub_len;
5157db96d56Sopenharmony_ci    Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
5167db96d56Sopenharmony_ci    Py_ssize_t res;
5177db96d56Sopenharmony_ci
5187db96d56Sopenharmony_ci    if (!parse_args_finds_byte(function_name, args,
5197db96d56Sopenharmony_ci                               &subobj, &byte, &start, &end))
5207db96d56Sopenharmony_ci        return -2;
5217db96d56Sopenharmony_ci
5227db96d56Sopenharmony_ci    if (subobj) {
5237db96d56Sopenharmony_ci        if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
5247db96d56Sopenharmony_ci            return -2;
5257db96d56Sopenharmony_ci
5267db96d56Sopenharmony_ci        sub = subbuf.buf;
5277db96d56Sopenharmony_ci        sub_len = subbuf.len;
5287db96d56Sopenharmony_ci    }
5297db96d56Sopenharmony_ci    else {
5307db96d56Sopenharmony_ci        sub = &byte;
5317db96d56Sopenharmony_ci        sub_len = 1;
5327db96d56Sopenharmony_ci    }
5337db96d56Sopenharmony_ci
5347db96d56Sopenharmony_ci    ADJUST_INDICES(start, end, len);
5357db96d56Sopenharmony_ci    if (end - start < sub_len)
5367db96d56Sopenharmony_ci        res = -1;
5377db96d56Sopenharmony_ci    else if (sub_len == 1) {
5387db96d56Sopenharmony_ci        if (dir > 0)
5397db96d56Sopenharmony_ci            res = stringlib_find_char(
5407db96d56Sopenharmony_ci                str + start, end - start,
5417db96d56Sopenharmony_ci                *sub);
5427db96d56Sopenharmony_ci        else
5437db96d56Sopenharmony_ci            res = stringlib_rfind_char(
5447db96d56Sopenharmony_ci                str + start, end - start,
5457db96d56Sopenharmony_ci                *sub);
5467db96d56Sopenharmony_ci        if (res >= 0)
5477db96d56Sopenharmony_ci            res += start;
5487db96d56Sopenharmony_ci    }
5497db96d56Sopenharmony_ci    else {
5507db96d56Sopenharmony_ci        if (dir > 0)
5517db96d56Sopenharmony_ci            res = stringlib_find_slice(
5527db96d56Sopenharmony_ci                str, len,
5537db96d56Sopenharmony_ci                sub, sub_len, start, end);
5547db96d56Sopenharmony_ci        else
5557db96d56Sopenharmony_ci            res = stringlib_rfind_slice(
5567db96d56Sopenharmony_ci                str, len,
5577db96d56Sopenharmony_ci                sub, sub_len, start, end);
5587db96d56Sopenharmony_ci    }
5597db96d56Sopenharmony_ci
5607db96d56Sopenharmony_ci    if (subobj)
5617db96d56Sopenharmony_ci        PyBuffer_Release(&subbuf);
5627db96d56Sopenharmony_ci
5637db96d56Sopenharmony_ci    return res;
5647db96d56Sopenharmony_ci}
5657db96d56Sopenharmony_ci
5667db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_find__doc__,
5677db96d56Sopenharmony_ci"B.find(sub[, start[, end]]) -> int\n\
5687db96d56Sopenharmony_ci\n\
5697db96d56Sopenharmony_ciReturn the lowest index in B where subsection sub is found,\n\
5707db96d56Sopenharmony_cisuch that sub is contained within B[start,end].  Optional\n\
5717db96d56Sopenharmony_ciarguments start and end are interpreted as in slice notation.\n\
5727db96d56Sopenharmony_ci\n\
5737db96d56Sopenharmony_ciReturn -1 on failure.");
5747db96d56Sopenharmony_ci
5757db96d56Sopenharmony_ciPyObject *
5767db96d56Sopenharmony_ci_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args)
5777db96d56Sopenharmony_ci{
5787db96d56Sopenharmony_ci    Py_ssize_t result = find_internal(str, len, "find", args, +1);
5797db96d56Sopenharmony_ci    if (result == -2)
5807db96d56Sopenharmony_ci        return NULL;
5817db96d56Sopenharmony_ci    return PyLong_FromSsize_t(result);
5827db96d56Sopenharmony_ci}
5837db96d56Sopenharmony_ci
5847db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_index__doc__,
5857db96d56Sopenharmony_ci"B.index(sub[, start[, end]]) -> int\n\
5867db96d56Sopenharmony_ci\n\
5877db96d56Sopenharmony_ciReturn the lowest index in B where subsection sub is found,\n\
5887db96d56Sopenharmony_cisuch that sub is contained within B[start,end].  Optional\n\
5897db96d56Sopenharmony_ciarguments start and end are interpreted as in slice notation.\n\
5907db96d56Sopenharmony_ci\n\
5917db96d56Sopenharmony_ciRaises ValueError when the subsection is not found.");
5927db96d56Sopenharmony_ci
5937db96d56Sopenharmony_ciPyObject *
5947db96d56Sopenharmony_ci_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
5957db96d56Sopenharmony_ci{
5967db96d56Sopenharmony_ci    Py_ssize_t result = find_internal(str, len, "index", args, +1);
5977db96d56Sopenharmony_ci    if (result == -2)
5987db96d56Sopenharmony_ci        return NULL;
5997db96d56Sopenharmony_ci    if (result == -1) {
6007db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
6017db96d56Sopenharmony_ci                        "subsection not found");
6027db96d56Sopenharmony_ci        return NULL;
6037db96d56Sopenharmony_ci    }
6047db96d56Sopenharmony_ci    return PyLong_FromSsize_t(result);
6057db96d56Sopenharmony_ci}
6067db96d56Sopenharmony_ci
6077db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_rfind__doc__,
6087db96d56Sopenharmony_ci"B.rfind(sub[, start[, end]]) -> int\n\
6097db96d56Sopenharmony_ci\n\
6107db96d56Sopenharmony_ciReturn the highest index in B where subsection sub is found,\n\
6117db96d56Sopenharmony_cisuch that sub is contained within B[start,end].  Optional\n\
6127db96d56Sopenharmony_ciarguments start and end are interpreted as in slice notation.\n\
6137db96d56Sopenharmony_ci\n\
6147db96d56Sopenharmony_ciReturn -1 on failure.");
6157db96d56Sopenharmony_ci
6167db96d56Sopenharmony_ciPyObject *
6177db96d56Sopenharmony_ci_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args)
6187db96d56Sopenharmony_ci{
6197db96d56Sopenharmony_ci    Py_ssize_t result = find_internal(str, len, "rfind", args, -1);
6207db96d56Sopenharmony_ci    if (result == -2)
6217db96d56Sopenharmony_ci        return NULL;
6227db96d56Sopenharmony_ci    return PyLong_FromSsize_t(result);
6237db96d56Sopenharmony_ci}
6247db96d56Sopenharmony_ci
6257db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_rindex__doc__,
6267db96d56Sopenharmony_ci"B.rindex(sub[, start[, end]]) -> int\n\
6277db96d56Sopenharmony_ci\n\
6287db96d56Sopenharmony_ciReturn the highest index in B where subsection sub is found,\n\
6297db96d56Sopenharmony_cisuch that sub is contained within B[start,end].  Optional\n\
6307db96d56Sopenharmony_ciarguments start and end are interpreted as in slice notation.\n\
6317db96d56Sopenharmony_ci\n\
6327db96d56Sopenharmony_ciRaise ValueError when the subsection is not found.");
6337db96d56Sopenharmony_ci
6347db96d56Sopenharmony_ciPyObject *
6357db96d56Sopenharmony_ci_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
6367db96d56Sopenharmony_ci{
6377db96d56Sopenharmony_ci    Py_ssize_t result = find_internal(str, len, "rindex", args, -1);
6387db96d56Sopenharmony_ci    if (result == -2)
6397db96d56Sopenharmony_ci        return NULL;
6407db96d56Sopenharmony_ci    if (result == -1) {
6417db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError,
6427db96d56Sopenharmony_ci                        "subsection not found");
6437db96d56Sopenharmony_ci        return NULL;
6447db96d56Sopenharmony_ci    }
6457db96d56Sopenharmony_ci    return PyLong_FromSsize_t(result);
6467db96d56Sopenharmony_ci}
6477db96d56Sopenharmony_ci
6487db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_count__doc__,
6497db96d56Sopenharmony_ci"B.count(sub[, start[, end]]) -> int\n\
6507db96d56Sopenharmony_ci\n\
6517db96d56Sopenharmony_ciReturn the number of non-overlapping occurrences of subsection sub in\n\
6527db96d56Sopenharmony_cibytes B[start:end].  Optional arguments start and end are interpreted\n\
6537db96d56Sopenharmony_cias in slice notation.");
6547db96d56Sopenharmony_ci
6557db96d56Sopenharmony_ciPyObject *
6567db96d56Sopenharmony_ci_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args)
6577db96d56Sopenharmony_ci{
6587db96d56Sopenharmony_ci    PyObject *sub_obj;
6597db96d56Sopenharmony_ci    const char *sub;
6607db96d56Sopenharmony_ci    Py_ssize_t sub_len;
6617db96d56Sopenharmony_ci    char byte;
6627db96d56Sopenharmony_ci    Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
6637db96d56Sopenharmony_ci
6647db96d56Sopenharmony_ci    Py_buffer vsub;
6657db96d56Sopenharmony_ci    PyObject *count_obj;
6667db96d56Sopenharmony_ci
6677db96d56Sopenharmony_ci    if (!parse_args_finds_byte("count", args,
6687db96d56Sopenharmony_ci                               &sub_obj, &byte, &start, &end))
6697db96d56Sopenharmony_ci        return NULL;
6707db96d56Sopenharmony_ci
6717db96d56Sopenharmony_ci    if (sub_obj) {
6727db96d56Sopenharmony_ci        if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
6737db96d56Sopenharmony_ci            return NULL;
6747db96d56Sopenharmony_ci
6757db96d56Sopenharmony_ci        sub = vsub.buf;
6767db96d56Sopenharmony_ci        sub_len = vsub.len;
6777db96d56Sopenharmony_ci    }
6787db96d56Sopenharmony_ci    else {
6797db96d56Sopenharmony_ci        sub = &byte;
6807db96d56Sopenharmony_ci        sub_len = 1;
6817db96d56Sopenharmony_ci    }
6827db96d56Sopenharmony_ci
6837db96d56Sopenharmony_ci    ADJUST_INDICES(start, end, len);
6847db96d56Sopenharmony_ci
6857db96d56Sopenharmony_ci    count_obj = PyLong_FromSsize_t(
6867db96d56Sopenharmony_ci        stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX)
6877db96d56Sopenharmony_ci        );
6887db96d56Sopenharmony_ci
6897db96d56Sopenharmony_ci    if (sub_obj)
6907db96d56Sopenharmony_ci        PyBuffer_Release(&vsub);
6917db96d56Sopenharmony_ci
6927db96d56Sopenharmony_ci    return count_obj;
6937db96d56Sopenharmony_ci}
6947db96d56Sopenharmony_ci
6957db96d56Sopenharmony_ciint
6967db96d56Sopenharmony_ci_Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg)
6977db96d56Sopenharmony_ci{
6987db96d56Sopenharmony_ci    Py_ssize_t ival = PyNumber_AsSsize_t(arg, NULL);
6997db96d56Sopenharmony_ci    if (ival == -1 && PyErr_Occurred()) {
7007db96d56Sopenharmony_ci        Py_buffer varg;
7017db96d56Sopenharmony_ci        Py_ssize_t pos;
7027db96d56Sopenharmony_ci        PyErr_Clear();
7037db96d56Sopenharmony_ci        if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
7047db96d56Sopenharmony_ci            return -1;
7057db96d56Sopenharmony_ci        pos = stringlib_find(str, len,
7067db96d56Sopenharmony_ci                             varg.buf, varg.len, 0);
7077db96d56Sopenharmony_ci        PyBuffer_Release(&varg);
7087db96d56Sopenharmony_ci        return pos >= 0;
7097db96d56Sopenharmony_ci    }
7107db96d56Sopenharmony_ci    if (ival < 0 || ival >= 256) {
7117db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
7127db96d56Sopenharmony_ci        return -1;
7137db96d56Sopenharmony_ci    }
7147db96d56Sopenharmony_ci
7157db96d56Sopenharmony_ci    return memchr(str, (int) ival, len) != NULL;
7167db96d56Sopenharmony_ci}
7177db96d56Sopenharmony_ci
7187db96d56Sopenharmony_ci
7197db96d56Sopenharmony_ci/* Matches the end (direction >= 0) or start (direction < 0) of the buffer
7207db96d56Sopenharmony_ci * against substr, using the start and end arguments. Returns
7217db96d56Sopenharmony_ci * -1 on error, 0 if not found and 1 if found.
7227db96d56Sopenharmony_ci */
7237db96d56Sopenharmony_cistatic int
7247db96d56Sopenharmony_citailmatch(const char *str, Py_ssize_t len, PyObject *substr,
7257db96d56Sopenharmony_ci          Py_ssize_t start, Py_ssize_t end, int direction)
7267db96d56Sopenharmony_ci{
7277db96d56Sopenharmony_ci    Py_buffer sub_view = {NULL, NULL};
7287db96d56Sopenharmony_ci    const char *sub;
7297db96d56Sopenharmony_ci    Py_ssize_t slen;
7307db96d56Sopenharmony_ci
7317db96d56Sopenharmony_ci    if (PyBytes_Check(substr)) {
7327db96d56Sopenharmony_ci        sub = PyBytes_AS_STRING(substr);
7337db96d56Sopenharmony_ci        slen = PyBytes_GET_SIZE(substr);
7347db96d56Sopenharmony_ci    }
7357db96d56Sopenharmony_ci    else {
7367db96d56Sopenharmony_ci        if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
7377db96d56Sopenharmony_ci            return -1;
7387db96d56Sopenharmony_ci        sub = sub_view.buf;
7397db96d56Sopenharmony_ci        slen = sub_view.len;
7407db96d56Sopenharmony_ci    }
7417db96d56Sopenharmony_ci
7427db96d56Sopenharmony_ci    ADJUST_INDICES(start, end, len);
7437db96d56Sopenharmony_ci
7447db96d56Sopenharmony_ci    if (direction < 0) {
7457db96d56Sopenharmony_ci        /* startswith */
7467db96d56Sopenharmony_ci        if (start > len - slen)
7477db96d56Sopenharmony_ci            goto notfound;
7487db96d56Sopenharmony_ci    } else {
7497db96d56Sopenharmony_ci        /* endswith */
7507db96d56Sopenharmony_ci        if (end - start < slen || start > len)
7517db96d56Sopenharmony_ci            goto notfound;
7527db96d56Sopenharmony_ci
7537db96d56Sopenharmony_ci        if (end - slen > start)
7547db96d56Sopenharmony_ci            start = end - slen;
7557db96d56Sopenharmony_ci    }
7567db96d56Sopenharmony_ci    if (end - start < slen)
7577db96d56Sopenharmony_ci        goto notfound;
7587db96d56Sopenharmony_ci    if (memcmp(str + start, sub, slen) != 0)
7597db96d56Sopenharmony_ci        goto notfound;
7607db96d56Sopenharmony_ci
7617db96d56Sopenharmony_ci    PyBuffer_Release(&sub_view);
7627db96d56Sopenharmony_ci    return 1;
7637db96d56Sopenharmony_ci
7647db96d56Sopenharmony_cinotfound:
7657db96d56Sopenharmony_ci    PyBuffer_Release(&sub_view);
7667db96d56Sopenharmony_ci    return 0;
7677db96d56Sopenharmony_ci}
7687db96d56Sopenharmony_ci
7697db96d56Sopenharmony_cistatic PyObject *
7707db96d56Sopenharmony_ci_Py_bytes_tailmatch(const char *str, Py_ssize_t len,
7717db96d56Sopenharmony_ci                    const char *function_name, PyObject *args,
7727db96d56Sopenharmony_ci                    int direction)
7737db96d56Sopenharmony_ci{
7747db96d56Sopenharmony_ci    Py_ssize_t start = 0;
7757db96d56Sopenharmony_ci    Py_ssize_t end = PY_SSIZE_T_MAX;
7767db96d56Sopenharmony_ci    PyObject *subobj;
7777db96d56Sopenharmony_ci    int result;
7787db96d56Sopenharmony_ci
7797db96d56Sopenharmony_ci    if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end))
7807db96d56Sopenharmony_ci        return NULL;
7817db96d56Sopenharmony_ci    if (PyTuple_Check(subobj)) {
7827db96d56Sopenharmony_ci        Py_ssize_t i;
7837db96d56Sopenharmony_ci        for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
7847db96d56Sopenharmony_ci            result = tailmatch(str, len, PyTuple_GET_ITEM(subobj, i),
7857db96d56Sopenharmony_ci                               start, end, direction);
7867db96d56Sopenharmony_ci            if (result == -1)
7877db96d56Sopenharmony_ci                return NULL;
7887db96d56Sopenharmony_ci            else if (result) {
7897db96d56Sopenharmony_ci                Py_RETURN_TRUE;
7907db96d56Sopenharmony_ci            }
7917db96d56Sopenharmony_ci        }
7927db96d56Sopenharmony_ci        Py_RETURN_FALSE;
7937db96d56Sopenharmony_ci    }
7947db96d56Sopenharmony_ci    result = tailmatch(str, len, subobj, start, end, direction);
7957db96d56Sopenharmony_ci    if (result == -1) {
7967db96d56Sopenharmony_ci        if (PyErr_ExceptionMatches(PyExc_TypeError))
7977db96d56Sopenharmony_ci            PyErr_Format(PyExc_TypeError,
7987db96d56Sopenharmony_ci                         "%s first arg must be bytes or a tuple of bytes, "
7997db96d56Sopenharmony_ci                         "not %s",
8007db96d56Sopenharmony_ci                         function_name, Py_TYPE(subobj)->tp_name);
8017db96d56Sopenharmony_ci        return NULL;
8027db96d56Sopenharmony_ci    }
8037db96d56Sopenharmony_ci    else
8047db96d56Sopenharmony_ci        return PyBool_FromLong(result);
8057db96d56Sopenharmony_ci}
8067db96d56Sopenharmony_ci
8077db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_startswith__doc__,
8087db96d56Sopenharmony_ci"B.startswith(prefix[, start[, end]]) -> bool\n\
8097db96d56Sopenharmony_ci\n\
8107db96d56Sopenharmony_ciReturn True if B starts with the specified prefix, False otherwise.\n\
8117db96d56Sopenharmony_ciWith optional start, test B beginning at that position.\n\
8127db96d56Sopenharmony_ciWith optional end, stop comparing B at that position.\n\
8137db96d56Sopenharmony_ciprefix can also be a tuple of bytes to try.");
8147db96d56Sopenharmony_ci
8157db96d56Sopenharmony_ciPyObject *
8167db96d56Sopenharmony_ci_Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args)
8177db96d56Sopenharmony_ci{
8187db96d56Sopenharmony_ci    return _Py_bytes_tailmatch(str, len, "startswith", args, -1);
8197db96d56Sopenharmony_ci}
8207db96d56Sopenharmony_ci
8217db96d56Sopenharmony_ciPyDoc_STRVAR_shared(_Py_endswith__doc__,
8227db96d56Sopenharmony_ci"B.endswith(suffix[, start[, end]]) -> bool\n\
8237db96d56Sopenharmony_ci\n\
8247db96d56Sopenharmony_ciReturn True if B ends with the specified suffix, False otherwise.\n\
8257db96d56Sopenharmony_ciWith optional start, test B beginning at that position.\n\
8267db96d56Sopenharmony_ciWith optional end, stop comparing B at that position.\n\
8277db96d56Sopenharmony_cisuffix can also be a tuple of bytes to try.");
8287db96d56Sopenharmony_ci
8297db96d56Sopenharmony_ciPyObject *
8307db96d56Sopenharmony_ci_Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args)
8317db96d56Sopenharmony_ci{
8327db96d56Sopenharmony_ci    return _Py_bytes_tailmatch(str, len, "endswith", args, +1);
8337db96d56Sopenharmony_ci}
834