xref: /kvm-unit-tests/lib/string.c (revision f583d9243296b7045a54f8980e3c00849e15ff8c)
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 __strtol(const char *nptr, char **endptr,
172                               int base, bool is_signed) {
173     unsigned long acc = 0;
174     const char *s = nptr;
175     int neg, c;
176 
177     assert(base == 0 || (base >= 2 && base <= 36));
178 
179     while (isspace(*s))
180         s++;
181 
182     if (*s == '-') {
183         neg = 1;
184         s++;
185     } else {
186         neg = 0;
187         if (*s == '+')
188             s++;
189     }
190 
191     if (base == 0 || base == 16) {
192         if (*s == '0') {
193             s++;
194             if (*s == 'x' || *s == 'X') {
195                  s++;
196                  base = 16;
197             } else if (base == 0)
198                  base = 8;
199         } else if (base == 0)
200             base = 10;
201     }
202 
203     while (*s) {
204         if (*s >= '0' && *s < '0' + base && *s <= '9')
205             c = *s - '0';
206         else if (*s >= 'a' && *s < 'a' + base - 10)
207             c = *s - 'a' + 10;
208         else if (*s >= 'A' && *s < 'A' + base - 10)
209             c = *s - 'A' + 10;
210         else
211             break;
212 
213         if (is_signed) {
214             long sacc = (long)acc;
215             assert(!check_mul_overflow(sacc, base));
216             assert(!check_add_overflow(sacc * base, c));
217         } else {
218             assert(!check_mul_overflow(acc, base));
219             assert(!check_add_overflow(acc * base, c));
220         }
221 
222         acc = acc * base + c;
223         s++;
224     }
225 
226     if (neg)
227         acc = -acc;
228 
229     if (endptr)
230         *endptr = (char *)s;
231 
232     return acc;
233 }
234 
235 long int strtol(const char *nptr, char **endptr, int base)
236 {
237     return __strtol(nptr, endptr, base, true);
238 }
239 
240 unsigned long int strtoul(const char *nptr, char **endptr, int base)
241 {
242     return __strtol(nptr, endptr, base, false);
243 }
244 
245 long atol(const char *ptr)
246 {
247     return strtol(ptr, NULL, 10);
248 }
249 
250 extern char **environ;
251 
252 char *getenv(const char *name)
253 {
254     char **envp = environ, *delim;
255     int len;
256 
257     while (*envp) {
258         delim = strchr(*envp, '=');
259         assert(delim);
260         len = delim - *envp;
261         if (memcmp(name, *envp, len) == 0 && !name[len])
262             return delim + 1;
263         ++envp;
264     }
265     return NULL;
266 }
267 
268 /* Very simple glob matching. Allows '*' at beginning and end of pattern. */
269 bool simple_glob(const char *text, const char *pattern)
270 {
271 	bool star_start = false;
272 	bool star_end = false;
273 	size_t n = strlen(pattern);
274 	char copy[n + 1];
275 
276 	if (pattern[0] == '*') {
277 		pattern += 1;
278 		n -= 1;
279 		star_start = true;
280 	}
281 
282 	strcpy(copy, pattern);
283 
284 	if (n > 0 && pattern[n - 1] == '*') {
285 		n -= 1;
286 		copy[n] = '\0';
287 		star_end = true;
288 	}
289 
290 	if (star_start && star_end)
291 		return strstr(text, copy);
292 
293 	if (star_end)
294 		return strstr(text, copy) == text;
295 
296 	if (star_start) {
297 		size_t text_len = strlen(text);
298 		const char *suffix;
299 
300 		if (n > text_len)
301 			return false;
302 		suffix = text + text_len - n;
303 		return !strcmp(suffix, copy);
304 	}
305 
306 	return !strcmp(text, copy);
307 }
308