| 39 #include <limits.h> |
39 #include <limits.h> |
| 40 #include <float.h> |
40 #include <float.h> |
| 41 #include <ctype.h> |
41 #include <ctype.h> |
| 42 |
42 |
| 43 #ifdef _WIN32 |
43 #ifdef _WIN32 |
| 44 #define cx_strcasecmp_impl _strnicmp |
44 static int cx_fixed_strnicmp(const char* s1, const char* s2, size_t count) { |
| |
45 // Microsoft's implementation crashes when count == 0 and either string is NULL |
| |
46 if (count == 0) return 0; |
| |
47 return _strnicmp(s1, s2, count); |
| |
48 } |
| |
49 #define cx_strcasecmp_impl cx_fixed_strnicmp |
| 45 #else |
50 #else |
| 46 #include <strings.h> |
51 #include <strings.h> |
| 47 #define cx_strcasecmp_impl strncasecmp |
52 #define cx_strcasecmp_impl strncasecmp |
| 48 #endif |
53 #endif |
| 49 |
54 |
| 62 cxFree(alloc, str->ptr); |
67 cxFree(alloc, str->ptr); |
| 63 str->ptr = NULL; |
68 str->ptr = NULL; |
| 64 str->length = 0; |
69 str->length = 0; |
| 65 } |
70 } |
| 66 |
71 |
| 67 int cx_strcpy_a( |
72 int cx_strcpy_a_( |
| 68 const CxAllocator *alloc, |
73 const CxAllocator *alloc, |
| 69 cxmutstr *dest, |
74 cxmutstr *dest, |
| 70 cxstring src |
75 cxstring src |
| 71 ) { |
76 ) { |
| 72 if (cxReallocate(alloc, &dest->ptr, src.length + 1)) { |
77 if (cxReallocate(alloc, &dest->ptr, src.length + 1)) { |
| 123 |
134 |
| 124 // abort in case of overflow |
135 // abort in case of overflow |
| 125 if (overflow) { |
136 if (overflow) { |
| 126 va_end(ap2); |
137 va_end(ap2); |
| 127 errno = EOVERFLOW; |
138 errno = EOVERFLOW; |
| 128 return (cxmutstr) { NULL, 0 }; |
139 return CX_NULLSTR; |
| 129 } |
140 } |
| 130 |
141 |
| 131 // reallocate or create new string |
142 // reallocate or create a new string |
| 132 char *newstr; |
143 if (cxReallocate(alloc, &str.ptr, slen + 1)) { |
| 133 if (str.ptr == NULL) { |
144 // 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); |
145 va_end(ap2); |
| 140 return (cxmutstr) {NULL, 0}; |
146 return CX_NULLSTR; |
| 141 } // LCOV_EXCL_STOP |
147 // LCOV_EXCL_STOP |
| 142 str.ptr = newstr; |
148 } |
| 143 |
149 |
| 144 // concatenate strings |
150 // concatenate strings |
| 145 size_t pos = str.length; |
151 size_t pos = str.length; |
| 146 str.length = slen; |
152 str.length = slen; |
| 147 for (size_t i = 0; i < count; i++) { |
153 for (size_t i = 0; i < count; i++) { |
| 155 str.ptr[str.length] = '\0'; |
161 str.ptr[str.length] = '\0'; |
| 156 |
162 |
| 157 return str; |
163 return str; |
| 158 } |
164 } |
| 159 |
165 |
| 160 cxstring cx_strsubs( |
166 cxstring cx_strsubs_( |
| 161 cxstring string, |
167 cxstring string, |
| 162 size_t start |
168 size_t start |
| 163 ) { |
169 ) { |
| 164 return cx_strsubsl(string, start, string.length - start); |
170 return cx_strsubsl_(string, start, string.length); |
| 165 } |
171 } |
| 166 |
172 |
| 167 cxmutstr cx_strsubs_m( |
173 cxstring cx_strsubsl_( |
| 168 cxmutstr string, |
|
| 169 size_t start |
|
| 170 ) { |
|
| 171 return cx_strsubsl_m(string, start, string.length - start); |
|
| 172 } |
|
| 173 |
|
| 174 cxstring cx_strsubsl( |
|
| 175 cxstring string, |
174 cxstring string, |
| 176 size_t start, |
175 size_t start, |
| 177 size_t length |
176 size_t length |
| 178 ) { |
177 ) { |
| 179 if (start > string.length) { |
178 if (start > string.length) { |
| 186 } |
185 } |
| 187 |
186 |
| 188 return (cxstring) {string.ptr + start, length}; |
187 return (cxstring) {string.ptr + start, length}; |
| 189 } |
188 } |
| 190 |
189 |
| 191 cxmutstr cx_strsubsl_m( |
190 cxstring cx_strchr_( |
| 192 cxmutstr string, |
|
| 193 size_t start, |
|
| 194 size_t length |
|
| 195 ) { |
|
| 196 cxstring result = cx_strsubsl(cx_strcast(string), start, length); |
|
| 197 return (cxmutstr) {(char *) result.ptr, result.length}; |
|
| 198 } |
|
| 199 |
|
| 200 cxstring cx_strchr( |
|
| 201 cxstring string, |
191 cxstring string, |
| 202 int chr |
192 int chr |
| 203 ) { |
193 ) { |
| 204 char *ret = memchr(string.ptr, 0xFF & chr, string.length); |
194 char *ret = memchr(string.ptr, 0xFF & chr, string.length); |
| 205 if (ret == NULL) return (cxstring) {NULL, 0}; |
195 if (ret == NULL) return (cxstring) {NULL, 0}; |
| 206 return (cxstring) {ret, string.length - (ret - string.ptr)}; |
196 return (cxstring) {ret, string.length - (ret - string.ptr)}; |
| 207 } |
197 } |
| 208 |
198 |
| 209 cxmutstr cx_strchr_m( |
199 cxstring cx_strrchr_( |
| 210 cxmutstr string, |
|
| 211 int chr |
|
| 212 ) { |
|
| 213 cxstring result = cx_strchr(cx_strcast(string), chr); |
|
| 214 return (cxmutstr) {(char *) result.ptr, result.length}; |
|
| 215 } |
|
| 216 |
|
| 217 cxstring cx_strrchr( |
|
| 218 cxstring string, |
200 cxstring string, |
| 219 int chr |
201 int chr |
| 220 ) { |
202 ) { |
| 221 #ifdef WITH_MEMRCHR |
203 #ifdef WITH_MEMRCHR |
| 222 char *ret = memrchr(string.ptr, 0xFF & chr, string.length); |
204 char *ret = memrchr(string.ptr, 0xFF & chr, string.length); |
| 233 } |
215 } |
| 234 return (cxstring) {NULL, 0}; |
216 return (cxstring) {NULL, 0}; |
| 235 #endif |
217 #endif |
| 236 } |
218 } |
| 237 |
219 |
| 238 cxmutstr cx_strrchr_m( |
|
| 239 cxmutstr string, |
|
| 240 int chr |
|
| 241 ) { |
|
| 242 cxstring result = cx_strrchr(cx_strcast(string), chr); |
|
| 243 return (cxmutstr) {(char *) result.ptr, result.length}; |
|
| 244 } |
|
| 245 |
|
| 246 #ifndef CX_STRSTR_SBO_SIZE |
220 #ifndef CX_STRSTR_SBO_SIZE |
| 247 #define CX_STRSTR_SBO_SIZE 128 |
221 #define CX_STRSTR_SBO_SIZE 128 |
| 248 #endif |
222 #endif |
| 249 const unsigned cx_strstr_sbo_size = CX_STRSTR_SBO_SIZE; |
223 const unsigned cx_strstr_sbo_size = CX_STRSTR_SBO_SIZE; |
| 250 |
224 |
| 251 cxstring cx_strstr( |
225 cxstring cx_strstr_(cxstring haystack, cxstring needle) { |
| 252 cxstring haystack, |
|
| 253 cxstring needle |
|
| 254 ) { |
|
| 255 if (needle.length == 0) { |
226 if (needle.length == 0) { |
| 256 return haystack; |
227 return haystack; |
| 257 } |
228 } |
| 258 |
229 |
| 259 // optimize for single-char needles |
230 // optimize for single-char needles |
| 414 // no more matches |
377 // no more matches |
| 415 break; |
378 break; |
| 416 } |
379 } |
| 417 } |
380 } |
| 418 *output = cxCalloc(allocator, n, sizeof(cxstring)); |
381 *output = cxCalloc(allocator, n, sizeof(cxstring)); |
| 419 return cx_strsplit(string, delim, n, *output); |
382 return cx_strsplit_(string, delim, n, *output); |
| 420 } |
383 } |
| 421 |
384 |
| 422 size_t cx_strsplit_m( |
385 size_t cx_strsplit_m_( |
| 423 cxmutstr string, |
386 cxmutstr string, |
| 424 cxstring delim, |
387 cxstring delim, |
| 425 size_t limit, |
388 size_t limit, |
| 426 cxmutstr *output |
389 cxmutstr *output |
| 427 ) { |
390 ) { |
| 428 return cx_strsplit(cx_strcast(string), |
391 return cx_strsplit_(cx_strcast(string), |
| 429 delim, limit, (cxstring *) output); |
392 delim, limit, (cxstring *) output); |
| 430 } |
393 } |
| 431 |
394 |
| 432 size_t cx_strsplit_ma( |
395 size_t cx_strsplit_ma_( |
| 433 const CxAllocator *allocator, |
396 const CxAllocator *allocator, |
| 434 cxmutstr string, |
397 cxmutstr string, |
| 435 cxstring delim, |
398 cxstring delim, |
| 436 size_t limit, |
399 size_t limit, |
| 437 cxmutstr **output |
400 cxmutstr **output |
| 438 ) { |
401 ) { |
| 439 return cx_strsplit_a(allocator, cx_strcast(string), |
402 return cx_strsplit_a_(allocator, cx_strcast(string), |
| 440 delim, limit, (cxstring **) output); |
403 delim, limit, (cxstring **) output); |
| 441 } |
404 } |
| 442 |
405 |
| 443 int cx_strcmp_( |
406 int cx_strcmp_( |
| 444 cxstring s1, |
407 cxstring s1, |
| 509 memcpy(result.ptr, string.ptr, string.length); |
472 memcpy(result.ptr, string.ptr, string.length); |
| 510 result.ptr[string.length] = '\0'; |
473 result.ptr[string.length] = '\0'; |
| 511 return result; |
474 return result; |
| 512 } |
475 } |
| 513 |
476 |
| 514 cxstring cx_strtrim(cxstring string) { |
477 cxstring cx_strtrim_(cxstring string) { |
| 515 cxstring result = string; |
478 cxstring result = string; |
| 516 while (result.length > 0 && isspace((unsigned char)(result.ptr[0]))) { |
479 while (isspace((unsigned char)cx_strat(result, 0))) { |
| 517 result.ptr++; |
480 result.ptr++; |
| 518 result.length--; |
481 result.length--; |
| 519 } |
482 } |
| 520 while (result.length > 0 && isspace((unsigned char)result.ptr[result.length - 1])) { |
483 while (isspace((unsigned char)cx_strat(result, -1))) { |
| 521 result.length--; |
484 result.length--; |
| 522 } |
485 } |
| 523 return result; |
486 return result; |
| 524 } |
|
| 525 |
|
| 526 cxmutstr cx_strtrim_m(cxmutstr string) { |
|
| 527 cxstring result = cx_strtrim(cx_strcast(string)); |
|
| 528 return (cxmutstr) {(char *) result.ptr, result.length}; |
|
| 529 } |
487 } |
| 530 |
488 |
| 531 bool cx_strprefix_( |
489 bool cx_strprefix_( |
| 532 cxstring string, |
490 cxstring string, |
| 533 cxstring prefix |
491 cxstring prefix |
| 569 return strncasecmp(string.ptr + string.length - suffix.length, |
527 return strncasecmp(string.ptr + string.length - suffix.length, |
| 570 suffix.ptr, suffix.length) == 0; |
528 suffix.ptr, suffix.length) == 0; |
| 571 #endif |
529 #endif |
| 572 } |
530 } |
| 573 |
531 |
| 574 cxmutstr cx_strreplacen_a( |
532 cxmutstr cx_strreplace_( |
| 575 const CxAllocator *allocator, |
533 const CxAllocator *allocator, |
| 576 cxstring str, |
534 cxstring str, |
| 577 cxstring search, |
535 cxstring search, |
| 578 cxstring replacement, |
536 cxstring replacement, |
| 579 size_t replmax |
537 size_t replmax |
| 691 ctx->str.length : (size_t) (delim.ptr - ctx->str.ptr); |
649 ctx->str.length : (size_t) (delim.ptr - ctx->str.ptr); |
| 692 token->length = ctx->delim_pos - ctx->pos; |
650 token->length = ctx->delim_pos - ctx->pos; |
| 693 ctx->next_pos = ctx->delim_pos + delim.length; |
651 ctx->next_pos = ctx->delim_pos + delim.length; |
| 694 |
652 |
| 695 return true; |
653 return true; |
| 696 } |
|
| 697 |
|
| 698 bool cx_strtok_next_m( |
|
| 699 CxStrtokCtx *ctx, |
|
| 700 cxmutstr *token |
|
| 701 ) { |
|
| 702 return cx_strtok_next(ctx, (cxstring *) token); |
|
| 703 } |
654 } |
| 704 |
655 |
| 705 void cx_strtok_delim( |
656 void cx_strtok_delim( |
| 706 CxStrtokCtx *ctx, |
657 CxStrtokCtx *ctx, |
| 707 const cxstring *delim, |
658 const cxstring *delim, |