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); |