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 if (has_prefix != NULL) { 343 *has_prefix = false; 344 } 345 return 0; 346 } else if (rc == 0) { 347 if (errno == 0) { 348 /* No scanf matches - the string does not start with a digit */ 349 return -EINVAL; 350 } else { 351 /* Parsing error */ 352 return -errno; 353 } 354 } 355 356 if (has_prefix != NULL) { 357 *has_prefix = true; 358 } 359 360 switch (bin_prefix) { 361 case 'k': 362 case 'K': 363 *cap *= 1024; 364 break; 365 case 'm': 366 case 'M': 367 *cap *= 1024 * 1024; 368 break; 369 case 'g': 370 case 'G': 371 *cap *= 1024 * 1024 * 1024; 372 break; 373 default: 374 return -EINVAL; 375 } 376 377 return 0; 378 } 379 380 bool 381 spdk_mem_all_zero(const void *data, size_t size) 382 { 383 const uint8_t *buf = data; 384 385 while (size--) { 386 if (*buf++ != 0) { 387 return false; 388 } 389 } 390 391 return true; 392 } 393 394 long int 395 spdk_strtol(const char *nptr, int base) 396 { 397 long val; 398 char *endptr; 399 400 /* Since strtoll() can legitimately return 0, LONG_MAX, or LONG_MIN 401 * on both success and failure, the calling program should set errno 402 * to 0 before the call. 403 */ 404 errno = 0; 405 406 val = strtol(nptr, &endptr, base); 407 408 if (!errno && *endptr != '\0') { 409 /* Non integer character was found. */ 410 return -EINVAL; 411 } else if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) { 412 /* Overflow occurred. */ 413 return -ERANGE; 414 } else if (errno != 0 && val == 0) { 415 /* Other error occurred. */ 416 return -errno; 417 } else if (val < 0) { 418 /* Input string was negative number. */ 419 return -ERANGE; 420 } 421 422 return val; 423 } 424 425 long long int 426 spdk_strtoll(const char *nptr, int base) 427 { 428 long long val; 429 char *endptr; 430 431 /* Since strtoll() can legitimately return 0, LLONG_MAX, or LLONG_MIN 432 * on both success and failure, the calling program should set errno 433 * to 0 before the call. 434 */ 435 errno = 0; 436 437 val = strtoll(nptr, &endptr, base); 438 439 if (!errno && *endptr != '\0') { 440 /* Non integer character was found. */ 441 return -EINVAL; 442 } else if (errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) { 443 /* Overflow occurred. */ 444 return -ERANGE; 445 } else if (errno != 0 && val == 0) { 446 /* Other error occurred. */ 447 return -errno; 448 } else if (val < 0) { 449 /* Input string was negative number. */ 450 return -ERANGE; 451 } 452 453 return val; 454 } 455 456 void 457 spdk_strarray_free(char **strarray) 458 { 459 size_t i; 460 461 if (strarray == NULL) { 462 return; 463 } 464 465 for (i = 0; strarray[i] != NULL; i++) { 466 free(strarray[i]); 467 } 468 free(strarray); 469 } 470 471 char ** 472 spdk_strarray_from_string(const char *str, const char *delim) 473 { 474 const char *c = str; 475 size_t count = 0; 476 char **result; 477 size_t i; 478 479 assert(str != NULL); 480 assert(delim != NULL); 481 482 /* Count number of entries. */ 483 for (;;) { 484 const char *next = strpbrk(c, delim); 485 486 count++; 487 488 if (next == NULL) { 489 break; 490 } 491 492 c = next + 1; 493 } 494 495 /* Account for the terminating NULL entry. */ 496 result = calloc(count + 1, sizeof(char *)); 497 if (result == NULL) { 498 return NULL; 499 } 500 501 c = str; 502 503 for (i = 0; i < count; i++) { 504 const char *next = strpbrk(c, delim); 505 506 if (next == NULL) { 507 result[i] = strdup(c); 508 } else { 509 result[i] = strndup(c, next - c); 510 } 511 512 if (result[i] == NULL) { 513 spdk_strarray_free(result); 514 return NULL; 515 } 516 517 if (next != NULL) { 518 c = next + 1; 519 } 520 } 521 522 return result; 523 } 524 525 char ** 526 spdk_strarray_dup(const char **strarray) 527 { 528 size_t count, i; 529 char **result; 530 531 assert(strarray != NULL); 532 533 for (count = 0; strarray[count] != NULL; count++) 534 ; 535 536 result = calloc(count + 1, sizeof(char *)); 537 if (result == NULL) { 538 return NULL; 539 } 540 541 for (i = 0; i < count; i++) { 542 result[i] = strdup(strarray[i]); 543 if (result[i] == NULL) { 544 spdk_strarray_free(result); 545 return NULL; 546 } 547 } 548 549 return result; 550 } 551 552 int 553 spdk_strcpy_replace(char *dst, size_t size, const char *src, const char *search, 554 const char *replace) 555 { 556 const char *p, *q; 557 char *r; 558 size_t c, search_size, replace_size, dst_size; 559 560 if (dst == NULL || src == NULL || search == NULL || replace == NULL) { 561 return -EINVAL; 562 } 563 564 search_size = strlen(search); 565 replace_size = strlen(replace); 566 567 c = 0; 568 for (p = strstr(src, search); p != NULL; p = strstr(p + search_size, search)) { 569 c++; 570 } 571 572 dst_size = strlen(src) + (replace_size - search_size) * c; 573 if (dst_size >= size) { 574 return -EINVAL; 575 } 576 577 q = src; 578 r = dst; 579 580 for (p = strstr(src, search); p != NULL; p = strstr(p + search_size, search)) { 581 memcpy(r, q, p - q); 582 r += p - q; 583 584 memcpy(r, replace, replace_size); 585 r += replace_size; 586 587 q = p + search_size; 588 } 589 590 memcpy(r, q, strlen(q)); 591 r += strlen(q); 592 593 *r = '\0'; 594 595 return 0; 596 } 597