| 610 } |
610 } |
| 611 |
611 |
| 612 cxmutstr cx_strreplacen_a( |
612 cxmutstr cx_strreplacen_a( |
| 613 const CxAllocator *allocator, |
613 const CxAllocator *allocator, |
| 614 cxstring str, |
614 cxstring str, |
| 615 cxstring pattern, |
615 cxstring search, |
| 616 cxstring replacement, |
616 cxstring replacement, |
| 617 size_t replmax |
617 size_t replmax |
| 618 ) { |
618 ) { |
| 619 |
619 |
| 620 if (pattern.length == 0 || pattern.length > str.length || replmax == 0) |
620 if (search.length == 0 || search.length > str.length || replmax == 0) |
| 621 return cx_strdup_a(allocator, str); |
621 return cx_strdup_a(allocator, str); |
| 622 |
622 |
| 623 // Compute expected buffer length |
623 // Compute expected buffer length |
| 624 size_t ibufmax = str.length / pattern.length; |
624 size_t ibufmax = str.length / search.length; |
| 625 size_t ibuflen = replmax < ibufmax ? replmax : ibufmax; |
625 size_t ibuflen = replmax < ibufmax ? replmax : ibufmax; |
| 626 if (ibuflen > CX_STRREPLACE_INDEX_BUFFER_SIZE) { |
626 if (ibuflen > CX_STRREPLACE_INDEX_BUFFER_SIZE) { |
| 627 ibuflen = CX_STRREPLACE_INDEX_BUFFER_SIZE; |
627 ibuflen = CX_STRREPLACE_INDEX_BUFFER_SIZE; |
| 628 } |
628 } |
| 629 |
629 |
| 636 |
636 |
| 637 // Search occurrences |
637 // Search occurrences |
| 638 cxstring searchstr = str; |
638 cxstring searchstr = str; |
| 639 size_t found = 0; |
639 size_t found = 0; |
| 640 do { |
640 do { |
| 641 cxstring match = cx_strstr(searchstr, pattern); |
641 cxstring match = cx_strstr(searchstr, search); |
| 642 if (match.length > 0) { |
642 if (match.length > 0) { |
| 643 // Allocate next buffer in chain, if required |
643 // Allocate next buffer in chain, if required |
| 644 if (curbuf->len == ibuflen) { |
644 if (curbuf->len == ibuflen) { |
| 645 struct cx_strreplace_ibuf *nextbuf = |
645 struct cx_strreplace_ibuf *nextbuf = |
| 646 calloc(1, sizeof(struct cx_strreplace_ibuf)); |
646 calloc(1, sizeof(struct cx_strreplace_ibuf)); |
| 660 |
660 |
| 661 // Record match index |
661 // Record match index |
| 662 found++; |
662 found++; |
| 663 size_t idx = match.ptr - str.ptr; |
663 size_t idx = match.ptr - str.ptr; |
| 664 curbuf->buf[curbuf->len++] = idx; |
664 curbuf->buf[curbuf->len++] = idx; |
| 665 searchstr.ptr = match.ptr + pattern.length; |
665 searchstr.ptr = match.ptr + search.length; |
| 666 searchstr.length = str.length - idx - pattern.length; |
666 searchstr.length = str.length - idx - search.length; |
| 667 } else { |
667 } else { |
| 668 break; |
668 break; |
| 669 } |
669 } |
| 670 } while (searchstr.length > 0 && found < replmax); |
670 } while (searchstr.length > 0 && found < replmax); |
| 671 |
671 |
| 672 // Allocate result string |
672 // Allocate result string |
| 673 cxmutstr result; |
673 cxmutstr result; |
| 674 { |
674 { |
| 675 long long adjlen = (long long) replacement.length - (long long) pattern.length; |
675 long long adjlen = (long long) replacement.length - (long long) search.length; |
| 676 size_t rcount = 0; |
676 size_t rcount = 0; |
| 677 curbuf = &ibuf; |
677 curbuf = &ibuf; |
| 678 do { |
678 do { |
| 679 rcount += curbuf->len; |
679 rcount += curbuf->len; |
| 680 curbuf = curbuf->next; |
680 curbuf = curbuf->next; |
| 701 destptr += srclen; |
701 destptr += srclen; |
| 702 srcidx += srclen; |
702 srcidx += srclen; |
| 703 } |
703 } |
| 704 |
704 |
| 705 // Copy the replacement and skip the source pattern |
705 // Copy the replacement and skip the source pattern |
| 706 srcidx += pattern.length; |
706 srcidx += search.length; |
| 707 memcpy(destptr, replacement.ptr, replacement.length); |
707 memcpy(destptr, replacement.ptr, replacement.length); |
| 708 destptr += replacement.length; |
708 destptr += replacement.length; |
| 709 } |
709 } |
| 710 curbuf = curbuf->next; |
710 curbuf = curbuf->next; |
| 711 } while (curbuf); |
711 } while (curbuf); |