src/string.c

Mon, 30 Dec 2019 09:52:44 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 30 Dec 2019 09:52:44 +0100
changeset 388
871a8ffe6c9d
parent 383
db4c6b94939b
permissions
-rw-r--r--

merges closed feature/array branch

olaf@20 1 /*
universe@103 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
olaf@20 3 *
universe@259 4 * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved.
universe@103 5 *
universe@103 6 * Redistribution and use in source and binary forms, with or without
universe@103 7 * modification, are permitted provided that the following conditions are met:
universe@103 8 *
universe@103 9 * 1. Redistributions of source code must retain the above copyright
universe@103 10 * notice, this list of conditions and the following disclaimer.
universe@103 11 *
universe@103 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@103 13 * notice, this list of conditions and the following disclaimer in the
universe@103 14 * documentation and/or other materials provided with the distribution.
universe@103 15 *
universe@103 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@103 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@103 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@103 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@103 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@103 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@103 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@103 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@103 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@103 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@103 26 * POSSIBILITY OF SUCH DAMAGE.
olaf@20 27 */
olaf@20 28
universe@251 29 #include "ucx/string.h"
universe@251 30
universe@251 31 #include "ucx/allocator.h"
universe@251 32
olaf@20 33 #include <stdlib.h>
universe@69 34 #include <string.h>
olaf@20 35 #include <stdarg.h>
universe@236 36 #include <stdint.h>
universe@189 37 #include <ctype.h>
olaf@20 38
universe@361 39 #ifndef _WIN32
universe@361 40 #include <strings.h> /* for strncasecmp() */
universe@361 41 #endif /* _WIN32 */
universe@361 42
universe@116 43 sstr_t sstr(char *cstring) {
olaf@20 44 sstr_t string;
universe@116 45 string.ptr = cstring;
universe@116 46 string.length = strlen(cstring);
olaf@20 47 return string;
olaf@20 48 }
olaf@20 49
universe@116 50 sstr_t sstrn(char *cstring, size_t length) {
olaf@20 51 sstr_t string;
universe@116 52 string.ptr = cstring;
universe@116 53 string.length = length;
olaf@20 54 return string;
olaf@20 55 }
olaf@20 56
olaf@275 57 scstr_t scstr(const char *cstring) {
olaf@275 58 scstr_t string;
olaf@275 59 string.ptr = cstring;
olaf@275 60 string.length = strlen(cstring);
olaf@275 61 return string;
olaf@275 62 }
olaf@275 63
olaf@275 64 scstr_t scstrn(const char *cstring, size_t length) {
olaf@275 65 scstr_t string;
olaf@275 66 string.ptr = cstring;
olaf@275 67 string.length = length;
olaf@275 68 return string;
olaf@275 69 }
olaf@275 70
olaf@275 71
universe@319 72 size_t scstrnlen(size_t n, ...) {
universe@363 73 if (n == 0) return 0;
universe@363 74
olaf@20 75 va_list ap;
olaf@288 76 va_start(ap, n);
olaf@288 77
olaf@288 78 size_t size = 0;
olaf@20 79
olaf@288 80 for (size_t i = 0 ; i < n ; i++) {
olaf@288 81 scstr_t str = va_arg(ap, scstr_t);
universe@317 82 if(SIZE_MAX - str.length < size) {
universe@317 83 size = SIZE_MAX;
olaf@272 84 break;
olaf@272 85 }
olaf@20 86 size += str.length;
olaf@20 87 }
universe@24 88 va_end(ap);
olaf@20 89
olaf@20 90 return size;
olaf@20 91 }
olaf@20 92
olaf@180 93 static sstr_t sstrvcat_a(
olaf@180 94 UcxAllocator *a,
olaf@180 95 size_t count,
olaf@288 96 scstr_t s1,
olaf@180 97 va_list ap) {
olaf@180 98 sstr_t str;
olaf@180 99 str.ptr = NULL;
olaf@180 100 str.length = 0;
olaf@180 101 if(count < 2) {
olaf@180 102 return str;
olaf@180 103 }
olaf@180 104
olaf@288 105 scstr_t s2 = va_arg (ap, scstr_t);
olaf@288 106
olaf@272 107 if(((size_t)-1) - s1.length < s2.length) {
olaf@272 108 return str;
olaf@272 109 }
olaf@272 110
olaf@288 111 scstr_t *strings = (scstr_t*) calloc(count, sizeof(scstr_t));
olaf@180 112 if(!strings) {
olaf@180 113 return str;
olaf@180 114 }
olaf@180 115
olaf@180 116 // get all args and overall length
olaf@180 117 strings[0] = s1;
olaf@180 118 strings[1] = s2;
olaf@272 119 size_t slen = s1.length + s2.length;
olaf@272 120 int error = 0;
olaf@180 121 for (size_t i=2;i<count;i++) {
olaf@288 122 scstr_t s = va_arg (ap, scstr_t);
olaf@180 123 strings[i] = s;
olaf@272 124 if(((size_t)-1) - s.length < slen) {
olaf@272 125 error = 1;
olaf@272 126 break;
olaf@272 127 }
olaf@272 128 slen += s.length;
olaf@272 129 }
olaf@272 130 if(error) {
olaf@272 131 free(strings);
olaf@272 132 return str;
olaf@180 133 }
olaf@180 134
olaf@180 135 // create new string
olaf@272 136 str.ptr = (char*) almalloc(a, slen + 1);
olaf@272 137 str.length = slen;
olaf@180 138 if(!str.ptr) {
olaf@180 139 free(strings);
olaf@180 140 str.length = 0;
olaf@180 141 return str;
olaf@180 142 }
olaf@180 143
olaf@180 144 // concatenate strings
olaf@180 145 size_t pos = 0;
olaf@180 146 for (size_t i=0;i<count;i++) {
olaf@288 147 scstr_t s = strings[i];
olaf@180 148 memcpy(str.ptr + pos, s.ptr, s.length);
olaf@180 149 pos += s.length;
olaf@180 150 }
olaf@180 151
olaf@180 152 str.ptr[str.length] = '\0';
olaf@180 153
olaf@180 154 free(strings);
olaf@180 155
olaf@180 156 return str;
olaf@180 157 }
olaf@180 158
universe@319 159 sstr_t scstrcat(size_t count, scstr_t s1, ...) {
olaf@180 160 va_list ap;
olaf@288 161 va_start(ap, s1);
olaf@288 162 sstr_t s = sstrvcat_a(ucx_default_allocator(), count, s1, ap);
olaf@180 163 va_end(ap);
olaf@180 164 return s;
olaf@180 165 }
olaf@180 166
universe@319 167 sstr_t scstrcat_a(UcxAllocator *a, size_t count, scstr_t s1, ...) {
olaf@180 168 va_list ap;
olaf@288 169 va_start(ap, s1);
olaf@288 170 sstr_t s = sstrvcat_a(a, count, s1, ap);
olaf@180 171 va_end(ap);
olaf@180 172 return s;
olaf@180 173 }
olaf@180 174
olaf@300 175 static int ucx_substring(
olaf@300 176 size_t str_length,
olaf@300 177 size_t start,
olaf@300 178 size_t length,
olaf@300 179 size_t *newlen,
olaf@300 180 size_t *newpos)
olaf@300 181 {
olaf@300 182 *newlen = 0;
olaf@300 183 *newpos = 0;
olaf@300 184
olaf@300 185 if(start > str_length) {
olaf@300 186 return 0;
olaf@300 187 }
olaf@300 188
olaf@300 189 if(length > str_length - start) {
olaf@300 190 length = str_length - start;
olaf@300 191 }
olaf@300 192 *newlen = length;
olaf@300 193 *newpos = start;
olaf@300 194 return 1;
olaf@300 195 }
olaf@300 196
olaf@68 197 sstr_t sstrsubs(sstr_t s, size_t start) {
olaf@20 198 return sstrsubsl (s, start, s.length-start);
olaf@20 199 }
olaf@20 200
olaf@68 201 sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) {
olaf@300 202 size_t pos;
olaf@300 203 sstr_t ret = { NULL, 0 };
olaf@300 204 if(ucx_substring(s.length, start, length, &ret.length, &pos)) {
olaf@300 205 ret.ptr = s.ptr + pos;
olaf@300 206 }
olaf@300 207 return ret;
olaf@300 208 }
olaf@300 209
universe@318 210 scstr_t scstrsubs(scstr_t string, size_t start) {
universe@318 211 return scstrsubsl(string, start, string.length-start);
olaf@300 212 }
olaf@300 213
olaf@300 214 scstr_t scstrsubsl(scstr_t s, size_t start, size_t length) {
olaf@300 215 size_t pos;
olaf@300 216 scstr_t ret = { NULL, 0 };
olaf@300 217 if(ucx_substring(s.length, start, length, &ret.length, &pos)) {
olaf@300 218 ret.ptr = s.ptr + pos;
olaf@300 219 }
olaf@300 220 return ret;
olaf@300 221 }
olaf@300 222
olaf@300 223
universe@318 224 static int ucx_strchr(const char *str, size_t length, int chr, size_t *pos) {
olaf@300 225 for(size_t i=0;i<length;i++) {
universe@318 226 if(str[i] == chr) {
olaf@300 227 *pos = i;
olaf@300 228 return 1;
universe@173 229 }
olaf@20 230 }
olaf@300 231 return 0;
olaf@300 232 }
olaf@300 233
universe@318 234 static int ucx_strrchr(const char *str, size_t length, int chr, size_t *pos) {
olaf@300 235 if(length > 0) {
universe@306 236 for(size_t i=length ; i>0 ; i--) {
universe@318 237 if(str[i-1] == chr) {
universe@306 238 *pos = i-1;
olaf@300 239 return 1;
olaf@300 240 }
olaf@300 241 }
olaf@300 242 }
olaf@300 243 return 0;
olaf@20 244 }
olaf@20 245
olaf@108 246 sstr_t sstrchr(sstr_t s, int c) {
olaf@300 247 size_t pos = 0;
olaf@300 248 if(ucx_strchr(s.ptr, s.length, c, &pos)) {
olaf@300 249 return sstrsubs(s, pos);
olaf@108 250 }
olaf@300 251 return sstrn(NULL, 0);
olaf@108 252 }
olaf@108 253
universe@148 254 sstr_t sstrrchr(sstr_t s, int c) {
olaf@300 255 size_t pos = 0;
olaf@300 256 if(ucx_strrchr(s.ptr, s.length, c, &pos)) {
olaf@300 257 return sstrsubs(s, pos);
universe@148 258 }
olaf@300 259 return sstrn(NULL, 0);
olaf@300 260 }
olaf@300 261
olaf@300 262 scstr_t scstrchr(scstr_t s, int c) {
olaf@300 263 size_t pos = 0;
olaf@300 264 if(ucx_strchr(s.ptr, s.length, c, &pos)) {
olaf@300 265 return scstrsubs(s, pos);
olaf@300 266 }
olaf@300 267 return scstrn(NULL, 0);
olaf@300 268 }
olaf@300 269
olaf@300 270 scstr_t scstrrchr(scstr_t s, int c) {
olaf@300 271 size_t pos = 0;
olaf@300 272 if(ucx_strrchr(s.ptr, s.length, c, &pos)) {
olaf@300 273 return scstrsubs(s, pos);
olaf@300 274 }
olaf@300 275 return scstrn(NULL, 0);
universe@148 276 }
universe@148 277
universe@237 278 #define ptable_r(dest, useheap, ptable, index) (dest = useheap ? \
universe@237 279 ((size_t*)ptable)[index] : (size_t) ((uint8_t*)ptable)[index])
universe@236 280
universe@237 281 #define ptable_w(useheap, ptable, index, src) do {\
universe@237 282 if (!useheap) ((uint8_t*)ptable)[index] = (uint8_t) src;\
universe@237 283 else ((size_t*)ptable)[index] = src;\
universe@237 284 } while (0);
universe@236 285
olaf@276 286
universe@318 287 static const char* ucx_strstr(
olaf@276 288 const char *str,
olaf@276 289 size_t length,
olaf@276 290 const char *match,
olaf@276 291 size_t matchlen,
olaf@276 292 size_t *newlen)
olaf@276 293 {
olaf@276 294 *newlen = length;
olaf@276 295 if (matchlen == 0) {
olaf@276 296 return str;
universe@214 297 }
universe@214 298
olaf@276 299 const char *result = NULL;
olaf@276 300 size_t resultlen = 0;
universe@236 301
universe@236 302 /*
universe@236 303 * IMPORTANT:
universe@236 304 * our prefix table contains the prefix length PLUS ONE
universe@236 305 * this is our decision, because we want to use the full range of size_t
universe@236 306 * the original algorithm needs a (-1) at one single place
universe@236 307 * and we want to avoid that
universe@236 308 */
universe@236 309
universe@236 310 /* static prefix table */
universe@236 311 static uint8_t s_prefix_table[256];
universe@236 312
universe@236 313 /* check pattern length and use appropriate prefix table */
universe@237 314 /* if the pattern exceeds static prefix table, allocate on the heap */
olaf@276 315 register int useheap = matchlen > 255;
universe@237 316 register void* ptable = useheap ?
olaf@276 317 calloc(matchlen+1, sizeof(size_t)): s_prefix_table;
universe@236 318
universe@236 319 /* keep counter in registers */
universe@236 320 register size_t i, j;
universe@236 321
universe@236 322 /* fill prefix table */
universe@236 323 i = 0; j = 0;
universe@237 324 ptable_w(useheap, ptable, i, j);
olaf@276 325 while (i < matchlen) {
olaf@276 326 while (j >= 1 && match[j-1] != match[i]) {
universe@238 327 ptable_r(j, useheap, ptable, j-1);
universe@236 328 }
universe@236 329 i++; j++;
universe@237 330 ptable_w(useheap, ptable, i, j);
universe@236 331 }
universe@236 332
universe@236 333 /* search */
universe@236 334 i = 0; j = 1;
olaf@276 335 while (i < length) {
olaf@276 336 while (j >= 1 && str[i] != match[j-1]) {
universe@237 337 ptable_r(j, useheap, ptable, j-1);
universe@236 338 }
universe@236 339 i++; j++;
olaf@276 340 if (j-1 == matchlen) {
olaf@276 341 size_t start = i - matchlen;
olaf@276 342 result = str + start;
olaf@276 343 resultlen = length - start;
universe@236 344 break;
universe@214 345 }
universe@214 346 }
universe@236 347
universe@236 348 /* if prefix table was allocated on the heap, free it */
universe@236 349 if (ptable != s_prefix_table) {
universe@236 350 free(ptable);
universe@236 351 }
universe@214 352
olaf@276 353 *newlen = resultlen;
olaf@276 354 return result;
olaf@276 355 }
olaf@276 356
universe@319 357 sstr_t scstrsstr(sstr_t string, scstr_t match) {
olaf@276 358 sstr_t result;
olaf@276 359
olaf@276 360 size_t reslen;
olaf@276 361 const char *resstr = ucx_strstr(string.ptr, string.length, match.ptr, match.length, &reslen);
olaf@276 362 if(!resstr) {
olaf@276 363 result.ptr = NULL;
olaf@276 364 result.length = 0;
olaf@276 365 return result;
olaf@276 366 }
olaf@276 367
olaf@276 368 size_t pos = resstr - string.ptr;
olaf@276 369 result.ptr = string.ptr + pos;
olaf@276 370 result.length = reslen;
olaf@276 371
olaf@276 372 return result;
olaf@276 373 }
olaf@276 374
universe@319 375 scstr_t scstrscstr(scstr_t string, scstr_t match) {
olaf@276 376 scstr_t result;
olaf@276 377
olaf@276 378 size_t reslen;
olaf@276 379 const char *resstr = ucx_strstr(string.ptr, string.length, match.ptr, match.length, &reslen);
olaf@276 380 if(!resstr) {
olaf@276 381 result.ptr = NULL;
olaf@276 382 result.length = 0;
olaf@276 383 return result;
olaf@276 384 }
olaf@276 385
olaf@276 386 size_t pos = resstr - string.ptr;
olaf@276 387 result.ptr = string.ptr + pos;
olaf@276 388 result.length = reslen;
olaf@276 389
universe@236 390 return result;
universe@214 391 }
universe@214 392
universe@237 393 #undef ptable_r
universe@237 394 #undef ptable_w
universe@237 395
universe@319 396 sstr_t* scstrsplit(scstr_t s, scstr_t d, ssize_t *n) {
universe@319 397 return scstrsplit_a(ucx_default_allocator(), s, d, n);
universe@119 398 }
universe@119 399
universe@319 400 sstr_t* scstrsplit_a(UcxAllocator *allocator, scstr_t s, scstr_t d, ssize_t *n) {
universe@119 401 if (s.length == 0 || d.length == 0) {
universe@119 402 *n = -1;
universe@39 403 return NULL;
universe@39 404 }
universe@231 405
universe@231 406 /* special cases: delimiter is at least as large as the string */
universe@231 407 if (d.length >= s.length) {
universe@231 408 /* exact match */
universe@231 409 if (sstrcmp(s, d) == 0) {
universe@231 410 *n = 0;
universe@231 411 return NULL;
universe@231 412 } else /* no match possible */ {
universe@231 413 *n = 1;
universe@231 414 sstr_t *result = (sstr_t*) almalloc(allocator, sizeof(sstr_t));
olaf@270 415 if(result) {
olaf@270 416 *result = sstrdup_a(allocator, s);
olaf@270 417 } else {
olaf@270 418 *n = -2;
olaf@270 419 }
universe@231 420 return result;
universe@231 421 }
universe@231 422 }
universe@231 423
universe@173 424 ssize_t nmax = *n;
universe@235 425 size_t arrlen = 16;
olaf@270 426 sstr_t* result = (sstr_t*) alcalloc(allocator, arrlen, sizeof(sstr_t));
universe@39 427
universe@119 428 if (result) {
olaf@276 429 scstr_t curpos = s;
universe@233 430 ssize_t j = 1;
universe@233 431 while (1) {
olaf@276 432 scstr_t match;
universe@234 433 /* optimize for one byte delimiters */
universe@234 434 if (d.length == 1) {
universe@234 435 match = curpos;
universe@234 436 for (size_t i = 0 ; i < curpos.length ; i++) {
universe@234 437 if (curpos.ptr[i] == *(d.ptr)) {
universe@234 438 match.ptr = curpos.ptr + i;
universe@234 439 break;
universe@234 440 }
universe@234 441 match.length--;
universe@234 442 }
universe@234 443 } else {
universe@319 444 match = scstrscstr(curpos, d);
universe@234 445 }
universe@233 446 if (match.length > 0) {
universe@233 447 /* is this our last try? */
universe@233 448 if (nmax == 0 || j < nmax) {
universe@233 449 /* copy the current string to the array */
olaf@276 450 scstr_t item = scstrn(curpos.ptr, match.ptr - curpos.ptr);
universe@233 451 result[j-1] = sstrdup_a(allocator, item);
universe@233 452 size_t processed = item.length + d.length;
universe@233 453 curpos.ptr += processed;
universe@233 454 curpos.length -= processed;
universe@39 455
universe@233 456 /* allocate memory for the next string */
universe@233 457 j++;
universe@235 458 if (j > arrlen) {
universe@235 459 arrlen *= 2;
olaf@270 460 size_t reallocsz;
olaf@270 461 sstr_t* reallocated = NULL;
olaf@270 462 if(!ucx_szmul(arrlen, sizeof(sstr_t), &reallocsz)) {
olaf@270 463 reallocated = (sstr_t*) alrealloc(
olaf@270 464 allocator, result, reallocsz);
olaf@270 465 }
universe@235 466 if (reallocated) {
universe@235 467 result = reallocated;
universe@235 468 } else {
universe@235 469 for (ssize_t i = 0 ; i < j-1 ; i++) {
universe@235 470 alfree(allocator, result[i].ptr);
universe@235 471 }
universe@235 472 alfree(allocator, result);
universe@235 473 *n = -2;
universe@235 474 return NULL;
universe@233 475 }
universe@233 476 }
universe@233 477 } else {
universe@233 478 /* nmax reached, copy the _full_ remaining string */
universe@233 479 result[j-1] = sstrdup_a(allocator, curpos);
universe@233 480 break;
universe@233 481 }
universe@173 482 } else {
universe@233 483 /* no more matches, copy last string */
universe@233 484 result[j-1] = sstrdup_a(allocator, curpos);
universe@173 485 break;
universe@173 486 }
universe@119 487 }
universe@233 488 *n = j;
universe@119 489 } else {
universe@119 490 *n = -2;
universe@39 491 }
universe@39 492
universe@39 493 return result;
universe@39 494 }
universe@39 495
universe@319 496 int scstrcmp(scstr_t s1, scstr_t s2) {
universe@116 497 if (s1.length == s2.length) {
universe@116 498 return memcmp(s1.ptr, s2.ptr, s1.length);
universe@116 499 } else if (s1.length > s2.length) {
universe@116 500 return 1;
universe@116 501 } else {
universe@116 502 return -1;
universe@116 503 }
olaf@20 504 }
olaf@20 505
universe@319 506 int scstrcasecmp(scstr_t s1, scstr_t s2) {
universe@149 507 if (s1.length == s2.length) {
universe@149 508 #ifdef _WIN32
universe@149 509 return _strnicmp(s1.ptr, s2.ptr, s1.length);
universe@149 510 #else
universe@149 511 return strncasecmp(s1.ptr, s2.ptr, s1.length);
universe@149 512 #endif
universe@149 513 } else if (s1.length > s2.length) {
universe@149 514 return 1;
universe@149 515 } else {
universe@149 516 return -1;
universe@149 517 }
universe@149 518 }
universe@149 519
universe@319 520 sstr_t scstrdup(scstr_t s) {
universe@125 521 return sstrdup_a(ucx_default_allocator(), s);
olaf@109 522 }
olaf@20 523
universe@319 524 sstr_t scstrdup_a(UcxAllocator *allocator, scstr_t s) {
olaf@109 525 sstr_t newstring;
universe@173 526 newstring.ptr = (char*)almalloc(allocator, s.length + 1);
olaf@109 527 if (newstring.ptr) {
olaf@109 528 newstring.length = s.length;
olaf@109 529 newstring.ptr[newstring.length] = 0;
olaf@109 530
olaf@109 531 memcpy(newstring.ptr, s.ptr, s.length);
olaf@109 532 } else {
olaf@109 533 newstring.length = 0;
olaf@109 534 }
olaf@109 535
olaf@20 536 return newstring;
olaf@20 537 }
olaf@96 538
olaf@276 539
universe@318 540 static size_t ucx_strtrim(const char *s, size_t len, size_t *newlen) {
olaf@276 541 const char *newptr = s;
olaf@276 542 size_t length = len;
universe@189 543
olaf@276 544 while(length > 0 && isspace(*newptr)) {
olaf@276 545 newptr++;
olaf@276 546 length--;
universe@98 547 }
olaf@276 548 while(length > 0 && isspace(newptr[length-1])) {
olaf@276 549 length--;
olaf@96 550 }
olaf@96 551
olaf@276 552 *newlen = length;
olaf@276 553 return newptr - s;
olaf@276 554 }
olaf@276 555
olaf@276 556 sstr_t sstrtrim(sstr_t string) {
olaf@276 557 sstr_t newstr;
olaf@276 558 newstr.ptr = string.ptr
olaf@276 559 + ucx_strtrim(string.ptr, string.length, &newstr.length);
olaf@276 560 return newstr;
olaf@276 561 }
olaf@276 562
olaf@276 563 scstr_t scstrtrim(scstr_t string) {
olaf@276 564 scstr_t newstr;
olaf@276 565 newstr.ptr = string.ptr
olaf@276 566 + ucx_strtrim(string.ptr, string.length, &newstr.length);
olaf@96 567 return newstr;
olaf@96 568 }
universe@146 569
universe@319 570 int scstrprefix(scstr_t string, scstr_t prefix) {
universe@146 571 if (string.length == 0) {
universe@146 572 return prefix.length == 0;
universe@146 573 }
universe@146 574 if (prefix.length == 0) {
universe@146 575 return 1;
universe@146 576 }
universe@146 577
universe@146 578 if (prefix.length > string.length) {
universe@146 579 return 0;
universe@146 580 } else {
universe@146 581 return memcmp(string.ptr, prefix.ptr, prefix.length) == 0;
universe@146 582 }
universe@146 583 }
universe@146 584
universe@319 585 int scstrsuffix(scstr_t string, scstr_t suffix) {
universe@146 586 if (string.length == 0) {
universe@146 587 return suffix.length == 0;
universe@146 588 }
universe@146 589 if (suffix.length == 0) {
universe@146 590 return 1;
universe@146 591 }
universe@146 592
universe@146 593 if (suffix.length > string.length) {
universe@146 594 return 0;
universe@146 595 } else {
universe@146 596 return memcmp(string.ptr+string.length-suffix.length,
universe@146 597 suffix.ptr, suffix.length) == 0;
universe@146 598 }
universe@146 599 }
universe@210 600
universe@364 601 int scstrcaseprefix(scstr_t string, scstr_t prefix) {
universe@364 602 if (string.length == 0) {
universe@364 603 return prefix.length == 0;
universe@364 604 }
universe@364 605 if (prefix.length == 0) {
universe@364 606 return 1;
universe@364 607 }
universe@364 608
universe@364 609 if (prefix.length > string.length) {
universe@364 610 return 0;
universe@364 611 } else {
universe@364 612 scstr_t subs = scstrsubsl(string, 0, prefix.length);
universe@364 613 return scstrcasecmp(subs, prefix) == 0;
universe@364 614 }
universe@364 615 }
universe@364 616
universe@364 617 int scstrcasesuffix(scstr_t string, scstr_t suffix) {
universe@364 618 if (string.length == 0) {
universe@364 619 return suffix.length == 0;
universe@364 620 }
universe@364 621 if (suffix.length == 0) {
universe@364 622 return 1;
universe@364 623 }
universe@364 624
universe@364 625 if (suffix.length > string.length) {
universe@364 626 return 0;
universe@364 627 } else {
universe@364 628 scstr_t subs = scstrsubs(string, string.length-suffix.length);
universe@364 629 return scstrcasecmp(subs, suffix) == 0;
universe@364 630 }
universe@364 631 }
universe@364 632
universe@319 633 sstr_t scstrlower(scstr_t string) {
universe@210 634 sstr_t ret = sstrdup(string);
universe@210 635 for (size_t i = 0; i < ret.length ; i++) {
universe@210 636 ret.ptr[i] = tolower(ret.ptr[i]);
universe@210 637 }
universe@210 638 return ret;
universe@210 639 }
universe@210 640
universe@319 641 sstr_t scstrlower_a(UcxAllocator *allocator, scstr_t string) {
universe@210 642 sstr_t ret = sstrdup_a(allocator, string);
universe@210 643 for (size_t i = 0; i < ret.length ; i++) {
universe@210 644 ret.ptr[i] = tolower(ret.ptr[i]);
universe@210 645 }
universe@210 646 return ret;
universe@210 647 }
universe@210 648
universe@319 649 sstr_t scstrupper(scstr_t string) {
universe@210 650 sstr_t ret = sstrdup(string);
universe@210 651 for (size_t i = 0; i < ret.length ; i++) {
universe@210 652 ret.ptr[i] = toupper(ret.ptr[i]);
universe@210 653 }
universe@210 654 return ret;
universe@210 655 }
universe@210 656
universe@319 657 sstr_t scstrupper_a(UcxAllocator *allocator, scstr_t string) {
universe@210 658 sstr_t ret = sstrdup_a(allocator, string);
universe@210 659 for (size_t i = 0; i < ret.length ; i++) {
universe@210 660 ret.ptr[i] = toupper(ret.ptr[i]);
universe@210 661 }
universe@210 662 return ret;
universe@210 663 }
olaf@275 664
universe@378 665 #define REPLACE_INDEX_BUFFER_MAX 100
universe@378 666
universe@378 667 struct scstrreplace_ibuf {
universe@378 668 size_t* buf;
universe@378 669 unsigned int len; /* small indices */
universe@378 670 struct scstrreplace_ibuf* next;
universe@378 671 };
universe@378 672
universe@378 673 static void scstrrepl_free_ibuf(struct scstrreplace_ibuf *buf) {
universe@378 674 while (buf) {
universe@378 675 struct scstrreplace_ibuf *next = buf->next;
universe@378 676 free(buf->buf);
universe@378 677 free(buf);
universe@378 678 buf = next;
universe@378 679 }
universe@378 680 }
universe@378 681
universe@378 682 sstr_t scstrreplacen_a(UcxAllocator *allocator, scstr_t str,
universe@378 683 scstr_t pattern, scstr_t replacement, size_t replmax) {
universe@378 684
olaf@383 685 if (pattern.length == 0 || pattern.length > str.length || replmax == 0)
universe@378 686 return sstrdup(str);
universe@378 687
universe@378 688 /* Compute expected buffer length */
universe@378 689 size_t ibufmax = str.length / pattern.length;
universe@378 690 size_t ibuflen = replmax < ibufmax ? replmax : ibufmax;
universe@378 691 if (ibuflen > REPLACE_INDEX_BUFFER_MAX) {
universe@378 692 ibuflen = REPLACE_INDEX_BUFFER_MAX;
universe@378 693 }
universe@378 694
universe@378 695 /* Allocate first index buffer */
universe@378 696 struct scstrreplace_ibuf *firstbuf, *curbuf;
universe@378 697 firstbuf = curbuf = calloc(1, sizeof(struct scstrreplace_ibuf));
universe@378 698 if (!firstbuf) return sstrn(NULL, 0);
universe@378 699 firstbuf->buf = calloc(ibuflen, sizeof(size_t));
universe@378 700 if (!firstbuf->buf) {
universe@378 701 free(firstbuf);
universe@378 702 return sstrn(NULL, 0);
universe@378 703 }
universe@378 704
universe@378 705 /* Search occurrences */
universe@378 706 scstr_t searchstr = str;
universe@378 707 size_t found = 0;
universe@378 708 do {
universe@378 709 scstr_t match = scstrscstr(searchstr, pattern);
universe@378 710 if (match.length > 0) {
universe@378 711 /* Allocate next buffer in chain, if required */
universe@378 712 if (curbuf->len == ibuflen) {
universe@378 713 struct scstrreplace_ibuf *nextbuf =
universe@378 714 calloc(1, sizeof(struct scstrreplace_ibuf));
universe@380 715 if (!nextbuf) {
universe@380 716 scstrrepl_free_ibuf(firstbuf);
universe@380 717 return sstrn(NULL, 0);
universe@380 718 }
universe@378 719 nextbuf->buf = calloc(ibuflen, sizeof(size_t));
universe@378 720 if (!nextbuf->buf) {
universe@378 721 free(nextbuf);
universe@378 722 scstrrepl_free_ibuf(firstbuf);
universe@378 723 return sstrn(NULL, 0);
universe@378 724 }
universe@378 725 curbuf->next = nextbuf;
universe@378 726 curbuf = nextbuf;
universe@378 727 }
universe@378 728
universe@378 729 /* Record match index */
universe@378 730 found++;
universe@378 731 size_t idx = match.ptr - str.ptr;
universe@378 732 curbuf->buf[curbuf->len++] = idx;
universe@378 733 searchstr.ptr = match.ptr + pattern.length;
universe@378 734 searchstr.length = str.length - idx - pattern.length;
universe@378 735 } else {
universe@378 736 break;
universe@378 737 }
universe@378 738 } while (searchstr.length > 0 && found < replmax);
universe@378 739
universe@378 740 /* Allocate result string */
universe@378 741 sstr_t result;
universe@378 742 {
universe@378 743 ssize_t adjlen = (ssize_t) replacement.length - (ssize_t) pattern.length;
universe@378 744 size_t rcount = 0;
universe@378 745 curbuf = firstbuf;
universe@378 746 do {
universe@378 747 rcount += curbuf->len;
universe@378 748 curbuf = curbuf->next;
universe@378 749 } while (curbuf);
universe@378 750 result.length = str.length + rcount * adjlen;
universe@378 751 result.ptr = almalloc(allocator, result.length);
universe@378 752 if (!result.ptr) {
universe@378 753 scstrrepl_free_ibuf(firstbuf);
universe@378 754 return sstrn(NULL, 0);
universe@378 755 }
universe@378 756 }
universe@378 757
universe@378 758 /* Build result string */
universe@378 759 curbuf = firstbuf;
universe@378 760 size_t srcidx = 0;
universe@378 761 char* destptr = result.ptr;
universe@378 762 do {
universe@378 763 for (size_t i = 0; i < curbuf->len; i++) {
universe@378 764 /* Copy source part up to next match*/
universe@378 765 size_t idx = curbuf->buf[i];
universe@378 766 size_t srclen = idx - srcidx;
universe@378 767 if (srclen > 0) {
universe@378 768 memcpy(destptr, str.ptr+srcidx, srclen);
universe@378 769 destptr += srclen;
universe@378 770 srcidx += srclen;
universe@378 771 }
universe@378 772
universe@378 773 /* Copy the replacement and skip the source pattern */
universe@378 774 srcidx += pattern.length;
universe@378 775 memcpy(destptr, replacement.ptr, replacement.length);
universe@378 776 destptr += replacement.length;
universe@378 777 }
universe@378 778 curbuf = curbuf->next;
universe@378 779 } while (curbuf);
universe@378 780 memcpy(destptr, str.ptr+srcidx, str.length-srcidx);
universe@378 781
universe@379 782 /* Free index buffer */
universe@379 783 scstrrepl_free_ibuf(firstbuf);
universe@379 784
universe@378 785 return result;
universe@378 786 }
universe@378 787
universe@378 788 sstr_t scstrreplacen(scstr_t str, scstr_t pattern,
universe@378 789 scstr_t replacement, size_t replmax) {
universe@378 790 return scstrreplacen_a(ucx_default_allocator(),
universe@378 791 str, pattern, replacement, replmax);
universe@378 792 }
universe@378 793
universe@378 794
universe@316 795 // type adjustment functions
universe@316 796 scstr_t ucx_sc2sc(scstr_t str) {
universe@316 797 return str;
olaf@275 798 }
olaf@275 799 scstr_t ucx_ss2sc(sstr_t str) {
olaf@275 800 scstr_t cs;
olaf@275 801 cs.ptr = str.ptr;
olaf@275 802 cs.length = str.length;
olaf@275 803 return cs;
olaf@275 804 }
olaf@275 805 scstr_t ucx_ss2c_s(scstr_t c) {
olaf@275 806 return c;
olaf@275 807 }

mercurial