1.1 --- a/src/string.c Mon Dec 30 09:54:10 2019 +0100 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,807 +0,0 @@ 1.4 -/* 1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 - * 1.7 - * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. 1.8 - * 1.9 - * Redistribution and use in source and binary forms, with or without 1.10 - * modification, are permitted provided that the following conditions are met: 1.11 - * 1.12 - * 1. Redistributions of source code must retain the above copyright 1.13 - * notice, this list of conditions and the following disclaimer. 1.14 - * 1.15 - * 2. Redistributions in binary form must reproduce the above copyright 1.16 - * notice, this list of conditions and the following disclaimer in the 1.17 - * documentation and/or other materials provided with the distribution. 1.18 - * 1.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 - * POSSIBILITY OF SUCH DAMAGE. 1.30 - */ 1.31 - 1.32 -#include "ucx/string.h" 1.33 - 1.34 -#include "ucx/allocator.h" 1.35 - 1.36 -#include <stdlib.h> 1.37 -#include <string.h> 1.38 -#include <stdarg.h> 1.39 -#include <stdint.h> 1.40 -#include <ctype.h> 1.41 - 1.42 -#ifndef _WIN32 1.43 -#include <strings.h> /* for strncasecmp() */ 1.44 -#endif /* _WIN32 */ 1.45 - 1.46 -sstr_t sstr(char *cstring) { 1.47 - sstr_t string; 1.48 - string.ptr = cstring; 1.49 - string.length = strlen(cstring); 1.50 - return string; 1.51 -} 1.52 - 1.53 -sstr_t sstrn(char *cstring, size_t length) { 1.54 - sstr_t string; 1.55 - string.ptr = cstring; 1.56 - string.length = length; 1.57 - return string; 1.58 -} 1.59 - 1.60 -scstr_t scstr(const char *cstring) { 1.61 - scstr_t string; 1.62 - string.ptr = cstring; 1.63 - string.length = strlen(cstring); 1.64 - return string; 1.65 -} 1.66 - 1.67 -scstr_t scstrn(const char *cstring, size_t length) { 1.68 - scstr_t string; 1.69 - string.ptr = cstring; 1.70 - string.length = length; 1.71 - return string; 1.72 -} 1.73 - 1.74 - 1.75 -size_t scstrnlen(size_t n, ...) { 1.76 - if (n == 0) return 0; 1.77 - 1.78 - va_list ap; 1.79 - va_start(ap, n); 1.80 - 1.81 - size_t size = 0; 1.82 - 1.83 - for (size_t i = 0 ; i < n ; i++) { 1.84 - scstr_t str = va_arg(ap, scstr_t); 1.85 - if(SIZE_MAX - str.length < size) { 1.86 - size = SIZE_MAX; 1.87 - break; 1.88 - } 1.89 - size += str.length; 1.90 - } 1.91 - va_end(ap); 1.92 - 1.93 - return size; 1.94 -} 1.95 - 1.96 -static sstr_t sstrvcat_a( 1.97 - UcxAllocator *a, 1.98 - size_t count, 1.99 - scstr_t s1, 1.100 - va_list ap) { 1.101 - sstr_t str; 1.102 - str.ptr = NULL; 1.103 - str.length = 0; 1.104 - if(count < 2) { 1.105 - return str; 1.106 - } 1.107 - 1.108 - scstr_t s2 = va_arg (ap, scstr_t); 1.109 - 1.110 - if(((size_t)-1) - s1.length < s2.length) { 1.111 - return str; 1.112 - } 1.113 - 1.114 - scstr_t *strings = (scstr_t*) calloc(count, sizeof(scstr_t)); 1.115 - if(!strings) { 1.116 - return str; 1.117 - } 1.118 - 1.119 - // get all args and overall length 1.120 - strings[0] = s1; 1.121 - strings[1] = s2; 1.122 - size_t slen = s1.length + s2.length; 1.123 - int error = 0; 1.124 - for (size_t i=2;i<count;i++) { 1.125 - scstr_t s = va_arg (ap, scstr_t); 1.126 - strings[i] = s; 1.127 - if(((size_t)-1) - s.length < slen) { 1.128 - error = 1; 1.129 - break; 1.130 - } 1.131 - slen += s.length; 1.132 - } 1.133 - if(error) { 1.134 - free(strings); 1.135 - return str; 1.136 - } 1.137 - 1.138 - // create new string 1.139 - str.ptr = (char*) almalloc(a, slen + 1); 1.140 - str.length = slen; 1.141 - if(!str.ptr) { 1.142 - free(strings); 1.143 - str.length = 0; 1.144 - return str; 1.145 - } 1.146 - 1.147 - // concatenate strings 1.148 - size_t pos = 0; 1.149 - for (size_t i=0;i<count;i++) { 1.150 - scstr_t s = strings[i]; 1.151 - memcpy(str.ptr + pos, s.ptr, s.length); 1.152 - pos += s.length; 1.153 - } 1.154 - 1.155 - str.ptr[str.length] = '\0'; 1.156 - 1.157 - free(strings); 1.158 - 1.159 - return str; 1.160 -} 1.161 - 1.162 -sstr_t scstrcat(size_t count, scstr_t s1, ...) { 1.163 - va_list ap; 1.164 - va_start(ap, s1); 1.165 - sstr_t s = sstrvcat_a(ucx_default_allocator(), count, s1, ap); 1.166 - va_end(ap); 1.167 - return s; 1.168 -} 1.169 - 1.170 -sstr_t scstrcat_a(UcxAllocator *a, size_t count, scstr_t s1, ...) { 1.171 - va_list ap; 1.172 - va_start(ap, s1); 1.173 - sstr_t s = sstrvcat_a(a, count, s1, ap); 1.174 - va_end(ap); 1.175 - return s; 1.176 -} 1.177 - 1.178 -static int ucx_substring( 1.179 - size_t str_length, 1.180 - size_t start, 1.181 - size_t length, 1.182 - size_t *newlen, 1.183 - size_t *newpos) 1.184 -{ 1.185 - *newlen = 0; 1.186 - *newpos = 0; 1.187 - 1.188 - if(start > str_length) { 1.189 - return 0; 1.190 - } 1.191 - 1.192 - if(length > str_length - start) { 1.193 - length = str_length - start; 1.194 - } 1.195 - *newlen = length; 1.196 - *newpos = start; 1.197 - return 1; 1.198 -} 1.199 - 1.200 -sstr_t sstrsubs(sstr_t s, size_t start) { 1.201 - return sstrsubsl (s, start, s.length-start); 1.202 -} 1.203 - 1.204 -sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) { 1.205 - size_t pos; 1.206 - sstr_t ret = { NULL, 0 }; 1.207 - if(ucx_substring(s.length, start, length, &ret.length, &pos)) { 1.208 - ret.ptr = s.ptr + pos; 1.209 - } 1.210 - return ret; 1.211 -} 1.212 - 1.213 -scstr_t scstrsubs(scstr_t string, size_t start) { 1.214 - return scstrsubsl(string, start, string.length-start); 1.215 -} 1.216 - 1.217 -scstr_t scstrsubsl(scstr_t s, size_t start, size_t length) { 1.218 - size_t pos; 1.219 - scstr_t ret = { NULL, 0 }; 1.220 - if(ucx_substring(s.length, start, length, &ret.length, &pos)) { 1.221 - ret.ptr = s.ptr + pos; 1.222 - } 1.223 - return ret; 1.224 -} 1.225 - 1.226 - 1.227 -static int ucx_strchr(const char *str, size_t length, int chr, size_t *pos) { 1.228 - for(size_t i=0;i<length;i++) { 1.229 - if(str[i] == chr) { 1.230 - *pos = i; 1.231 - return 1; 1.232 - } 1.233 - } 1.234 - return 0; 1.235 -} 1.236 - 1.237 -static int ucx_strrchr(const char *str, size_t length, int chr, size_t *pos) { 1.238 - if(length > 0) { 1.239 - for(size_t i=length ; i>0 ; i--) { 1.240 - if(str[i-1] == chr) { 1.241 - *pos = i-1; 1.242 - return 1; 1.243 - } 1.244 - } 1.245 - } 1.246 - return 0; 1.247 -} 1.248 - 1.249 -sstr_t sstrchr(sstr_t s, int c) { 1.250 - size_t pos = 0; 1.251 - if(ucx_strchr(s.ptr, s.length, c, &pos)) { 1.252 - return sstrsubs(s, pos); 1.253 - } 1.254 - return sstrn(NULL, 0); 1.255 -} 1.256 - 1.257 -sstr_t sstrrchr(sstr_t s, int c) { 1.258 - size_t pos = 0; 1.259 - if(ucx_strrchr(s.ptr, s.length, c, &pos)) { 1.260 - return sstrsubs(s, pos); 1.261 - } 1.262 - return sstrn(NULL, 0); 1.263 -} 1.264 - 1.265 -scstr_t scstrchr(scstr_t s, int c) { 1.266 - size_t pos = 0; 1.267 - if(ucx_strchr(s.ptr, s.length, c, &pos)) { 1.268 - return scstrsubs(s, pos); 1.269 - } 1.270 - return scstrn(NULL, 0); 1.271 -} 1.272 - 1.273 -scstr_t scstrrchr(scstr_t s, int c) { 1.274 - size_t pos = 0; 1.275 - if(ucx_strrchr(s.ptr, s.length, c, &pos)) { 1.276 - return scstrsubs(s, pos); 1.277 - } 1.278 - return scstrn(NULL, 0); 1.279 -} 1.280 - 1.281 -#define ptable_r(dest, useheap, ptable, index) (dest = useheap ? \ 1.282 - ((size_t*)ptable)[index] : (size_t) ((uint8_t*)ptable)[index]) 1.283 - 1.284 -#define ptable_w(useheap, ptable, index, src) do {\ 1.285 - if (!useheap) ((uint8_t*)ptable)[index] = (uint8_t) src;\ 1.286 - else ((size_t*)ptable)[index] = src;\ 1.287 - } while (0); 1.288 - 1.289 - 1.290 -static const char* ucx_strstr( 1.291 - const char *str, 1.292 - size_t length, 1.293 - const char *match, 1.294 - size_t matchlen, 1.295 - size_t *newlen) 1.296 -{ 1.297 - *newlen = length; 1.298 - if (matchlen == 0) { 1.299 - return str; 1.300 - } 1.301 - 1.302 - const char *result = NULL; 1.303 - size_t resultlen = 0; 1.304 - 1.305 - /* 1.306 - * IMPORTANT: 1.307 - * our prefix table contains the prefix length PLUS ONE 1.308 - * this is our decision, because we want to use the full range of size_t 1.309 - * the original algorithm needs a (-1) at one single place 1.310 - * and we want to avoid that 1.311 - */ 1.312 - 1.313 - /* static prefix table */ 1.314 - static uint8_t s_prefix_table[256]; 1.315 - 1.316 - /* check pattern length and use appropriate prefix table */ 1.317 - /* if the pattern exceeds static prefix table, allocate on the heap */ 1.318 - register int useheap = matchlen > 255; 1.319 - register void* ptable = useheap ? 1.320 - calloc(matchlen+1, sizeof(size_t)): s_prefix_table; 1.321 - 1.322 - /* keep counter in registers */ 1.323 - register size_t i, j; 1.324 - 1.325 - /* fill prefix table */ 1.326 - i = 0; j = 0; 1.327 - ptable_w(useheap, ptable, i, j); 1.328 - while (i < matchlen) { 1.329 - while (j >= 1 && match[j-1] != match[i]) { 1.330 - ptable_r(j, useheap, ptable, j-1); 1.331 - } 1.332 - i++; j++; 1.333 - ptable_w(useheap, ptable, i, j); 1.334 - } 1.335 - 1.336 - /* search */ 1.337 - i = 0; j = 1; 1.338 - while (i < length) { 1.339 - while (j >= 1 && str[i] != match[j-1]) { 1.340 - ptable_r(j, useheap, ptable, j-1); 1.341 - } 1.342 - i++; j++; 1.343 - if (j-1 == matchlen) { 1.344 - size_t start = i - matchlen; 1.345 - result = str + start; 1.346 - resultlen = length - start; 1.347 - break; 1.348 - } 1.349 - } 1.350 - 1.351 - /* if prefix table was allocated on the heap, free it */ 1.352 - if (ptable != s_prefix_table) { 1.353 - free(ptable); 1.354 - } 1.355 - 1.356 - *newlen = resultlen; 1.357 - return result; 1.358 -} 1.359 - 1.360 -sstr_t scstrsstr(sstr_t string, scstr_t match) { 1.361 - sstr_t result; 1.362 - 1.363 - size_t reslen; 1.364 - const char *resstr = ucx_strstr(string.ptr, string.length, match.ptr, match.length, &reslen); 1.365 - if(!resstr) { 1.366 - result.ptr = NULL; 1.367 - result.length = 0; 1.368 - return result; 1.369 - } 1.370 - 1.371 - size_t pos = resstr - string.ptr; 1.372 - result.ptr = string.ptr + pos; 1.373 - result.length = reslen; 1.374 - 1.375 - return result; 1.376 -} 1.377 - 1.378 -scstr_t scstrscstr(scstr_t string, scstr_t match) { 1.379 - scstr_t result; 1.380 - 1.381 - size_t reslen; 1.382 - const char *resstr = ucx_strstr(string.ptr, string.length, match.ptr, match.length, &reslen); 1.383 - if(!resstr) { 1.384 - result.ptr = NULL; 1.385 - result.length = 0; 1.386 - return result; 1.387 - } 1.388 - 1.389 - size_t pos = resstr - string.ptr; 1.390 - result.ptr = string.ptr + pos; 1.391 - result.length = reslen; 1.392 - 1.393 - return result; 1.394 -} 1.395 - 1.396 -#undef ptable_r 1.397 -#undef ptable_w 1.398 - 1.399 -sstr_t* scstrsplit(scstr_t s, scstr_t d, ssize_t *n) { 1.400 - return scstrsplit_a(ucx_default_allocator(), s, d, n); 1.401 -} 1.402 - 1.403 -sstr_t* scstrsplit_a(UcxAllocator *allocator, scstr_t s, scstr_t d, ssize_t *n) { 1.404 - if (s.length == 0 || d.length == 0) { 1.405 - *n = -1; 1.406 - return NULL; 1.407 - } 1.408 - 1.409 - /* special cases: delimiter is at least as large as the string */ 1.410 - if (d.length >= s.length) { 1.411 - /* exact match */ 1.412 - if (sstrcmp(s, d) == 0) { 1.413 - *n = 0; 1.414 - return NULL; 1.415 - } else /* no match possible */ { 1.416 - *n = 1; 1.417 - sstr_t *result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)); 1.418 - if(result) { 1.419 - *result = sstrdup_a(allocator, s); 1.420 - } else { 1.421 - *n = -2; 1.422 - } 1.423 - return result; 1.424 - } 1.425 - } 1.426 - 1.427 - ssize_t nmax = *n; 1.428 - size_t arrlen = 16; 1.429 - sstr_t* result = (sstr_t*) alcalloc(allocator, arrlen, sizeof(sstr_t)); 1.430 - 1.431 - if (result) { 1.432 - scstr_t curpos = s; 1.433 - ssize_t j = 1; 1.434 - while (1) { 1.435 - scstr_t match; 1.436 - /* optimize for one byte delimiters */ 1.437 - if (d.length == 1) { 1.438 - match = curpos; 1.439 - for (size_t i = 0 ; i < curpos.length ; i++) { 1.440 - if (curpos.ptr[i] == *(d.ptr)) { 1.441 - match.ptr = curpos.ptr + i; 1.442 - break; 1.443 - } 1.444 - match.length--; 1.445 - } 1.446 - } else { 1.447 - match = scstrscstr(curpos, d); 1.448 - } 1.449 - if (match.length > 0) { 1.450 - /* is this our last try? */ 1.451 - if (nmax == 0 || j < nmax) { 1.452 - /* copy the current string to the array */ 1.453 - scstr_t item = scstrn(curpos.ptr, match.ptr - curpos.ptr); 1.454 - result[j-1] = sstrdup_a(allocator, item); 1.455 - size_t processed = item.length + d.length; 1.456 - curpos.ptr += processed; 1.457 - curpos.length -= processed; 1.458 - 1.459 - /* allocate memory for the next string */ 1.460 - j++; 1.461 - if (j > arrlen) { 1.462 - arrlen *= 2; 1.463 - size_t reallocsz; 1.464 - sstr_t* reallocated = NULL; 1.465 - if(!ucx_szmul(arrlen, sizeof(sstr_t), &reallocsz)) { 1.466 - reallocated = (sstr_t*) alrealloc( 1.467 - allocator, result, reallocsz); 1.468 - } 1.469 - if (reallocated) { 1.470 - result = reallocated; 1.471 - } else { 1.472 - for (ssize_t i = 0 ; i < j-1 ; i++) { 1.473 - alfree(allocator, result[i].ptr); 1.474 - } 1.475 - alfree(allocator, result); 1.476 - *n = -2; 1.477 - return NULL; 1.478 - } 1.479 - } 1.480 - } else { 1.481 - /* nmax reached, copy the _full_ remaining string */ 1.482 - result[j-1] = sstrdup_a(allocator, curpos); 1.483 - break; 1.484 - } 1.485 - } else { 1.486 - /* no more matches, copy last string */ 1.487 - result[j-1] = sstrdup_a(allocator, curpos); 1.488 - break; 1.489 - } 1.490 - } 1.491 - *n = j; 1.492 - } else { 1.493 - *n = -2; 1.494 - } 1.495 - 1.496 - return result; 1.497 -} 1.498 - 1.499 -int scstrcmp(scstr_t s1, scstr_t s2) { 1.500 - if (s1.length == s2.length) { 1.501 - return memcmp(s1.ptr, s2.ptr, s1.length); 1.502 - } else if (s1.length > s2.length) { 1.503 - return 1; 1.504 - } else { 1.505 - return -1; 1.506 - } 1.507 -} 1.508 - 1.509 -int scstrcasecmp(scstr_t s1, scstr_t s2) { 1.510 - if (s1.length == s2.length) { 1.511 -#ifdef _WIN32 1.512 - return _strnicmp(s1.ptr, s2.ptr, s1.length); 1.513 -#else 1.514 - return strncasecmp(s1.ptr, s2.ptr, s1.length); 1.515 -#endif 1.516 - } else if (s1.length > s2.length) { 1.517 - return 1; 1.518 - } else { 1.519 - return -1; 1.520 - } 1.521 -} 1.522 - 1.523 -sstr_t scstrdup(scstr_t s) { 1.524 - return sstrdup_a(ucx_default_allocator(), s); 1.525 -} 1.526 - 1.527 -sstr_t scstrdup_a(UcxAllocator *allocator, scstr_t s) { 1.528 - sstr_t newstring; 1.529 - newstring.ptr = (char*)almalloc(allocator, s.length + 1); 1.530 - if (newstring.ptr) { 1.531 - newstring.length = s.length; 1.532 - newstring.ptr[newstring.length] = 0; 1.533 - 1.534 - memcpy(newstring.ptr, s.ptr, s.length); 1.535 - } else { 1.536 - newstring.length = 0; 1.537 - } 1.538 - 1.539 - return newstring; 1.540 -} 1.541 - 1.542 - 1.543 -static size_t ucx_strtrim(const char *s, size_t len, size_t *newlen) { 1.544 - const char *newptr = s; 1.545 - size_t length = len; 1.546 - 1.547 - while(length > 0 && isspace(*newptr)) { 1.548 - newptr++; 1.549 - length--; 1.550 - } 1.551 - while(length > 0 && isspace(newptr[length-1])) { 1.552 - length--; 1.553 - } 1.554 - 1.555 - *newlen = length; 1.556 - return newptr - s; 1.557 -} 1.558 - 1.559 -sstr_t sstrtrim(sstr_t string) { 1.560 - sstr_t newstr; 1.561 - newstr.ptr = string.ptr 1.562 - + ucx_strtrim(string.ptr, string.length, &newstr.length); 1.563 - return newstr; 1.564 -} 1.565 - 1.566 -scstr_t scstrtrim(scstr_t string) { 1.567 - scstr_t newstr; 1.568 - newstr.ptr = string.ptr 1.569 - + ucx_strtrim(string.ptr, string.length, &newstr.length); 1.570 - return newstr; 1.571 -} 1.572 - 1.573 -int scstrprefix(scstr_t string, scstr_t prefix) { 1.574 - if (string.length == 0) { 1.575 - return prefix.length == 0; 1.576 - } 1.577 - if (prefix.length == 0) { 1.578 - return 1; 1.579 - } 1.580 - 1.581 - if (prefix.length > string.length) { 1.582 - return 0; 1.583 - } else { 1.584 - return memcmp(string.ptr, prefix.ptr, prefix.length) == 0; 1.585 - } 1.586 -} 1.587 - 1.588 -int scstrsuffix(scstr_t string, scstr_t suffix) { 1.589 - if (string.length == 0) { 1.590 - return suffix.length == 0; 1.591 - } 1.592 - if (suffix.length == 0) { 1.593 - return 1; 1.594 - } 1.595 - 1.596 - if (suffix.length > string.length) { 1.597 - return 0; 1.598 - } else { 1.599 - return memcmp(string.ptr+string.length-suffix.length, 1.600 - suffix.ptr, suffix.length) == 0; 1.601 - } 1.602 -} 1.603 - 1.604 -int scstrcaseprefix(scstr_t string, scstr_t prefix) { 1.605 - if (string.length == 0) { 1.606 - return prefix.length == 0; 1.607 - } 1.608 - if (prefix.length == 0) { 1.609 - return 1; 1.610 - } 1.611 - 1.612 - if (prefix.length > string.length) { 1.613 - return 0; 1.614 - } else { 1.615 - scstr_t subs = scstrsubsl(string, 0, prefix.length); 1.616 - return scstrcasecmp(subs, prefix) == 0; 1.617 - } 1.618 -} 1.619 - 1.620 -int scstrcasesuffix(scstr_t string, scstr_t suffix) { 1.621 - if (string.length == 0) { 1.622 - return suffix.length == 0; 1.623 - } 1.624 - if (suffix.length == 0) { 1.625 - return 1; 1.626 - } 1.627 - 1.628 - if (suffix.length > string.length) { 1.629 - return 0; 1.630 - } else { 1.631 - scstr_t subs = scstrsubs(string, string.length-suffix.length); 1.632 - return scstrcasecmp(subs, suffix) == 0; 1.633 - } 1.634 -} 1.635 - 1.636 -sstr_t scstrlower(scstr_t string) { 1.637 - sstr_t ret = sstrdup(string); 1.638 - for (size_t i = 0; i < ret.length ; i++) { 1.639 - ret.ptr[i] = tolower(ret.ptr[i]); 1.640 - } 1.641 - return ret; 1.642 -} 1.643 - 1.644 -sstr_t scstrlower_a(UcxAllocator *allocator, scstr_t string) { 1.645 - sstr_t ret = sstrdup_a(allocator, string); 1.646 - for (size_t i = 0; i < ret.length ; i++) { 1.647 - ret.ptr[i] = tolower(ret.ptr[i]); 1.648 - } 1.649 - return ret; 1.650 -} 1.651 - 1.652 -sstr_t scstrupper(scstr_t string) { 1.653 - sstr_t ret = sstrdup(string); 1.654 - for (size_t i = 0; i < ret.length ; i++) { 1.655 - ret.ptr[i] = toupper(ret.ptr[i]); 1.656 - } 1.657 - return ret; 1.658 -} 1.659 - 1.660 -sstr_t scstrupper_a(UcxAllocator *allocator, scstr_t string) { 1.661 - sstr_t ret = sstrdup_a(allocator, string); 1.662 - for (size_t i = 0; i < ret.length ; i++) { 1.663 - ret.ptr[i] = toupper(ret.ptr[i]); 1.664 - } 1.665 - return ret; 1.666 -} 1.667 - 1.668 -#define REPLACE_INDEX_BUFFER_MAX 100 1.669 - 1.670 -struct scstrreplace_ibuf { 1.671 - size_t* buf; 1.672 - unsigned int len; /* small indices */ 1.673 - struct scstrreplace_ibuf* next; 1.674 -}; 1.675 - 1.676 -static void scstrrepl_free_ibuf(struct scstrreplace_ibuf *buf) { 1.677 - while (buf) { 1.678 - struct scstrreplace_ibuf *next = buf->next; 1.679 - free(buf->buf); 1.680 - free(buf); 1.681 - buf = next; 1.682 - } 1.683 -} 1.684 - 1.685 -sstr_t scstrreplacen_a(UcxAllocator *allocator, scstr_t str, 1.686 - scstr_t pattern, scstr_t replacement, size_t replmax) { 1.687 - 1.688 - if (pattern.length == 0 || pattern.length > str.length || replmax == 0) 1.689 - return sstrdup(str); 1.690 - 1.691 - /* Compute expected buffer length */ 1.692 - size_t ibufmax = str.length / pattern.length; 1.693 - size_t ibuflen = replmax < ibufmax ? replmax : ibufmax; 1.694 - if (ibuflen > REPLACE_INDEX_BUFFER_MAX) { 1.695 - ibuflen = REPLACE_INDEX_BUFFER_MAX; 1.696 - } 1.697 - 1.698 - /* Allocate first index buffer */ 1.699 - struct scstrreplace_ibuf *firstbuf, *curbuf; 1.700 - firstbuf = curbuf = calloc(1, sizeof(struct scstrreplace_ibuf)); 1.701 - if (!firstbuf) return sstrn(NULL, 0); 1.702 - firstbuf->buf = calloc(ibuflen, sizeof(size_t)); 1.703 - if (!firstbuf->buf) { 1.704 - free(firstbuf); 1.705 - return sstrn(NULL, 0); 1.706 - } 1.707 - 1.708 - /* Search occurrences */ 1.709 - scstr_t searchstr = str; 1.710 - size_t found = 0; 1.711 - do { 1.712 - scstr_t match = scstrscstr(searchstr, pattern); 1.713 - if (match.length > 0) { 1.714 - /* Allocate next buffer in chain, if required */ 1.715 - if (curbuf->len == ibuflen) { 1.716 - struct scstrreplace_ibuf *nextbuf = 1.717 - calloc(1, sizeof(struct scstrreplace_ibuf)); 1.718 - if (!nextbuf) { 1.719 - scstrrepl_free_ibuf(firstbuf); 1.720 - return sstrn(NULL, 0); 1.721 - } 1.722 - nextbuf->buf = calloc(ibuflen, sizeof(size_t)); 1.723 - if (!nextbuf->buf) { 1.724 - free(nextbuf); 1.725 - scstrrepl_free_ibuf(firstbuf); 1.726 - return sstrn(NULL, 0); 1.727 - } 1.728 - curbuf->next = nextbuf; 1.729 - curbuf = nextbuf; 1.730 - } 1.731 - 1.732 - /* Record match index */ 1.733 - found++; 1.734 - size_t idx = match.ptr - str.ptr; 1.735 - curbuf->buf[curbuf->len++] = idx; 1.736 - searchstr.ptr = match.ptr + pattern.length; 1.737 - searchstr.length = str.length - idx - pattern.length; 1.738 - } else { 1.739 - break; 1.740 - } 1.741 - } while (searchstr.length > 0 && found < replmax); 1.742 - 1.743 - /* Allocate result string */ 1.744 - sstr_t result; 1.745 - { 1.746 - ssize_t adjlen = (ssize_t) replacement.length - (ssize_t) pattern.length; 1.747 - size_t rcount = 0; 1.748 - curbuf = firstbuf; 1.749 - do { 1.750 - rcount += curbuf->len; 1.751 - curbuf = curbuf->next; 1.752 - } while (curbuf); 1.753 - result.length = str.length + rcount * adjlen; 1.754 - result.ptr = almalloc(allocator, result.length); 1.755 - if (!result.ptr) { 1.756 - scstrrepl_free_ibuf(firstbuf); 1.757 - return sstrn(NULL, 0); 1.758 - } 1.759 - } 1.760 - 1.761 - /* Build result string */ 1.762 - curbuf = firstbuf; 1.763 - size_t srcidx = 0; 1.764 - char* destptr = result.ptr; 1.765 - do { 1.766 - for (size_t i = 0; i < curbuf->len; i++) { 1.767 - /* Copy source part up to next match*/ 1.768 - size_t idx = curbuf->buf[i]; 1.769 - size_t srclen = idx - srcidx; 1.770 - if (srclen > 0) { 1.771 - memcpy(destptr, str.ptr+srcidx, srclen); 1.772 - destptr += srclen; 1.773 - srcidx += srclen; 1.774 - } 1.775 - 1.776 - /* Copy the replacement and skip the source pattern */ 1.777 - srcidx += pattern.length; 1.778 - memcpy(destptr, replacement.ptr, replacement.length); 1.779 - destptr += replacement.length; 1.780 - } 1.781 - curbuf = curbuf->next; 1.782 - } while (curbuf); 1.783 - memcpy(destptr, str.ptr+srcidx, str.length-srcidx); 1.784 - 1.785 - /* Free index buffer */ 1.786 - scstrrepl_free_ibuf(firstbuf); 1.787 - 1.788 - return result; 1.789 -} 1.790 - 1.791 -sstr_t scstrreplacen(scstr_t str, scstr_t pattern, 1.792 - scstr_t replacement, size_t replmax) { 1.793 - return scstrreplacen_a(ucx_default_allocator(), 1.794 - str, pattern, replacement, replmax); 1.795 -} 1.796 - 1.797 - 1.798 -// type adjustment functions 1.799 -scstr_t ucx_sc2sc(scstr_t str) { 1.800 - return str; 1.801 -} 1.802 -scstr_t ucx_ss2sc(sstr_t str) { 1.803 - scstr_t cs; 1.804 - cs.ptr = str.ptr; 1.805 - cs.length = str.length; 1.806 - return cs; 1.807 -} 1.808 -scstr_t ucx_ss2c_s(scstr_t c) { 1.809 - return c; 1.810 -}