blob: 8b147dec8221baeaef11420b875678eb88178de2 [file] [log] [blame]
Gregory P. Smith60d241f2007-10-16 06:31:30 +00001/* NOTE: this API is -ONLY- for use with single byte character strings. */
2/* Do not use it with Unicode. */
3
Gregory P. Smith60d241f2007-10-16 06:31:30 +00004/* the more complicated methods. parts of these should be pulled out into the
5 shared code in bytes_methods.c to cut down on duplicate code bloat. */
6
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +03007Py_LOCAL_INLINE(PyObject *)
8return_self(PyObject *self)
9{
10#if !STRINGLIB_MUTABLE
11 if (STRINGLIB_CHECK_EXACT(self)) {
12 Py_INCREF(self);
13 return self;
14 }
15#endif
16 return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self));
17}
18
Gregory P. Smith60d241f2007-10-16 06:31:30 +000019static PyObject*
Ezio Melotti745d54d2013-11-16 19:10:57 +020020stringlib_expandtabs(PyObject *self, PyObject *args, PyObject *kwds)
Gregory P. Smith60d241f2007-10-16 06:31:30 +000021{
22 const char *e, *p;
23 char *q;
Benjamin Peterson23cf4032014-03-30 19:47:57 -040024 Py_ssize_t i, j;
Gregory P. Smith60d241f2007-10-16 06:31:30 +000025 PyObject *u;
Ezio Melotti745d54d2013-11-16 19:10:57 +020026 static char *kwlist[] = {"tabsize", 0};
Gregory P. Smith60d241f2007-10-16 06:31:30 +000027 int tabsize = 8;
Ezio Melotti6b027722013-04-21 04:07:51 +030028
Ezio Melotti745d54d2013-11-16 19:10:57 +020029 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:expandtabs",
30 kwlist, &tabsize))
Antoine Pitrou8d4e5052009-01-13 22:59:11 +000031 return NULL;
Ezio Melotti6b027722013-04-21 04:07:51 +030032
Gregory P. Smith60d241f2007-10-16 06:31:30 +000033 /* First pass: determine size of output string */
Antoine Pitrou8d4e5052009-01-13 22:59:11 +000034 i = j = 0;
Gregory P. Smith60d241f2007-10-16 06:31:30 +000035 e = STRINGLIB_STR(self) + STRINGLIB_LEN(self);
Benjamin Peterson23cf4032014-03-30 19:47:57 -040036 for (p = STRINGLIB_STR(self); p < e; p++) {
Gregory P. Smith60d241f2007-10-16 06:31:30 +000037 if (*p == '\t') {
Antoine Pitrou8d4e5052009-01-13 22:59:11 +000038 if (tabsize > 0) {
Benjamin Peterson23cf4032014-03-30 19:47:57 -040039 Py_ssize_t incr = tabsize - (j % tabsize);
40 if (j > PY_SSIZE_T_MAX - incr)
41 goto overflow;
42 j += incr;
Gregory P. Smith60d241f2007-10-16 06:31:30 +000043 }
44 }
Antoine Pitrou8d4e5052009-01-13 22:59:11 +000045 else {
Benjamin Peterson23cf4032014-03-30 19:47:57 -040046 if (j > PY_SSIZE_T_MAX - 1)
47 goto overflow;
Antoine Pitrou8d4e5052009-01-13 22:59:11 +000048 j++;
49 if (*p == '\n' || *p == '\r') {
Benjamin Peterson23cf4032014-03-30 19:47:57 -040050 if (i > PY_SSIZE_T_MAX - j)
51 goto overflow;
Antoine Pitrou8d4e5052009-01-13 22:59:11 +000052 i += j;
53 j = 0;
Antoine Pitrou8d4e5052009-01-13 22:59:11 +000054 }
55 }
Gregory P. Smith60d241f2007-10-16 06:31:30 +000056 }
Ezio Melotti6b027722013-04-21 04:07:51 +030057
Benjamin Peterson23cf4032014-03-30 19:47:57 -040058 if (i > PY_SSIZE_T_MAX - j)
59 goto overflow;
Benjamin Peterson0ad60982014-03-30 19:52:22 -040060
Gregory P. Smith60d241f2007-10-16 06:31:30 +000061 /* Second pass: create output string and fill it */
62 u = STRINGLIB_NEW(NULL, i + j);
63 if (!u)
64 return NULL;
Ezio Melotti6b027722013-04-21 04:07:51 +030065
Gregory P. Smith60d241f2007-10-16 06:31:30 +000066 j = 0;
67 q = STRINGLIB_STR(u);
Serhiy Storchaka009b8112015-03-18 21:53:15 +020068
Benjamin Peterson23cf4032014-03-30 19:47:57 -040069 for (p = STRINGLIB_STR(self); p < e; p++) {
Gregory P. Smith60d241f2007-10-16 06:31:30 +000070 if (*p == '\t') {
Antoine Pitrou8d4e5052009-01-13 22:59:11 +000071 if (tabsize > 0) {
72 i = tabsize - (j % tabsize);
73 j += i;
74 while (i--)
75 *q++ = ' ';
76 }
77 }
78 else {
Gregory P. Smith60d241f2007-10-16 06:31:30 +000079 j++;
Antoine Pitrou8d4e5052009-01-13 22:59:11 +000080 *q++ = *p;
Gregory P. Smith60d241f2007-10-16 06:31:30 +000081 if (*p == '\n' || *p == '\r')
82 j = 0;
83 }
Benjamin Peterson23cf4032014-03-30 19:47:57 -040084 }
Ezio Melotti6b027722013-04-21 04:07:51 +030085
Gregory P. Smith60d241f2007-10-16 06:31:30 +000086 return u;
Benjamin Peterson23cf4032014-03-30 19:47:57 -040087 overflow:
88 PyErr_SetString(PyExc_OverflowError, "result too long");
89 return NULL;
Gregory P. Smith60d241f2007-10-16 06:31:30 +000090}
91
92Py_LOCAL_INLINE(PyObject *)
93pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill)
94{
95 PyObject *u;
96
97 if (left < 0)
98 left = 0;
99 if (right < 0)
100 right = 0;
101
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300102 if (left == 0 && right == 0) {
103 return return_self(self);
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000104 }
105
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300106 u = STRINGLIB_NEW(NULL, left + STRINGLIB_LEN(self) + right);
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000107 if (u) {
108 if (left)
109 memset(STRINGLIB_STR(u), fill, left);
110 Py_MEMCPY(STRINGLIB_STR(u) + left,
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300111 STRINGLIB_STR(self),
112 STRINGLIB_LEN(self));
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000113 if (right)
114 memset(STRINGLIB_STR(u) + left + STRINGLIB_LEN(self),
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300115 fill, right);
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000116 }
117
118 return u;
119}
120
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000121static PyObject *
122stringlib_ljust(PyObject *self, PyObject *args)
123{
124 Py_ssize_t width;
125 char fillchar = ' ';
126
127 if (!PyArg_ParseTuple(args, "n|c:ljust", &width, &fillchar))
128 return NULL;
129
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300130 if (STRINGLIB_LEN(self) >= width) {
131 return return_self(self);
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000132 }
133
134 return pad(self, 0, width - STRINGLIB_LEN(self), fillchar);
135}
136
137
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000138static PyObject *
139stringlib_rjust(PyObject *self, PyObject *args)
140{
141 Py_ssize_t width;
142 char fillchar = ' ';
143
144 if (!PyArg_ParseTuple(args, "n|c:rjust", &width, &fillchar))
145 return NULL;
146
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300147 if (STRINGLIB_LEN(self) >= width) {
148 return return_self(self);
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000149 }
150
151 return pad(self, width - STRINGLIB_LEN(self), 0, fillchar);
152}
153
154
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000155static PyObject *
156stringlib_center(PyObject *self, PyObject *args)
157{
158 Py_ssize_t marg, left;
159 Py_ssize_t width;
160 char fillchar = ' ';
161
162 if (!PyArg_ParseTuple(args, "n|c:center", &width, &fillchar))
163 return NULL;
164
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300165 if (STRINGLIB_LEN(self) >= width) {
166 return return_self(self);
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000167 }
168
169 marg = width - STRINGLIB_LEN(self);
170 left = marg / 2 + (marg & width & 1);
171
172 return pad(self, left, marg - left, fillchar);
173}
174
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000175static PyObject *
176stringlib_zfill(PyObject *self, PyObject *args)
177{
178 Py_ssize_t fill;
179 PyObject *s;
180 char *p;
181 Py_ssize_t width;
182
183 if (!PyArg_ParseTuple(args, "n:zfill", &width))
184 return NULL;
185
186 if (STRINGLIB_LEN(self) >= width) {
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300187 return return_self(self);
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000188 }
189
190 fill = width - STRINGLIB_LEN(self);
191
192 s = pad(self, fill, 0, '0');
193
194 if (s == NULL)
195 return NULL;
196
197 p = STRINGLIB_STR(s);
198 if (p[fill] == '+' || p[fill] == '-') {
199 /* move sign to beginning of string */
200 p[0] = p[fill];
201 p[fill] = '0';
202 }
203
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300204 return s;
Gregory P. Smith60d241f2007-10-16 06:31:30 +0000205}
Serhiy Storchakafb81d3c2016-05-05 09:26:07 +0300206
207
208/* find and count characters and substrings */
209
210#define findchar(target, target_len, c) \
211 ((char *)memchr((const void *)(target), c, target_len))
212
213
214Py_LOCAL_INLINE(Py_ssize_t)
215countchar(const char *target, Py_ssize_t target_len, char c,
216 Py_ssize_t maxcount)
217{
218 Py_ssize_t count = 0;
219 const char *start = target;
220 const char *end = target + target_len;
221
222 while ((start = findchar(start, end - start, c)) != NULL) {
223 count++;
224 if (count >= maxcount)
225 break;
226 start += 1;
227 }
228 return count;
229}
230
231
232/* Algorithms for different cases of string replacement */
233
234/* len(self)>=1, from="", len(to)>=1, maxcount>=1 */
235Py_LOCAL(PyObject *)
236stringlib_replace_interleave(PyObject *self,
237 const char *to_s, Py_ssize_t to_len,
238 Py_ssize_t maxcount)
239{
240 const char *self_s;
241 char *result_s;
242 Py_ssize_t self_len, result_len;
243 Py_ssize_t count, i;
244 PyObject *result;
245
246 self_len = STRINGLIB_LEN(self);
247
248 /* 1 at the end plus 1 after every character;
249 count = min(maxcount, self_len + 1) */
250 if (maxcount <= self_len) {
251 count = maxcount;
252 }
253 else {
254 /* Can't overflow: self_len + 1 <= maxcount <= PY_SSIZE_T_MAX. */
255 count = self_len + 1;
256 }
257
258 /* Check for overflow */
259 /* result_len = count * to_len + self_len; */
260 assert(count > 0);
261 if (to_len > (PY_SSIZE_T_MAX - self_len) / count) {
262 PyErr_SetString(PyExc_OverflowError,
263 "replace bytes are too long");
264 return NULL;
265 }
266 result_len = count * to_len + self_len;
267 result = STRINGLIB_NEW(NULL, result_len);
268 if (result == NULL) {
269 return NULL;
270 }
271
272 self_s = STRINGLIB_STR(self);
273 result_s = STRINGLIB_STR(result);
274
275 if (to_len > 1) {
276 /* Lay the first one down (guaranteed this will occur) */
277 Py_MEMCPY(result_s, to_s, to_len);
278 result_s += to_len;
279 count -= 1;
280
281 for (i = 0; i < count; i++) {
282 *result_s++ = *self_s++;
283 Py_MEMCPY(result_s, to_s, to_len);
284 result_s += to_len;
285 }
286 }
287 else {
288 result_s[0] = to_s[0];
289 result_s += to_len;
290 count -= 1;
291 for (i = 0; i < count; i++) {
292 *result_s++ = *self_s++;
293 result_s[0] = to_s[0];
294 result_s += to_len;
295 }
296 }
297
298 /* Copy the rest of the original string */
299 Py_MEMCPY(result_s, self_s, self_len - i);
300
301 return result;
302}
303
304/* Special case for deleting a single character */
305/* len(self)>=1, len(from)==1, to="", maxcount>=1 */
306Py_LOCAL(PyObject *)
307stringlib_replace_delete_single_character(PyObject *self,
308 char from_c, Py_ssize_t maxcount)
309{
310 const char *self_s, *start, *next, *end;
311 char *result_s;
312 Py_ssize_t self_len, result_len;
313 Py_ssize_t count;
314 PyObject *result;
315
316 self_len = STRINGLIB_LEN(self);
317 self_s = STRINGLIB_STR(self);
318
319 count = countchar(self_s, self_len, from_c, maxcount);
320 if (count == 0) {
321 return return_self(self);
322 }
323
324 result_len = self_len - count; /* from_len == 1 */
325 assert(result_len>=0);
326
327 result = STRINGLIB_NEW(NULL, result_len);
328 if (result == NULL) {
329 return NULL;
330 }
331 result_s = STRINGLIB_STR(result);
332
333 start = self_s;
334 end = self_s + self_len;
335 while (count-- > 0) {
336 next = findchar(start, end - start, from_c);
337 if (next == NULL)
338 break;
339 Py_MEMCPY(result_s, start, next - start);
340 result_s += (next - start);
341 start = next + 1;
342 }
343 Py_MEMCPY(result_s, start, end - start);
344
345 return result;
346}
347
348/* len(self)>=1, len(from)>=2, to="", maxcount>=1 */
349
350Py_LOCAL(PyObject *)
351stringlib_replace_delete_substring(PyObject *self,
352 const char *from_s, Py_ssize_t from_len,
353 Py_ssize_t maxcount)
354{
355 const char *self_s, *start, *next, *end;
356 char *result_s;
357 Py_ssize_t self_len, result_len;
358 Py_ssize_t count, offset;
359 PyObject *result;
360
361 self_len = STRINGLIB_LEN(self);
362 self_s = STRINGLIB_STR(self);
363
364 count = stringlib_count(self_s, self_len,
365 from_s, from_len,
366 maxcount);
367
368 if (count == 0) {
369 /* no matches */
370 return return_self(self);
371 }
372
373 result_len = self_len - (count * from_len);
374 assert (result_len>=0);
375
376 result = STRINGLIB_NEW(NULL, result_len);
377 if (result == NULL) {
378 return NULL;
379 }
380 result_s = STRINGLIB_STR(result);
381
382 start = self_s;
383 end = self_s + self_len;
384 while (count-- > 0) {
385 offset = stringlib_find(start, end - start,
386 from_s, from_len,
387 0);
388 if (offset == -1)
389 break;
390 next = start + offset;
391
392 Py_MEMCPY(result_s, start, next - start);
393
394 result_s += (next - start);
395 start = next + from_len;
396 }
397 Py_MEMCPY(result_s, start, end - start);
398 return result;
399}
400
401/* len(self)>=1, len(from)==len(to)==1, maxcount>=1 */
402Py_LOCAL(PyObject *)
403stringlib_replace_single_character_in_place(PyObject *self,
404 char from_c, char to_c,
405 Py_ssize_t maxcount)
406{
407 const char *self_s, *end;
408 char *result_s, *start, *next;
409 Py_ssize_t self_len;
410 PyObject *result;
411
412 /* The result string will be the same size */
413 self_s = STRINGLIB_STR(self);
414 self_len = STRINGLIB_LEN(self);
415
416 next = findchar(self_s, self_len, from_c);
417
418 if (next == NULL) {
419 /* No matches; return the original bytes */
420 return return_self(self);
421 }
422
423 /* Need to make a new bytes */
424 result = STRINGLIB_NEW(NULL, self_len);
425 if (result == NULL) {
426 return NULL;
427 }
428 result_s = STRINGLIB_STR(result);
429 Py_MEMCPY(result_s, self_s, self_len);
430
431 /* change everything in-place, starting with this one */
432 start = result_s + (next - self_s);
433 *start = to_c;
434 start++;
435 end = result_s + self_len;
436
437 while (--maxcount > 0) {
438 next = findchar(start, end - start, from_c);
439 if (next == NULL)
440 break;
441 *next = to_c;
442 start = next + 1;
443 }
444
445 return result;
446}
447
448/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */
449Py_LOCAL(PyObject *)
450stringlib_replace_substring_in_place(PyObject *self,
451 const char *from_s, Py_ssize_t from_len,
452 const char *to_s, Py_ssize_t to_len,
453 Py_ssize_t maxcount)
454{
455 const char *self_s, *end;
456 char *result_s, *start;
457 Py_ssize_t self_len, offset;
458 PyObject *result;
459
460 /* The result bytes will be the same size */
461
462 self_s = STRINGLIB_STR(self);
463 self_len = STRINGLIB_LEN(self);
464
465 offset = stringlib_find(self_s, self_len,
466 from_s, from_len,
467 0);
468 if (offset == -1) {
469 /* No matches; return the original bytes */
470 return return_self(self);
471 }
472
473 /* Need to make a new bytes */
474 result = STRINGLIB_NEW(NULL, self_len);
475 if (result == NULL) {
476 return NULL;
477 }
478 result_s = STRINGLIB_STR(result);
479 Py_MEMCPY(result_s, self_s, self_len);
480
481 /* change everything in-place, starting with this one */
482 start = result_s + offset;
483 Py_MEMCPY(start, to_s, from_len);
484 start += from_len;
485 end = result_s + self_len;
486
487 while ( --maxcount > 0) {
488 offset = stringlib_find(start, end - start,
489 from_s, from_len,
490 0);
491 if (offset == -1)
492 break;
493 Py_MEMCPY(start + offset, to_s, from_len);
494 start += offset + from_len;
495 }
496
497 return result;
498}
499
500/* len(self)>=1, len(from)==1, len(to)>=2, maxcount>=1 */
501Py_LOCAL(PyObject *)
502stringlib_replace_single_character(PyObject *self,
503 char from_c,
504 const char *to_s, Py_ssize_t to_len,
505 Py_ssize_t maxcount)
506{
507 const char *self_s, *start, *next, *end;
508 char *result_s;
509 Py_ssize_t self_len, result_len;
510 Py_ssize_t count;
511 PyObject *result;
512
513 self_s = STRINGLIB_STR(self);
514 self_len = STRINGLIB_LEN(self);
515
516 count = countchar(self_s, self_len, from_c, maxcount);
517 if (count == 0) {
518 /* no matches, return unchanged */
519 return return_self(self);
520 }
521
522 /* use the difference between current and new, hence the "-1" */
523 /* result_len = self_len + count * (to_len-1) */
524 assert(count > 0);
525 if (to_len - 1 > (PY_SSIZE_T_MAX - self_len) / count) {
526 PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
527 return NULL;
528 }
529 result_len = self_len + count * (to_len - 1);
530
531 result = STRINGLIB_NEW(NULL, result_len);
532 if (result == NULL) {
533 return NULL;
534 }
535 result_s = STRINGLIB_STR(result);
536
537 start = self_s;
538 end = self_s + self_len;
539 while (count-- > 0) {
540 next = findchar(start, end - start, from_c);
541 if (next == NULL)
542 break;
543
544 if (next == start) {
545 /* replace with the 'to' */
546 Py_MEMCPY(result_s, to_s, to_len);
547 result_s += to_len;
548 start += 1;
549 } else {
550 /* copy the unchanged old then the 'to' */
551 Py_MEMCPY(result_s, start, next - start);
552 result_s += (next - start);
553 Py_MEMCPY(result_s, to_s, to_len);
554 result_s += to_len;
555 start = next + 1;
556 }
557 }
558 /* Copy the remainder of the remaining bytes */
559 Py_MEMCPY(result_s, start, end - start);
560
561 return result;
562}
563
564/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */
565Py_LOCAL(PyObject *)
566stringlib_replace_substring(PyObject *self,
567 const char *from_s, Py_ssize_t from_len,
568 const char *to_s, Py_ssize_t to_len,
569 Py_ssize_t maxcount)
570{
571 const char *self_s, *start, *next, *end;
572 char *result_s;
573 Py_ssize_t self_len, result_len;
574 Py_ssize_t count, offset;
575 PyObject *result;
576
577 self_s = STRINGLIB_STR(self);
578 self_len = STRINGLIB_LEN(self);
579
580 count = stringlib_count(self_s, self_len,
581 from_s, from_len,
582 maxcount);
583
584 if (count == 0) {
585 /* no matches, return unchanged */
586 return return_self(self);
587 }
588
589 /* Check for overflow */
590 /* result_len = self_len + count * (to_len-from_len) */
591 assert(count > 0);
592 if (to_len - from_len > (PY_SSIZE_T_MAX - self_len) / count) {
593 PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
594 return NULL;
595 }
596 result_len = self_len + count * (to_len - from_len);
597
598 result = STRINGLIB_NEW(NULL, result_len);
599 if (result == NULL) {
600 return NULL;
601 }
602 result_s = STRINGLIB_STR(result);
603
604 start = self_s;
605 end = self_s + self_len;
606 while (count-- > 0) {
607 offset = stringlib_find(start, end - start,
608 from_s, from_len,
609 0);
610 if (offset == -1)
611 break;
612 next = start + offset;
613 if (next == start) {
614 /* replace with the 'to' */
615 Py_MEMCPY(result_s, to_s, to_len);
616 result_s += to_len;
617 start += from_len;
618 } else {
619 /* copy the unchanged old then the 'to' */
620 Py_MEMCPY(result_s, start, next - start);
621 result_s += (next - start);
622 Py_MEMCPY(result_s, to_s, to_len);
623 result_s += to_len;
624 start = next + from_len;
625 }
626 }
627 /* Copy the remainder of the remaining bytes */
628 Py_MEMCPY(result_s, start, end - start);
629
630 return result;
631}
632
633
634Py_LOCAL(PyObject *)
635stringlib_replace(PyObject *self,
636 const char *from_s, Py_ssize_t from_len,
637 const char *to_s, Py_ssize_t to_len,
638 Py_ssize_t maxcount)
639{
640 if (maxcount < 0) {
641 maxcount = PY_SSIZE_T_MAX;
642 } else if (maxcount == 0 || STRINGLIB_LEN(self) == 0) {
643 /* nothing to do; return the original bytes */
644 return return_self(self);
645 }
646
647 /* Handle zero-length special cases */
648 if (from_len == 0) {
649 if (to_len == 0) {
650 /* nothing to do; return the original bytes */
651 return return_self(self);
652 }
653 /* insert the 'to' bytes everywhere. */
654 /* >>> b"Python".replace(b"", b".") */
655 /* b'.P.y.t.h.o.n.' */
656 return stringlib_replace_interleave(self, to_s, to_len, maxcount);
657 }
658
659 /* Except for b"".replace(b"", b"A") == b"A" there is no way beyond this */
660 /* point for an empty self bytes to generate a non-empty bytes */
661 /* Special case so the remaining code always gets a non-empty bytes */
662 if (STRINGLIB_LEN(self) == 0) {
663 return return_self(self);
664 }
665
666 if (to_len == 0) {
667 /* delete all occurrences of 'from' bytes */
668 if (from_len == 1) {
669 return stringlib_replace_delete_single_character(
670 self, from_s[0], maxcount);
671 } else {
672 return stringlib_replace_delete_substring(
673 self, from_s, from_len, maxcount);
674 }
675 }
676
677 /* Handle special case where both bytes have the same length */
678
679 if (from_len == to_len) {
680 if (from_len == 1) {
681 return stringlib_replace_single_character_in_place(
682 self, from_s[0], to_s[0], maxcount);
683 } else {
684 return stringlib_replace_substring_in_place(
685 self, from_s, from_len, to_s, to_len, maxcount);
686 }
687 }
688
689 /* Otherwise use the more generic algorithms */
690 if (from_len == 1) {
691 return stringlib_replace_single_character(
692 self, from_s[0], to_s, to_len, maxcount);
693 } else {
694 /* len('from')>=2, len('to')>=1 */
695 return stringlib_replace_substring(
696 self, from_s, from_len, to_s, to_len, maxcount);
697 }
698}
699
700#undef findchar