| 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( |