Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2015 Intel Corporation.
3 : * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
4 : * All rights reserved.
5 : */
6 :
7 : #include "spdk/stdinc.h"
8 :
9 : #include "spdk/string.h"
10 :
11 : char *
12 275 : spdk_vsprintf_append_realloc(char *buffer, const char *format, va_list args)
13 : {
14 275 : va_list args_copy;
15 : char *new_buffer;
16 275 : int orig_size = 0, new_size;
17 :
18 : /* Original buffer size */
19 275 : if (buffer) {
20 5 : orig_size = strlen(buffer);
21 : }
22 :
23 : /* Necessary buffer size */
24 275 : va_copy(args_copy, args);
25 275 : new_size = vsnprintf(NULL, 0, format, args_copy);
26 275 : va_end(args_copy);
27 :
28 275 : if (new_size < 0) {
29 0 : return NULL;
30 : }
31 275 : new_size += orig_size + 1;
32 :
33 275 : new_buffer = realloc(buffer, new_size);
34 275 : if (new_buffer == NULL) {
35 0 : return NULL;
36 : }
37 :
38 275 : vsnprintf(new_buffer + orig_size, new_size - orig_size, format, args);
39 :
40 275 : return new_buffer;
41 : }
42 :
43 : char *
44 7 : spdk_sprintf_append_realloc(char *buffer, const char *format, ...)
45 : {
46 7 : va_list args;
47 : char *ret;
48 :
49 7 : va_start(args, format);
50 7 : ret = spdk_vsprintf_append_realloc(buffer, format, args);
51 7 : va_end(args);
52 :
53 7 : return ret;
54 : }
55 :
56 : char *
57 268 : spdk_vsprintf_alloc(const char *format, va_list args)
58 : {
59 268 : return spdk_vsprintf_append_realloc(NULL, format, args);
60 : }
61 :
62 : char *
63 254 : spdk_sprintf_alloc(const char *format, ...)
64 : {
65 254 : va_list args;
66 : char *ret;
67 :
68 254 : va_start(args, format);
69 254 : ret = spdk_vsprintf_alloc(format, args);
70 254 : va_end(args);
71 :
72 254 : return ret;
73 : }
74 :
75 : char *
76 0 : spdk_strlwr(char *s)
77 : {
78 : char *p;
79 :
80 0 : if (s == NULL) {
81 0 : return NULL;
82 : }
83 :
84 0 : p = s;
85 0 : while (*p != '\0') {
86 0 : *p = tolower(*p);
87 0 : p++;
88 : }
89 :
90 0 : return s;
91 : }
92 :
93 : char *
94 24 : spdk_strsepq(char **stringp, const char *delim)
95 : {
96 : char *p, *q, *r;
97 24 : int quoted = 0, bslash = 0;
98 :
99 24 : p = *stringp;
100 24 : if (p == NULL) {
101 0 : return NULL;
102 : }
103 :
104 24 : r = q = p;
105 156 : while (*q != '\0' && *q != '\n') {
106 : /* eat quoted characters */
107 144 : if (bslash) {
108 0 : bslash = 0;
109 0 : *r++ = *q++;
110 0 : continue;
111 144 : } else if (quoted) {
112 0 : if (quoted == '"' && *q == '\\') {
113 0 : bslash = 1;
114 0 : q++;
115 0 : continue;
116 0 : } else if (*q == quoted) {
117 0 : quoted = 0;
118 0 : q++;
119 0 : continue;
120 : }
121 0 : *r++ = *q++;
122 0 : continue;
123 144 : } else if (*q == '\\') {
124 0 : bslash = 1;
125 0 : q++;
126 0 : continue;
127 144 : } else if (*q == '"' || *q == '\'') {
128 0 : quoted = *q;
129 0 : q++;
130 0 : continue;
131 : }
132 :
133 : /* separator? */
134 144 : if (strchr(delim, *q) == NULL) {
135 132 : *r++ = *q++;
136 132 : continue;
137 : }
138 :
139 : /* new string */
140 12 : q++;
141 12 : break;
142 : }
143 24 : *r = '\0';
144 :
145 : /* skip tailer */
146 24 : while (*q != '\0' && strchr(delim, *q) != NULL) {
147 0 : q++;
148 : }
149 24 : if (*q != '\0') {
150 12 : *stringp = q;
151 : } else {
152 12 : *stringp = NULL;
153 : }
154 :
155 24 : return p;
156 : }
157 :
158 : char *
159 0 : spdk_str_trim(char *s)
160 : {
161 : char *p, *q;
162 :
163 0 : if (s == NULL) {
164 0 : return NULL;
165 : }
166 :
167 : /* remove header */
168 0 : p = s;
169 0 : while (*p != '\0' && isspace(*p)) {
170 0 : p++;
171 : }
172 :
173 : /* remove tailer */
174 0 : q = p + strlen(p);
175 0 : while (q - 1 >= p && isspace(*(q - 1))) {
176 0 : q--;
177 0 : *q = '\0';
178 : }
179 :
180 : /* if remove header, move */
181 0 : if (p != s) {
182 0 : q = s;
183 0 : while (*p != '\0') {
184 0 : *q++ = *p++;
185 : }
186 0 : *q = '\0';
187 : }
188 :
189 0 : return s;
190 : }
191 :
192 : void
193 1069 : spdk_strcpy_pad(void *dst, const char *src, size_t size, int pad)
194 : {
195 : size_t len;
196 :
197 1069 : len = strlen(src);
198 1069 : if (len < size) {
199 812 : memcpy(dst, src, len);
200 812 : memset((char *)dst + len, pad, size - len);
201 : } else {
202 257 : memcpy(dst, src, size);
203 : }
204 1069 : }
205 :
206 : size_t
207 2 : spdk_strlen_pad(const void *str, size_t size, int pad)
208 : {
209 : const uint8_t *start;
210 : const uint8_t *iter;
211 : uint8_t pad_byte;
212 :
213 2 : pad_byte = (uint8_t)pad;
214 2 : start = (const uint8_t *)str;
215 :
216 2 : if (size == 0) {
217 0 : return 0;
218 : }
219 :
220 2 : iter = start + size - 1;
221 : while (1) {
222 2 : if (*iter != pad_byte) {
223 2 : return iter - start + 1;
224 : }
225 :
226 0 : if (iter == start) {
227 : /* Hit the start of the string finding only pad_byte. */
228 0 : return 0;
229 : }
230 0 : iter--;
231 : }
232 : }
233 :
234 : int
235 5 : spdk_parse_ip_addr(char *ip, char **host, char **port)
236 : {
237 : char *p;
238 :
239 5 : if (ip == NULL) {
240 0 : return -EINVAL;
241 : }
242 :
243 5 : *host = NULL;
244 5 : *port = NULL;
245 :
246 5 : if (ip[0] == '[') {
247 : /* IPv6 */
248 3 : p = strchr(ip, ']');
249 3 : if (p == NULL) {
250 0 : return -EINVAL;
251 : }
252 3 : *host = &ip[1];
253 3 : *p = '\0';
254 :
255 3 : p++;
256 3 : if (*p == '\0') {
257 1 : return 0;
258 2 : } else if (*p != ':') {
259 0 : return -EINVAL;
260 : }
261 :
262 2 : p++;
263 2 : if (*p == '\0') {
264 1 : return 0;
265 : }
266 :
267 1 : *port = p;
268 : } else {
269 : /* IPv4 */
270 2 : p = strchr(ip, ':');
271 2 : if (p == NULL) {
272 1 : *host = ip;
273 1 : return 0;
274 : }
275 :
276 1 : *host = ip;
277 1 : *p = '\0';
278 :
279 1 : p++;
280 1 : if (*p == '\0') {
281 0 : return 0;
282 : }
283 :
284 1 : *port = p;
285 : }
286 :
287 2 : return 0;
288 : }
289 :
290 : size_t
291 9 : spdk_str_chomp(char *s)
292 : {
293 9 : size_t len = strlen(s);
294 9 : size_t removed = 0;
295 :
296 15 : while (len > 0) {
297 13 : if (s[len - 1] != '\r' && s[len - 1] != '\n') {
298 7 : break;
299 : }
300 :
301 6 : s[len - 1] = '\0';
302 6 : len--;
303 6 : removed++;
304 : }
305 :
306 9 : return removed;
307 : }
308 :
309 : void
310 37 : spdk_strerror_r(int errnum, char *buf, size_t buflen)
311 : {
312 : int rc;
313 :
314 : #if defined(__USE_GNU)
315 : char *new_buffer;
316 37 : new_buffer = strerror_r(errnum, buf, buflen);
317 37 : if (new_buffer == buf) {
318 20 : rc = 0;
319 17 : } else if (new_buffer != NULL) {
320 17 : snprintf(buf, buflen, "%s", new_buffer);
321 17 : rc = 0;
322 : } else {
323 0 : rc = 1;
324 : }
325 : #else
326 : rc = strerror_r(errnum, buf, buflen);
327 : #endif
328 :
329 37 : if (rc != 0) {
330 0 : snprintf(buf, buflen, "Unknown error %d", errnum);
331 : }
332 37 : }
333 :
334 : int
335 12 : spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix)
336 : {
337 : int rc;
338 12 : char bin_prefix;
339 :
340 12 : rc = sscanf(cap_str, "%"SCNu64"%c", cap, &bin_prefix);
341 12 : if (rc == 1) {
342 2 : if (has_prefix != NULL) {
343 2 : *has_prefix = false;
344 : }
345 2 : return 0;
346 10 : } else if (rc == 0) {
347 2 : if (errno == 0) {
348 : /* No scanf matches - the string does not start with a digit */
349 0 : return -EINVAL;
350 : } else {
351 : /* Parsing error */
352 2 : return -errno;
353 : }
354 : }
355 :
356 8 : if (has_prefix != NULL) {
357 8 : *has_prefix = true;
358 : }
359 :
360 8 : switch (bin_prefix) {
361 4 : case 'k':
362 : case 'K':
363 4 : *cap *= 1024;
364 4 : break;
365 3 : case 'm':
366 : case 'M':
367 3 : *cap *= 1024 * 1024;
368 3 : break;
369 1 : case 'g':
370 : case 'G':
371 1 : *cap *= 1024 * 1024 * 1024;
372 1 : break;
373 0 : default:
374 0 : return -EINVAL;
375 : }
376 :
377 8 : return 0;
378 : }
379 :
380 : bool
381 945 : spdk_mem_all_zero(const void *data, size_t size)
382 : {
383 945 : const uint8_t *buf = data;
384 :
385 104989886 : while (size--) {
386 104988989 : if (*buf++ != 0) {
387 48 : return false;
388 : }
389 : }
390 :
391 897 : return true;
392 : }
393 :
394 : long int
395 31 : spdk_strtol(const char *nptr, int base)
396 : {
397 : long val;
398 31 : char *endptr;
399 :
400 : /* Since strtoll() can legitimately return 0, LONG_MAX, or LONG_MIN
401 : * on both success and failure, the calling program should set errno
402 : * to 0 before the call.
403 : */
404 31 : errno = 0;
405 :
406 31 : val = strtol(nptr, &endptr, base);
407 :
408 31 : if (!errno && *endptr != '\0') {
409 : /* Non integer character was found. */
410 4 : return -EINVAL;
411 27 : } else if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) {
412 : /* Overflow occurred. */
413 2 : return -ERANGE;
414 25 : } else if (errno != 0 && val == 0) {
415 : /* Other error occurred. */
416 1 : return -errno;
417 24 : } else if (val < 0) {
418 : /* Input string was negative number. */
419 2 : return -ERANGE;
420 : }
421 :
422 22 : return val;
423 : }
424 :
425 : long long int
426 12 : spdk_strtoll(const char *nptr, int base)
427 : {
428 : long long val;
429 12 : char *endptr;
430 :
431 : /* Since strtoll() can legitimately return 0, LLONG_MAX, or LLONG_MIN
432 : * on both success and failure, the calling program should set errno
433 : * to 0 before the call.
434 : */
435 12 : errno = 0;
436 :
437 12 : val = strtoll(nptr, &endptr, base);
438 :
439 12 : if (!errno && *endptr != '\0') {
440 : /* Non integer character was found. */
441 3 : return -EINVAL;
442 9 : } else if (errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) {
443 : /* Overflow occurred. */
444 2 : return -ERANGE;
445 7 : } else if (errno != 0 && val == 0) {
446 : /* Other error occurred. */
447 1 : return -errno;
448 6 : } else if (val < 0) {
449 : /* Input string was negative number. */
450 2 : return -ERANGE;
451 : }
452 :
453 4 : return val;
454 : }
455 :
456 : void
457 14 : spdk_strarray_free(char **strarray)
458 : {
459 : size_t i;
460 :
461 14 : if (strarray == NULL) {
462 5 : return;
463 : }
464 :
465 34 : for (i = 0; strarray[i] != NULL; i++) {
466 25 : free(strarray[i]);
467 : }
468 9 : free(strarray);
469 : }
470 :
471 : char **
472 8 : spdk_strarray_from_string(const char *str, const char *delim)
473 : {
474 8 : const char *c = str;
475 8 : size_t count = 0;
476 : char **result;
477 : size_t i;
478 :
479 8 : assert(str != NULL);
480 8 : assert(delim != NULL);
481 :
482 : /* Count number of entries. */
483 12 : for (;;) {
484 20 : const char *next = strpbrk(c, delim);
485 :
486 20 : count++;
487 :
488 20 : if (next == NULL) {
489 8 : break;
490 : }
491 :
492 12 : c = next + 1;
493 : }
494 :
495 : /* Account for the terminating NULL entry. */
496 8 : result = calloc(count + 1, sizeof(char *));
497 8 : if (result == NULL) {
498 0 : return NULL;
499 : }
500 :
501 8 : c = str;
502 :
503 28 : for (i = 0; i < count; i++) {
504 20 : const char *next = strpbrk(c, delim);
505 :
506 20 : if (next == NULL) {
507 8 : result[i] = strdup(c);
508 : } else {
509 12 : result[i] = strndup(c, next - c);
510 : }
511 :
512 20 : if (result[i] == NULL) {
513 0 : spdk_strarray_free(result);
514 0 : return NULL;
515 : }
516 :
517 20 : if (next != NULL) {
518 12 : c = next + 1;
519 : }
520 : }
521 :
522 8 : return result;
523 : }
524 :
525 : char **
526 1 : spdk_strarray_dup(const char **strarray)
527 : {
528 : size_t count, i;
529 : char **result;
530 :
531 1 : assert(strarray != NULL);
532 :
533 6 : for (count = 0; strarray[count] != NULL; count++)
534 : ;
535 :
536 1 : result = calloc(count + 1, sizeof(char *));
537 1 : if (result == NULL) {
538 0 : return NULL;
539 : }
540 :
541 6 : for (i = 0; i < count; i++) {
542 5 : result[i] = strdup(strarray[i]);
543 5 : if (result[i] == NULL) {
544 0 : spdk_strarray_free(result);
545 0 : return NULL;
546 : }
547 : }
548 :
549 1 : return result;
550 : }
551 :
552 : int
553 9 : spdk_strcpy_replace(char *dst, size_t size, const char *src, const char *search,
554 : const char *replace)
555 : {
556 : const char *p, *q;
557 : char *r;
558 : size_t c, search_size, replace_size, dst_size;
559 :
560 9 : if (dst == NULL || src == NULL || search == NULL || replace == NULL) {
561 1 : return -EINVAL;
562 : }
563 :
564 8 : search_size = strlen(search);
565 8 : replace_size = strlen(replace);
566 :
567 8 : c = 0;
568 19 : for (p = strstr(src, search); p != NULL; p = strstr(p + search_size, search)) {
569 11 : c++;
570 : }
571 :
572 8 : dst_size = strlen(src) + (replace_size - search_size) * c;
573 8 : if (dst_size >= size) {
574 1 : return -EINVAL;
575 : }
576 :
577 7 : q = src;
578 7 : r = dst;
579 :
580 17 : for (p = strstr(src, search); p != NULL; p = strstr(p + search_size, search)) {
581 10 : memcpy(r, q, p - q);
582 10 : r += p - q;
583 :
584 10 : memcpy(r, replace, replace_size);
585 10 : r += replace_size;
586 :
587 10 : q = p + search_size;
588 : }
589 :
590 7 : memcpy(r, q, strlen(q));
591 7 : r += strlen(q);
592 :
593 7 : *r = '\0';
594 :
595 7 : return 0;
596 : }
|