1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 8 #include "spdk/string.h" 9 10 char * 11 spdk_vsprintf_append_realloc(char *buffer, const char *format, va_list args) 12 { 13 va_list args_copy; 14 char *new_buffer; 15 int orig_size = 0, new_size; 16 17 /* Original buffer size */ 18 if (buffer) { 19 orig_size = strlen(buffer); 20 } 21 22 /* Necessary buffer size */ 23 va_copy(args_copy, args); 24 new_size = vsnprintf(NULL, 0, format, args_copy); 25 va_end(args_copy); 26 27 if (new_size < 0) { 28 return NULL; 29 } 30 new_size += orig_size + 1; 31 32 new_buffer = realloc(buffer, new_size); 33 if (new_buffer == NULL) { 34 return NULL; 35 } 36 37 vsnprintf(new_buffer + orig_size, new_size - orig_size, format, args); 38 39 return new_buffer; 40 } 41 42 char * 43 spdk_sprintf_append_realloc(char *buffer, const char *format, ...) 44 { 45 va_list args; 46 char *ret; 47 48 va_start(args, format); 49 ret = spdk_vsprintf_append_realloc(buffer, format, args); 50 va_end(args); 51 52 return ret; 53 } 54 55 char * 56 spdk_vsprintf_alloc(const char *format, va_list args) 57 { 58 return spdk_vsprintf_append_realloc(NULL, format, args); 59 } 60 61 char * 62 spdk_sprintf_alloc(const char *format, ...) 63 { 64 va_list args; 65 char *ret; 66 67 va_start(args, format); 68 ret = spdk_vsprintf_alloc(format, args); 69 va_end(args); 70 71 return ret; 72 } 73 74 char * 75 spdk_strlwr(char *s) 76 { 77 char *p; 78 79 if (s == NULL) { 80 return NULL; 81 } 82 83 p = s; 84 while (*p != '\0') { 85 *p = tolower(*p); 86 p++; 87 } 88 89 return s; 90 } 91 92 char * 93 spdk_strsepq(char **stringp, const char *delim) 94 { 95 char *p, *q, *r; 96 int quoted = 0, bslash = 0; 97 98 p = *stringp; 99 if (p == NULL) { 100 return NULL; 101 } 102 103 r = q = p; 104 while (*q != '\0' && *q != '\n') { 105 /* eat quoted characters */ 106 if (bslash) { 107 bslash = 0; 108 *r++ = *q++; 109 continue; 110 } else if (quoted) { 111 if (quoted == '"' && *q == '\\') { 112 bslash = 1; 113 q++; 114 continue; 115 } else if (*q == quoted) { 116 quoted = 0; 117 q++; 118 continue; 119 } 120 *r++ = *q++; 121 continue; 122 } else if (*q == '\\') { 123 bslash = 1; 124 q++; 125 continue; 126 } else if (*q == '"' || *q == '\'') { 127 quoted = *q; 128 q++; 129 continue; 130 } 131 132 /* separator? */ 133 if (strchr(delim, *q) == NULL) { 134 *r++ = *q++; 135 continue; 136 } 137 138 /* new string */ 139 q++; 140 break; 141 } 142 *r = '\0'; 143 144 /* skip tailer */ 145 while (*q != '\0' && strchr(delim, *q) != NULL) { 146 q++; 147 } 148 if (*q != '\0') { 149 *stringp = q; 150 } else { 151 *stringp = NULL; 152 } 153 154 return p; 155 } 156 157 char * 158 spdk_str_trim(char *s) 159 { 160 char *p, *q; 161 162 if (s == NULL) { 163 return NULL; 164 } 165 166 /* remove header */ 167 p = s; 168 while (*p != '\0' && isspace(*p)) { 169 p++; 170 } 171 172 /* remove tailer */ 173 q = p + strlen(p); 174 while (q - 1 >= p && isspace(*(q - 1))) { 175 q--; 176 *q = '\0'; 177 } 178 179 /* if remove header, move */ 180 if (p != s) { 181 q = s; 182 while (*p != '\0') { 183 *q++ = *p++; 184 } 185 *q = '\0'; 186 } 187 188 return s; 189 } 190 191 void 192 spdk_strcpy_pad(void *dst, const char *src, size_t size, int pad) 193 { 194 size_t len; 195 196 len = strlen(src); 197 if (len < size) { 198 memcpy(dst, src, len); 199 memset((char *)dst + len, pad, size - len); 200 } else { 201 memcpy(dst, src, size); 202 } 203 } 204 205 size_t 206 spdk_strlen_pad(const void *str, size_t size, int pad) 207 { 208 const uint8_t *start; 209 const uint8_t *iter; 210 uint8_t pad_byte; 211 212 pad_byte = (uint8_t)pad; 213 start = (const uint8_t *)str; 214 215 if (size == 0) { 216 return 0; 217 } 218 219 iter = start + size - 1; 220 while (1) { 221 if (*iter != pad_byte) { 222 return iter - start + 1; 223 } 224 225 if (iter == start) { 226 /* Hit the start of the string finding only pad_byte. */ 227 return 0; 228 } 229 iter--; 230 } 231 } 232 233 int 234 spdk_parse_ip_addr(char *ip, char **host, char **port) 235 { 236 char *p; 237 238 if (ip == NULL) { 239 return -EINVAL; 240 } 241 242 *host = NULL; 243 *port = NULL; 244 245 if (ip[0] == '[') { 246 /* IPv6 */ 247 p = strchr(ip, ']'); 248 if (p == NULL) { 249 return -EINVAL; 250 } 251 *host = &ip[1]; 252 *p = '\0'; 253 254 p++; 255 if (*p == '\0') { 256 return 0; 257 } else if (*p != ':') { 258 return -EINVAL; 259 } 260 261 p++; 262 if (*p == '\0') { 263 return 0; 264 } 265 266 *port = p; 267 } else { 268 /* IPv4 */ 269 p = strchr(ip, ':'); 270 if (p == NULL) { 271 *host = ip; 272 return 0; 273 } 274 275 *host = ip; 276 *p = '\0'; 277 278 p++; 279 if (*p == '\0') { 280 return 0; 281 } 282 283 *port = p; 284 } 285 286 return 0; 287 } 288 289 size_t 290 spdk_str_chomp(char *s) 291 { 292 size_t len = strlen(s); 293 size_t removed = 0; 294 295 while (len > 0) { 296 if (s[len - 1] != '\r' && s[len - 1] != '\n') { 297 break; 298 } 299 300 s[len - 1] = '\0'; 301 len--; 302 removed++; 303 } 304 305 return removed; 306 } 307 308 void 309 spdk_strerror_r(int errnum, char *buf, size_t buflen) 310 { 311 int rc; 312 313 #if defined(__USE_GNU) 314 char *new_buffer; 315 new_buffer = strerror_r(errnum, buf, buflen); 316 if (new_buffer == buf) { 317 rc = 0; 318 } else if (new_buffer != NULL) { 319 snprintf(buf, buflen, "%s", new_buffer); 320 rc = 0; 321 } else { 322 rc = 1; 323 } 324 #else 325 rc = strerror_r(errnum, buf, buflen); 326 #endif 327 328 if (rc != 0) { 329 snprintf(buf, buflen, "Unknown error %d", errnum); 330 } 331 } 332 333 int 334 spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix) 335 { 336 int rc; 337 char bin_prefix; 338 339 rc = sscanf(cap_str, "%"SCNu64"%c", cap, &bin_prefix); 340 if (rc == 1) { 341 *has_prefix = false; 342 return 0; 343 } else if (rc == 0) { 344 if (errno == 0) { 345 /* No scanf matches - the string does not start with a digit */ 346 return -EINVAL; 347 } else { 348 /* Parsing error */ 349 return -errno; 350 } 351 } 352 353 *has_prefix = true; 354 switch (bin_prefix) { 355 case 'k': 356 case 'K': 357 *cap *= 1024; 358 break; 359 case 'm': 360 case 'M': 361 *cap *= 1024 * 1024; 362 break; 363 case 'g': 364 case 'G': 365 *cap *= 1024 * 1024 * 1024; 366 break; 367 default: 368 return -EINVAL; 369 } 370 371 return 0; 372 } 373 374 bool 375 spdk_mem_all_zero(const void *data, size_t size) 376 { 377 const uint8_t *buf = data; 378 379 while (size--) { 380 if (*buf++ != 0) { 381 return false; 382 } 383 } 384 385 return true; 386 } 387 388 long int 389 spdk_strtol(const char *nptr, int base) 390 { 391 long val; 392 char *endptr; 393 394 /* Since strtoll() can legitimately return 0, LONG_MAX, or LONG_MIN 395 * on both success and failure, the calling program should set errno 396 * to 0 before the call. 397 */ 398 errno = 0; 399 400 val = strtol(nptr, &endptr, base); 401 402 if (!errno && *endptr != '\0') { 403 /* Non integer character was found. */ 404 return -EINVAL; 405 } else if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) { 406 /* Overflow occurred. */ 407 return -ERANGE; 408 } else if (errno != 0 && val == 0) { 409 /* Other error occurred. */ 410 return -errno; 411 } else if (val < 0) { 412 /* Input string was negative number. */ 413 return -ERANGE; 414 } 415 416 return val; 417 } 418 419 long long int 420 spdk_strtoll(const char *nptr, int base) 421 { 422 long long val; 423 char *endptr; 424 425 /* Since strtoll() can legitimately return 0, LLONG_MAX, or LLONG_MIN 426 * on both success and failure, the calling program should set errno 427 * to 0 before the call. 428 */ 429 errno = 0; 430 431 val = strtoll(nptr, &endptr, base); 432 433 if (!errno && *endptr != '\0') { 434 /* Non integer character was found. */ 435 return -EINVAL; 436 } else if (errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) { 437 /* Overflow occurred. */ 438 return -ERANGE; 439 } else if (errno != 0 && val == 0) { 440 /* Other error occurred. */ 441 return -errno; 442 } else if (val < 0) { 443 /* Input string was negative number. */ 444 return -ERANGE; 445 } 446 447 return val; 448 } 449