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