xref: /spdk/lib/util/string.c (revision 856388d8738ae265b142b395d01e616a69257602)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2015 Intel Corporation.
3d6e57b53SShuhei Matsumoto  *   Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
492da7447SDaniel Verkamp  *   All rights reserved.
592da7447SDaniel Verkamp  */
692da7447SDaniel Verkamp 
7b961d9ccSBen Walker #include "spdk/stdinc.h"
892da7447SDaniel Verkamp 
992da7447SDaniel Verkamp #include "spdk/string.h"
1092da7447SDaniel Verkamp 
1192da7447SDaniel Verkamp char *
spdk_vsprintf_append_realloc(char * buffer,const char * format,va_list args)128adbd909SShuhei Matsumoto spdk_vsprintf_append_realloc(char *buffer, const char *format, va_list args)
1392da7447SDaniel Verkamp {
14b4bd76bcSDaniel Verkamp 	va_list args_copy;
158adbd909SShuhei Matsumoto 	char *new_buffer;
168adbd909SShuhei Matsumoto 	int orig_size = 0, new_size;
1792da7447SDaniel Verkamp 
188adbd909SShuhei Matsumoto 	/* Original buffer size */
198adbd909SShuhei Matsumoto 	if (buffer) {
208adbd909SShuhei Matsumoto 		orig_size = strlen(buffer);
2192da7447SDaniel Verkamp 	}
2292da7447SDaniel Verkamp 
238adbd909SShuhei Matsumoto 	/* Necessary buffer size */
24b4bd76bcSDaniel Verkamp 	va_copy(args_copy, args);
258adbd909SShuhei Matsumoto 	new_size = vsnprintf(NULL, 0, format, args_copy);
26b4bd76bcSDaniel Verkamp 	va_end(args_copy);
2792da7447SDaniel Verkamp 
288adbd909SShuhei Matsumoto 	if (new_size < 0) {
2992da7447SDaniel Verkamp 		return NULL;
3092da7447SDaniel Verkamp 	}
318adbd909SShuhei Matsumoto 	new_size += orig_size + 1;
328adbd909SShuhei Matsumoto 
338adbd909SShuhei Matsumoto 	new_buffer = realloc(buffer, new_size);
348adbd909SShuhei Matsumoto 	if (new_buffer == NULL) {
358adbd909SShuhei Matsumoto 		return NULL;
368adbd909SShuhei Matsumoto 	}
378adbd909SShuhei Matsumoto 
388adbd909SShuhei Matsumoto 	vsnprintf(new_buffer + orig_size, new_size - orig_size, format, args);
398adbd909SShuhei Matsumoto 
408adbd909SShuhei Matsumoto 	return new_buffer;
418adbd909SShuhei Matsumoto }
428adbd909SShuhei Matsumoto 
438adbd909SShuhei Matsumoto char *
spdk_sprintf_append_realloc(char * buffer,const char * format,...)448adbd909SShuhei Matsumoto spdk_sprintf_append_realloc(char *buffer, const char *format, ...)
458adbd909SShuhei Matsumoto {
468adbd909SShuhei Matsumoto 	va_list args;
478adbd909SShuhei Matsumoto 	char *ret;
488adbd909SShuhei Matsumoto 
498adbd909SShuhei Matsumoto 	va_start(args, format);
508adbd909SShuhei Matsumoto 	ret = spdk_vsprintf_append_realloc(buffer, format, args);
518adbd909SShuhei Matsumoto 	va_end(args);
528adbd909SShuhei Matsumoto 
538adbd909SShuhei Matsumoto 	return ret;
548adbd909SShuhei Matsumoto }
558adbd909SShuhei Matsumoto 
568adbd909SShuhei Matsumoto char *
spdk_vsprintf_alloc(const char * format,va_list args)578adbd909SShuhei Matsumoto spdk_vsprintf_alloc(const char *format, va_list args)
588adbd909SShuhei Matsumoto {
598adbd909SShuhei Matsumoto 	return spdk_vsprintf_append_realloc(NULL, format, args);
608adbd909SShuhei Matsumoto }
61c5611b26SDaniel Verkamp 
62c5611b26SDaniel Verkamp char *
spdk_sprintf_alloc(const char * format,...)63b4bd76bcSDaniel Verkamp spdk_sprintf_alloc(const char *format, ...)
64b4bd76bcSDaniel Verkamp {
65b4bd76bcSDaniel Verkamp 	va_list args;
66b4bd76bcSDaniel Verkamp 	char *ret;
67b4bd76bcSDaniel Verkamp 
68b4bd76bcSDaniel Verkamp 	va_start(args, format);
69b4bd76bcSDaniel Verkamp 	ret = spdk_vsprintf_alloc(format, args);
70b4bd76bcSDaniel Verkamp 	va_end(args);
71b4bd76bcSDaniel Verkamp 
72b4bd76bcSDaniel Verkamp 	return ret;
73b4bd76bcSDaniel Verkamp }
74b4bd76bcSDaniel Verkamp 
75b4bd76bcSDaniel Verkamp char *
spdk_strlwr(char * s)76c5611b26SDaniel Verkamp spdk_strlwr(char *s)
77c5611b26SDaniel Verkamp {
78c5611b26SDaniel Verkamp 	char *p;
79c5611b26SDaniel Verkamp 
80c5611b26SDaniel Verkamp 	if (s == NULL) {
81c5611b26SDaniel Verkamp 		return NULL;
82c5611b26SDaniel Verkamp 	}
83c5611b26SDaniel Verkamp 
84c5611b26SDaniel Verkamp 	p = s;
85c5611b26SDaniel Verkamp 	while (*p != '\0') {
86c5611b26SDaniel Verkamp 		*p = tolower(*p);
87c5611b26SDaniel Verkamp 		p++;
88c5611b26SDaniel Verkamp 	}
89c5611b26SDaniel Verkamp 
90c5611b26SDaniel Verkamp 	return s;
91c5611b26SDaniel Verkamp }
92e56aab98SDaniel Verkamp 
93e56aab98SDaniel Verkamp char *
spdk_strsepq(char ** stringp,const char * delim)94e56aab98SDaniel Verkamp spdk_strsepq(char **stringp, const char *delim)
95e56aab98SDaniel Verkamp {
96e56aab98SDaniel Verkamp 	char *p, *q, *r;
97e56aab98SDaniel Verkamp 	int quoted = 0, bslash = 0;
98e56aab98SDaniel Verkamp 
99e56aab98SDaniel Verkamp 	p = *stringp;
100e56aab98SDaniel Verkamp 	if (p == NULL) {
101e56aab98SDaniel Verkamp 		return NULL;
102e56aab98SDaniel Verkamp 	}
103e56aab98SDaniel Verkamp 
104e56aab98SDaniel Verkamp 	r = q = p;
105e56aab98SDaniel Verkamp 	while (*q != '\0' && *q != '\n') {
106e56aab98SDaniel Verkamp 		/* eat quoted characters */
107e56aab98SDaniel Verkamp 		if (bslash) {
108e56aab98SDaniel Verkamp 			bslash = 0;
109e56aab98SDaniel Verkamp 			*r++ = *q++;
110e56aab98SDaniel Verkamp 			continue;
111e56aab98SDaniel Verkamp 		} else if (quoted) {
112e56aab98SDaniel Verkamp 			if (quoted == '"' && *q == '\\') {
113e56aab98SDaniel Verkamp 				bslash = 1;
114e56aab98SDaniel Verkamp 				q++;
115e56aab98SDaniel Verkamp 				continue;
116e56aab98SDaniel Verkamp 			} else if (*q == quoted) {
117e56aab98SDaniel Verkamp 				quoted = 0;
118e56aab98SDaniel Verkamp 				q++;
119e56aab98SDaniel Verkamp 				continue;
120e56aab98SDaniel Verkamp 			}
121e56aab98SDaniel Verkamp 			*r++ = *q++;
122e56aab98SDaniel Verkamp 			continue;
123e56aab98SDaniel Verkamp 		} else if (*q == '\\') {
124e56aab98SDaniel Verkamp 			bslash = 1;
125e56aab98SDaniel Verkamp 			q++;
126e56aab98SDaniel Verkamp 			continue;
127e56aab98SDaniel Verkamp 		} else if (*q == '"' || *q == '\'') {
128e56aab98SDaniel Verkamp 			quoted = *q;
129e56aab98SDaniel Verkamp 			q++;
130e56aab98SDaniel Verkamp 			continue;
131e56aab98SDaniel Verkamp 		}
132e56aab98SDaniel Verkamp 
133e56aab98SDaniel Verkamp 		/* separator? */
134e56aab98SDaniel Verkamp 		if (strchr(delim, *q) == NULL) {
135e56aab98SDaniel Verkamp 			*r++ = *q++;
136e56aab98SDaniel Verkamp 			continue;
137e56aab98SDaniel Verkamp 		}
138e56aab98SDaniel Verkamp 
139e56aab98SDaniel Verkamp 		/* new string */
140e56aab98SDaniel Verkamp 		q++;
141e56aab98SDaniel Verkamp 		break;
142e56aab98SDaniel Verkamp 	}
143e56aab98SDaniel Verkamp 	*r = '\0';
144e56aab98SDaniel Verkamp 
145e56aab98SDaniel Verkamp 	/* skip tailer */
146e56aab98SDaniel Verkamp 	while (*q != '\0' && strchr(delim, *q) != NULL) {
147e56aab98SDaniel Verkamp 		q++;
148e56aab98SDaniel Verkamp 	}
149e56aab98SDaniel Verkamp 	if (*q != '\0') {
150e56aab98SDaniel Verkamp 		*stringp = q;
151e56aab98SDaniel Verkamp 	} else {
152e56aab98SDaniel Verkamp 		*stringp = NULL;
153e56aab98SDaniel Verkamp 	}
154e56aab98SDaniel Verkamp 
155e56aab98SDaniel Verkamp 	return p;
156e56aab98SDaniel Verkamp }
157d0cbec4aSDaniel Verkamp 
158d0cbec4aSDaniel Verkamp char *
spdk_str_trim(char * s)159d0cbec4aSDaniel Verkamp spdk_str_trim(char *s)
160d0cbec4aSDaniel Verkamp {
161d0cbec4aSDaniel Verkamp 	char *p, *q;
162d0cbec4aSDaniel Verkamp 
163d0cbec4aSDaniel Verkamp 	if (s == NULL) {
164d0cbec4aSDaniel Verkamp 		return NULL;
165d0cbec4aSDaniel Verkamp 	}
166d0cbec4aSDaniel Verkamp 
167d0cbec4aSDaniel Verkamp 	/* remove header */
168d0cbec4aSDaniel Verkamp 	p = s;
169d0cbec4aSDaniel Verkamp 	while (*p != '\0' && isspace(*p)) {
170d0cbec4aSDaniel Verkamp 		p++;
171d0cbec4aSDaniel Verkamp 	}
172d0cbec4aSDaniel Verkamp 
173d0cbec4aSDaniel Verkamp 	/* remove tailer */
174d0cbec4aSDaniel Verkamp 	q = p + strlen(p);
175d0cbec4aSDaniel Verkamp 	while (q - 1 >= p && isspace(*(q - 1))) {
176d0cbec4aSDaniel Verkamp 		q--;
177d0cbec4aSDaniel Verkamp 		*q = '\0';
178d0cbec4aSDaniel Verkamp 	}
179d0cbec4aSDaniel Verkamp 
180d0cbec4aSDaniel Verkamp 	/* if remove header, move */
181d0cbec4aSDaniel Verkamp 	if (p != s) {
182d0cbec4aSDaniel Verkamp 		q = s;
183d0cbec4aSDaniel Verkamp 		while (*p != '\0') {
184d0cbec4aSDaniel Verkamp 			*q++ = *p++;
185d0cbec4aSDaniel Verkamp 		}
186d0cbec4aSDaniel Verkamp 		*q = '\0';
187d0cbec4aSDaniel Verkamp 	}
188d0cbec4aSDaniel Verkamp 
189d0cbec4aSDaniel Verkamp 	return s;
190d0cbec4aSDaniel Verkamp }
19198c8867eSDaniel Verkamp 
19298c8867eSDaniel Verkamp void
spdk_strcpy_pad(void * dst,const char * src,size_t size,int pad)19398c8867eSDaniel Verkamp spdk_strcpy_pad(void *dst, const char *src, size_t size, int pad)
19498c8867eSDaniel Verkamp {
19598c8867eSDaniel Verkamp 	size_t len;
19698c8867eSDaniel Verkamp 
19798c8867eSDaniel Verkamp 	len = strlen(src);
19898c8867eSDaniel Verkamp 	if (len < size) {
19998c8867eSDaniel Verkamp 		memcpy(dst, src, len);
20098c8867eSDaniel Verkamp 		memset((char *)dst + len, pad, size - len);
20198c8867eSDaniel Verkamp 	} else {
20298c8867eSDaniel Verkamp 		memcpy(dst, src, size);
20398c8867eSDaniel Verkamp 	}
20498c8867eSDaniel Verkamp }
205ae6fbf1dSDaniel Verkamp 
206ae6fbf1dSDaniel Verkamp size_t
spdk_strlen_pad(const void * str,size_t size,int pad)207ae6fbf1dSDaniel Verkamp spdk_strlen_pad(const void *str, size_t size, int pad)
208ae6fbf1dSDaniel Verkamp {
209ae6fbf1dSDaniel Verkamp 	const uint8_t *start;
210ae6fbf1dSDaniel Verkamp 	const uint8_t *iter;
211ae6fbf1dSDaniel Verkamp 	uint8_t pad_byte;
212ae6fbf1dSDaniel Verkamp 
213ae6fbf1dSDaniel Verkamp 	pad_byte = (uint8_t)pad;
214ae6fbf1dSDaniel Verkamp 	start = (const uint8_t *)str;
215ae6fbf1dSDaniel Verkamp 
216ae6fbf1dSDaniel Verkamp 	if (size == 0) {
217ae6fbf1dSDaniel Verkamp 		return 0;
218ae6fbf1dSDaniel Verkamp 	}
219ae6fbf1dSDaniel Verkamp 
220ae6fbf1dSDaniel Verkamp 	iter = start + size - 1;
221ae6fbf1dSDaniel Verkamp 	while (1) {
222ae6fbf1dSDaniel Verkamp 		if (*iter != pad_byte) {
223ae6fbf1dSDaniel Verkamp 			return iter - start + 1;
224ae6fbf1dSDaniel Verkamp 		}
225ae6fbf1dSDaniel Verkamp 
226ae6fbf1dSDaniel Verkamp 		if (iter == start) {
227ae6fbf1dSDaniel Verkamp 			/* Hit the start of the string finding only pad_byte. */
228ae6fbf1dSDaniel Verkamp 			return 0;
229ae6fbf1dSDaniel Verkamp 		}
230ae6fbf1dSDaniel Verkamp 		iter--;
231ae6fbf1dSDaniel Verkamp 	}
232ae6fbf1dSDaniel Verkamp }
23308238af7SBen Walker 
23408238af7SBen Walker int
spdk_parse_ip_addr(char * ip,char ** host,char ** port)2354404793dSDaniel Verkamp spdk_parse_ip_addr(char *ip, char **host, char **port)
23608238af7SBen Walker {
23708238af7SBen Walker 	char *p;
23808238af7SBen Walker 
23908238af7SBen Walker 	if (ip == NULL) {
2407818939cSPawel Wodkowski 		return -EINVAL;
24108238af7SBen Walker 	}
24208238af7SBen Walker 
24308238af7SBen Walker 	*host = NULL;
24408238af7SBen Walker 	*port = NULL;
24508238af7SBen Walker 
24608238af7SBen Walker 	if (ip[0] == '[') {
24708238af7SBen Walker 		/* IPv6 */
24808238af7SBen Walker 		p = strchr(ip, ']');
24908238af7SBen Walker 		if (p == NULL) {
2507818939cSPawel Wodkowski 			return -EINVAL;
25108238af7SBen Walker 		}
25208238af7SBen Walker 		*host = &ip[1];
25308238af7SBen Walker 		*p = '\0';
25408238af7SBen Walker 
25508238af7SBen Walker 		p++;
25608238af7SBen Walker 		if (*p == '\0') {
25708238af7SBen Walker 			return 0;
25808238af7SBen Walker 		} else if (*p != ':') {
2597818939cSPawel Wodkowski 			return -EINVAL;
26008238af7SBen Walker 		}
26108238af7SBen Walker 
26208238af7SBen Walker 		p++;
26308238af7SBen Walker 		if (*p == '\0') {
26408238af7SBen Walker 			return 0;
26508238af7SBen Walker 		}
26608238af7SBen Walker 
26708238af7SBen Walker 		*port = p;
26808238af7SBen Walker 	} else {
26908238af7SBen Walker 		/* IPv4 */
27008238af7SBen Walker 		p = strchr(ip, ':');
27108238af7SBen Walker 		if (p == NULL) {
27208238af7SBen Walker 			*host = ip;
27308238af7SBen Walker 			return 0;
27408238af7SBen Walker 		}
27508238af7SBen Walker 
27608238af7SBen Walker 		*host = ip;
27708238af7SBen Walker 		*p = '\0';
27808238af7SBen Walker 
27908238af7SBen Walker 		p++;
28008238af7SBen Walker 		if (*p == '\0') {
28108238af7SBen Walker 			return 0;
28208238af7SBen Walker 		}
28308238af7SBen Walker 
28408238af7SBen Walker 		*port = p;
28508238af7SBen Walker 	}
28608238af7SBen Walker 
28708238af7SBen Walker 	return 0;
28808238af7SBen Walker }
28916c362a8SDaniel Verkamp 
29016c362a8SDaniel Verkamp size_t
spdk_str_chomp(char * s)29116c362a8SDaniel Verkamp spdk_str_chomp(char *s)
29216c362a8SDaniel Verkamp {
29316c362a8SDaniel Verkamp 	size_t len = strlen(s);
29416c362a8SDaniel Verkamp 	size_t removed = 0;
29516c362a8SDaniel Verkamp 
29616c362a8SDaniel Verkamp 	while (len > 0) {
29716c362a8SDaniel Verkamp 		if (s[len - 1] != '\r' && s[len - 1] != '\n') {
29816c362a8SDaniel Verkamp 			break;
29916c362a8SDaniel Verkamp 		}
30016c362a8SDaniel Verkamp 
30116c362a8SDaniel Verkamp 		s[len - 1] = '\0';
30216c362a8SDaniel Verkamp 		len--;
30316c362a8SDaniel Verkamp 		removed++;
30416c362a8SDaniel Verkamp 	}
30516c362a8SDaniel Verkamp 
30616c362a8SDaniel Verkamp 	return removed;
30716c362a8SDaniel Verkamp }
3084d43844fSSeth Howell 
30971db3a08SDaniel Verkamp void
spdk_strerror_r(int errnum,char * buf,size_t buflen)3104d43844fSSeth Howell spdk_strerror_r(int errnum, char *buf, size_t buflen)
3114d43844fSSeth Howell {
31271db3a08SDaniel Verkamp 	int rc;
31371db3a08SDaniel Verkamp 
3144d43844fSSeth Howell #if defined(__USE_GNU)
3154d43844fSSeth Howell 	char *new_buffer;
3164d43844fSSeth Howell 	new_buffer = strerror_r(errnum, buf, buflen);
317772db556SVitaliy Mysak 	if (new_buffer == buf) {
318772db556SVitaliy Mysak 		rc = 0;
319772db556SVitaliy Mysak 	} else if (new_buffer != NULL) {
3204d43844fSSeth Howell 		snprintf(buf, buflen, "%s", new_buffer);
32171db3a08SDaniel Verkamp 		rc = 0;
32271db3a08SDaniel Verkamp 	} else {
32371db3a08SDaniel Verkamp 		rc = 1;
3244d43844fSSeth Howell 	}
3254d43844fSSeth Howell #else
32671db3a08SDaniel Verkamp 	rc = strerror_r(errnum, buf, buflen);
3274d43844fSSeth Howell #endif
32871db3a08SDaniel Verkamp 
32971db3a08SDaniel Verkamp 	if (rc != 0) {
33071db3a08SDaniel Verkamp 		snprintf(buf, buflen, "Unknown error %d", errnum);
33171db3a08SDaniel Verkamp 	}
3324d43844fSSeth Howell }
333ec6a1afbSDariusz Stojaczyk 
334ec6a1afbSDariusz Stojaczyk int
spdk_parse_capacity(const char * cap_str,uint64_t * cap,bool * has_prefix)335ec6a1afbSDariusz Stojaczyk spdk_parse_capacity(const char *cap_str, uint64_t *cap, bool *has_prefix)
336ec6a1afbSDariusz Stojaczyk {
337ec6a1afbSDariusz Stojaczyk 	int rc;
338ec6a1afbSDariusz Stojaczyk 	char bin_prefix;
339ec6a1afbSDariusz Stojaczyk 
340ec6a1afbSDariusz Stojaczyk 	rc = sscanf(cap_str, "%"SCNu64"%c", cap, &bin_prefix);
341ec6a1afbSDariusz Stojaczyk 	if (rc == 1) {
342*856388d8SKonrad Sztyber 		if (has_prefix != NULL) {
343ec6a1afbSDariusz Stojaczyk 			*has_prefix = false;
344*856388d8SKonrad Sztyber 		}
345ec6a1afbSDariusz Stojaczyk 		return 0;
346ec6a1afbSDariusz Stojaczyk 	} else if (rc == 0) {
347ec6a1afbSDariusz Stojaczyk 		if (errno == 0) {
348ec6a1afbSDariusz Stojaczyk 			/* No scanf matches - the string does not start with a digit */
349ec6a1afbSDariusz Stojaczyk 			return -EINVAL;
350ec6a1afbSDariusz Stojaczyk 		} else {
351ec6a1afbSDariusz Stojaczyk 			/* Parsing error */
352ec6a1afbSDariusz Stojaczyk 			return -errno;
353ec6a1afbSDariusz Stojaczyk 		}
354ec6a1afbSDariusz Stojaczyk 	}
355ec6a1afbSDariusz Stojaczyk 
356*856388d8SKonrad Sztyber 	if (has_prefix != NULL) {
357ec6a1afbSDariusz Stojaczyk 		*has_prefix = true;
358*856388d8SKonrad Sztyber 	}
359*856388d8SKonrad Sztyber 
360ec6a1afbSDariusz Stojaczyk 	switch (bin_prefix) {
361ec6a1afbSDariusz Stojaczyk 	case 'k':
362ec6a1afbSDariusz Stojaczyk 	case 'K':
363ec6a1afbSDariusz Stojaczyk 		*cap *= 1024;
364ec6a1afbSDariusz Stojaczyk 		break;
365ec6a1afbSDariusz Stojaczyk 	case 'm':
366ec6a1afbSDariusz Stojaczyk 	case 'M':
367ec6a1afbSDariusz Stojaczyk 		*cap *= 1024 * 1024;
368ec6a1afbSDariusz Stojaczyk 		break;
369ec6a1afbSDariusz Stojaczyk 	case 'g':
370ec6a1afbSDariusz Stojaczyk 	case 'G':
371ec6a1afbSDariusz Stojaczyk 		*cap *= 1024 * 1024 * 1024;
372ec6a1afbSDariusz Stojaczyk 		break;
373ec6a1afbSDariusz Stojaczyk 	default:
374ec6a1afbSDariusz Stojaczyk 		return -EINVAL;
375ec6a1afbSDariusz Stojaczyk 	}
376ec6a1afbSDariusz Stojaczyk 
377ec6a1afbSDariusz Stojaczyk 	return 0;
378ec6a1afbSDariusz Stojaczyk }
379d81f3dfdSDaniel Verkamp 
380d81f3dfdSDaniel Verkamp bool
spdk_mem_all_zero(const void * data,size_t size)381d81f3dfdSDaniel Verkamp spdk_mem_all_zero(const void *data, size_t size)
382d81f3dfdSDaniel Verkamp {
383d81f3dfdSDaniel Verkamp 	const uint8_t *buf = data;
384d81f3dfdSDaniel Verkamp 
385d81f3dfdSDaniel Verkamp 	while (size--) {
386d81f3dfdSDaniel Verkamp 		if (*buf++ != 0) {
387d81f3dfdSDaniel Verkamp 			return false;
388d81f3dfdSDaniel Verkamp 		}
389d81f3dfdSDaniel Verkamp 	}
390d81f3dfdSDaniel Verkamp 
391d81f3dfdSDaniel Verkamp 	return true;
392d81f3dfdSDaniel Verkamp }
393b78e763cSShuhei Matsumoto 
394b78e763cSShuhei Matsumoto long int
spdk_strtol(const char * nptr,int base)395b78e763cSShuhei Matsumoto spdk_strtol(const char *nptr, int base)
396b78e763cSShuhei Matsumoto {
397b78e763cSShuhei Matsumoto 	long val;
398b78e763cSShuhei Matsumoto 	char *endptr;
399b78e763cSShuhei Matsumoto 
400b78e763cSShuhei Matsumoto 	/* Since strtoll() can legitimately return 0, LONG_MAX, or LONG_MIN
401b78e763cSShuhei Matsumoto 	 * on both success and failure, the calling program should set errno
402b78e763cSShuhei Matsumoto 	 * to 0 before the call.
403b78e763cSShuhei Matsumoto 	 */
404b78e763cSShuhei Matsumoto 	errno = 0;
405b78e763cSShuhei Matsumoto 
406b78e763cSShuhei Matsumoto 	val = strtol(nptr, &endptr, base);
407b78e763cSShuhei Matsumoto 
408f0e6bbeaSWojciech Malikowski 	if (!errno && *endptr != '\0') {
409b78e763cSShuhei Matsumoto 		/* Non integer character was found. */
410b78e763cSShuhei Matsumoto 		return -EINVAL;
411b78e763cSShuhei Matsumoto 	} else if (errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) {
412b78e763cSShuhei Matsumoto 		/* Overflow occurred. */
413b78e763cSShuhei Matsumoto 		return -ERANGE;
414b78e763cSShuhei Matsumoto 	} else if (errno != 0 && val == 0) {
415b78e763cSShuhei Matsumoto 		/* Other error occurred. */
416b78e763cSShuhei Matsumoto 		return -errno;
417b78e763cSShuhei Matsumoto 	} else if (val < 0) {
418b78e763cSShuhei Matsumoto 		/* Input string was negative number. */
419b78e763cSShuhei Matsumoto 		return -ERANGE;
420b78e763cSShuhei Matsumoto 	}
421b78e763cSShuhei Matsumoto 
422b78e763cSShuhei Matsumoto 	return val;
423b78e763cSShuhei Matsumoto }
424b78e763cSShuhei Matsumoto 
425b78e763cSShuhei Matsumoto long long int
spdk_strtoll(const char * nptr,int base)426b78e763cSShuhei Matsumoto spdk_strtoll(const char *nptr, int base)
427b78e763cSShuhei Matsumoto {
428b78e763cSShuhei Matsumoto 	long long val;
429b78e763cSShuhei Matsumoto 	char *endptr;
430b78e763cSShuhei Matsumoto 
431b78e763cSShuhei Matsumoto 	/* Since strtoll() can legitimately return 0, LLONG_MAX, or LLONG_MIN
432b78e763cSShuhei Matsumoto 	 * on both success and failure, the calling program should set errno
433b78e763cSShuhei Matsumoto 	 * to 0 before the call.
434b78e763cSShuhei Matsumoto 	 */
435b78e763cSShuhei Matsumoto 	errno = 0;
436b78e763cSShuhei Matsumoto 
437b78e763cSShuhei Matsumoto 	val = strtoll(nptr, &endptr, base);
438b78e763cSShuhei Matsumoto 
439f0e6bbeaSWojciech Malikowski 	if (!errno && *endptr != '\0') {
440b78e763cSShuhei Matsumoto 		/* Non integer character was found. */
441b78e763cSShuhei Matsumoto 		return -EINVAL;
442b78e763cSShuhei Matsumoto 	} else if (errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) {
443b78e763cSShuhei Matsumoto 		/* Overflow occurred. */
444b78e763cSShuhei Matsumoto 		return -ERANGE;
445b78e763cSShuhei Matsumoto 	} else if (errno != 0 && val == 0) {
446b78e763cSShuhei Matsumoto 		/* Other error occurred. */
447b78e763cSShuhei Matsumoto 		return -errno;
448b78e763cSShuhei Matsumoto 	} else if (val < 0) {
449b78e763cSShuhei Matsumoto 		/* Input string was negative number. */
450b78e763cSShuhei Matsumoto 		return -ERANGE;
451b78e763cSShuhei Matsumoto 	}
452b78e763cSShuhei Matsumoto 
453b78e763cSShuhei Matsumoto 	return val;
454b78e763cSShuhei Matsumoto }
4551139cb14SJohn Levon 
4561139cb14SJohn Levon void
spdk_strarray_free(char ** strarray)4571139cb14SJohn Levon spdk_strarray_free(char **strarray)
4581139cb14SJohn Levon {
4591139cb14SJohn Levon 	size_t i;
4601139cb14SJohn Levon 
4611139cb14SJohn Levon 	if (strarray == NULL) {
4621139cb14SJohn Levon 		return;
4631139cb14SJohn Levon 	}
4641139cb14SJohn Levon 
4651139cb14SJohn Levon 	for (i = 0; strarray[i] != NULL; i++) {
4661139cb14SJohn Levon 		free(strarray[i]);
4671139cb14SJohn Levon 	}
4681139cb14SJohn Levon 	free(strarray);
4691139cb14SJohn Levon }
4701139cb14SJohn Levon 
4711139cb14SJohn Levon char **
spdk_strarray_from_string(const char * str,const char * delim)4721139cb14SJohn Levon spdk_strarray_from_string(const char *str, const char *delim)
4731139cb14SJohn Levon {
4741139cb14SJohn Levon 	const char *c = str;
4751139cb14SJohn Levon 	size_t count = 0;
4761139cb14SJohn Levon 	char **result;
4771139cb14SJohn Levon 	size_t i;
4781139cb14SJohn Levon 
4791139cb14SJohn Levon 	assert(str != NULL);
4801139cb14SJohn Levon 	assert(delim != NULL);
4811139cb14SJohn Levon 
4821139cb14SJohn Levon 	/* Count number of entries. */
4831139cb14SJohn Levon 	for (;;) {
4841139cb14SJohn Levon 		const char *next = strpbrk(c, delim);
4851139cb14SJohn Levon 
4861139cb14SJohn Levon 		count++;
4871139cb14SJohn Levon 
4881139cb14SJohn Levon 		if (next == NULL) {
4891139cb14SJohn Levon 			break;
4901139cb14SJohn Levon 		}
4911139cb14SJohn Levon 
4921139cb14SJohn Levon 		c = next + 1;
4931139cb14SJohn Levon 	}
4941139cb14SJohn Levon 
4951139cb14SJohn Levon 	/* Account for the terminating NULL entry. */
4961139cb14SJohn Levon 	result = calloc(count + 1, sizeof(char *));
4971139cb14SJohn Levon 	if (result == NULL) {
4981139cb14SJohn Levon 		return NULL;
4991139cb14SJohn Levon 	}
5001139cb14SJohn Levon 
5011139cb14SJohn Levon 	c = str;
5021139cb14SJohn Levon 
5031139cb14SJohn Levon 	for (i = 0; i < count; i++) {
5041139cb14SJohn Levon 		const char *next = strpbrk(c, delim);
5051139cb14SJohn Levon 
5061139cb14SJohn Levon 		if (next == NULL) {
5071139cb14SJohn Levon 			result[i] = strdup(c);
5081139cb14SJohn Levon 		} else {
5091139cb14SJohn Levon 			result[i] = strndup(c, next - c);
5101139cb14SJohn Levon 		}
5111139cb14SJohn Levon 
5121139cb14SJohn Levon 		if (result[i] == NULL) {
5131139cb14SJohn Levon 			spdk_strarray_free(result);
5141139cb14SJohn Levon 			return NULL;
5151139cb14SJohn Levon 		}
5161139cb14SJohn Levon 
5171139cb14SJohn Levon 		if (next != NULL) {
5181139cb14SJohn Levon 			c = next + 1;
5191139cb14SJohn Levon 		}
5201139cb14SJohn Levon 	}
5211139cb14SJohn Levon 
5221139cb14SJohn Levon 	return result;
5231139cb14SJohn Levon }
5241139cb14SJohn Levon 
5251139cb14SJohn Levon char **
spdk_strarray_dup(const char ** strarray)5261139cb14SJohn Levon spdk_strarray_dup(const char **strarray)
5271139cb14SJohn Levon {
5281139cb14SJohn Levon 	size_t count, i;
5291139cb14SJohn Levon 	char **result;
5301139cb14SJohn Levon 
5311139cb14SJohn Levon 	assert(strarray != NULL);
5321139cb14SJohn Levon 
5331139cb14SJohn Levon 	for (count = 0; strarray[count] != NULL; count++)
5341139cb14SJohn Levon 		;
5351139cb14SJohn Levon 
5361139cb14SJohn Levon 	result = calloc(count + 1, sizeof(char *));
5371139cb14SJohn Levon 	if (result == NULL) {
5381139cb14SJohn Levon 		return NULL;
5391139cb14SJohn Levon 	}
5401139cb14SJohn Levon 
5411139cb14SJohn Levon 	for (i = 0; i < count; i++) {
5421139cb14SJohn Levon 		result[i] = strdup(strarray[i]);
5431139cb14SJohn Levon 		if (result[i] == NULL) {
5441139cb14SJohn Levon 			spdk_strarray_free(result);
5451139cb14SJohn Levon 			return NULL;
5461139cb14SJohn Levon 		}
5471139cb14SJohn Levon 	}
5481139cb14SJohn Levon 
5491139cb14SJohn Levon 	return result;
5501139cb14SJohn Levon }
551d6e57b53SShuhei Matsumoto 
552d6e57b53SShuhei Matsumoto int
spdk_strcpy_replace(char * dst,size_t size,const char * src,const char * search,const char * replace)553d6e57b53SShuhei Matsumoto spdk_strcpy_replace(char *dst, size_t size, const char *src, const char *search,
554d6e57b53SShuhei Matsumoto 		    const char *replace)
555d6e57b53SShuhei Matsumoto {
556d6e57b53SShuhei Matsumoto 	const char *p, *q;
557d6e57b53SShuhei Matsumoto 	char *r;
558d6e57b53SShuhei Matsumoto 	size_t c, search_size, replace_size, dst_size;
559d6e57b53SShuhei Matsumoto 
560d6e57b53SShuhei Matsumoto 	if (dst == NULL || src == NULL || search == NULL || replace == NULL) {
561d6e57b53SShuhei Matsumoto 		return -EINVAL;
562d6e57b53SShuhei Matsumoto 	}
563d6e57b53SShuhei Matsumoto 
564d6e57b53SShuhei Matsumoto 	search_size = strlen(search);
565d6e57b53SShuhei Matsumoto 	replace_size = strlen(replace);
566d6e57b53SShuhei Matsumoto 
567d6e57b53SShuhei Matsumoto 	c = 0;
568d6e57b53SShuhei Matsumoto 	for (p = strstr(src, search); p != NULL; p = strstr(p + search_size, search)) {
569d6e57b53SShuhei Matsumoto 		c++;
570d6e57b53SShuhei Matsumoto 	}
571d6e57b53SShuhei Matsumoto 
572d6e57b53SShuhei Matsumoto 	dst_size = strlen(src) + (replace_size - search_size) * c;
573d6e57b53SShuhei Matsumoto 	if (dst_size >= size) {
574d6e57b53SShuhei Matsumoto 		return -EINVAL;
575d6e57b53SShuhei Matsumoto 	}
576d6e57b53SShuhei Matsumoto 
577d6e57b53SShuhei Matsumoto 	q = src;
578d6e57b53SShuhei Matsumoto 	r = dst;
579d6e57b53SShuhei Matsumoto 
580d6e57b53SShuhei Matsumoto 	for (p = strstr(src, search); p != NULL; p = strstr(p + search_size, search)) {
581d6e57b53SShuhei Matsumoto 		memcpy(r, q, p - q);
582d6e57b53SShuhei Matsumoto 		r += p - q;
583d6e57b53SShuhei Matsumoto 
584d6e57b53SShuhei Matsumoto 		memcpy(r, replace, replace_size);
585d6e57b53SShuhei Matsumoto 		r += replace_size;
586d6e57b53SShuhei Matsumoto 
587d6e57b53SShuhei Matsumoto 		q = p + search_size;
588d6e57b53SShuhei Matsumoto 	}
589d6e57b53SShuhei Matsumoto 
590d6e57b53SShuhei Matsumoto 	memcpy(r, q, strlen(q));
591d6e57b53SShuhei Matsumoto 	r += strlen(q);
592d6e57b53SShuhei Matsumoto 
593d6e57b53SShuhei Matsumoto 	*r = '\0';
594d6e57b53SShuhei Matsumoto 
595d6e57b53SShuhei Matsumoto 	return 0;
596d6e57b53SShuhei Matsumoto }
597