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 != NULL) { 345 snprintf(buf, buflen, "%s", new_buffer); 346 rc = 0; 347 } else { 348 rc = 1; 349 } 350 #else 351 rc = strerror_r(errnum, buf, buflen); 352 #endif 353 354 if (rc != 0) { 355 snprintf(buf, buflen, "Unknown error %d", errnum); 356 } 357 } 358 359 int 360 spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix) 361 { 362 int rc; 363 char bin_prefix; 364 365 rc = sscanf(cap_str, "%"SCNu64"%c", cap, &bin_prefix); 366 if (rc == 1) { 367 *has_prefix = false; 368 return 0; 369 } else if (rc == 0) { 370 if (errno == 0) { 371 /* No scanf matches - the string does not start with a digit */ 372 return -EINVAL; 373 } else { 374 /* Parsing error */ 375 return -errno; 376 } 377 } 378 379 *has_prefix = true; 380 switch (bin_prefix) { 381 case 'k': 382 case 'K': 383 *cap *= 1024; 384 break; 385 case 'm': 386 case 'M': 387 *cap *= 1024 * 1024; 388 break; 389 case 'g': 390 case 'G': 391 *cap *= 1024 * 1024 * 1024; 392 break; 393 default: 394 return -EINVAL; 395 } 396 397 return 0; 398 } 399 400 bool 401 spdk_mem_all_zero(const void *data, size_t size) 402 { 403 const uint8_t *buf = data; 404 405 while (size--) { 406 if (*buf++ != 0) { 407 return false; 408 } 409 } 410 411 return true; 412 } 413 414 long int 415 spdk_strtol(const char *nptr, int base) 416 { 417 long val; 418 char *endptr; 419 420 /* Since strtoll() can legitimately return 0, LONG_MAX, or LONG_MIN 421 * on both success and failure, the calling program should set errno 422 * to 0 before the call. 423 */ 424 errno = 0; 425 426 val = strtol(nptr, &endptr, base); 427 428 if (!errno && *endptr != '\0') { 429 /* Non integer character was found. */ 430 return -EINVAL; 431 } else if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) { 432 /* Overflow occurred. */ 433 return -ERANGE; 434 } else if (errno != 0 && val == 0) { 435 /* Other error occurred. */ 436 return -errno; 437 } else if (val < 0) { 438 /* Input string was negative number. */ 439 return -ERANGE; 440 } 441 442 return val; 443 } 444 445 long long int 446 spdk_strtoll(const char *nptr, int base) 447 { 448 long long val; 449 char *endptr; 450 451 /* Since strtoll() can legitimately return 0, LLONG_MAX, or LLONG_MIN 452 * on both success and failure, the calling program should set errno 453 * to 0 before the call. 454 */ 455 errno = 0; 456 457 val = strtoll(nptr, &endptr, base); 458 459 if (!errno && *endptr != '\0') { 460 /* Non integer character was found. */ 461 return -EINVAL; 462 } else if (errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) { 463 /* Overflow occurred. */ 464 return -ERANGE; 465 } else if (errno != 0 && val == 0) { 466 /* Other error occurred. */ 467 return -errno; 468 } else if (val < 0) { 469 /* Input string was negative number. */ 470 return -ERANGE; 471 } 472 473 return val; 474 } 475