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 str; |
109 |
|
110 cxstring strings_stack[8]; |
|
111 cxstring *strings; |
|
112 if (count > 8) { |
|
113 strings = calloc(count, sizeof(cxstring)); |
|
114 if (strings == NULL) { |
|
115 return (cxmutstr) {NULL, 0}; |
|
116 } |
|
117 } else { |
|
118 strings = strings_stack; |
|
119 } |
|
120 |
|
121 va_list ap; |
109 va_list ap; |
122 va_start(ap, count); |
110 va_start(ap, count); |
123 |
111 va_list ap2; |
124 // get all args and overall length |
112 va_copy(ap2, ap); |
|
113 |
|
114 // compute overall length |
125 bool overflow = false; |
115 bool overflow = false; |
126 size_t slen = str.length; |
116 size_t slen = str.length; |
127 for (size_t i = 0; i < count; i++) { |
117 for (size_t i = 0; i < count; i++) { |
128 cxstring s = va_arg (ap, cxstring); |
118 cxstring s = va_arg(ap, cxstring); |
129 strings[i] = s; |
|
130 if (slen > SIZE_MAX - str.length) overflow = true; |
119 if (slen > SIZE_MAX - str.length) overflow = true; |
131 slen += s.length; |
120 slen += s.length; |
132 } |
121 } |
133 va_end(ap); |
122 va_end(ap); |
134 |
123 |
135 // abort in case of overflow |
124 // abort in case of overflow |
136 if (overflow) { |
125 if (overflow) { |
|
126 va_end(ap2); |
137 errno = EOVERFLOW; |
127 errno = EOVERFLOW; |
138 if (strings != strings_stack) { |
|
139 free(strings); |
|
140 } |
|
141 return (cxmutstr) { NULL, 0 }; |
128 return (cxmutstr) { NULL, 0 }; |
142 } |
129 } |
143 |
130 |
144 // reallocate or create new string |
131 // reallocate or create new string |
145 char *newstr; |
132 char *newstr; |
147 newstr = cxMalloc(alloc, slen + 1); |
134 newstr = cxMalloc(alloc, slen + 1); |
148 } else { |
135 } else { |
149 newstr = cxRealloc(alloc, str.ptr, slen + 1); |
136 newstr = cxRealloc(alloc, str.ptr, slen + 1); |
150 } |
137 } |
151 if (newstr == NULL) { |
138 if (newstr == NULL) { |
152 if (strings != strings_stack) { |
139 va_end(ap2); |
153 free(strings); |
|
154 } |
|
155 return (cxmutstr) {NULL, 0}; |
140 return (cxmutstr) {NULL, 0}; |
156 } |
141 } |
157 str.ptr = newstr; |
142 str.ptr = newstr; |
158 |
143 |
159 // concatenate strings |
144 // concatenate strings |
160 size_t pos = str.length; |
145 size_t pos = str.length; |
161 str.length = slen; |
146 str.length = slen; |
162 for (size_t i = 0; i < count; i++) { |
147 for (size_t i = 0; i < count; i++) { |
163 cxstring s = strings[i]; |
148 cxstring s = va_arg(ap2, cxstring); |
164 memcpy(str.ptr + pos, s.ptr, s.length); |
149 memcpy(str.ptr + pos, s.ptr, s.length); |
165 pos += s.length; |
150 pos += s.length; |
166 } |
151 } |
|
152 va_end(ap2); |
167 |
153 |
168 // terminate string |
154 // terminate string |
169 str.ptr[str.length] = '\0'; |
155 str.ptr[str.length] = '\0'; |
170 |
|
171 // free temporary array |
|
172 if (strings != strings_stack) { |
|
173 free(strings); |
|
174 } |
|
175 |
156 |
176 return str; |
157 return str; |
177 } |
158 } |
178 |
159 |
179 cxstring cx_strsubs( |
160 cxstring cx_strsubs( |