1#define PY_SSIZE_T_CLEAN
2#include "Python.h"
3#include "pycore_abstract.h" // _PyIndex_Check()
4#include "pycore_bytes_methods.h"
5
6PyDoc_STRVAR_shared(_Py_isspace__doc__,
7"B.isspace() -> bool\n\
8\n\
9Return True if all characters in B are whitespace\n\
10and there is at least one character in B, False otherwise.");
11
12PyObject*
13_Py_bytes_isspace(const char *cptr, Py_ssize_t len)
14{
15 const unsigned char *p
16 = (const unsigned char *) cptr;
17 const unsigned char *e;
18
19 /* Shortcut for single character strings */
20 if (len == 1 && Py_ISSPACE(*p))
21 Py_RETURN_TRUE;
22
23 /* Special case for empty strings */
24 if (len == 0)
25 Py_RETURN_FALSE;
26
27 e = p + len;
28 for (; p < e; p++) {
29 if (!Py_ISSPACE(*p))
30 Py_RETURN_FALSE;
31 }
32 Py_RETURN_TRUE;
33}
34
35
36PyDoc_STRVAR_shared(_Py_isalpha__doc__,
37"B.isalpha() -> bool\n\
38\n\
39Return True if all characters in B are alphabetic\n\
40and there is at least one character in B, False otherwise.");
41
42PyObject*
43_Py_bytes_isalpha(const char *cptr, Py_ssize_t len)
44{
45 const unsigned char *p
46 = (const unsigned char *) cptr;
47 const unsigned char *e;
48
49 /* Shortcut for single character strings */
50 if (len == 1 && Py_ISALPHA(*p))
51 Py_RETURN_TRUE;
52
53 /* Special case for empty strings */
54 if (len == 0)
55 Py_RETURN_FALSE;
56
57 e = p + len;
58 for (; p < e; p++) {
59 if (!Py_ISALPHA(*p))
60 Py_RETURN_FALSE;
61 }
62 Py_RETURN_TRUE;
63}
64
65
66PyDoc_STRVAR_shared(_Py_isalnum__doc__,
67"B.isalnum() -> bool\n\
68\n\
69Return True if all characters in B are alphanumeric\n\
70and there is at least one character in B, False otherwise.");
71
72PyObject*
73_Py_bytes_isalnum(const char *cptr, Py_ssize_t len)
74{
75 const unsigned char *p
76 = (const unsigned char *) cptr;
77 const unsigned char *e;
78
79 /* Shortcut for single character strings */
80 if (len == 1 && Py_ISALNUM(*p))
81 Py_RETURN_TRUE;
82
83 /* Special case for empty strings */
84 if (len == 0)
85 Py_RETURN_FALSE;
86
87 e = p + len;
88 for (; p < e; p++) {
89 if (!Py_ISALNUM(*p))
90 Py_RETURN_FALSE;
91 }
92 Py_RETURN_TRUE;
93}
94
95
96PyDoc_STRVAR_shared(_Py_isascii__doc__,
97"B.isascii() -> bool\n\
98\n\
99Return True if B is empty or all characters in B are ASCII,\n\
100False otherwise.");
101
102// Optimization is copied from ascii_decode in unicodeobject.c
103/* Mask to quickly check whether a C 'size_t' contains a
104 non-ASCII, UTF8-encoded char. */
105#if (SIZEOF_SIZE_T == 8)
106# define ASCII_CHAR_MASK 0x8080808080808080ULL
107#elif (SIZEOF_SIZE_T == 4)
108# define ASCII_CHAR_MASK 0x80808080U
109#else
110# error C 'size_t' size should be either 4 or 8!
111#endif
112
113PyObject*
114_Py_bytes_isascii(const char *cptr, Py_ssize_t len)
115{
116 const char *p = cptr;
117 const char *end = p + len;
118
119 while (p < end) {
120 /* Fast path, see in STRINGLIB(utf8_decode) in stringlib/codecs.h
121 for an explanation. */
122 if (_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) {
123 /* Help allocation */
124 const char *_p = p;
125 while (_p + SIZEOF_SIZE_T <= end) {
126 size_t value = *(const size_t *) _p;
127 if (value & ASCII_CHAR_MASK) {
128 Py_RETURN_FALSE;
129 }
130 _p += SIZEOF_SIZE_T;
131 }
132 p = _p;
133 if (_p == end)
134 break;
135 }
136 if ((unsigned char)*p & 0x80) {
137 Py_RETURN_FALSE;
138 }
139 p++;
140 }
141 Py_RETURN_TRUE;
142}
143
144#undef ASCII_CHAR_MASK
145
146
147PyDoc_STRVAR_shared(_Py_isdigit__doc__,
148"B.isdigit() -> bool\n\
149\n\
150Return True if all characters in B are digits\n\
151and there is at least one character in B, False otherwise.");
152
153PyObject*
154_Py_bytes_isdigit(const char *cptr, Py_ssize_t len)
155{
156 const unsigned char *p
157 = (const unsigned char *) cptr;
158 const unsigned char *e;
159
160 /* Shortcut for single character strings */
161 if (len == 1 && Py_ISDIGIT(*p))
162 Py_RETURN_TRUE;
163
164 /* Special case for empty strings */
165 if (len == 0)
166 Py_RETURN_FALSE;
167
168 e = p + len;
169 for (; p < e; p++) {
170 if (!Py_ISDIGIT(*p))
171 Py_RETURN_FALSE;
172 }
173 Py_RETURN_TRUE;
174}
175
176
177PyDoc_STRVAR_shared(_Py_islower__doc__,
178"B.islower() -> bool\n\
179\n\
180Return True if all cased characters in B are lowercase and there is\n\
181at least one cased character in B, False otherwise.");
182
183PyObject*
184_Py_bytes_islower(const char *cptr, Py_ssize_t len)
185{
186 const unsigned char *p
187 = (const unsigned char *) cptr;
188 const unsigned char *e;
189 int cased;
190
191 /* Shortcut for single character strings */
192 if (len == 1)
193 return PyBool_FromLong(Py_ISLOWER(*p));
194
195 /* Special case for empty strings */
196 if (len == 0)
197 Py_RETURN_FALSE;
198
199 e = p + len;
200 cased = 0;
201 for (; p < e; p++) {
202 if (Py_ISUPPER(*p))
203 Py_RETURN_FALSE;
204 else if (!cased && Py_ISLOWER(*p))
205 cased = 1;
206 }
207 return PyBool_FromLong(cased);
208}
209
210
211PyDoc_STRVAR_shared(_Py_isupper__doc__,
212"B.isupper() -> bool\n\
213\n\
214Return True if all cased characters in B are uppercase and there is\n\
215at least one cased character in B, False otherwise.");
216
217PyObject*
218_Py_bytes_isupper(const char *cptr, Py_ssize_t len)
219{
220 const unsigned char *p
221 = (const unsigned char *) cptr;
222 const unsigned char *e;
223 int cased;
224
225 /* Shortcut for single character strings */
226 if (len == 1)
227 return PyBool_FromLong(Py_ISUPPER(*p));
228
229 /* Special case for empty strings */
230 if (len == 0)
231 Py_RETURN_FALSE;
232
233 e = p + len;
234 cased = 0;
235 for (; p < e; p++) {
236 if (Py_ISLOWER(*p))
237 Py_RETURN_FALSE;
238 else if (!cased && Py_ISUPPER(*p))
239 cased = 1;
240 }
241 return PyBool_FromLong(cased);
242}
243
244
245PyDoc_STRVAR_shared(_Py_istitle__doc__,
246"B.istitle() -> bool\n\
247\n\
248Return True if B is a titlecased string and there is at least one\n\
249character in B, i.e. uppercase characters may only follow uncased\n\
250characters and lowercase characters only cased ones. Return False\n\
251otherwise.");
252
253PyObject*
254_Py_bytes_istitle(const char *cptr, Py_ssize_t len)
255{
256 const unsigned char *p
257 = (const unsigned char *) cptr;
258 const unsigned char *e;
259 int cased, previous_is_cased;
260
261 /* Shortcut for single character strings */
262 if (len == 1)
263 return PyBool_FromLong(Py_ISUPPER(*p));
264
265 /* Special case for empty strings */
266 if (len == 0)
267 Py_RETURN_FALSE;
268
269 e = p + len;
270 cased = 0;
271 previous_is_cased = 0;
272 for (; p < e; p++) {
273 const unsigned char ch = *p;
274
275 if (Py_ISUPPER(ch)) {
276 if (previous_is_cased)
277 Py_RETURN_FALSE;
278 previous_is_cased = 1;
279 cased = 1;
280 }
281 else if (Py_ISLOWER(ch)) {
282 if (!previous_is_cased)
283 Py_RETURN_FALSE;
284 previous_is_cased = 1;
285 cased = 1;
286 }
287 else
288 previous_is_cased = 0;
289 }
290 return PyBool_FromLong(cased);
291}
292
293
294PyDoc_STRVAR_shared(_Py_lower__doc__,
295"B.lower() -> copy of B\n\
296\n\
297Return a copy of B with all ASCII characters converted to lowercase.");
298
299void
300_Py_bytes_lower(char *result, const char *cptr, Py_ssize_t len)
301{
302 Py_ssize_t i;
303
304 for (i = 0; i < len; i++) {
305 result[i] = Py_TOLOWER((unsigned char) cptr[i]);
306 }
307}
308
309
310PyDoc_STRVAR_shared(_Py_upper__doc__,
311"B.upper() -> copy of B\n\
312\n\
313Return a copy of B with all ASCII characters converted to uppercase.");
314
315void
316_Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len)
317{
318 Py_ssize_t i;
319
320 for (i = 0; i < len; i++) {
321 result[i] = Py_TOUPPER((unsigned char) cptr[i]);
322 }
323}
324
325
326PyDoc_STRVAR_shared(_Py_title__doc__,
327"B.title() -> copy of B\n\
328\n\
329Return a titlecased version of B, i.e. ASCII words start with uppercase\n\
330characters, all remaining cased characters have lowercase.");
331
332void
333_Py_bytes_title(char *result, const char *s, Py_ssize_t len)
334{
335 Py_ssize_t i;
336 int previous_is_cased = 0;
337
338 for (i = 0; i < len; i++) {
339 int c = Py_CHARMASK(*s++);
340 if (Py_ISLOWER(c)) {
341 if (!previous_is_cased)
342 c = Py_TOUPPER(c);
343 previous_is_cased = 1;
344 } else if (Py_ISUPPER(c)) {
345 if (previous_is_cased)
346 c = Py_TOLOWER(c);
347 previous_is_cased = 1;
348 } else
349 previous_is_cased = 0;
350 *result++ = c;
351 }
352}
353
354
355PyDoc_STRVAR_shared(_Py_capitalize__doc__,
356"B.capitalize() -> copy of B\n\
357\n\
358Return a copy of B with only its first character capitalized (ASCII)\n\
359and the rest lower-cased.");
360
361void
362_Py_bytes_capitalize(char *result, const char *s, Py_ssize_t len)
363{
364 if (len > 0) {
365 *result = Py_TOUPPER(*s);
366 _Py_bytes_lower(result + 1, s + 1, len - 1);
367 }
368}
369
370
371PyDoc_STRVAR_shared(_Py_swapcase__doc__,
372"B.swapcase() -> copy of B\n\
373\n\
374Return a copy of B with uppercase ASCII characters converted\n\
375to lowercase ASCII and vice versa.");
376
377void
378_Py_bytes_swapcase(char *result, const char *s, Py_ssize_t len)
379{
380 Py_ssize_t i;
381
382 for (i = 0; i < len; i++) {
383 int c = Py_CHARMASK(*s++);
384 if (Py_ISLOWER(c)) {
385 *result = Py_TOUPPER(c);
386 }
387 else if (Py_ISUPPER(c)) {
388 *result = Py_TOLOWER(c);
389 }
390 else
391 *result = c;
392 result++;
393 }
394}
395
396
397PyDoc_STRVAR_shared(_Py_maketrans__doc__,
398"B.maketrans(frm, to) -> translation table\n\
399\n\
400Return a translation table (a bytes object of length 256) suitable\n\
401for use in the bytes or bytearray translate method where each byte\n\
402in frm is mapped to the byte at the same position in to.\n\
403The bytes objects frm and to must be of the same length.");
404
405PyObject *
406_Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to)
407{
408 PyObject *res = NULL;
409 Py_ssize_t i;
410 char *p;
411
412 if (frm->len != to->len) {
413 PyErr_Format(PyExc_ValueError,
414 "maketrans arguments must have same length");
415 return NULL;
416 }
417 res = PyBytes_FromStringAndSize(NULL, 256);
418 if (!res)
419 return NULL;
420 p = PyBytes_AS_STRING(res);
421 for (i = 0; i < 256; i++)
422 p[i] = (char) i;
423 for (i = 0; i < frm->len; i++) {
424 p[((unsigned char *)frm->buf)[i]] = ((char *)to->buf)[i];
425 }
426
427 return res;
428}
429
430#define FASTSEARCH fastsearch
431#define STRINGLIB(F) stringlib_##F
432#define STRINGLIB_CHAR char
433#define STRINGLIB_SIZEOF_CHAR 1
434
435#include "stringlib/fastsearch.h"
436#include "stringlib/count.h"
437#include "stringlib/find.h"
438
439/*
440Wraps stringlib_parse_args_finds() and additionally checks the first
441argument type.
442
443In case the first argument is a bytes-like object, sets it to subobj,
444and doesn't touch the byte parameter.
445In case it is an integer in range(0, 256), writes the integer value
446to byte, and sets subobj to NULL.
447
448The other parameters are similar to those of
449stringlib_parse_args_finds().
450*/
451
452Py_LOCAL_INLINE(int)
453parse_args_finds_byte(const char *function_name, PyObject *args,
454 PyObject **subobj, char *byte,
455 Py_ssize_t *start, Py_ssize_t *end)
456{
457 PyObject *tmp_subobj;
458 Py_ssize_t ival;
459
460 if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj,
461 start, end))
462 return 0;
463
464 if (PyObject_CheckBuffer(tmp_subobj)) {
465 *subobj = tmp_subobj;
466 return 1;
467 }
468
469 if (!_PyIndex_Check(tmp_subobj)) {
470 PyErr_Format(PyExc_TypeError,
471 "argument should be integer or bytes-like object, "
472 "not '%.200s'",
473 Py_TYPE(tmp_subobj)->tp_name);
474 return 0;
475 }
476
477 ival = PyNumber_AsSsize_t(tmp_subobj, NULL);
478 if (ival == -1 && PyErr_Occurred()) {
479 return 0;
480 }
481 if (ival < 0 || ival > 255) {
482 PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
483 return 0;
484 }
485
486 *subobj = NULL;
487 *byte = (char)ival;
488 return 1;
489}
490
491/* helper macro to fixup start/end slice values */
492#define ADJUST_INDICES(start, end, len) \
493 if (end > len) \
494 end = len; \
495 else if (end < 0) { \
496 end += len; \
497 if (end < 0) \
498 end = 0; \
499 } \
500 if (start < 0) { \
501 start += len; \
502 if (start < 0) \
503 start = 0; \
504 }
505
506Py_LOCAL_INLINE(Py_ssize_t)
507find_internal(const char *str, Py_ssize_t len,
508 const char *function_name, PyObject *args, int dir)
509{
510 PyObject *subobj;
511 char byte;
512 Py_buffer subbuf;
513 const char *sub;
514 Py_ssize_t sub_len;
515 Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
516 Py_ssize_t res;
517
518 if (!parse_args_finds_byte(function_name, args,
519 &subobj, &byte, &start, &end))
520 return -2;
521
522 if (subobj) {
523 if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
524 return -2;
525
526 sub = subbuf.buf;
527 sub_len = subbuf.len;
528 }
529 else {
530 sub = &byte;
531 sub_len = 1;
532 }
533
534 ADJUST_INDICES(start, end, len);
535 if (end - start < sub_len)
536 res = -1;
537 else if (sub_len == 1) {
538 if (dir > 0)
539 res = stringlib_find_char(
540 str + start, end - start,
541 *sub);
542 else
543 res = stringlib_rfind_char(
544 str + start, end - start,
545 *sub);
546 if (res >= 0)
547 res += start;
548 }
549 else {
550 if (dir > 0)
551 res = stringlib_find_slice(
552 str, len,
553 sub, sub_len, start, end);
554 else
555 res = stringlib_rfind_slice(
556 str, len,
557 sub, sub_len, start, end);
558 }
559
560 if (subobj)
561 PyBuffer_Release(&subbuf);
562
563 return res;
564}
565
566PyDoc_STRVAR_shared(_Py_find__doc__,
567"B.find(sub[, start[, end]]) -> int\n\
568\n\
569Return the lowest index in B where subsection sub is found,\n\
570such that sub is contained within B[start,end]. Optional\n\
571arguments start and end are interpreted as in slice notation.\n\
572\n\
573Return -1 on failure.");
574
575PyObject *
576_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args)
577{
578 Py_ssize_t result = find_internal(str, len, "find", args, +1);
579 if (result == -2)
580 return NULL;
581 return PyLong_FromSsize_t(result);
582}
583
584PyDoc_STRVAR_shared(_Py_index__doc__,
585"B.index(sub[, start[, end]]) -> int\n\
586\n\
587Return the lowest index in B where subsection sub is found,\n\
588such that sub is contained within B[start,end]. Optional\n\
589arguments start and end are interpreted as in slice notation.\n\
590\n\
591Raises ValueError when the subsection is not found.");
592
593PyObject *
594_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
595{
596 Py_ssize_t result = find_internal(str, len, "index", args, +1);
597 if (result == -2)
598 return NULL;
599 if (result == -1) {
600 PyErr_SetString(PyExc_ValueError,
601 "subsection not found");
602 return NULL;
603 }
604 return PyLong_FromSsize_t(result);
605}
606
607PyDoc_STRVAR_shared(_Py_rfind__doc__,
608"B.rfind(sub[, start[, end]]) -> int\n\
609\n\
610Return the highest index in B where subsection sub is found,\n\
611such that sub is contained within B[start,end]. Optional\n\
612arguments start and end are interpreted as in slice notation.\n\
613\n\
614Return -1 on failure.");
615
616PyObject *
617_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args)
618{
619 Py_ssize_t result = find_internal(str, len, "rfind", args, -1);
620 if (result == -2)
621 return NULL;
622 return PyLong_FromSsize_t(result);
623}
624
625PyDoc_STRVAR_shared(_Py_rindex__doc__,
626"B.rindex(sub[, start[, end]]) -> int\n\
627\n\
628Return the highest index in B where subsection sub is found,\n\
629such that sub is contained within B[start,end]. Optional\n\
630arguments start and end are interpreted as in slice notation.\n\
631\n\
632Raise ValueError when the subsection is not found.");
633
634PyObject *
635_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
636{
637 Py_ssize_t result = find_internal(str, len, "rindex", args, -1);
638 if (result == -2)
639 return NULL;
640 if (result == -1) {
641 PyErr_SetString(PyExc_ValueError,
642 "subsection not found");
643 return NULL;
644 }
645 return PyLong_FromSsize_t(result);
646}
647
648PyDoc_STRVAR_shared(_Py_count__doc__,
649"B.count(sub[, start[, end]]) -> int\n\
650\n\
651Return the number of non-overlapping occurrences of subsection sub in\n\
652bytes B[start:end]. Optional arguments start and end are interpreted\n\
653as in slice notation.");
654
655PyObject *
656_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args)
657{
658 PyObject *sub_obj;
659 const char *sub;
660 Py_ssize_t sub_len;
661 char byte;
662 Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
663
664 Py_buffer vsub;
665 PyObject *count_obj;
666
667 if (!parse_args_finds_byte("count", args,
668 &sub_obj, &byte, &start, &end))
669 return NULL;
670
671 if (sub_obj) {
672 if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
673 return NULL;
674
675 sub = vsub.buf;
676 sub_len = vsub.len;
677 }
678 else {
679 sub = &byte;
680 sub_len = 1;
681 }
682
683 ADJUST_INDICES(start, end, len);
684
685 count_obj = PyLong_FromSsize_t(
686 stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX)
687 );
688
689 if (sub_obj)
690 PyBuffer_Release(&vsub);
691
692 return count_obj;
693}
694
695int
696_Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg)
697{
698 Py_ssize_t ival = PyNumber_AsSsize_t(arg, NULL);
699 if (ival == -1 && PyErr_Occurred()) {
700 Py_buffer varg;
701 Py_ssize_t pos;
702 PyErr_Clear();
703 if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
704 return -1;
705 pos = stringlib_find(str, len,
706 varg.buf, varg.len, 0);
707 PyBuffer_Release(&varg);
708 return pos >= 0;
709 }
710 if (ival < 0 || ival >= 256) {
711 PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
712 return -1;
713 }
714
715 return memchr(str, (int) ival, len) != NULL;
716}
717
718
719/* Matches the end (direction >= 0) or start (direction < 0) of the buffer
720 * against substr, using the start and end arguments. Returns
721 * -1 on error, 0 if not found and 1 if found.
722 */
723static int
724tailmatch(const char *str, Py_ssize_t len, PyObject *substr,
725 Py_ssize_t start, Py_ssize_t end, int direction)
726{
727 Py_buffer sub_view = {NULL, NULL};
728 const char *sub;
729 Py_ssize_t slen;
730
731 if (PyBytes_Check(substr)) {
732 sub = PyBytes_AS_STRING(substr);
733 slen = PyBytes_GET_SIZE(substr);
734 }
735 else {
736 if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
737 return -1;
738 sub = sub_view.buf;
739 slen = sub_view.len;
740 }
741
742 ADJUST_INDICES(start, end, len);
743
744 if (direction < 0) {
745 /* startswith */
746 if (start > len - slen)
747 goto notfound;
748 } else {
749 /* endswith */
750 if (end - start < slen || start > len)
751 goto notfound;
752
753 if (end - slen > start)
754 start = end - slen;
755 }
756 if (end - start < slen)
757 goto notfound;
758 if (memcmp(str + start, sub, slen) != 0)
759 goto notfound;
760
761 PyBuffer_Release(&sub_view);
762 return 1;
763
764notfound:
765 PyBuffer_Release(&sub_view);
766 return 0;
767}
768
769static PyObject *
770_Py_bytes_tailmatch(const char *str, Py_ssize_t len,
771 const char *function_name, PyObject *args,
772 int direction)
773{
774 Py_ssize_t start = 0;
775 Py_ssize_t end = PY_SSIZE_T_MAX;
776 PyObject *subobj;
777 int result;
778
779 if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end))
780 return NULL;
781 if (PyTuple_Check(subobj)) {
782 Py_ssize_t i;
783 for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
784 result = tailmatch(str, len, PyTuple_GET_ITEM(subobj, i),
785 start, end, direction);
786 if (result == -1)
787 return NULL;
788 else if (result) {
789 Py_RETURN_TRUE;
790 }
791 }
792 Py_RETURN_FALSE;
793 }
794 result = tailmatch(str, len, subobj, start, end, direction);
795 if (result == -1) {
796 if (PyErr_ExceptionMatches(PyExc_TypeError))
797 PyErr_Format(PyExc_TypeError,
798 "%s first arg must be bytes or a tuple of bytes, "
799 "not %s",
800 function_name, Py_TYPE(subobj)->tp_name);
801 return NULL;
802 }
803 else
804 return PyBool_FromLong(result);
805}
806
807PyDoc_STRVAR_shared(_Py_startswith__doc__,
808"B.startswith(prefix[, start[, end]]) -> bool\n\
809\n\
810Return True if B starts with the specified prefix, False otherwise.\n\
811With optional start, test B beginning at that position.\n\
812With optional end, stop comparing B at that position.\n\
813prefix can also be a tuple of bytes to try.");
814
815PyObject *
816_Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args)
817{
818 return _Py_bytes_tailmatch(str, len, "startswith", args, -1);
819}
820
821PyDoc_STRVAR_shared(_Py_endswith__doc__,
822"B.endswith(suffix[, start[, end]]) -> bool\n\
823\n\
824Return True if B ends with the specified suffix, False otherwise.\n\
825With optional start, test B beginning at that position.\n\
826With optional end, stop comparing B at that position.\n\
827suffix can also be a tuple of bytes to try.");
828
829PyObject *
830_Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args)
831{
832 return _Py_bytes_tailmatch(str, len, "endswith", args, +1);
833}
834