1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2015 Intel Corporation. 3 * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. 4 * All rights reserved. 5 */ 6 7 #include "spdk/stdinc.h" 8 9 #include "spdk/string.h" 10 11 char * 12 spdk_vsprintf_append_realloc(char *buffer, const char *format, va_list args) 13 { 14 va_list args_copy; 15 char *new_buffer; 16 int orig_size = 0, new_size; 17 18 /* Original buffer size */ 19 if (buffer) { 20 orig_size = strlen(buffer); 21 } 22 23 /* Necessary buffer size */ 24 va_copy(args_copy, args); 25 new_size = vsnprintf(NULL, 0, format, args_copy); 26 va_end(args_copy); 27 28 if (new_size < 0) { 29 return NULL; 30 } 31 new_size += orig_size + 1; 32 33 new_buffer = realloc(buffer, new_size); 34 if (new_buffer == NULL) { 35 return NULL; 36 } 37 38 vsnprintf(new_buffer + orig_size, new_size - orig_size, format, args); 39 40 return new_buffer; 41 } 42 43 char * 44 spdk_sprintf_append_realloc(char *buffer, const char *format, ...) 45 { 46 va_list args; 47 char *ret; 48 49 va_start(args, format); 50 ret = spdk_vsprintf_append_realloc(buffer, format, args); 51 va_end(args); 52 53 return ret; 54 } 55 56 char * 57 spdk_vsprintf_alloc(const char *format, va_list args) 58 { 59 return spdk_vsprintf_append_realloc(NULL, format, args); 60 } 61 62 char * 63 spdk_sprintf_alloc(const char *format, ...) 64 { 65 va_list args; 66 char *ret; 67 68 va_start(args, format); 69 ret = spdk_vsprintf_alloc(format, args); 70 va_end(args); 71 72 return ret; 73 } 74 75 char * 76 spdk_strlwr(char *s) 77 { 78 char *p; 79 80 if (s == NULL) { 81 return NULL; 82 } 83 84 p = s; 85 while (*p != '\0') { 86 *p = tolower(*p); 87 p++; 88 } 89 90 return s; 91 } 92 93 char * 94 spdk_strsepq(char **stringp, const char *delim) 95 { 96 char *p, *q, *r; 97 int quoted = 0, bslash = 0; 98 99 p = *stringp; 100 if (p == NULL) { 101 return NULL; 102 } 103 104 r = q = p; 105 while (*q != '\0' && *q != '\n') { 106 /* eat quoted characters */ 107 if (bslash) { 108 bslash = 0; 109 *r++ = *q++; 110 continue; 111 } else if (quoted) { 112 if (quoted == '"' && *q == '\\') { 113 bslash = 1; 114 q++; 115 continue; 116 } else if (*q == quoted) { 117 quoted = 0; 118 q++; 119 continue; 120 } 121 *r++ = *q++; 122 continue; 123 } else if (*q == '\\') { 124 bslash = 1; 125 q++; 126 continue; 127 } else if (*q == '"' || *q == '\'') { 128 quoted = *q; 129 q++; 130 continue; 131 } 132 133 /* separator? */ 134 if (strchr(delim, *q) == NULL) { 135 *r++ = *q++; 136 continue; 137 } 138 139 /* new string */ 140 q++; 141 break; 142 } 143 *r = '\0'; 144 145 /* skip tailer */ 146 while (*q != '\0' && strchr(delim, *q) != NULL) { 147 q++; 148 } 149 if (*q != '\0') { 150 *stringp = q; 151 } else { 152 *stringp = NULL; 153 } 154 155 return p; 156 } 157 158 char * 159 spdk_str_trim(char *s) 160 { 161 char *p, *q; 162 163 if (s == NULL) { 164 return NULL; 165 } 166 167 /* remove header */ 168 p = s; 169 while (*p != '\0' && isspace(*p)) { 170 p++; 171 } 172 173 /* remove tailer */ 174 q = p + strlen(p); 175 while (q - 1 >= p && isspace(*(q - 1))) { 176 q--; 177 *q = '\0'; 178 } 179 180 /* if remove header, move */ 181 if (p != s) { 182 q = s; 183 while (*p != '\0') { 184 *q++ = *p++; 185 } 186 *q = '\0'; 187 } 188 189 return s; 190 } 191 192 void 193 spdk_strcpy_pad(void *dst, const char *src, size_t size, int pad) 194 { 195 size_t len; 196 197 len = strlen(src); 198 if (len < size) { 199 memcpy(dst, src, len); 200 memset((char *)dst + len, pad, size - len); 201 } else { 202 memcpy(dst, src, size); 203 } 204 } 205 206 size_t 207 spdk_strlen_pad(const void *str, size_t size, int pad) 208 { 209 const uint8_t *start; 210 const uint8_t *iter; 211 uint8_t pad_byte; 212 213 pad_byte = (uint8_t)pad; 214 start = (const uint8_t *)str; 215 216 if (size == 0) { 217 return 0; 218 } 219 220 iter = start + size - 1; 221 while (1) { 222 if (*iter != pad_byte) { 223 return iter - start + 1; 224 } 225 226 if (iter == start) { 227 /* Hit the start of the string finding only pad_byte. */ 228 return 0; 229 } 230 iter--; 231 } 232 } 233 234 int 235 spdk_parse_ip_addr(char *ip, char **host, char **port) 236 { 237 char *p; 238 239 if (ip == NULL) { 240 return -EINVAL; 241 } 242 243 *host = NULL; 244 *port = NULL; 245 246 if (ip[0] == '[') { 247 /* IPv6 */ 248 p = strchr(ip, ']'); 249 if (p == NULL) { 250 return -EINVAL; 251 } 252 *host = &ip[1]; 253 *p = '\0'; 254 255 p++; 256 if (*p == '\0') { 257 return 0; 258 } else if (*p != ':') { 259 return -EINVAL; 260 } 261 262 p++; 263 if (*p == '\0') { 264 return 0; 265 } 266 267 *port = p; 268 } else { 269 /* IPv4 */ 270 p = strchr(ip, ':'); 271 if (p == NULL) { 272 *host = ip; 273 return 0; 274 } 275 276 *host = ip; 277 *p = '\0'; 278 279 p++; 280 if (*p == '\0') { 281 return 0; 282 } 283 284 *port = p; 285 } 286 287 return 0; 288 } 289 290 size_t 291 spdk_str_chomp(char *s) 292 { 293 size_t len = strlen(s); 294 size_t removed = 0; 295 296 while (len > 0) { 297 if (s[len - 1] != '\r' && s[len - 1] != '\n') { 298 break; 299 } 300 301 s[len - 1] = '\0'; 302 len--; 303 removed++; 304 } 305 306 return removed; 307 } 308 309 void 310 spdk_strerror_r(int errnum, char *buf, size_t buflen) 311 { 312 int rc; 313 314 #if defined(__USE_GNU) 315 char *new_buffer; 316 new_buffer = strerror_r(errnum, buf, buflen); 317 if (new_buffer == buf) { 318 rc = 0; 319 } else if (new_buffer != NULL) { 320 snprintf(buf, buflen, "%s", new_buffer); 321 rc = 0; 322 } else { 323 rc = 1; 324 } 325 #else 326 rc = strerror_r(errnum, buf, buflen); 327 #endif 328 329 if (rc != 0) { 330 snprintf(buf, buflen, "Unknown error %d", errnum); 331 } 332 } 333 334 int 335 spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix) 336 { 337 int rc; 338 char bin_prefix; 339 340 rc = sscanf(cap_str, "%"SCNu64"%c", cap, &bin_prefix); 341 if (rc == 1) { 342 *has_prefix = false; 343 return 0; 344 } else if (rc == 0) { 345 if (errno == 0) { 346 /* No scanf matches - the string does not start with a digit */ 347 return -EINVAL; 348 } else { 349 /* Parsing error */ 350 return -errno; 351 } 352 } 353 354 *has_prefix = true; 355 switch (bin_prefix) { 356 case 'k': 357 case 'K': 358 *cap *= 1024; 359 break; 360 case 'm': 361 case 'M': 362 *cap *= 1024 * 1024; 363 break; 364 case 'g': 365 case 'G': 366 *cap *= 1024 * 1024 * 1024; 367 break; 368 default: 369 return -EINVAL; 370 } 371 372 return 0; 373 } 374 375 bool 376 spdk_mem_all_zero(const void *data, size_t size) 377 { 378 const uint8_t *buf = data; 379 380 while (size--) { 381 if (*buf++ != 0) { 382 return false; 383 } 384 } 385 386 return true; 387 } 388 389 long int 390 spdk_strtol(const char *nptr, int base) 391 { 392 long val; 393 char *endptr; 394 395 /* Since strtoll() can legitimately return 0, LONG_MAX, or LONG_MIN 396 * on both success and failure, the calling program should set errno 397 * to 0 before the call. 398 */ 399 errno = 0; 400 401 val = strtol(nptr, &endptr, base); 402 403 if (!errno && *endptr != '\0') { 404 /* Non integer character was found. */ 405 return -EINVAL; 406 } else if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) { 407 /* Overflow occurred. */ 408 return -ERANGE; 409 } else if (errno != 0 && val == 0) { 410 /* Other error occurred. */ 411 return -errno; 412 } else if (val < 0) { 413 /* Input string was negative number. */ 414 return -ERANGE; 415 } 416 417 return val; 418 } 419 420 long long int 421 spdk_strtoll(const char *nptr, int base) 422 { 423 long long val; 424 char *endptr; 425 426 /* Since strtoll() can legitimately return 0, LLONG_MAX, or LLONG_MIN 427 * on both success and failure, the calling program should set errno 428 * to 0 before the call. 429 */ 430 errno = 0; 431 432 val = strtoll(nptr, &endptr, base); 433 434 if (!errno && *endptr != '\0') { 435 /* Non integer character was found. */ 436 return -EINVAL; 437 } else if (errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) { 438 /* Overflow occurred. */ 439 return -ERANGE; 440 } else if (errno != 0 && val == 0) { 441 /* Other error occurred. */ 442 return -errno; 443 } else if (val < 0) { 444 /* Input string was negative number. */ 445 return -ERANGE; 446 } 447 448 return val; 449 } 450 451 void 452 spdk_strarray_free(char **strarray) 453 { 454 size_t i; 455 456 if (strarray == NULL) { 457 return; 458 } 459 460 for (i = 0; strarray[i] != NULL; i++) { 461 free(strarray[i]); 462 } 463 free(strarray); 464 } 465 466 char ** 467 spdk_strarray_from_string(const char *str, const char *delim) 468 { 469 const char *c = str; 470 size_t count = 0; 471 char **result; 472 size_t i; 473 474 assert(str != NULL); 475 assert(delim != NULL); 476 477 /* Count number of entries. */ 478 for (;;) { 479 const char *next = strpbrk(c, delim); 480 481 count++; 482 483 if (next == NULL) { 484 break; 485 } 486 487 c = next + 1; 488 } 489 490 /* Account for the terminating NULL entry. */ 491 result = calloc(count + 1, sizeof(char *)); 492 if (result == NULL) { 493 return NULL; 494 } 495 496 c = str; 497 498 for (i = 0; i < count; i++) { 499 const char *next = strpbrk(c, delim); 500 501 if (next == NULL) { 502 result[i] = strdup(c); 503 } else { 504 result[i] = strndup(c, next - c); 505 } 506 507 if (result[i] == NULL) { 508 spdk_strarray_free(result); 509 return NULL; 510 } 511 512 if (next != NULL) { 513 c = next + 1; 514 } 515 } 516 517 return result; 518 } 519 520 char ** 521 spdk_strarray_dup(const char **strarray) 522 { 523 size_t count, i; 524 char **result; 525 526 assert(strarray != NULL); 527 528 for (count = 0; strarray[count] != NULL; count++) 529 ; 530 531 result = calloc(count + 1, sizeof(char *)); 532 if (result == NULL) { 533 return NULL; 534 } 535 536 for (i = 0; i < count; i++) { 537 result[i] = strdup(strarray[i]); 538 if (result[i] == NULL) { 539 spdk_strarray_free(result); 540 return NULL; 541 } 542 } 543 544 return result; 545 } 546 547 int 548 spdk_strcpy_replace(char *dst, size_t size, const char *src, const char *search, 549 const char *replace) 550 { 551 const char *p, *q; 552 char *r; 553 size_t c, search_size, replace_size, dst_size; 554 555 if (dst == NULL || src == NULL || search == NULL || replace == NULL) { 556 return -EINVAL; 557 } 558 559 search_size = strlen(search); 560 replace_size = strlen(replace); 561 562 c = 0; 563 for (p = strstr(src, search); p != NULL; p = strstr(p + search_size, search)) { 564 c++; 565 } 566 567 dst_size = strlen(src) + (replace_size - search_size) * c; 568 if (dst_size >= size) { 569 return -EINVAL; 570 } 571 572 q = src; 573 r = dst; 574 575 for (p = strstr(src, search); p != NULL; p = strstr(p + search_size, search)) { 576 memcpy(r, q, p - q); 577 r += p - q; 578 579 memcpy(r, replace, replace_size); 580 r += replace_size; 581 582 q = p + search_size; 583 } 584 585 memcpy(r, q, strlen(q)); 586 r += strlen(q); 587 588 *r = '\0'; 589 590 return 0; 591 } 592