| 97 va_end(ap); |
97 va_end(ap); |
| 98 |
98 |
| 99 return size; |
99 return size; |
| 100 } |
100 } |
| 101 |
101 |
| 102 cxmutstr cx_strcat_ma( |
102 int cx_strcat_a( |
| 103 const CxAllocator *alloc, |
103 const CxAllocator *alloc, |
| 104 cxmutstr str, |
104 cxmutstr *str, |
| 105 size_t count, |
105 size_t count, |
| 106 ... |
106 ... |
| 107 ) { |
107 ) { |
| 108 if (count == 0) return str; |
108 if (count == 0) return 0; |
| 109 va_list ap; |
109 va_list ap; |
| 110 va_start(ap, count); |
110 va_start(ap, count); |
| 111 va_list ap2; |
111 va_list ap2; |
| 112 va_copy(ap2, ap); |
112 va_copy(ap2, ap); |
| 113 |
113 |
| 114 // compute overall length |
114 // compute overall length |
| 115 bool overflow = false; |
115 bool overflow = false; |
| 116 size_t slen = str.length; |
116 size_t slen = str->length; |
| 117 for (size_t i = 0; i < count; i++) { |
117 for (size_t i = 0; i < count; i++) { |
| 118 cxstring s = va_arg(ap, cxstring); |
118 cxstring s = va_arg(ap, cxstring); |
| 119 if (slen > SIZE_MAX - s.length) overflow = true; |
119 if (slen > SIZE_MAX - s.length) overflow = true; |
| 120 slen += s.length; |
120 slen += s.length; |
| 121 } |
121 } |
| 123 |
123 |
| 124 // abort in case of overflow |
124 // abort in case of overflow |
| 125 if (overflow) { |
125 if (overflow) { |
| 126 va_end(ap2); |
126 va_end(ap2); |
| 127 errno = EOVERFLOW; |
127 errno = EOVERFLOW; |
| 128 return (cxmutstr) { NULL, 0 }; |
128 return -1; |
| 129 } |
129 } |
| 130 |
130 |
| 131 // reallocate or create new string |
131 // reallocate or create new string |
| 132 char *newstr; |
132 if (cxReallocate(alloc, &str->ptr, slen + 1)) { |
| 133 if (str.ptr == NULL) { |
133 // LCOV_EXCL_START |
| 134 newstr = cxMalloc(alloc, slen + 1); |
|
| 135 } else { |
|
| 136 newstr = cxRealloc(alloc, str.ptr, slen + 1); |
|
| 137 } |
|
| 138 if (newstr == NULL) { // LCOV_EXCL_START |
|
| 139 va_end(ap2); |
134 va_end(ap2); |
| 140 return (cxmutstr) {NULL, 0}; |
135 return -1; |
| 141 } // LCOV_EXCL_STOP |
136 // LCOV_EXCL_STOP |
| 142 str.ptr = newstr; |
137 } |
| 143 |
138 |
| 144 // concatenate strings |
139 // concatenate strings |
| 145 size_t pos = str.length; |
140 size_t pos = str->length; |
| 146 str.length = slen; |
141 str->length = slen; |
| 147 for (size_t i = 0; i < count; i++) { |
142 for (size_t i = 0; i < count; i++) { |
| 148 cxstring s = va_arg(ap2, cxstring); |
143 cxstring s = va_arg(ap2, cxstring); |
| 149 memcpy(str.ptr + pos, s.ptr, s.length); |
144 memcpy(str->ptr + pos, s.ptr, s.length); |
| 150 pos += s.length; |
145 pos += s.length; |
| 151 } |
146 } |
| 152 va_end(ap2); |
147 va_end(ap2); |
| 153 |
148 |
| 154 // terminate string |
149 // terminate string |
| 155 str.ptr[str.length] = '\0'; |
150 str->ptr[str->length] = '\0'; |
| 156 |
151 |
| 157 return str; |
152 return 0; |
| 158 } |
153 } |
| 159 |
154 |
| 160 cxstring cx_strsubs( |
155 cxstring cx_strsubs( |
| 161 cxstring string, |
156 cxstring string, |
| 162 size_t start |
157 size_t start |