src/string.c

changeset 378
952c2df7e7ac
parent 364
5577d6c27a33
child 379
477404eb380e
equal deleted inserted replaced
377:2099a3aff61e 378:952c2df7e7ac
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) {

mercurial