660 ret.ptr[i] = toupper(ret.ptr[i]); |
660 ret.ptr[i] = toupper(ret.ptr[i]); |
661 } |
661 } |
662 return ret; |
662 return ret; |
663 } |
663 } |
664 |
664 |
|
665 #define REPLACE_INDEX_BUFFER_MAX 100 |
|
666 |
|
667 struct scstrreplace_ibuf { |
|
668 size_t* buf; |
|
669 unsigned int len; /* small indices */ |
|
670 struct scstrreplace_ibuf* next; |
|
671 }; |
|
672 |
|
673 static void scstrrepl_free_ibuf(struct scstrreplace_ibuf *buf) { |
|
674 while (buf) { |
|
675 struct scstrreplace_ibuf *next = buf->next; |
|
676 free(buf->buf); |
|
677 free(buf); |
|
678 buf = next; |
|
679 } |
|
680 } |
|
681 |
|
682 sstr_t scstrreplacen_a(UcxAllocator *allocator, scstr_t str, |
|
683 scstr_t pattern, scstr_t replacement, size_t replmax) { |
|
684 |
|
685 if (pattern.length == 0 || pattern.length > str.length) |
|
686 return sstrdup(str); |
|
687 |
|
688 /* Compute expected buffer length */ |
|
689 size_t ibufmax = str.length / pattern.length; |
|
690 size_t ibuflen = replmax < ibufmax ? replmax : ibufmax; |
|
691 if (ibuflen > REPLACE_INDEX_BUFFER_MAX) { |
|
692 ibuflen = REPLACE_INDEX_BUFFER_MAX; |
|
693 } |
|
694 |
|
695 /* Allocate first index buffer */ |
|
696 struct scstrreplace_ibuf *firstbuf, *curbuf; |
|
697 firstbuf = curbuf = calloc(1, sizeof(struct scstrreplace_ibuf)); |
|
698 if (!firstbuf) return sstrn(NULL, 0); |
|
699 firstbuf->buf = calloc(ibuflen, sizeof(size_t)); |
|
700 if (!firstbuf->buf) { |
|
701 free(firstbuf); |
|
702 return sstrn(NULL, 0); |
|
703 } |
|
704 |
|
705 /* Search occurrences */ |
|
706 scstr_t searchstr = str; |
|
707 size_t found = 0; |
|
708 do { |
|
709 scstr_t match = scstrscstr(searchstr, pattern); |
|
710 if (match.length > 0) { |
|
711 /* Allocate next buffer in chain, if required */ |
|
712 if (curbuf->len == ibuflen) { |
|
713 struct scstrreplace_ibuf *nextbuf = |
|
714 calloc(1, sizeof(struct scstrreplace_ibuf)); |
|
715 if (!nextbuf) return sstrn(NULL, 0); |
|
716 nextbuf->buf = calloc(ibuflen, sizeof(size_t)); |
|
717 if (!nextbuf->buf) { |
|
718 free(nextbuf); |
|
719 scstrrepl_free_ibuf(firstbuf); |
|
720 return sstrn(NULL, 0); |
|
721 } |
|
722 curbuf->next = nextbuf; |
|
723 curbuf = nextbuf; |
|
724 } |
|
725 |
|
726 /* Record match index */ |
|
727 found++; |
|
728 size_t idx = match.ptr - str.ptr; |
|
729 curbuf->buf[curbuf->len++] = idx; |
|
730 searchstr.ptr = match.ptr + pattern.length; |
|
731 searchstr.length = str.length - idx - pattern.length; |
|
732 } else { |
|
733 break; |
|
734 } |
|
735 } while (searchstr.length > 0 && found < replmax); |
|
736 |
|
737 /* Allocate result string */ |
|
738 sstr_t result; |
|
739 { |
|
740 ssize_t adjlen = (ssize_t) replacement.length - (ssize_t) pattern.length; |
|
741 size_t rcount = 0; |
|
742 curbuf = firstbuf; |
|
743 do { |
|
744 rcount += curbuf->len; |
|
745 curbuf = curbuf->next; |
|
746 } while (curbuf); |
|
747 result.length = str.length + rcount * adjlen; |
|
748 result.ptr = almalloc(allocator, result.length); |
|
749 if (!result.ptr) { |
|
750 scstrrepl_free_ibuf(firstbuf); |
|
751 return sstrn(NULL, 0); |
|
752 } |
|
753 } |
|
754 |
|
755 /* Build result string */ |
|
756 curbuf = firstbuf; |
|
757 size_t srcidx = 0; |
|
758 char* destptr = result.ptr; |
|
759 do { |
|
760 for (size_t i = 0; i < curbuf->len; i++) { |
|
761 /* Copy source part up to next match*/ |
|
762 size_t idx = curbuf->buf[i]; |
|
763 size_t srclen = idx - srcidx; |
|
764 if (srclen > 0) { |
|
765 memcpy(destptr, str.ptr+srcidx, srclen); |
|
766 destptr += srclen; |
|
767 srcidx += srclen; |
|
768 } |
|
769 |
|
770 /* Copy the replacement and skip the source pattern */ |
|
771 srcidx += pattern.length; |
|
772 memcpy(destptr, replacement.ptr, replacement.length); |
|
773 destptr += replacement.length; |
|
774 } |
|
775 curbuf = curbuf->next; |
|
776 } while (curbuf); |
|
777 memcpy(destptr, str.ptr+srcidx, str.length-srcidx); |
|
778 |
|
779 return result; |
|
780 } |
|
781 |
|
782 sstr_t scstrreplacen(scstr_t str, scstr_t pattern, |
|
783 scstr_t replacement, size_t replmax) { |
|
784 return scstrreplacen_a(ucx_default_allocator(), |
|
785 str, pattern, replacement, replmax); |
|
786 } |
|
787 |
|
788 |
665 // type adjustment functions |
789 // type adjustment functions |
666 scstr_t ucx_sc2sc(scstr_t str) { |
790 scstr_t ucx_sc2sc(scstr_t str) { |
667 return str; |
791 return str; |
668 } |
792 } |
669 scstr_t ucx_ss2sc(sstr_t str) { |
793 scstr_t ucx_ss2sc(sstr_t str) { |