]>
Commit | Line | Data |
---|---|---|
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 | ||
38 | char * | |
9f95a23c | 39 | spdk_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 | ||
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); | |
7c673cae FG |
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) { | |
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 | |
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); | |
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 | ||
361 | int | |
362 | spdk_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 | ||
402 | bool | |
403 | spdk_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 | |
416 | long int | |
417 | spdk_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 | ||
447 | long long int | |
448 | spdk_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 | } |