Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Objects/bytes_methods.c
12 views
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*
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*
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*
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*
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*
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*
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*
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*
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
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
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
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
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
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 *
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)
456
parse_args_finds_byte(const char *function_name, PyObject *args,
457
PyObject **subobj, char *byte,
458
Py_ssize_t *start, Py_ssize_t *end)
459
{
460
PyObject *tmp_subobj;
461
Py_ssize_t ival;
462
463
if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj,
464
start, end))
465
return 0;
466
467
if (PyObject_CheckBuffer(tmp_subobj)) {
468
*subobj = tmp_subobj;
469
return 1;
470
}
471
472
if (!_PyIndex_Check(tmp_subobj)) {
473
PyErr_Format(PyExc_TypeError,
474
"argument should be integer or bytes-like object, "
475
"not '%.200s'",
476
Py_TYPE(tmp_subobj)->tp_name);
477
return 0;
478
}
479
480
ival = PyNumber_AsSsize_t(tmp_subobj, NULL);
481
if (ival == -1 && PyErr_Occurred()) {
482
return 0;
483
}
484
if (ival < 0 || ival > 255) {
485
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
486
return 0;
487
}
488
489
*subobj = NULL;
490
*byte = (char)ival;
491
return 1;
492
}
493
494
/* helper macro to fixup start/end slice values */
495
#define ADJUST_INDICES(start, end, len) \
496
if (end > len) \
497
end = len; \
498
else if (end < 0) { \
499
end += len; \
500
if (end < 0) \
501
end = 0; \
502
} \
503
if (start < 0) { \
504
start += len; \
505
if (start < 0) \
506
start = 0; \
507
}
508
509
Py_LOCAL_INLINE(Py_ssize_t)
510
find_internal(const char *str, Py_ssize_t len,
511
const char *function_name, PyObject *args, int dir)
512
{
513
PyObject *subobj;
514
char byte;
515
Py_buffer subbuf;
516
const char *sub;
517
Py_ssize_t sub_len;
518
Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
519
Py_ssize_t res;
520
521
if (!parse_args_finds_byte(function_name, args,
522
&subobj, &byte, &start, &end))
523
return -2;
524
525
if (subobj) {
526
if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
527
return -2;
528
529
sub = subbuf.buf;
530
sub_len = subbuf.len;
531
}
532
else {
533
sub = &byte;
534
sub_len = 1;
535
}
536
537
ADJUST_INDICES(start, end, len);
538
if (end - start < sub_len)
539
res = -1;
540
else if (sub_len == 1) {
541
if (dir > 0)
542
res = stringlib_find_char(
543
str + start, end - start,
544
*sub);
545
else
546
res = stringlib_rfind_char(
547
str + start, end - start,
548
*sub);
549
if (res >= 0)
550
res += start;
551
}
552
else {
553
if (dir > 0)
554
res = stringlib_find_slice(
555
str, len,
556
sub, sub_len, start, end);
557
else
558
res = stringlib_rfind_slice(
559
str, len,
560
sub, sub_len, start, end);
561
}
562
563
if (subobj)
564
PyBuffer_Release(&subbuf);
565
566
return res;
567
}
568
569
PyDoc_STRVAR_shared(_Py_find__doc__,
570
"B.find(sub[, start[, end]]) -> int\n\
571
\n\
572
Return the lowest index in B where subsection sub is found,\n\
573
such that sub is contained within B[start,end]. Optional\n\
574
arguments start and end are interpreted as in slice notation.\n\
575
\n\
576
Return -1 on failure.");
577
578
PyObject *
579
_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args)
580
{
581
Py_ssize_t result = find_internal(str, len, "find", args, +1);
582
if (result == -2)
583
return NULL;
584
return PyLong_FromSsize_t(result);
585
}
586
587
PyDoc_STRVAR_shared(_Py_index__doc__,
588
"B.index(sub[, start[, end]]) -> int\n\
589
\n\
590
Return the lowest index in B where subsection sub is found,\n\
591
such that sub is contained within B[start,end]. Optional\n\
592
arguments start and end are interpreted as in slice notation.\n\
593
\n\
594
Raises ValueError when the subsection is not found.");
595
596
PyObject *
597
_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
598
{
599
Py_ssize_t result = find_internal(str, len, "index", args, +1);
600
if (result == -2)
601
return NULL;
602
if (result == -1) {
603
PyErr_SetString(PyExc_ValueError,
604
"subsection not found");
605
return NULL;
606
}
607
return PyLong_FromSsize_t(result);
608
}
609
610
PyDoc_STRVAR_shared(_Py_rfind__doc__,
611
"B.rfind(sub[, start[, end]]) -> int\n\
612
\n\
613
Return the highest index in B where subsection sub is found,\n\
614
such that sub is contained within B[start,end]. Optional\n\
615
arguments start and end are interpreted as in slice notation.\n\
616
\n\
617
Return -1 on failure.");
618
619
PyObject *
620
_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args)
621
{
622
Py_ssize_t result = find_internal(str, len, "rfind", args, -1);
623
if (result == -2)
624
return NULL;
625
return PyLong_FromSsize_t(result);
626
}
627
628
PyDoc_STRVAR_shared(_Py_rindex__doc__,
629
"B.rindex(sub[, start[, end]]) -> int\n\
630
\n\
631
Return the highest index in B where subsection sub is found,\n\
632
such that sub is contained within B[start,end]. Optional\n\
633
arguments start and end are interpreted as in slice notation.\n\
634
\n\
635
Raise ValueError when the subsection is not found.");
636
637
PyObject *
638
_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
639
{
640
Py_ssize_t result = find_internal(str, len, "rindex", args, -1);
641
if (result == -2)
642
return NULL;
643
if (result == -1) {
644
PyErr_SetString(PyExc_ValueError,
645
"subsection not found");
646
return NULL;
647
}
648
return PyLong_FromSsize_t(result);
649
}
650
651
PyDoc_STRVAR_shared(_Py_count__doc__,
652
"B.count(sub[, start[, end]]) -> int\n\
653
\n\
654
Return the number of non-overlapping occurrences of subsection sub in\n\
655
bytes B[start:end]. Optional arguments start and end are interpreted\n\
656
as in slice notation.");
657
658
PyObject *
659
_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args)
660
{
661
PyObject *sub_obj;
662
const char *sub;
663
Py_ssize_t sub_len;
664
char byte;
665
Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
666
667
Py_buffer vsub;
668
PyObject *count_obj;
669
670
if (!parse_args_finds_byte("count", args,
671
&sub_obj, &byte, &start, &end))
672
return NULL;
673
674
if (sub_obj) {
675
if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
676
return NULL;
677
678
sub = vsub.buf;
679
sub_len = vsub.len;
680
}
681
else {
682
sub = &byte;
683
sub_len = 1;
684
}
685
686
ADJUST_INDICES(start, end, len);
687
688
count_obj = PyLong_FromSsize_t(
689
stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX)
690
);
691
692
if (sub_obj)
693
PyBuffer_Release(&vsub);
694
695
return count_obj;
696
}
697
698
int
699
_Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg)
700
{
701
Py_ssize_t ival = PyNumber_AsSsize_t(arg, NULL);
702
if (ival == -1 && PyErr_Occurred()) {
703
Py_buffer varg;
704
Py_ssize_t pos;
705
PyErr_Clear();
706
if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
707
return -1;
708
pos = stringlib_find(str, len,
709
varg.buf, varg.len, 0);
710
PyBuffer_Release(&varg);
711
return pos >= 0;
712
}
713
if (ival < 0 || ival >= 256) {
714
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
715
return -1;
716
}
717
718
return memchr(str, (int) ival, len) != NULL;
719
}
720
721
722
/* Matches the end (direction >= 0) or start (direction < 0) of the buffer
723
* against substr, using the start and end arguments. Returns
724
* -1 on error, 0 if not found and 1 if found.
725
*/
726
static int
727
tailmatch(const char *str, Py_ssize_t len, PyObject *substr,
728
Py_ssize_t start, Py_ssize_t end, int direction)
729
{
730
Py_buffer sub_view = {NULL, NULL};
731
const char *sub;
732
Py_ssize_t slen;
733
734
if (PyBytes_Check(substr)) {
735
sub = PyBytes_AS_STRING(substr);
736
slen = PyBytes_GET_SIZE(substr);
737
}
738
else {
739
if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
740
return -1;
741
sub = sub_view.buf;
742
slen = sub_view.len;
743
}
744
745
ADJUST_INDICES(start, end, len);
746
747
if (direction < 0) {
748
/* startswith */
749
if (start > len - slen)
750
goto notfound;
751
} else {
752
/* endswith */
753
if (end - start < slen || start > len)
754
goto notfound;
755
756
if (end - slen > start)
757
start = end - slen;
758
}
759
if (end - start < slen)
760
goto notfound;
761
if (memcmp(str + start, sub, slen) != 0)
762
goto notfound;
763
764
PyBuffer_Release(&sub_view);
765
return 1;
766
767
notfound:
768
PyBuffer_Release(&sub_view);
769
return 0;
770
}
771
772
static PyObject *
773
_Py_bytes_tailmatch(const char *str, Py_ssize_t len,
774
const char *function_name, PyObject *args,
775
int direction)
776
{
777
Py_ssize_t start = 0;
778
Py_ssize_t end = PY_SSIZE_T_MAX;
779
PyObject *subobj = NULL;
780
int result;
781
782
if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end))
783
return NULL;
784
if (PyTuple_Check(subobj)) {
785
Py_ssize_t i;
786
for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
787
result = tailmatch(str, len, PyTuple_GET_ITEM(subobj, i),
788
start, end, direction);
789
if (result == -1)
790
return NULL;
791
else if (result) {
792
Py_RETURN_TRUE;
793
}
794
}
795
Py_RETURN_FALSE;
796
}
797
result = tailmatch(str, len, subobj, start, end, direction);
798
if (result == -1) {
799
if (PyErr_ExceptionMatches(PyExc_TypeError))
800
PyErr_Format(PyExc_TypeError,
801
"%s first arg must be bytes or a tuple of bytes, "
802
"not %s",
803
function_name, Py_TYPE(subobj)->tp_name);
804
return NULL;
805
}
806
else
807
return PyBool_FromLong(result);
808
}
809
810
PyDoc_STRVAR_shared(_Py_startswith__doc__,
811
"B.startswith(prefix[, start[, end]]) -> bool\n\
812
\n\
813
Return True if B starts with the specified prefix, False otherwise.\n\
814
With optional start, test B beginning at that position.\n\
815
With optional end, stop comparing B at that position.\n\
816
prefix can also be a tuple of bytes to try.");
817
818
PyObject *
819
_Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args)
820
{
821
return _Py_bytes_tailmatch(str, len, "startswith", args, -1);
822
}
823
824
PyDoc_STRVAR_shared(_Py_endswith__doc__,
825
"B.endswith(suffix[, start[, end]]) -> bool\n\
826
\n\
827
Return True if B ends with the specified suffix, False otherwise.\n\
828
With optional start, test B beginning at that position.\n\
829
With optional end, stop comparing B at that position.\n\
830
suffix can also be a tuple of bytes to try.");
831
832
PyObject *
833
_Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args)
834
{
835
return _Py_bytes_tailmatch(str, len, "endswith", args, +1);
836
}
837
838