123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837 |
- #define PY_SSIZE_T_CLEAN
- #include "Python.h"
- #include "pycore_abstract.h" // _PyIndex_Check()
- #include "pycore_bytes_methods.h"
- PyDoc_STRVAR_shared(_Py_isspace__doc__,
- "B.isspace() -> bool\n\
- \n\
- Return True if all characters in B are whitespace\n\
- and there is at least one character in B, False otherwise.");
- PyObject*
- _Py_bytes_isspace(const char *cptr, Py_ssize_t len)
- {
- const unsigned char *p
- = (const unsigned char *) cptr;
- const unsigned char *e;
- /* Shortcut for single character strings */
- if (len == 1 && Py_ISSPACE(*p))
- Py_RETURN_TRUE;
- /* Special case for empty strings */
- if (len == 0)
- Py_RETURN_FALSE;
- e = p + len;
- for (; p < e; p++) {
- if (!Py_ISSPACE(*p))
- Py_RETURN_FALSE;
- }
- Py_RETURN_TRUE;
- }
- PyDoc_STRVAR_shared(_Py_isalpha__doc__,
- "B.isalpha() -> bool\n\
- \n\
- Return True if all characters in B are alphabetic\n\
- and there is at least one character in B, False otherwise.");
- PyObject*
- _Py_bytes_isalpha(const char *cptr, Py_ssize_t len)
- {
- const unsigned char *p
- = (const unsigned char *) cptr;
- const unsigned char *e;
- /* Shortcut for single character strings */
- if (len == 1 && Py_ISALPHA(*p))
- Py_RETURN_TRUE;
- /* Special case for empty strings */
- if (len == 0)
- Py_RETURN_FALSE;
- e = p + len;
- for (; p < e; p++) {
- if (!Py_ISALPHA(*p))
- Py_RETURN_FALSE;
- }
- Py_RETURN_TRUE;
- }
- PyDoc_STRVAR_shared(_Py_isalnum__doc__,
- "B.isalnum() -> bool\n\
- \n\
- Return True if all characters in B are alphanumeric\n\
- and there is at least one character in B, False otherwise.");
- PyObject*
- _Py_bytes_isalnum(const char *cptr, Py_ssize_t len)
- {
- const unsigned char *p
- = (const unsigned char *) cptr;
- const unsigned char *e;
- /* Shortcut for single character strings */
- if (len == 1 && Py_ISALNUM(*p))
- Py_RETURN_TRUE;
- /* Special case for empty strings */
- if (len == 0)
- Py_RETURN_FALSE;
- e = p + len;
- for (; p < e; p++) {
- if (!Py_ISALNUM(*p))
- Py_RETURN_FALSE;
- }
- Py_RETURN_TRUE;
- }
- PyDoc_STRVAR_shared(_Py_isascii__doc__,
- "B.isascii() -> bool\n\
- \n\
- Return True if B is empty or all characters in B are ASCII,\n\
- False otherwise.");
- // Optimization is copied from ascii_decode in unicodeobject.c
- /* Mask to quickly check whether a C 'size_t' contains a
- non-ASCII, UTF8-encoded char. */
- #if (SIZEOF_SIZE_T == 8)
- # define ASCII_CHAR_MASK 0x8080808080808080ULL
- #elif (SIZEOF_SIZE_T == 4)
- # define ASCII_CHAR_MASK 0x80808080U
- #else
- # error C 'size_t' size should be either 4 or 8!
- #endif
- PyObject*
- _Py_bytes_isascii(const char *cptr, Py_ssize_t len)
- {
- const char *p = cptr;
- const char *end = p + len;
- while (p < end) {
- /* Fast path, see in STRINGLIB(utf8_decode) in stringlib/codecs.h
- for an explanation. */
- if (_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) {
- /* Help allocation */
- const char *_p = p;
- while (_p + SIZEOF_SIZE_T <= end) {
- size_t value = *(const size_t *) _p;
- if (value & ASCII_CHAR_MASK) {
- Py_RETURN_FALSE;
- }
- _p += SIZEOF_SIZE_T;
- }
- p = _p;
- if (_p == end)
- break;
- }
- if ((unsigned char)*p & 0x80) {
- Py_RETURN_FALSE;
- }
- p++;
- }
- Py_RETURN_TRUE;
- }
- #undef ASCII_CHAR_MASK
- PyDoc_STRVAR_shared(_Py_isdigit__doc__,
- "B.isdigit() -> bool\n\
- \n\
- Return True if all characters in B are digits\n\
- and there is at least one character in B, False otherwise.");
- PyObject*
- _Py_bytes_isdigit(const char *cptr, Py_ssize_t len)
- {
- const unsigned char *p
- = (const unsigned char *) cptr;
- const unsigned char *e;
- /* Shortcut for single character strings */
- if (len == 1 && Py_ISDIGIT(*p))
- Py_RETURN_TRUE;
- /* Special case for empty strings */
- if (len == 0)
- Py_RETURN_FALSE;
- e = p + len;
- for (; p < e; p++) {
- if (!Py_ISDIGIT(*p))
- Py_RETURN_FALSE;
- }
- Py_RETURN_TRUE;
- }
- PyDoc_STRVAR_shared(_Py_islower__doc__,
- "B.islower() -> bool\n\
- \n\
- Return True if all cased characters in B are lowercase and there is\n\
- at least one cased character in B, False otherwise.");
- PyObject*
- _Py_bytes_islower(const char *cptr, Py_ssize_t len)
- {
- const unsigned char *p
- = (const unsigned char *) cptr;
- const unsigned char *e;
- int cased;
- /* Shortcut for single character strings */
- if (len == 1)
- return PyBool_FromLong(Py_ISLOWER(*p));
- /* Special case for empty strings */
- if (len == 0)
- Py_RETURN_FALSE;
- e = p + len;
- cased = 0;
- for (; p < e; p++) {
- if (Py_ISUPPER(*p))
- Py_RETURN_FALSE;
- else if (!cased && Py_ISLOWER(*p))
- cased = 1;
- }
- return PyBool_FromLong(cased);
- }
- PyDoc_STRVAR_shared(_Py_isupper__doc__,
- "B.isupper() -> bool\n\
- \n\
- Return True if all cased characters in B are uppercase and there is\n\
- at least one cased character in B, False otherwise.");
- PyObject*
- _Py_bytes_isupper(const char *cptr, Py_ssize_t len)
- {
- const unsigned char *p
- = (const unsigned char *) cptr;
- const unsigned char *e;
- int cased;
- /* Shortcut for single character strings */
- if (len == 1)
- return PyBool_FromLong(Py_ISUPPER(*p));
- /* Special case for empty strings */
- if (len == 0)
- Py_RETURN_FALSE;
- e = p + len;
- cased = 0;
- for (; p < e; p++) {
- if (Py_ISLOWER(*p))
- Py_RETURN_FALSE;
- else if (!cased && Py_ISUPPER(*p))
- cased = 1;
- }
- return PyBool_FromLong(cased);
- }
- PyDoc_STRVAR_shared(_Py_istitle__doc__,
- "B.istitle() -> bool\n\
- \n\
- Return True if B is a titlecased string and there is at least one\n\
- character in B, i.e. uppercase characters may only follow uncased\n\
- characters and lowercase characters only cased ones. Return False\n\
- otherwise.");
- PyObject*
- _Py_bytes_istitle(const char *cptr, Py_ssize_t len)
- {
- const unsigned char *p
- = (const unsigned char *) cptr;
- const unsigned char *e;
- int cased, previous_is_cased;
- if (len == 1) {
- if (Py_ISUPPER(*p)) {
- Py_RETURN_TRUE;
- }
- Py_RETURN_FALSE;
- }
- /* Special case for empty strings */
- if (len == 0)
- Py_RETURN_FALSE;
- e = p + len;
- cased = 0;
- previous_is_cased = 0;
- for (; p < e; p++) {
- const unsigned char ch = *p;
- if (Py_ISUPPER(ch)) {
- if (previous_is_cased)
- Py_RETURN_FALSE;
- previous_is_cased = 1;
- cased = 1;
- }
- else if (Py_ISLOWER(ch)) {
- if (!previous_is_cased)
- Py_RETURN_FALSE;
- previous_is_cased = 1;
- cased = 1;
- }
- else
- previous_is_cased = 0;
- }
- return PyBool_FromLong(cased);
- }
- PyDoc_STRVAR_shared(_Py_lower__doc__,
- "B.lower() -> copy of B\n\
- \n\
- Return a copy of B with all ASCII characters converted to lowercase.");
- void
- _Py_bytes_lower(char *result, const char *cptr, Py_ssize_t len)
- {
- Py_ssize_t i;
- for (i = 0; i < len; i++) {
- result[i] = Py_TOLOWER((unsigned char) cptr[i]);
- }
- }
- PyDoc_STRVAR_shared(_Py_upper__doc__,
- "B.upper() -> copy of B\n\
- \n\
- Return a copy of B with all ASCII characters converted to uppercase.");
- void
- _Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len)
- {
- Py_ssize_t i;
- for (i = 0; i < len; i++) {
- result[i] = Py_TOUPPER((unsigned char) cptr[i]);
- }
- }
- PyDoc_STRVAR_shared(_Py_title__doc__,
- "B.title() -> copy of B\n\
- \n\
- Return a titlecased version of B, i.e. ASCII words start with uppercase\n\
- characters, all remaining cased characters have lowercase.");
- void
- _Py_bytes_title(char *result, const char *s, Py_ssize_t len)
- {
- Py_ssize_t i;
- int previous_is_cased = 0;
- for (i = 0; i < len; i++) {
- int c = Py_CHARMASK(*s++);
- if (Py_ISLOWER(c)) {
- if (!previous_is_cased)
- c = Py_TOUPPER(c);
- previous_is_cased = 1;
- } else if (Py_ISUPPER(c)) {
- if (previous_is_cased)
- c = Py_TOLOWER(c);
- previous_is_cased = 1;
- } else
- previous_is_cased = 0;
- *result++ = c;
- }
- }
- PyDoc_STRVAR_shared(_Py_capitalize__doc__,
- "B.capitalize() -> copy of B\n\
- \n\
- Return a copy of B with only its first character capitalized (ASCII)\n\
- and the rest lower-cased.");
- void
- _Py_bytes_capitalize(char *result, const char *s, Py_ssize_t len)
- {
- if (len > 0) {
- *result = Py_TOUPPER(*s);
- _Py_bytes_lower(result + 1, s + 1, len - 1);
- }
- }
- PyDoc_STRVAR_shared(_Py_swapcase__doc__,
- "B.swapcase() -> copy of B\n\
- \n\
- Return a copy of B with uppercase ASCII characters converted\n\
- to lowercase ASCII and vice versa.");
- void
- _Py_bytes_swapcase(char *result, const char *s, Py_ssize_t len)
- {
- Py_ssize_t i;
- for (i = 0; i < len; i++) {
- int c = Py_CHARMASK(*s++);
- if (Py_ISLOWER(c)) {
- *result = Py_TOUPPER(c);
- }
- else if (Py_ISUPPER(c)) {
- *result = Py_TOLOWER(c);
- }
- else
- *result = c;
- result++;
- }
- }
- PyDoc_STRVAR_shared(_Py_maketrans__doc__,
- "B.maketrans(frm, to) -> translation table\n\
- \n\
- Return a translation table (a bytes object of length 256) suitable\n\
- for use in the bytes or bytearray translate method where each byte\n\
- in frm is mapped to the byte at the same position in to.\n\
- The bytes objects frm and to must be of the same length.");
- PyObject *
- _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to)
- {
- PyObject *res = NULL;
- Py_ssize_t i;
- char *p;
- if (frm->len != to->len) {
- PyErr_Format(PyExc_ValueError,
- "maketrans arguments must have same length");
- return NULL;
- }
- res = PyBytes_FromStringAndSize(NULL, 256);
- if (!res)
- return NULL;
- p = PyBytes_AS_STRING(res);
- for (i = 0; i < 256; i++)
- p[i] = (char) i;
- for (i = 0; i < frm->len; i++) {
- p[((unsigned char *)frm->buf)[i]] = ((char *)to->buf)[i];
- }
- return res;
- }
- #define FASTSEARCH fastsearch
- #define STRINGLIB(F) stringlib_##F
- #define STRINGLIB_CHAR char
- #define STRINGLIB_SIZEOF_CHAR 1
- #define STRINGLIB_FAST_MEMCHR memchr
- #include "stringlib/fastsearch.h"
- #include "stringlib/count.h"
- #include "stringlib/find.h"
- /*
- Wraps stringlib_parse_args_finds() and additionally checks the first
- argument type.
- In case the first argument is a bytes-like object, sets it to subobj,
- and doesn't touch the byte parameter.
- In case it is an integer in range(0, 256), writes the integer value
- to byte, and sets subobj to NULL.
- The other parameters are similar to those of
- stringlib_parse_args_finds().
- */
- Py_LOCAL_INLINE(int)
- parse_args_finds_byte(const char *function_name, PyObject *args,
- PyObject **subobj, char *byte,
- Py_ssize_t *start, Py_ssize_t *end)
- {
- PyObject *tmp_subobj;
- Py_ssize_t ival;
- if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj,
- start, end))
- return 0;
- if (PyObject_CheckBuffer(tmp_subobj)) {
- *subobj = tmp_subobj;
- return 1;
- }
- if (!_PyIndex_Check(tmp_subobj)) {
- PyErr_Format(PyExc_TypeError,
- "argument should be integer or bytes-like object, "
- "not '%.200s'",
- Py_TYPE(tmp_subobj)->tp_name);
- return 0;
- }
- ival = PyNumber_AsSsize_t(tmp_subobj, NULL);
- if (ival == -1 && PyErr_Occurred()) {
- return 0;
- }
- if (ival < 0 || ival > 255) {
- PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
- return 0;
- }
- *subobj = NULL;
- *byte = (char)ival;
- return 1;
- }
- /* helper macro to fixup start/end slice values */
- #define ADJUST_INDICES(start, end, len) \
- if (end > len) \
- end = len; \
- else if (end < 0) { \
- end += len; \
- if (end < 0) \
- end = 0; \
- } \
- if (start < 0) { \
- start += len; \
- if (start < 0) \
- start = 0; \
- }
- Py_LOCAL_INLINE(Py_ssize_t)
- find_internal(const char *str, Py_ssize_t len,
- const char *function_name, PyObject *args, int dir)
- {
- PyObject *subobj;
- char byte;
- Py_buffer subbuf;
- const char *sub;
- Py_ssize_t sub_len;
- Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
- Py_ssize_t res;
- if (!parse_args_finds_byte(function_name, args,
- &subobj, &byte, &start, &end))
- return -2;
- if (subobj) {
- if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
- return -2;
- sub = subbuf.buf;
- sub_len = subbuf.len;
- }
- else {
- sub = &byte;
- sub_len = 1;
- }
- ADJUST_INDICES(start, end, len);
- if (end - start < sub_len)
- res = -1;
- else if (sub_len == 1) {
- if (dir > 0)
- res = stringlib_find_char(
- str + start, end - start,
- *sub);
- else
- res = stringlib_rfind_char(
- str + start, end - start,
- *sub);
- if (res >= 0)
- res += start;
- }
- else {
- if (dir > 0)
- res = stringlib_find_slice(
- str, len,
- sub, sub_len, start, end);
- else
- res = stringlib_rfind_slice(
- str, len,
- sub, sub_len, start, end);
- }
- if (subobj)
- PyBuffer_Release(&subbuf);
- return res;
- }
- PyDoc_STRVAR_shared(_Py_find__doc__,
- "B.find(sub[, start[, end]]) -> int\n\
- \n\
- Return the lowest index in B where subsection sub is found,\n\
- such that sub is contained within B[start,end]. Optional\n\
- arguments start and end are interpreted as in slice notation.\n\
- \n\
- Return -1 on failure.");
- PyObject *
- _Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args)
- {
- Py_ssize_t result = find_internal(str, len, "find", args, +1);
- if (result == -2)
- return NULL;
- return PyLong_FromSsize_t(result);
- }
- PyDoc_STRVAR_shared(_Py_index__doc__,
- "B.index(sub[, start[, end]]) -> int\n\
- \n\
- Return the lowest index in B where subsection sub is found,\n\
- such that sub is contained within B[start,end]. Optional\n\
- arguments start and end are interpreted as in slice notation.\n\
- \n\
- Raises ValueError when the subsection is not found.");
- PyObject *
- _Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
- {
- Py_ssize_t result = find_internal(str, len, "index", args, +1);
- if (result == -2)
- return NULL;
- if (result == -1) {
- PyErr_SetString(PyExc_ValueError,
- "subsection not found");
- return NULL;
- }
- return PyLong_FromSsize_t(result);
- }
- PyDoc_STRVAR_shared(_Py_rfind__doc__,
- "B.rfind(sub[, start[, end]]) -> int\n\
- \n\
- Return the highest index in B where subsection sub is found,\n\
- such that sub is contained within B[start,end]. Optional\n\
- arguments start and end are interpreted as in slice notation.\n\
- \n\
- Return -1 on failure.");
- PyObject *
- _Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args)
- {
- Py_ssize_t result = find_internal(str, len, "rfind", args, -1);
- if (result == -2)
- return NULL;
- return PyLong_FromSsize_t(result);
- }
- PyDoc_STRVAR_shared(_Py_rindex__doc__,
- "B.rindex(sub[, start[, end]]) -> int\n\
- \n\
- Return the highest index in B where subsection sub is found,\n\
- such that sub is contained within B[start,end]. Optional\n\
- arguments start and end are interpreted as in slice notation.\n\
- \n\
- Raise ValueError when the subsection is not found.");
- PyObject *
- _Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
- {
- Py_ssize_t result = find_internal(str, len, "rindex", args, -1);
- if (result == -2)
- return NULL;
- if (result == -1) {
- PyErr_SetString(PyExc_ValueError,
- "subsection not found");
- return NULL;
- }
- return PyLong_FromSsize_t(result);
- }
- PyDoc_STRVAR_shared(_Py_count__doc__,
- "B.count(sub[, start[, end]]) -> int\n\
- \n\
- Return the number of non-overlapping occurrences of subsection sub in\n\
- bytes B[start:end]. Optional arguments start and end are interpreted\n\
- as in slice notation.");
- PyObject *
- _Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args)
- {
- PyObject *sub_obj;
- const char *sub;
- Py_ssize_t sub_len;
- char byte;
- Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
- Py_buffer vsub;
- PyObject *count_obj;
- if (!parse_args_finds_byte("count", args,
- &sub_obj, &byte, &start, &end))
- return NULL;
- if (sub_obj) {
- if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
- return NULL;
- sub = vsub.buf;
- sub_len = vsub.len;
- }
- else {
- sub = &byte;
- sub_len = 1;
- }
- ADJUST_INDICES(start, end, len);
- count_obj = PyLong_FromSsize_t(
- stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX)
- );
- if (sub_obj)
- PyBuffer_Release(&vsub);
- return count_obj;
- }
- int
- _Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg)
- {
- Py_ssize_t ival = PyNumber_AsSsize_t(arg, NULL);
- if (ival == -1 && PyErr_Occurred()) {
- Py_buffer varg;
- Py_ssize_t pos;
- PyErr_Clear();
- if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
- return -1;
- pos = stringlib_find(str, len,
- varg.buf, varg.len, 0);
- PyBuffer_Release(&varg);
- return pos >= 0;
- }
- if (ival < 0 || ival >= 256) {
- PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
- return -1;
- }
- return memchr(str, (int) ival, len) != NULL;
- }
- /* Matches the end (direction >= 0) or start (direction < 0) of the buffer
- * against substr, using the start and end arguments. Returns
- * -1 on error, 0 if not found and 1 if found.
- */
- static int
- tailmatch(const char *str, Py_ssize_t len, PyObject *substr,
- Py_ssize_t start, Py_ssize_t end, int direction)
- {
- Py_buffer sub_view = {NULL, NULL};
- const char *sub;
- Py_ssize_t slen;
- if (PyBytes_Check(substr)) {
- sub = PyBytes_AS_STRING(substr);
- slen = PyBytes_GET_SIZE(substr);
- }
- else {
- if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
- return -1;
- sub = sub_view.buf;
- slen = sub_view.len;
- }
- ADJUST_INDICES(start, end, len);
- if (direction < 0) {
- /* startswith */
- if (start > len - slen)
- goto notfound;
- } else {
- /* endswith */
- if (end - start < slen || start > len)
- goto notfound;
- if (end - slen > start)
- start = end - slen;
- }
- if (end - start < slen)
- goto notfound;
- if (memcmp(str + start, sub, slen) != 0)
- goto notfound;
- PyBuffer_Release(&sub_view);
- return 1;
- notfound:
- PyBuffer_Release(&sub_view);
- return 0;
- }
- static PyObject *
- _Py_bytes_tailmatch(const char *str, Py_ssize_t len,
- const char *function_name, PyObject *args,
- int direction)
- {
- Py_ssize_t start = 0;
- Py_ssize_t end = PY_SSIZE_T_MAX;
- PyObject *subobj = NULL;
- int result;
- if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end))
- return NULL;
- if (PyTuple_Check(subobj)) {
- Py_ssize_t i;
- for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
- result = tailmatch(str, len, PyTuple_GET_ITEM(subobj, i),
- start, end, direction);
- if (result == -1)
- return NULL;
- else if (result) {
- Py_RETURN_TRUE;
- }
- }
- Py_RETURN_FALSE;
- }
- result = tailmatch(str, len, subobj, start, end, direction);
- if (result == -1) {
- if (PyErr_ExceptionMatches(PyExc_TypeError))
- PyErr_Format(PyExc_TypeError,
- "%s first arg must be bytes or a tuple of bytes, "
- "not %s",
- function_name, Py_TYPE(subobj)->tp_name);
- return NULL;
- }
- else
- return PyBool_FromLong(result);
- }
- PyDoc_STRVAR_shared(_Py_startswith__doc__,
- "B.startswith(prefix[, start[, end]]) -> bool\n\
- \n\
- Return True if B starts with the specified prefix, False otherwise.\n\
- With optional start, test B beginning at that position.\n\
- With optional end, stop comparing B at that position.\n\
- prefix can also be a tuple of bytes to try.");
- PyObject *
- _Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args)
- {
- return _Py_bytes_tailmatch(str, len, "startswith", args, -1);
- }
- PyDoc_STRVAR_shared(_Py_endswith__doc__,
- "B.endswith(suffix[, start[, end]]) -> bool\n\
- \n\
- Return True if B ends with the specified suffix, False otherwise.\n\
- With optional start, test B beginning at that position.\n\
- With optional end, stop comparing B at that position.\n\
- suffix can also be a tuple of bytes to try.");
- PyObject *
- _Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args)
- {
- return _Py_bytes_tailmatch(str, len, "endswith", args, +1);
- }
|