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