xref: /kvm-unit-tests/lib/string.c (revision 0b7501c3b516bde6bd3d74b17e6af76b6aa2a116)
1 /*
2  * libc string functions
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Library General Public License version 2.
6  */
7 
8 #include "libcflat.h"
9 #include "ctype.h"
10 #include "stdlib.h"
11 #include "linux/compiler.h"
12 
13 size_t strlen(const char *buf)
14 {
15 	size_t len = 0;
16 
17 	while (*buf++)
18 		++len;
19 	return len;
20 }
21 
22 size_t strnlen(const char *buf, size_t maxlen)
23 {
24 	const char *sc;
25 
26 	for (sc = buf; maxlen-- && *sc != '\0'; ++sc)
27 		/* nothing */ ;
28 	return sc - buf;
29 }
30 
31 char *strcat(char *dest, const char *src)
32 {
33 	char *p = dest;
34 
35 	while (*p)
36 		++p;
37 	while ((*p++ = *src++) != 0)
38 		;
39 	return dest;
40 }
41 
42 char *strcpy(char *dest, const char *src)
43 {
44 	*dest = 0;
45 	return strcat(dest, src);
46 }
47 
48 int strncmp(const char *a, const char *b, size_t n)
49 {
50 	for (; n--; ++a, ++b)
51 		if (*a != *b || *a == '\0')
52 			return *a - *b;
53 
54 	return 0;
55 }
56 
57 int strcmp(const char *a, const char *b)
58 {
59 	return strncmp(a, b, SIZE_MAX);
60 }
61 
62 char *strchr(const char *s, int c)
63 {
64 	while (*s != (char)c)
65 		if (*s++ == '\0')
66 			return NULL;
67 	return (char *)s;
68 }
69 
70 char *strrchr(const char *s, int c)
71 {
72 	const char *last = NULL;
73 	do {
74 		if (*s == (char)c)
75 			last = s;
76 	} while (*s++);
77 	return (char *)last;
78 }
79 
80 char *strchrnul(const char *s, int c)
81 {
82 	while (*s && *s != (char)c)
83 		s++;
84 	return (char *)s;
85 }
86 
87 char *strstr(const char *s1, const char *s2)
88 {
89 	size_t l1, l2;
90 
91 	l2 = strlen(s2);
92 	if (!l2)
93 		return (char *)s1;
94 	l1 = strlen(s1);
95 	while (l1 >= l2) {
96 		l1--;
97 		if (!memcmp(s1, s2, l2))
98 			return (char *)s1;
99 		s1++;
100 	}
101 	return NULL;
102 }
103 
104 void *memset(void *s, int c, size_t n)
105 {
106 	size_t i;
107 	char *a = s;
108 
109 	for (i = 0; i < n; ++i)
110 		a[i] = c;
111 
112 	return s;
113 }
114 
115 void *memcpy(void *dest, const void *src, size_t n)
116 {
117 	size_t i;
118 	char *a = dest;
119 	const char *b = src;
120 
121 	for (i = 0; i < n; ++i)
122 		a[i] = b[i];
123 
124 	return dest;
125 }
126 
127 int memcmp(const void *s1, const void *s2, size_t n)
128 {
129 	const unsigned char *a = s1, *b = s2;
130 	int ret = 0;
131 
132 	while (n--) {
133 		ret = *a - *b;
134 		if (ret)
135 			break;
136 		++a, ++b;
137 	}
138 	return ret;
139 }
140 
141 void *memmove(void *dest, const void *src, size_t n)
142 {
143 	const unsigned char *s = src;
144 	unsigned char *d = dest;
145 
146 	if (d <= s) {
147 		while (n--)
148 			*d++ = *s++;
149 	} else {
150 		d += n, s += n;
151 		while (n--)
152 			*--d = *--s;
153 	}
154 	return dest;
155 }
156 
157 void *memchr(const void *s, int c, size_t n)
158 {
159 	const unsigned char *str = s, chr = (unsigned char)c;
160 
161 	while (n--)
162 		if (*str++ == chr)
163 			return (void *)(str - 1);
164 	return NULL;
165 }
166 
167 static unsigned long long __strtoll(const char *nptr, char **endptr,
168 				    int base, bool is_signed, bool is_longlong)
169 {
170 	unsigned long long ull = 0;
171 	const char *s = nptr;
172 	int neg, c;
173 
174 	assert(base == 0 || (base >= 2 && base <= 36));
175 
176 	while (isspace(*s))
177 		s++;
178 
179 	if (*s == '-') {
180 		neg = 1;
181 		s++;
182 	} else {
183 		neg = 0;
184 		if (*s == '+')
185 			s++;
186 	}
187 
188 	if (base == 0 || base == 16) {
189 		if (*s == '0') {
190 			s++;
191 			if (*s == 'x' || *s == 'X') {
192 				s++;
193 				base = 16;
194 			} else if (base == 0)
195 				base = 8;
196 		} else if (base == 0)
197 			base = 10;
198 	}
199 
200 	while (*s) {
201 		if (*s >= '0' && *s < '0' + base && *s <= '9')
202 			c = *s - '0';
203 		else if (*s >= 'a' && *s < 'a' + base - 10)
204 			c = *s - 'a' + 10;
205 		else if (*s >= 'A' && *s < 'A' + base - 10)
206 			c = *s - 'A' + 10;
207 		else
208 			break;
209 
210 		if (!is_longlong) {
211 			if (is_signed) {
212 				long sl = (long)ull;
213 				assert(!check_mul_overflow(sl, base));
214 				assert(!check_add_overflow(sl * base, c));
215 			} else {
216 				unsigned long ul = (unsigned long)ull;
217 				assert(!check_mul_overflow(ul, base));
218 				assert(!check_add_overflow(ul * base, c));
219 			}
220 		} else {
221 			if (is_signed) {
222 				long long sll = (long long)ull;
223 				assert(!check_mul_overflow(sll, base));
224 				assert(!check_add_overflow(sll * base, c));
225 			} else {
226 				assert(!check_mul_overflow(ull, base));
227 				assert(!check_add_overflow(ull * base, c));
228 			}
229 		}
230 
231 		ull = ull * base + c;
232 		s++;
233 	}
234 
235 	if (neg)
236 		ull = -ull;
237 
238 	if (endptr)
239 		*endptr = (char *)s;
240 
241 	return ull;
242 }
243 
244 long int strtol(const char *nptr, char **endptr, int base)
245 {
246 	return __strtoll(nptr, endptr, base, true, false);
247 }
248 
249 unsigned long int strtoul(const char *nptr, char **endptr, int base)
250 {
251 	return __strtoll(nptr, endptr, base, false, false);
252 }
253 
254 long long int strtoll(const char *nptr, char **endptr, int base)
255 {
256 	return __strtoll(nptr, endptr, base, true, true);
257 }
258 
259 unsigned long long int strtoull(const char *nptr, char **endptr, int base)
260 {
261 	return __strtoll(nptr, endptr, base, false, true);
262 }
263 
264 long atol(const char *ptr)
265 {
266 	return strtol(ptr, NULL, 10);
267 }
268 
269 extern char **environ;
270 
271 char *getenv(const char *name)
272 {
273 	char **envp = environ, *delim;
274 	int len;
275 
276 	while (*envp) {
277 		delim = strchr(*envp, '=');
278 		assert(delim);
279 		len = delim - *envp;
280 		if (memcmp(name, *envp, len) == 0 && !name[len])
281 			return delim + 1;
282 		++envp;
283 	}
284 	return NULL;
285 }
286 
287 /* Very simple glob matching. Allows '*' at beginning and end of pattern. */
288 bool simple_glob(const char *text, const char *pattern)
289 {
290 	bool star_start = false;
291 	bool star_end = false;
292 	size_t n = strlen(pattern);
293 	char copy[n + 1];
294 
295 	if (pattern[0] == '*') {
296 		pattern += 1;
297 		n -= 1;
298 		star_start = true;
299 	}
300 
301 	strcpy(copy, pattern);
302 
303 	if (n > 0 && pattern[n - 1] == '*') {
304 		n -= 1;
305 		copy[n] = '\0';
306 		star_end = true;
307 	}
308 
309 	if (star_start && star_end)
310 		return strstr(text, copy);
311 
312 	if (star_end)
313 		return strstr(text, copy) == text;
314 
315 	if (star_start) {
316 		size_t text_len = strlen(text);
317 		const char *suffix;
318 
319 		if (n > text_len)
320 			return false;
321 		suffix = text + text_len - n;
322 		return !strcmp(suffix, copy);
323 	}
324 
325 	return !strcmp(text, copy);
326 }
327