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_alloc(const char *format, va_list args) 40 { 41 va_list args_copy; 42 char *buf; 43 size_t bufsize; 44 int rc; 45 46 /* Try with a small buffer first. */ 47 bufsize = 32; 48 49 /* Limit maximum buffer size to something reasonable so we don't loop forever. */ 50 while (bufsize <= 1024 * 1024) { 51 buf = malloc(bufsize); 52 if (buf == NULL) { 53 return NULL; 54 } 55 56 va_copy(args_copy, args); 57 rc = vsnprintf(buf, bufsize, format, args_copy); 58 va_end(args_copy); 59 60 /* 61 * If vsnprintf() returned a count within our current buffer size, we are done. 62 * The count does not include the \0 terminator, so rc == bufsize is not OK. 63 */ 64 if (rc >= 0 && (size_t)rc < bufsize) { 65 return buf; 66 } 67 68 /* 69 * vsnprintf() should return the required space, but some libc versions do not 70 * implement this correctly, so just double the buffer size and try again. 71 * 72 * We don't need the data in buf, so rather than realloc(), use free() and malloc() 73 * again to avoid a copy. 74 */ 75 free(buf); 76 bufsize *= 2; 77 } 78 79 return NULL; 80 } 81 82 char * 83 spdk_sprintf_alloc(const char *format, ...) 84 { 85 va_list args; 86 char *ret; 87 88 va_start(args, format); 89 ret = spdk_vsprintf_alloc(format, args); 90 va_end(args); 91 92 return ret; 93 } 94 95 char * 96 spdk_strlwr(char *s) 97 { 98 char *p; 99 100 if (s == NULL) { 101 return NULL; 102 } 103 104 p = s; 105 while (*p != '\0') { 106 *p = tolower(*p); 107 p++; 108 } 109 110 return s; 111 } 112 113 char * 114 spdk_strsepq(char **stringp, const char *delim) 115 { 116 char *p, *q, *r; 117 int quoted = 0, bslash = 0; 118 119 p = *stringp; 120 if (p == NULL) { 121 return NULL; 122 } 123 124 r = q = p; 125 while (*q != '\0' && *q != '\n') { 126 /* eat quoted characters */ 127 if (bslash) { 128 bslash = 0; 129 *r++ = *q++; 130 continue; 131 } else if (quoted) { 132 if (quoted == '"' && *q == '\\') { 133 bslash = 1; 134 q++; 135 continue; 136 } else if (*q == quoted) { 137 quoted = 0; 138 q++; 139 continue; 140 } 141 *r++ = *q++; 142 continue; 143 } else if (*q == '\\') { 144 bslash = 1; 145 q++; 146 continue; 147 } else if (*q == '"' || *q == '\'') { 148 quoted = *q; 149 q++; 150 continue; 151 } 152 153 /* separator? */ 154 if (strchr(delim, *q) == NULL) { 155 *r++ = *q++; 156 continue; 157 } 158 159 /* new string */ 160 q++; 161 break; 162 } 163 *r = '\0'; 164 165 /* skip tailer */ 166 while (*q != '\0' && strchr(delim, *q) != NULL) { 167 q++; 168 } 169 if (*q != '\0') { 170 *stringp = q; 171 } else { 172 *stringp = NULL; 173 } 174 175 return p; 176 } 177 178 char * 179 spdk_str_trim(char *s) 180 { 181 char *p, *q; 182 183 if (s == NULL) { 184 return NULL; 185 } 186 187 /* remove header */ 188 p = s; 189 while (*p != '\0' && isspace(*p)) { 190 p++; 191 } 192 193 /* remove tailer */ 194 q = p + strlen(p); 195 while (q - 1 >= p && isspace(*(q - 1))) { 196 q--; 197 *q = '\0'; 198 } 199 200 /* if remove header, move */ 201 if (p != s) { 202 q = s; 203 while (*p != '\0') { 204 *q++ = *p++; 205 } 206 *q = '\0'; 207 } 208 209 return s; 210 } 211 212 void 213 spdk_strcpy_pad(void *dst, const char *src, size_t size, int pad) 214 { 215 size_t len; 216 217 len = strlen(src); 218 if (len < size) { 219 memcpy(dst, src, len); 220 memset((char *)dst + len, pad, size - len); 221 } else { 222 memcpy(dst, src, size); 223 } 224 } 225 226 size_t 227 spdk_strlen_pad(const void *str, size_t size, int pad) 228 { 229 const uint8_t *start; 230 const uint8_t *iter; 231 uint8_t pad_byte; 232 233 pad_byte = (uint8_t)pad; 234 start = (const uint8_t *)str; 235 236 if (size == 0) { 237 return 0; 238 } 239 240 iter = start + size - 1; 241 while (1) { 242 if (*iter != pad_byte) { 243 return iter - start + 1; 244 } 245 246 if (iter == start) { 247 /* Hit the start of the string finding only pad_byte. */ 248 return 0; 249 } 250 iter--; 251 } 252 } 253 254 int 255 spdk_parse_ip_addr(char *ip, char **host, char **port) 256 { 257 char *p; 258 259 if (ip == NULL) { 260 return -EINVAL; 261 } 262 263 *host = NULL; 264 *port = NULL; 265 266 if (ip[0] == '[') { 267 /* IPv6 */ 268 p = strchr(ip, ']'); 269 if (p == NULL) { 270 return -EINVAL; 271 } 272 *host = &ip[1]; 273 *p = '\0'; 274 275 p++; 276 if (*p == '\0') { 277 return 0; 278 } else if (*p != ':') { 279 return -EINVAL; 280 } 281 282 p++; 283 if (*p == '\0') { 284 return 0; 285 } 286 287 *port = p; 288 } else { 289 /* IPv4 */ 290 p = strchr(ip, ':'); 291 if (p == NULL) { 292 *host = ip; 293 return 0; 294 } 295 296 *host = ip; 297 *p = '\0'; 298 299 p++; 300 if (*p == '\0') { 301 return 0; 302 } 303 304 *port = p; 305 } 306 307 return 0; 308 } 309 310 size_t 311 spdk_str_chomp(char *s) 312 { 313 size_t len = strlen(s); 314 size_t removed = 0; 315 316 while (len > 0) { 317 if (s[len - 1] != '\r' && s[len - 1] != '\n') { 318 break; 319 } 320 321 s[len - 1] = '\0'; 322 len--; 323 removed++; 324 } 325 326 return removed; 327 } 328 329 void 330 spdk_strerror_r(int errnum, char *buf, size_t buflen) 331 { 332 int rc; 333 334 #if defined(__USE_GNU) 335 char *new_buffer; 336 new_buffer = strerror_r(errnum, buf, buflen); 337 if (new_buffer != NULL) { 338 snprintf(buf, buflen, "%s", new_buffer); 339 rc = 0; 340 } else { 341 rc = 1; 342 } 343 #else 344 rc = strerror_r(errnum, buf, buflen); 345 #endif 346 347 if (rc != 0) { 348 snprintf(buf, buflen, "Unknown error %d", errnum); 349 } 350 } 351 352 int 353 spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix) 354 { 355 int rc; 356 char bin_prefix; 357 358 rc = sscanf(cap_str, "%"SCNu64"%c", cap, &bin_prefix); 359 if (rc == 1) { 360 *has_prefix = false; 361 return 0; 362 } else if (rc == 0) { 363 if (errno == 0) { 364 /* No scanf matches - the string does not start with a digit */ 365 return -EINVAL; 366 } else { 367 /* Parsing error */ 368 return -errno; 369 } 370 } 371 372 *has_prefix = true; 373 switch (bin_prefix) { 374 case 'k': 375 case 'K': 376 *cap *= 1024; 377 break; 378 case 'm': 379 case 'M': 380 *cap *= 1024 * 1024; 381 break; 382 case 'g': 383 case 'G': 384 *cap *= 1024 * 1024 * 1024; 385 break; 386 default: 387 return -EINVAL; 388 } 389 390 return 0; 391 } 392 393 bool 394 spdk_mem_all_zero(const void *data, size_t size) 395 { 396 const uint8_t *buf = data; 397 398 while (size--) { 399 if (*buf++ != 0) { 400 return false; 401 } 402 } 403 404 return true; 405 } 406