]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/lib/util/string.c
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / spdk / lib / util / string.c
CommitLineData
7c673cae
FG
1/*-
2 * BSD LICENSE
3 *
7c673cae
FG
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
11fdf7f2 34#include "spdk/stdinc.h"
7c673cae
FG
35
36#include "spdk/string.h"
37
38char *
9f95a23c 39spdk_vsprintf_append_realloc(char *buffer, const char *format, va_list args)
7c673cae
FG
40{
41 va_list args_copy;
9f95a23c
TL
42 char *new_buffer;
43 int orig_size = 0, new_size;
7c673cae 44
9f95a23c
TL
45 /* Original buffer size */
46 if (buffer) {
47 orig_size = strlen(buffer);
48 }
7c673cae 49
9f95a23c
TL
50 /* Necessary buffer size */
51 va_copy(args_copy, args);
52 new_size = vsnprintf(NULL, 0, format, args_copy);
53 va_end(args_copy);
7c673cae 54
9f95a23c
TL
55 if (new_size < 0) {
56 return NULL;
57 }
58 new_size += orig_size + 1;
7c673cae 59
9f95a23c
TL
60 new_buffer = realloc(buffer, new_size);
61 if (new_buffer == NULL) {
62 return NULL;
7c673cae
FG
63 }
64
9f95a23c
TL
65 vsnprintf(new_buffer + orig_size, new_size - orig_size, format, args);
66
67 return new_buffer;
68}
69
70char *
71spdk_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
83char *
84spdk_vsprintf_alloc(const char *format, va_list args)
85{
86 return spdk_vsprintf_append_realloc(NULL, format, args);
7c673cae
FG
87}
88
89char *
90spdk_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
102char *
103spdk_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
120char *
121spdk_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
185char *
186spdk_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
219void
220spdk_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
233size_t
234spdk_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
261int
262spdk_parse_ip_addr(char *ip, char **host, char **port)
263{
264 char *p;
265
266 if (ip == NULL) {
11fdf7f2 267 return -EINVAL;
7c673cae
FG
268 }
269
270 *host = NULL;
271 *port = NULL;
272
273 if (ip[0] == '[') {
274 /* IPv6 */
275 p = strchr(ip, ']');
276 if (p == NULL) {
11fdf7f2 277 return -EINVAL;
7c673cae
FG
278 }
279 *host = &ip[1];
280 *p = '\0';
281
282 p++;
283 if (*p == '\0') {
284 return 0;
285 } else if (*p != ':') {
11fdf7f2 286 return -EINVAL;
7c673cae
FG
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}
11fdf7f2
TL
316
317size_t
318spdk_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
336void
337spdk_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);
f67539c2
TL
344 if (new_buffer == buf) {
345 rc = 0;
346 } else if (new_buffer != NULL) {
11fdf7f2
TL
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
361int
362spdk_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
402bool
403spdk_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}
9f95a23c
TL
415
416long int
417spdk_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
447long long int
448spdk_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}