Branch data Line data Source code
1 : : #if STRINGLIB_IS_UNICODE
2 : : # error "transmogrify.h only compatible with byte-wise strings"
3 : : #endif
4 : :
5 : : /* the more complicated methods. parts of these should be pulled out into the
6 : : shared code in bytes_methods.c to cut down on duplicate code bloat. */
7 : :
8 : : /*[clinic input]
9 : : class B "PyObject *" "&PyType_Type"
10 : : [clinic start generated code]*/
11 : : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=2935558188d97c76]*/
12 : :
13 : : #include "clinic/transmogrify.h.h"
14 : :
15 : : static inline PyObject *
16 : 114 : return_self(PyObject *self)
17 : : {
18 : : #if !STRINGLIB_MUTABLE
19 [ + - ]: 114 : if (STRINGLIB_CHECK_EXACT(self)) {
20 : 114 : return Py_NewRef(self);
21 : : }
22 : : #endif
23 : 0 : return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self));
24 : : }
25 : :
26 : : /*[clinic input]
27 : : B.expandtabs as stringlib_expandtabs
28 : :
29 : : tabsize: int = 8
30 : :
31 : : Return a copy where all tab characters are expanded using spaces.
32 : :
33 : : If tabsize is not given, a tab size of 8 characters is assumed.
34 : : [clinic start generated code]*/
35 : :
36 : : static PyObject *
37 : 0 : stringlib_expandtabs_impl(PyObject *self, int tabsize)
38 : : /*[clinic end generated code: output=069cb7fae72e4c2b input=3c6d3b12aa3ccbea]*/
39 : : {
40 : : const char *e, *p;
41 : : char *q;
42 : : Py_ssize_t i, j;
43 : : PyObject *u;
44 : :
45 : : /* First pass: determine size of output string */
46 : 0 : i = j = 0;
47 : 0 : e = STRINGLIB_STR(self) + STRINGLIB_LEN(self);
48 [ # # ]: 0 : for (p = STRINGLIB_STR(self); p < e; p++) {
49 [ # # ]: 0 : if (*p == '\t') {
50 [ # # ]: 0 : if (tabsize > 0) {
51 : 0 : Py_ssize_t incr = tabsize - (j % tabsize);
52 [ # # ]: 0 : if (j > PY_SSIZE_T_MAX - incr)
53 : 0 : goto overflow;
54 : 0 : j += incr;
55 : : }
56 : : }
57 : : else {
58 [ # # ]: 0 : if (j > PY_SSIZE_T_MAX - 1)
59 : 0 : goto overflow;
60 : 0 : j++;
61 [ # # # # ]: 0 : if (*p == '\n' || *p == '\r') {
62 [ # # ]: 0 : if (i > PY_SSIZE_T_MAX - j)
63 : 0 : goto overflow;
64 : 0 : i += j;
65 : 0 : j = 0;
66 : : }
67 : : }
68 : : }
69 : :
70 [ # # ]: 0 : if (i > PY_SSIZE_T_MAX - j)
71 : 0 : goto overflow;
72 : :
73 : : /* Second pass: create output string and fill it */
74 : 0 : u = STRINGLIB_NEW(NULL, i + j);
75 [ # # ]: 0 : if (!u)
76 : 0 : return NULL;
77 : :
78 : 0 : j = 0;
79 : 0 : q = STRINGLIB_STR(u);
80 : :
81 [ # # ]: 0 : for (p = STRINGLIB_STR(self); p < e; p++) {
82 [ # # ]: 0 : if (*p == '\t') {
83 [ # # ]: 0 : if (tabsize > 0) {
84 : 0 : i = tabsize - (j % tabsize);
85 : 0 : j += i;
86 [ # # ]: 0 : while (i--)
87 : 0 : *q++ = ' ';
88 : : }
89 : : }
90 : : else {
91 : 0 : j++;
92 : 0 : *q++ = *p;
93 [ # # # # ]: 0 : if (*p == '\n' || *p == '\r')
94 : 0 : j = 0;
95 : : }
96 : : }
97 : :
98 : 0 : return u;
99 : 0 : overflow:
100 : 0 : PyErr_SetString(PyExc_OverflowError, "result too long");
101 : 0 : return NULL;
102 : : }
103 : :
104 : : static inline PyObject *
105 : 0 : pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill)
106 : : {
107 : : PyObject *u;
108 : :
109 [ # # ]: 0 : if (left < 0)
110 : 0 : left = 0;
111 [ # # ]: 0 : if (right < 0)
112 : 0 : right = 0;
113 : :
114 [ # # # # ]: 0 : if (left == 0 && right == 0) {
115 : 0 : return return_self(self);
116 : : }
117 : :
118 : 0 : u = STRINGLIB_NEW(NULL, left + STRINGLIB_LEN(self) + right);
119 [ # # ]: 0 : if (u) {
120 [ # # ]: 0 : if (left)
121 : 0 : memset(STRINGLIB_STR(u), fill, left);
122 : 0 : memcpy(STRINGLIB_STR(u) + left,
123 : 0 : STRINGLIB_STR(self),
124 : 0 : STRINGLIB_LEN(self));
125 [ # # ]: 0 : if (right)
126 : 0 : memset(STRINGLIB_STR(u) + left + STRINGLIB_LEN(self),
127 : : fill, right);
128 : : }
129 : :
130 : 0 : return u;
131 : : }
132 : :
133 : : /*[clinic input]
134 : : B.ljust as stringlib_ljust
135 : :
136 : : width: Py_ssize_t
137 : : fillchar: char = b' '
138 : : /
139 : :
140 : : Return a left-justified string of length width.
141 : :
142 : : Padding is done using the specified fill character.
143 : : [clinic start generated code]*/
144 : :
145 : : static PyObject *
146 : 0 : stringlib_ljust_impl(PyObject *self, Py_ssize_t width, char fillchar)
147 : : /*[clinic end generated code: output=c79ca173c5ff8337 input=eff2d014bc7d80df]*/
148 : : {
149 [ # # ]: 0 : if (STRINGLIB_LEN(self) >= width) {
150 : 0 : return return_self(self);
151 : : }
152 : :
153 : 0 : return pad(self, 0, width - STRINGLIB_LEN(self), fillchar);
154 : : }
155 : :
156 : :
157 : : /*[clinic input]
158 : : B.rjust as stringlib_rjust
159 : :
160 : : width: Py_ssize_t
161 : : fillchar: char = b' '
162 : : /
163 : :
164 : : Return a right-justified string of length width.
165 : :
166 : : Padding is done using the specified fill character.
167 : : [clinic start generated code]*/
168 : :
169 : : static PyObject *
170 : 0 : stringlib_rjust_impl(PyObject *self, Py_ssize_t width, char fillchar)
171 : : /*[clinic end generated code: output=7df5d728a5439570 input=218b0bd31308955d]*/
172 : : {
173 [ # # ]: 0 : if (STRINGLIB_LEN(self) >= width) {
174 : 0 : return return_self(self);
175 : : }
176 : :
177 : 0 : return pad(self, width - STRINGLIB_LEN(self), 0, fillchar);
178 : : }
179 : :
180 : :
181 : : /*[clinic input]
182 : : B.center as stringlib_center
183 : :
184 : : width: Py_ssize_t
185 : : fillchar: char = b' '
186 : : /
187 : :
188 : : Return a centered string of length width.
189 : :
190 : : Padding is done using the specified fill character.
191 : : [clinic start generated code]*/
192 : :
193 : : static PyObject *
194 : 0 : stringlib_center_impl(PyObject *self, Py_ssize_t width, char fillchar)
195 : : /*[clinic end generated code: output=d8da2e055288b4c2 input=3776fd278765d89b]*/
196 : : {
197 : : Py_ssize_t marg, left;
198 : :
199 [ # # ]: 0 : if (STRINGLIB_LEN(self) >= width) {
200 : 0 : return return_self(self);
201 : : }
202 : :
203 : 0 : marg = width - STRINGLIB_LEN(self);
204 : 0 : left = marg / 2 + (marg & width & 1);
205 : :
206 : 0 : return pad(self, left, marg - left, fillchar);
207 : : }
208 : :
209 : : /*[clinic input]
210 : : B.zfill as stringlib_zfill
211 : :
212 : : width: Py_ssize_t
213 : : /
214 : :
215 : : Pad a numeric string with zeros on the left, to fill a field of the given width.
216 : :
217 : : The original string is never truncated.
218 : : [clinic start generated code]*/
219 : :
220 : : static PyObject *
221 : 0 : stringlib_zfill_impl(PyObject *self, Py_ssize_t width)
222 : : /*[clinic end generated code: output=0b3c684a7f1b2319 input=2da6d7b8e9bcb19a]*/
223 : : {
224 : : Py_ssize_t fill;
225 : : PyObject *s;
226 : : char *p;
227 : :
228 [ # # ]: 0 : if (STRINGLIB_LEN(self) >= width) {
229 : 0 : return return_self(self);
230 : : }
231 : :
232 : 0 : fill = width - STRINGLIB_LEN(self);
233 : :
234 : 0 : s = pad(self, fill, 0, '0');
235 : :
236 [ # # ]: 0 : if (s == NULL)
237 : 0 : return NULL;
238 : :
239 : 0 : p = STRINGLIB_STR(s);
240 [ # # # # ]: 0 : if (p[fill] == '+' || p[fill] == '-') {
241 : : /* move sign to beginning of string */
242 : 0 : p[0] = p[fill];
243 : 0 : p[fill] = '0';
244 : : }
245 : :
246 : 0 : return s;
247 : : }
248 : :
249 : :
250 : : /* find and count characters and substrings */
251 : :
252 : : #define findchar(target, target_len, c) \
253 : : ((char *)memchr((const void *)(target), c, target_len))
254 : :
255 : :
256 : : static Py_ssize_t
257 : 0 : countchar(const char *target, Py_ssize_t target_len, char c,
258 : : Py_ssize_t maxcount)
259 : : {
260 : 0 : Py_ssize_t count = 0;
261 : 0 : const char *start = target;
262 : 0 : const char *end = target + target_len;
263 : :
264 [ # # ]: 0 : while ((start = findchar(start, end - start, c)) != NULL) {
265 : 0 : count++;
266 [ # # ]: 0 : if (count >= maxcount)
267 : 0 : break;
268 : 0 : start += 1;
269 : : }
270 : 0 : return count;
271 : : }
272 : :
273 : :
274 : : /* Algorithms for different cases of string replacement */
275 : :
276 : : /* len(self)>=1, from="", len(to)>=1, maxcount>=1 */
277 : : static PyObject *
278 : 0 : stringlib_replace_interleave(PyObject *self,
279 : : const char *to_s, Py_ssize_t to_len,
280 : : Py_ssize_t maxcount)
281 : : {
282 : : const char *self_s;
283 : : char *result_s;
284 : : Py_ssize_t self_len, result_len;
285 : : Py_ssize_t count, i;
286 : : PyObject *result;
287 : :
288 : 0 : self_len = STRINGLIB_LEN(self);
289 : :
290 : : /* 1 at the end plus 1 after every character;
291 : : count = min(maxcount, self_len + 1) */
292 [ # # ]: 0 : if (maxcount <= self_len) {
293 : 0 : count = maxcount;
294 : : }
295 : : else {
296 : : /* Can't overflow: self_len + 1 <= maxcount <= PY_SSIZE_T_MAX. */
297 : 0 : count = self_len + 1;
298 : : }
299 : :
300 : : /* Check for overflow */
301 : : /* result_len = count * to_len + self_len; */
302 : : assert(count > 0);
303 [ # # ]: 0 : if (to_len > (PY_SSIZE_T_MAX - self_len) / count) {
304 : 0 : PyErr_SetString(PyExc_OverflowError,
305 : : "replace bytes is too long");
306 : 0 : return NULL;
307 : : }
308 : 0 : result_len = count * to_len + self_len;
309 : 0 : result = STRINGLIB_NEW(NULL, result_len);
310 [ # # ]: 0 : if (result == NULL) {
311 : 0 : return NULL;
312 : : }
313 : :
314 : 0 : self_s = STRINGLIB_STR(self);
315 : 0 : result_s = STRINGLIB_STR(result);
316 : :
317 [ # # ]: 0 : if (to_len > 1) {
318 : : /* Lay the first one down (guaranteed this will occur) */
319 : 0 : memcpy(result_s, to_s, to_len);
320 : 0 : result_s += to_len;
321 : 0 : count -= 1;
322 : :
323 [ # # ]: 0 : for (i = 0; i < count; i++) {
324 : 0 : *result_s++ = *self_s++;
325 : 0 : memcpy(result_s, to_s, to_len);
326 : 0 : result_s += to_len;
327 : : }
328 : : }
329 : : else {
330 : 0 : result_s[0] = to_s[0];
331 : 0 : result_s += to_len;
332 : 0 : count -= 1;
333 [ # # ]: 0 : for (i = 0; i < count; i++) {
334 : 0 : *result_s++ = *self_s++;
335 : 0 : result_s[0] = to_s[0];
336 : 0 : result_s += to_len;
337 : : }
338 : : }
339 : :
340 : : /* Copy the rest of the original string */
341 : 0 : memcpy(result_s, self_s, self_len - i);
342 : :
343 : 0 : return result;
344 : : }
345 : :
346 : : /* Special case for deleting a single character */
347 : : /* len(self)>=1, len(from)==1, to="", maxcount>=1 */
348 : : static PyObject *
349 : 0 : stringlib_replace_delete_single_character(PyObject *self,
350 : : char from_c, Py_ssize_t maxcount)
351 : : {
352 : : const char *self_s, *start, *next, *end;
353 : : char *result_s;
354 : : Py_ssize_t self_len, result_len;
355 : : Py_ssize_t count;
356 : : PyObject *result;
357 : :
358 : 0 : self_len = STRINGLIB_LEN(self);
359 : 0 : self_s = STRINGLIB_STR(self);
360 : :
361 : 0 : count = countchar(self_s, self_len, from_c, maxcount);
362 [ # # ]: 0 : if (count == 0) {
363 : 0 : return return_self(self);
364 : : }
365 : :
366 : 0 : result_len = self_len - count; /* from_len == 1 */
367 : : assert(result_len>=0);
368 : :
369 : 0 : result = STRINGLIB_NEW(NULL, result_len);
370 [ # # ]: 0 : if (result == NULL) {
371 : 0 : return NULL;
372 : : }
373 : 0 : result_s = STRINGLIB_STR(result);
374 : :
375 : 0 : start = self_s;
376 : 0 : end = self_s + self_len;
377 [ # # ]: 0 : while (count-- > 0) {
378 : 0 : next = findchar(start, end - start, from_c);
379 [ # # ]: 0 : if (next == NULL)
380 : 0 : break;
381 : 0 : memcpy(result_s, start, next - start);
382 : 0 : result_s += (next - start);
383 : 0 : start = next + 1;
384 : : }
385 : 0 : memcpy(result_s, start, end - start);
386 : :
387 : 0 : return result;
388 : : }
389 : :
390 : : /* len(self)>=1, len(from)>=2, to="", maxcount>=1 */
391 : :
392 : : static PyObject *
393 : 0 : stringlib_replace_delete_substring(PyObject *self,
394 : : const char *from_s, Py_ssize_t from_len,
395 : : Py_ssize_t maxcount)
396 : : {
397 : : const char *self_s, *start, *next, *end;
398 : : char *result_s;
399 : : Py_ssize_t self_len, result_len;
400 : : Py_ssize_t count, offset;
401 : : PyObject *result;
402 : :
403 : 0 : self_len = STRINGLIB_LEN(self);
404 : 0 : self_s = STRINGLIB_STR(self);
405 : :
406 : 0 : count = stringlib_count(self_s, self_len,
407 : : from_s, from_len,
408 : : maxcount);
409 : :
410 [ # # ]: 0 : if (count == 0) {
411 : : /* no matches */
412 : 0 : return return_self(self);
413 : : }
414 : :
415 : 0 : result_len = self_len - (count * from_len);
416 : : assert (result_len>=0);
417 : :
418 : 0 : result = STRINGLIB_NEW(NULL, result_len);
419 [ # # ]: 0 : if (result == NULL) {
420 : 0 : return NULL;
421 : : }
422 : 0 : result_s = STRINGLIB_STR(result);
423 : :
424 : 0 : start = self_s;
425 : 0 : end = self_s + self_len;
426 [ # # ]: 0 : while (count-- > 0) {
427 : 0 : offset = stringlib_find(start, end - start,
428 : : from_s, from_len,
429 : : 0);
430 [ # # ]: 0 : if (offset == -1)
431 : 0 : break;
432 : 0 : next = start + offset;
433 : :
434 : 0 : memcpy(result_s, start, next - start);
435 : :
436 : 0 : result_s += (next - start);
437 : 0 : start = next + from_len;
438 : : }
439 : 0 : memcpy(result_s, start, end - start);
440 : 0 : return result;
441 : : }
442 : :
443 : : /* len(self)>=1, len(from)==len(to)==1, maxcount>=1 */
444 : : static PyObject *
445 : 114 : stringlib_replace_single_character_in_place(PyObject *self,
446 : : char from_c, char to_c,
447 : : Py_ssize_t maxcount)
448 : : {
449 : : const char *self_s, *end;
450 : : char *result_s, *start, *next;
451 : : Py_ssize_t self_len;
452 : : PyObject *result;
453 : :
454 : : /* The result string will be the same size */
455 : 114 : self_s = STRINGLIB_STR(self);
456 : 114 : self_len = STRINGLIB_LEN(self);
457 : :
458 : 114 : next = findchar(self_s, self_len, from_c);
459 : :
460 [ + - ]: 114 : if (next == NULL) {
461 : : /* No matches; return the original bytes */
462 : 114 : return return_self(self);
463 : : }
464 : :
465 : : /* Need to make a new bytes */
466 : 0 : result = STRINGLIB_NEW(NULL, self_len);
467 [ # # ]: 0 : if (result == NULL) {
468 : 0 : return NULL;
469 : : }
470 : 0 : result_s = STRINGLIB_STR(result);
471 : 0 : memcpy(result_s, self_s, self_len);
472 : :
473 : : /* change everything in-place, starting with this one */
474 : 0 : start = result_s + (next - self_s);
475 : 0 : *start = to_c;
476 : 0 : start++;
477 : 0 : end = result_s + self_len;
478 : :
479 [ # # ]: 0 : while (--maxcount > 0) {
480 : 0 : next = findchar(start, end - start, from_c);
481 [ # # ]: 0 : if (next == NULL)
482 : 0 : break;
483 : 0 : *next = to_c;
484 : 0 : start = next + 1;
485 : : }
486 : :
487 : 0 : return result;
488 : : }
489 : :
490 : : /* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */
491 : : static PyObject *
492 : 0 : stringlib_replace_substring_in_place(PyObject *self,
493 : : const char *from_s, Py_ssize_t from_len,
494 : : const char *to_s, Py_ssize_t to_len,
495 : : Py_ssize_t maxcount)
496 : : {
497 : : const char *self_s, *end;
498 : : char *result_s, *start;
499 : : Py_ssize_t self_len, offset;
500 : : PyObject *result;
501 : :
502 : : /* The result bytes will be the same size */
503 : :
504 : 0 : self_s = STRINGLIB_STR(self);
505 : 0 : self_len = STRINGLIB_LEN(self);
506 : :
507 : 0 : offset = stringlib_find(self_s, self_len,
508 : : from_s, from_len,
509 : : 0);
510 [ # # ]: 0 : if (offset == -1) {
511 : : /* No matches; return the original bytes */
512 : 0 : return return_self(self);
513 : : }
514 : :
515 : : /* Need to make a new bytes */
516 : 0 : result = STRINGLIB_NEW(NULL, self_len);
517 [ # # ]: 0 : if (result == NULL) {
518 : 0 : return NULL;
519 : : }
520 : 0 : result_s = STRINGLIB_STR(result);
521 : 0 : memcpy(result_s, self_s, self_len);
522 : :
523 : : /* change everything in-place, starting with this one */
524 : 0 : start = result_s + offset;
525 : 0 : memcpy(start, to_s, from_len);
526 : 0 : start += from_len;
527 : 0 : end = result_s + self_len;
528 : :
529 [ # # ]: 0 : while ( --maxcount > 0) {
530 : 0 : offset = stringlib_find(start, end - start,
531 : : from_s, from_len,
532 : : 0);
533 [ # # ]: 0 : if (offset == -1)
534 : 0 : break;
535 : 0 : memcpy(start + offset, to_s, from_len);
536 : 0 : start += offset + from_len;
537 : : }
538 : :
539 : 0 : return result;
540 : : }
541 : :
542 : : /* len(self)>=1, len(from)==1, len(to)>=2, maxcount>=1 */
543 : : static PyObject *
544 : 0 : stringlib_replace_single_character(PyObject *self,
545 : : char from_c,
546 : : const char *to_s, Py_ssize_t to_len,
547 : : Py_ssize_t maxcount)
548 : : {
549 : : const char *self_s, *start, *next, *end;
550 : : char *result_s;
551 : : Py_ssize_t self_len, result_len;
552 : : Py_ssize_t count;
553 : : PyObject *result;
554 : :
555 : 0 : self_s = STRINGLIB_STR(self);
556 : 0 : self_len = STRINGLIB_LEN(self);
557 : :
558 : 0 : count = countchar(self_s, self_len, from_c, maxcount);
559 [ # # ]: 0 : if (count == 0) {
560 : : /* no matches, return unchanged */
561 : 0 : return return_self(self);
562 : : }
563 : :
564 : : /* use the difference between current and new, hence the "-1" */
565 : : /* result_len = self_len + count * (to_len-1) */
566 : : assert(count > 0);
567 [ # # ]: 0 : if (to_len - 1 > (PY_SSIZE_T_MAX - self_len) / count) {
568 : 0 : PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
569 : 0 : return NULL;
570 : : }
571 : 0 : result_len = self_len + count * (to_len - 1);
572 : :
573 : 0 : result = STRINGLIB_NEW(NULL, result_len);
574 [ # # ]: 0 : if (result == NULL) {
575 : 0 : return NULL;
576 : : }
577 : 0 : result_s = STRINGLIB_STR(result);
578 : :
579 : 0 : start = self_s;
580 : 0 : end = self_s + self_len;
581 [ # # ]: 0 : while (count-- > 0) {
582 : 0 : next = findchar(start, end - start, from_c);
583 [ # # ]: 0 : if (next == NULL)
584 : 0 : break;
585 : :
586 [ # # ]: 0 : if (next == start) {
587 : : /* replace with the 'to' */
588 : 0 : memcpy(result_s, to_s, to_len);
589 : 0 : result_s += to_len;
590 : 0 : start += 1;
591 : : } else {
592 : : /* copy the unchanged old then the 'to' */
593 : 0 : memcpy(result_s, start, next - start);
594 : 0 : result_s += (next - start);
595 : 0 : memcpy(result_s, to_s, to_len);
596 : 0 : result_s += to_len;
597 : 0 : start = next + 1;
598 : : }
599 : : }
600 : : /* Copy the remainder of the remaining bytes */
601 : 0 : memcpy(result_s, start, end - start);
602 : :
603 : 0 : return result;
604 : : }
605 : :
606 : : /* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */
607 : : static PyObject *
608 : 0 : stringlib_replace_substring(PyObject *self,
609 : : const char *from_s, Py_ssize_t from_len,
610 : : const char *to_s, Py_ssize_t to_len,
611 : : Py_ssize_t maxcount)
612 : : {
613 : : const char *self_s, *start, *next, *end;
614 : : char *result_s;
615 : : Py_ssize_t self_len, result_len;
616 : : Py_ssize_t count, offset;
617 : : PyObject *result;
618 : :
619 : 0 : self_s = STRINGLIB_STR(self);
620 : 0 : self_len = STRINGLIB_LEN(self);
621 : :
622 : 0 : count = stringlib_count(self_s, self_len,
623 : : from_s, from_len,
624 : : maxcount);
625 : :
626 [ # # ]: 0 : if (count == 0) {
627 : : /* no matches, return unchanged */
628 : 0 : return return_self(self);
629 : : }
630 : :
631 : : /* Check for overflow */
632 : : /* result_len = self_len + count * (to_len-from_len) */
633 : : assert(count > 0);
634 [ # # ]: 0 : if (to_len - from_len > (PY_SSIZE_T_MAX - self_len) / count) {
635 : 0 : PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
636 : 0 : return NULL;
637 : : }
638 : 0 : result_len = self_len + count * (to_len - from_len);
639 : :
640 : 0 : result = STRINGLIB_NEW(NULL, result_len);
641 [ # # ]: 0 : if (result == NULL) {
642 : 0 : return NULL;
643 : : }
644 : 0 : result_s = STRINGLIB_STR(result);
645 : :
646 : 0 : start = self_s;
647 : 0 : end = self_s + self_len;
648 [ # # ]: 0 : while (count-- > 0) {
649 : 0 : offset = stringlib_find(start, end - start,
650 : : from_s, from_len,
651 : : 0);
652 [ # # ]: 0 : if (offset == -1)
653 : 0 : break;
654 : 0 : next = start + offset;
655 [ # # ]: 0 : if (next == start) {
656 : : /* replace with the 'to' */
657 : 0 : memcpy(result_s, to_s, to_len);
658 : 0 : result_s += to_len;
659 : 0 : start += from_len;
660 : : } else {
661 : : /* copy the unchanged old then the 'to' */
662 : 0 : memcpy(result_s, start, next - start);
663 : 0 : result_s += (next - start);
664 : 0 : memcpy(result_s, to_s, to_len);
665 : 0 : result_s += to_len;
666 : 0 : start = next + from_len;
667 : : }
668 : : }
669 : : /* Copy the remainder of the remaining bytes */
670 : 0 : memcpy(result_s, start, end - start);
671 : :
672 : 0 : return result;
673 : : }
674 : :
675 : :
676 : : static PyObject *
677 : 114 : stringlib_replace(PyObject *self,
678 : : const char *from_s, Py_ssize_t from_len,
679 : : const char *to_s, Py_ssize_t to_len,
680 : : Py_ssize_t maxcount)
681 : : {
682 [ - + ]: 114 : if (STRINGLIB_LEN(self) < from_len) {
683 : : /* nothing to do; return the original bytes */
684 : 0 : return return_self(self);
685 : : }
686 [ + - ]: 114 : if (maxcount < 0) {
687 : 114 : maxcount = PY_SSIZE_T_MAX;
688 [ # # ]: 0 : } else if (maxcount == 0) {
689 : : /* nothing to do; return the original bytes */
690 : 0 : return return_self(self);
691 : : }
692 : :
693 : : /* Handle zero-length special cases */
694 [ - + ]: 114 : if (from_len == 0) {
695 [ # # ]: 0 : if (to_len == 0) {
696 : : /* nothing to do; return the original bytes */
697 : 0 : return return_self(self);
698 : : }
699 : : /* insert the 'to' bytes everywhere. */
700 : : /* >>> b"Python".replace(b"", b".") */
701 : : /* b'.P.y.t.h.o.n.' */
702 : 0 : return stringlib_replace_interleave(self, to_s, to_len, maxcount);
703 : : }
704 : :
705 [ - + ]: 114 : if (to_len == 0) {
706 : : /* delete all occurrences of 'from' bytes */
707 [ # # ]: 0 : if (from_len == 1) {
708 : 0 : return stringlib_replace_delete_single_character(
709 : 0 : self, from_s[0], maxcount);
710 : : } else {
711 : 0 : return stringlib_replace_delete_substring(
712 : : self, from_s, from_len, maxcount);
713 : : }
714 : : }
715 : :
716 : : /* Handle special case where both bytes have the same length */
717 : :
718 [ + - ]: 114 : if (from_len == to_len) {
719 [ + - ]: 114 : if (from_len == 1) {
720 : 114 : return stringlib_replace_single_character_in_place(
721 : 114 : self, from_s[0], to_s[0], maxcount);
722 : : } else {
723 : 0 : return stringlib_replace_substring_in_place(
724 : : self, from_s, from_len, to_s, to_len, maxcount);
725 : : }
726 : : }
727 : :
728 : : /* Otherwise use the more generic algorithms */
729 [ # # ]: 0 : if (from_len == 1) {
730 : 0 : return stringlib_replace_single_character(
731 : 0 : self, from_s[0], to_s, to_len, maxcount);
732 : : } else {
733 : : /* len('from')>=2, len('to')>=1 */
734 : 0 : return stringlib_replace_substring(
735 : : self, from_s, from_len, to_s, to_len, maxcount);
736 : : }
737 : : }
738 : :
739 : : #undef findchar
|