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