ucx/string.c

branch
dav-2
changeset 894
e86049631677
parent 891
4d58cbcc9efa
equal deleted inserted replaced
893:38800d479cd4 894:e86049631677
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)) {
97 va_end(ap); 102 va_end(ap);
98 103
99 return size; 104 return size;
100 } 105 }
101 106
102 cxmutstr cx_strcat_ma( 107 cxmutstr cx_strcat_a(
103 const CxAllocator *alloc, 108 const CxAllocator *alloc,
104 cxmutstr str, 109 cxmutstr str,
105 size_t count, 110 size_t count,
106 ... 111 ...
107 ) { 112 ) {
108 if (count == 0) return str; 113 if (count == 0) {
114 if (cxReallocate(alloc, &str.ptr, str.length + 1)) {
115 return CX_NULLSTR; // LCOV_EXCL_LINE
116 }
117 str.ptr[str.length] = '\0';
118 return str;
119 }
109 va_list ap; 120 va_list ap;
110 va_start(ap, count); 121 va_start(ap, count);
111 va_list ap2; 122 va_list ap2;
112 va_copy(ap2, ap); 123 va_copy(ap2, ap);
113 124
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
319 } 290 }
320 291
321 return result; 292 return result;
322 } 293 }
323 294
324 cxmutstr cx_strstr_m( 295 size_t cx_strsplit_(
325 cxmutstr haystack,
326 cxstring needle
327 ) {
328 cxstring result = cx_strstr(cx_strcast(haystack), needle);
329 return (cxmutstr) {(char *) result.ptr, result.length};
330 }
331
332 size_t cx_strsplit(
333 cxstring string, 296 cxstring string,
334 cxstring delim, 297 cxstring delim,
335 size_t limit, 298 size_t limit,
336 cxstring *output 299 cxstring *output
337 ) { 300 ) {
385 } 348 }
386 349
387 return n; 350 return n;
388 } 351 }
389 352
390 size_t cx_strsplit_a( 353 size_t cx_strsplit_a_(
391 const CxAllocator *allocator, 354 const CxAllocator *allocator,
392 cxstring string, 355 cxstring string,
393 cxstring delim, 356 cxstring delim,
394 size_t limit, 357 size_t limit,
395 cxstring **output 358 cxstring **output
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
650 ctx.delim_more = NULL; 608 ctx.delim_more = NULL;
651 ctx.delim_more_count = 0; 609 ctx.delim_more_count = 0;
652 return ctx; 610 return ctx;
653 } 611 }
654 612
655 bool cx_strtok_next( 613 bool cx_strtok_next_(
656 CxStrtokCtx *ctx, 614 CxStrtokCtx *ctx,
657 cxstring *token 615 cxstring *token
658 ) { 616 ) {
659 // abortion criteria 617 // abortion criteria
660 if (ctx->found >= ctx->limit || ctx->delim_pos >= ctx->str.length) { 618 if (ctx->found >= ctx->limit || ctx->delim_pos >= ctx->str.length) {
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,

mercurial