xref: /kvm-unit-tests/lib/string.c (revision 5927d1c22c597912edf8c023abf850243912cbd8)
14b6da826SThomas Huth /*
24b6da826SThomas Huth  * libc string functions
34b6da826SThomas Huth  *
44b6da826SThomas Huth  * This code is free software; you can redistribute it and/or modify it
54b6da826SThomas Huth  * under the terms of the GNU Library General Public License version 2.
64b6da826SThomas Huth  */
74b6da826SThomas Huth 
87d36db35SAvi Kivity #include "libcflat.h"
9*5927d1c2SAndrew Jones #include "ctype.h"
10b5501ed0SNikos Nikoleris #include "stdlib.h"
11b5501ed0SNikos Nikoleris #include "linux/compiler.h"
127d36db35SAvi Kivity 
13b5501ed0SNikos Nikoleris size_t strlen(const char *buf)
147d36db35SAvi Kivity {
15b5501ed0SNikos Nikoleris 	size_t len = 0;
167d36db35SAvi Kivity 
177d36db35SAvi Kivity 	while (*buf++)
187d36db35SAvi Kivity 		++len;
197d36db35SAvi Kivity 	return len;
207d36db35SAvi Kivity }
217d36db35SAvi Kivity 
22b5501ed0SNikos Nikoleris size_t strnlen(const char *buf, size_t maxlen)
23b5501ed0SNikos Nikoleris {
24b5501ed0SNikos Nikoleris 	const char *sc;
25b5501ed0SNikos Nikoleris 
26b5501ed0SNikos Nikoleris 	for (sc = buf; maxlen-- && *sc != '\0'; ++sc)
27b5501ed0SNikos Nikoleris 		/* nothing */ ;
28b5501ed0SNikos Nikoleris 	return sc - buf;
29b5501ed0SNikos Nikoleris }
30b5501ed0SNikos Nikoleris 
317d36db35SAvi Kivity char *strcat(char *dest, const char *src)
327d36db35SAvi Kivity {
337d36db35SAvi Kivity 	char *p = dest;
347d36db35SAvi Kivity 
357d36db35SAvi Kivity 	while (*p)
367d36db35SAvi Kivity 		++p;
377d36db35SAvi Kivity 	while ((*p++ = *src++) != 0)
387d36db35SAvi Kivity 		;
397d36db35SAvi Kivity 	return dest;
407d36db35SAvi Kivity }
417d36db35SAvi Kivity 
42782ebe33SAndrew Jones char *strcpy(char *dest, const char *src)
43782ebe33SAndrew Jones {
44782ebe33SAndrew Jones 	*dest = 0;
45782ebe33SAndrew Jones 	return strcat(dest, src);
46782ebe33SAndrew Jones }
47782ebe33SAndrew Jones 
484fd53297SRadim Krčmář int strncmp(const char *a, const char *b, size_t n)
494fd53297SRadim Krčmář {
504fd53297SRadim Krčmář 	for (; n--; ++a, ++b)
514fd53297SRadim Krčmář 		if (*a != *b || *a == '\0')
524fd53297SRadim Krčmář 			return *a - *b;
534fd53297SRadim Krčmář 
544fd53297SRadim Krčmář 	return 0;
554fd53297SRadim Krčmář }
564fd53297SRadim Krčmář 
5769da6c87SAvi Kivity int strcmp(const char *a, const char *b)
5869da6c87SAvi Kivity {
594fd53297SRadim Krčmář 	return strncmp(a, b, SIZE_MAX);
6069da6c87SAvi Kivity }
6169da6c87SAvi Kivity 
62782ebe33SAndrew Jones char *strchr(const char *s, int c)
63782ebe33SAndrew Jones {
64782ebe33SAndrew Jones 	while (*s != (char)c)
65782ebe33SAndrew Jones 		if (*s++ == '\0')
66782ebe33SAndrew Jones 			return NULL;
67782ebe33SAndrew Jones 	return (char *)s;
68782ebe33SAndrew Jones }
69782ebe33SAndrew Jones 
70b5501ed0SNikos Nikoleris char *strrchr(const char *s, int c)
71b5501ed0SNikos Nikoleris {
72b5501ed0SNikos Nikoleris 	const char *last = NULL;
73b5501ed0SNikos Nikoleris 	do {
74b5501ed0SNikos Nikoleris 		if (*s == (char)c)
75b5501ed0SNikos Nikoleris 			last = s;
76b5501ed0SNikos Nikoleris 	} while (*s++);
77b5501ed0SNikos Nikoleris 	return (char *)last;
78b5501ed0SNikos Nikoleris }
79b5501ed0SNikos Nikoleris 
80546914b4SNikos Nikoleris char *strchrnul(const char *s, int c)
81546914b4SNikos Nikoleris {
82546914b4SNikos Nikoleris 	while (*s && *s != (char)c)
83546914b4SNikos Nikoleris 		s++;
84546914b4SNikos Nikoleris 	return (char *)s;
85546914b4SNikos Nikoleris }
86546914b4SNikos Nikoleris 
8753da5cc0SAndrew Jones char *strstr(const char *s1, const char *s2)
8853da5cc0SAndrew Jones {
8953da5cc0SAndrew Jones 	size_t l1, l2;
9053da5cc0SAndrew Jones 
9153da5cc0SAndrew Jones 	l2 = strlen(s2);
9253da5cc0SAndrew Jones 	if (!l2)
9353da5cc0SAndrew Jones 		return (char *)s1;
9453da5cc0SAndrew Jones 	l1 = strlen(s1);
9553da5cc0SAndrew Jones 	while (l1 >= l2) {
9653da5cc0SAndrew Jones 		l1--;
9753da5cc0SAndrew Jones 		if (!memcmp(s1, s2, l2))
9853da5cc0SAndrew Jones 			return (char *)s1;
9953da5cc0SAndrew Jones 		s1++;
10053da5cc0SAndrew Jones 	}
10153da5cc0SAndrew Jones 	return NULL;
10253da5cc0SAndrew Jones }
10353da5cc0SAndrew Jones 
1047d36db35SAvi Kivity void *memset(void *s, int c, size_t n)
1057d36db35SAvi Kivity {
1067d36db35SAvi Kivity 	size_t i;
1077d36db35SAvi Kivity 	char *a = s;
1087d36db35SAvi Kivity 
1097d36db35SAvi Kivity 	for (i = 0; i < n; ++i)
1107d36db35SAvi Kivity 		a[i] = c;
1117d36db35SAvi Kivity 
1127d36db35SAvi Kivity 	return s;
1137d36db35SAvi Kivity }
1141b708e8cSJason Wang 
1158d68030eSArthur Chunqi Li void *memcpy(void *dest, const void *src, size_t n)
1168d68030eSArthur Chunqi Li {
1178d68030eSArthur Chunqi Li 	size_t i;
1188d68030eSArthur Chunqi Li 	char *a = dest;
1198d68030eSArthur Chunqi Li 	const char *b = src;
1208d68030eSArthur Chunqi Li 
1218d68030eSArthur Chunqi Li 	for (i = 0; i < n; ++i)
1228d68030eSArthur Chunqi Li 		a[i] = b[i];
1238d68030eSArthur Chunqi Li 
1248d68030eSArthur Chunqi Li 	return dest;
1258d68030eSArthur Chunqi Li }
1268d68030eSArthur Chunqi Li 
127782ebe33SAndrew Jones int memcmp(const void *s1, const void *s2, size_t n)
128782ebe33SAndrew Jones {
129782ebe33SAndrew Jones 	const unsigned char *a = s1, *b = s2;
130782ebe33SAndrew Jones 	int ret = 0;
131782ebe33SAndrew Jones 
132782ebe33SAndrew Jones 	while (n--) {
133782ebe33SAndrew Jones 		ret = *a - *b;
134782ebe33SAndrew Jones 		if (ret)
135782ebe33SAndrew Jones 			break;
136782ebe33SAndrew Jones 		++a, ++b;
137782ebe33SAndrew Jones 	}
138782ebe33SAndrew Jones 	return ret;
139782ebe33SAndrew Jones }
140782ebe33SAndrew Jones 
141782ebe33SAndrew Jones void *memmove(void *dest, const void *src, size_t n)
142782ebe33SAndrew Jones {
143782ebe33SAndrew Jones 	const unsigned char *s = src;
144782ebe33SAndrew Jones 	unsigned char *d = dest;
145782ebe33SAndrew Jones 
146782ebe33SAndrew Jones 	if (d <= s) {
147782ebe33SAndrew Jones 		while (n--)
148782ebe33SAndrew Jones 			*d++ = *s++;
149782ebe33SAndrew Jones 	} else {
150782ebe33SAndrew Jones 		d += n, s += n;
151782ebe33SAndrew Jones 		while (n--)
152782ebe33SAndrew Jones 			*--d = *--s;
153782ebe33SAndrew Jones 	}
154782ebe33SAndrew Jones 	return dest;
155782ebe33SAndrew Jones }
156782ebe33SAndrew Jones 
157782ebe33SAndrew Jones void *memchr(const void *s, int c, size_t n)
158782ebe33SAndrew Jones {
159782ebe33SAndrew Jones 	const unsigned char *str = s, chr = (unsigned char)c;
160782ebe33SAndrew Jones 
161782ebe33SAndrew Jones 	while (n--)
162782ebe33SAndrew Jones 		if (*str++ == chr)
163782ebe33SAndrew Jones 			return (void *)(str - 1);
164782ebe33SAndrew Jones 	return NULL;
165782ebe33SAndrew Jones }
166782ebe33SAndrew Jones 
1677f1ca26cSAndrew Jones static unsigned long long __strtoll(const char *nptr, char **endptr,
1680e981298SAndrew Jones 				    int base, bool is_signed, bool is_longlong)
1690e981298SAndrew Jones {
1707f1ca26cSAndrew Jones 	unsigned long long ull = 0;
171b5501ed0SNikos Nikoleris 	const char *s = nptr;
1721b708e8cSJason Wang 	int neg, c;
1731b708e8cSJason Wang 
174b5501ed0SNikos Nikoleris 	assert(base == 0 || (base >= 2 && base <= 36));
175b5501ed0SNikos Nikoleris 
176b5501ed0SNikos Nikoleris 	while (isspace(*s))
1771b708e8cSJason Wang 		s++;
178b5501ed0SNikos Nikoleris 
1791b708e8cSJason Wang 	if (*s == '-') {
1801b708e8cSJason Wang 		neg = 1;
1811b708e8cSJason Wang 		s++;
1821b708e8cSJason Wang 	} else {
1831b708e8cSJason Wang 		neg = 0;
1841b708e8cSJason Wang 		if (*s == '+')
1851b708e8cSJason Wang 			s++;
1861b708e8cSJason Wang 	}
1871b708e8cSJason Wang 
188b5501ed0SNikos Nikoleris 	if (base == 0 || base == 16) {
189b5501ed0SNikos Nikoleris 		if (*s == '0') {
190b5501ed0SNikos Nikoleris 			s++;
191b5501ed0SNikos Nikoleris 			if (*s == 'x' || *s == 'X') {
192b5501ed0SNikos Nikoleris 				s++;
193b5501ed0SNikos Nikoleris 				base = 16;
194b5501ed0SNikos Nikoleris 			} else if (base == 0)
195b5501ed0SNikos Nikoleris 				base = 8;
196b5501ed0SNikos Nikoleris 		} else if (base == 0)
197b5501ed0SNikos Nikoleris 			base = 10;
198b5501ed0SNikos Nikoleris 	}
199b5501ed0SNikos Nikoleris 
2001b708e8cSJason Wang 	while (*s) {
201b5501ed0SNikos Nikoleris 		if (*s >= '0' && *s < '0' + base && *s <= '9')
2021b708e8cSJason Wang 			c = *s - '0';
203b5501ed0SNikos Nikoleris 		else if (*s >= 'a' && *s < 'a' + base - 10)
204b5501ed0SNikos Nikoleris 			c = *s - 'a' + 10;
205b5501ed0SNikos Nikoleris 		else if (*s >= 'A' && *s < 'A' + base - 10)
206b5501ed0SNikos Nikoleris 			c = *s - 'A' + 10;
207b5501ed0SNikos Nikoleris 		else
208b5501ed0SNikos Nikoleris 			break;
209b5501ed0SNikos Nikoleris 
2107f1ca26cSAndrew Jones 		if (!is_longlong) {
211b5501ed0SNikos Nikoleris 			if (is_signed) {
2127f1ca26cSAndrew Jones 				long sl = (long)ull;
2137f1ca26cSAndrew Jones 				assert(!check_mul_overflow(sl, base));
2147f1ca26cSAndrew Jones 				assert(!check_add_overflow(sl * base, c));
215b5501ed0SNikos Nikoleris 			} else {
2167f1ca26cSAndrew Jones 				unsigned long ul = (unsigned long)ull;
2177f1ca26cSAndrew Jones 				assert(!check_mul_overflow(ul, base));
2187f1ca26cSAndrew Jones 				assert(!check_add_overflow(ul * base, c));
2197f1ca26cSAndrew Jones 			}
2207f1ca26cSAndrew Jones 		} else {
2217f1ca26cSAndrew Jones 			if (is_signed) {
2227f1ca26cSAndrew Jones 				long long sll = (long long)ull;
2237f1ca26cSAndrew Jones 				assert(!check_mul_overflow(sll, base));
2247f1ca26cSAndrew Jones 				assert(!check_add_overflow(sll * base, c));
2257f1ca26cSAndrew Jones 			} else {
2267f1ca26cSAndrew Jones 				assert(!check_mul_overflow(ull, base));
2277f1ca26cSAndrew Jones 				assert(!check_add_overflow(ull * base, c));
2287f1ca26cSAndrew Jones 			}
229b5501ed0SNikos Nikoleris 		}
230b5501ed0SNikos Nikoleris 
2317f1ca26cSAndrew Jones 		ull = ull * base + c;
2321b708e8cSJason Wang 		s++;
2331b708e8cSJason Wang 	}
2341b708e8cSJason Wang 
2351b708e8cSJason Wang 	if (neg)
2367f1ca26cSAndrew Jones 		ull = -ull;
2371b708e8cSJason Wang 
238b5501ed0SNikos Nikoleris 	if (endptr)
239b5501ed0SNikos Nikoleris 		*endptr = (char *)s;
240b5501ed0SNikos Nikoleris 
2417f1ca26cSAndrew Jones 	return ull;
2421b708e8cSJason Wang }
24369205bf1SAndrew Jones 
244b5501ed0SNikos Nikoleris long int strtol(const char *nptr, char **endptr, int base)
245b5501ed0SNikos Nikoleris {
2467f1ca26cSAndrew Jones 	return __strtoll(nptr, endptr, base, true, false);
247b5501ed0SNikos Nikoleris }
248b5501ed0SNikos Nikoleris 
249b5501ed0SNikos Nikoleris unsigned long int strtoul(const char *nptr, char **endptr, int base)
250b5501ed0SNikos Nikoleris {
2517f1ca26cSAndrew Jones 	return __strtoll(nptr, endptr, base, false, false);
2527f1ca26cSAndrew Jones }
2537f1ca26cSAndrew Jones 
2547f1ca26cSAndrew Jones long long int strtoll(const char *nptr, char **endptr, int base)
2557f1ca26cSAndrew Jones {
2567f1ca26cSAndrew Jones 	return __strtoll(nptr, endptr, base, true, true);
2577f1ca26cSAndrew Jones }
2587f1ca26cSAndrew Jones 
2597f1ca26cSAndrew Jones unsigned long long int strtoull(const char *nptr, char **endptr, int base)
2607f1ca26cSAndrew Jones {
2617f1ca26cSAndrew Jones 	return __strtoll(nptr, endptr, base, false, true);
262b5501ed0SNikos Nikoleris }
263b5501ed0SNikos Nikoleris 
264b5501ed0SNikos Nikoleris long atol(const char *ptr)
265b5501ed0SNikos Nikoleris {
266b5501ed0SNikos Nikoleris 	return strtol(ptr, NULL, 10);
267b5501ed0SNikos Nikoleris }
268b5501ed0SNikos Nikoleris 
26969205bf1SAndrew Jones extern char **environ;
27069205bf1SAndrew Jones 
27169205bf1SAndrew Jones char *getenv(const char *name)
27269205bf1SAndrew Jones {
27369205bf1SAndrew Jones 	char **envp = environ, *delim;
2744837df6eSAndrew Jones 	int len;
27569205bf1SAndrew Jones 
27669205bf1SAndrew Jones 	while (*envp) {
27769205bf1SAndrew Jones 		delim = strchr(*envp, '=');
2784837df6eSAndrew Jones 		assert(delim);
2794837df6eSAndrew Jones 		len = delim - *envp;
2804837df6eSAndrew Jones 		if (memcmp(name, *envp, len) == 0 && !name[len])
28169205bf1SAndrew Jones 			return delim + 1;
28269205bf1SAndrew Jones 		++envp;
28369205bf1SAndrew Jones 	}
28469205bf1SAndrew Jones 	return NULL;
28569205bf1SAndrew Jones }
286875b97b3SPeter Feiner 
287875b97b3SPeter Feiner /* Very simple glob matching. Allows '*' at beginning and end of pattern. */
288875b97b3SPeter Feiner bool simple_glob(const char *text, const char *pattern)
289875b97b3SPeter Feiner {
290875b97b3SPeter Feiner 	bool star_start = false;
291875b97b3SPeter Feiner 	bool star_end = false;
292875b97b3SPeter Feiner 	size_t n = strlen(pattern);
293875b97b3SPeter Feiner 	char copy[n + 1];
294875b97b3SPeter Feiner 
295875b97b3SPeter Feiner 	if (pattern[0] == '*') {
296875b97b3SPeter Feiner 		pattern += 1;
297875b97b3SPeter Feiner 		n -= 1;
298875b97b3SPeter Feiner 		star_start = true;
299875b97b3SPeter Feiner 	}
300875b97b3SPeter Feiner 
301875b97b3SPeter Feiner 	strcpy(copy, pattern);
302875b97b3SPeter Feiner 
303875b97b3SPeter Feiner 	if (n > 0 && pattern[n - 1] == '*') {
304875b97b3SPeter Feiner 		n -= 1;
305875b97b3SPeter Feiner 		copy[n] = '\0';
306875b97b3SPeter Feiner 		star_end = true;
307875b97b3SPeter Feiner 	}
308875b97b3SPeter Feiner 
309875b97b3SPeter Feiner 	if (star_start && star_end)
310875b97b3SPeter Feiner 		return strstr(text, copy);
311875b97b3SPeter Feiner 
312875b97b3SPeter Feiner 	if (star_end)
313875b97b3SPeter Feiner 		return strstr(text, copy) == text;
314875b97b3SPeter Feiner 
315875b97b3SPeter Feiner 	if (star_start) {
316875b97b3SPeter Feiner 		size_t text_len = strlen(text);
317875b97b3SPeter Feiner 		const char *suffix;
318875b97b3SPeter Feiner 
319875b97b3SPeter Feiner 		if (n > text_len)
320875b97b3SPeter Feiner 			return false;
321875b97b3SPeter Feiner 		suffix = text + text_len - n;
322875b97b3SPeter Feiner 		return !strcmp(suffix, copy);
323875b97b3SPeter Feiner 	}
324875b97b3SPeter Feiner 
325875b97b3SPeter Feiner 	return !strcmp(text, copy);
326875b97b3SPeter Feiner }
327