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