xref: /kvm-unit-tests/lib/string.c (revision b5501ed0f4af61e88a04cfb7eda0cc9a15edc5ec)
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 *strstr(const char *s1, const char *s2)
80 {
81     size_t l1, l2;
82 
83     l2 = strlen(s2);
84     if (!l2)
85 	return (char *)s1;
86     l1 = strlen(s1);
87     while (l1 >= l2) {
88 	l1--;
89 	if (!memcmp(s1, s2, l2))
90 	    return (char *)s1;
91 	s1++;
92     }
93     return NULL;
94 }
95 
96 void *memset(void *s, int c, size_t n)
97 {
98     size_t i;
99     char *a = s;
100 
101     for (i = 0; i < n; ++i)
102         a[i] = c;
103 
104     return s;
105 }
106 
107 void *memcpy(void *dest, const void *src, size_t n)
108 {
109     size_t i;
110     char *a = dest;
111     const char *b = src;
112 
113     for (i = 0; i < n; ++i)
114         a[i] = b[i];
115 
116     return dest;
117 }
118 
119 int memcmp(const void *s1, const void *s2, size_t n)
120 {
121     const unsigned char *a = s1, *b = s2;
122     int ret = 0;
123 
124     while (n--) {
125 	ret = *a - *b;
126 	if (ret)
127 	    break;
128 	++a, ++b;
129     }
130     return ret;
131 }
132 
133 void *memmove(void *dest, const void *src, size_t n)
134 {
135     const unsigned char *s = src;
136     unsigned char *d = dest;
137 
138     if (d <= s) {
139 	while (n--)
140 	    *d++ = *s++;
141     } else {
142 	d += n, s += n;
143 	while (n--)
144 	    *--d = *--s;
145     }
146     return dest;
147 }
148 
149 void *memchr(const void *s, int c, size_t n)
150 {
151     const unsigned char *str = s, chr = (unsigned char)c;
152 
153     while (n--)
154 	if (*str++ == chr)
155 	    return (void *)(str - 1);
156     return NULL;
157 }
158 
159 static int isspace(int c)
160 {
161     return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f';
162 }
163 
164 static unsigned long __strtol(const char *nptr, char **endptr,
165                               int base, bool is_signed) {
166     unsigned long acc = 0;
167     const char *s = nptr;
168     int neg, c;
169 
170     assert(base == 0 || (base >= 2 && base <= 36));
171 
172     while (isspace(*s))
173         s++;
174 
175     if (*s == '-') {
176         neg = 1;
177         s++;
178     } else {
179         neg = 0;
180         if (*s == '+')
181             s++;
182     }
183 
184     if (base == 0 || base == 16) {
185         if (*s == '0') {
186             s++;
187             if (*s == 'x' || *s == 'X') {
188                  s++;
189                  base = 16;
190             } else if (base == 0)
191                  base = 8;
192         } else if (base == 0)
193             base = 10;
194     }
195 
196     while (*s) {
197         if (*s >= '0' && *s < '0' + base && *s <= '9')
198             c = *s - '0';
199         else if (*s >= 'a' && *s < 'a' + base - 10)
200             c = *s - 'a' + 10;
201         else if (*s >= 'A' && *s < 'A' + base - 10)
202             c = *s - 'A' + 10;
203         else
204             break;
205 
206         if (is_signed) {
207             long sacc = (long)acc;
208             assert(!check_mul_overflow(sacc, base));
209             assert(!check_add_overflow(sacc * base, c));
210         } else {
211             assert(!check_mul_overflow(acc, base));
212             assert(!check_add_overflow(acc * base, c));
213         }
214 
215         acc = acc * base + c;
216         s++;
217     }
218 
219     if (neg)
220         acc = -acc;
221 
222     if (endptr)
223         *endptr = (char *)s;
224 
225     return acc;
226 }
227 
228 long int strtol(const char *nptr, char **endptr, int base)
229 {
230     return __strtol(nptr, endptr, base, true);
231 }
232 
233 unsigned long int strtoul(const char *nptr, char **endptr, int base)
234 {
235     return __strtol(nptr, endptr, base, false);
236 }
237 
238 long atol(const char *ptr)
239 {
240     return strtol(ptr, NULL, 10);
241 }
242 
243 extern char **environ;
244 
245 char *getenv(const char *name)
246 {
247     char **envp = environ, *delim;
248     int len;
249 
250     while (*envp) {
251         delim = strchr(*envp, '=');
252         assert(delim);
253         len = delim - *envp;
254         if (memcmp(name, *envp, len) == 0 && !name[len])
255             return delim + 1;
256         ++envp;
257     }
258     return NULL;
259 }
260 
261 /* Very simple glob matching. Allows '*' at beginning and end of pattern. */
262 bool simple_glob(const char *text, const char *pattern)
263 {
264 	bool star_start = false;
265 	bool star_end = false;
266 	size_t n = strlen(pattern);
267 	char copy[n + 1];
268 
269 	if (pattern[0] == '*') {
270 		pattern += 1;
271 		n -= 1;
272 		star_start = true;
273 	}
274 
275 	strcpy(copy, pattern);
276 
277 	if (n > 0 && pattern[n - 1] == '*') {
278 		n -= 1;
279 		copy[n] = '\0';
280 		star_end = true;
281 	}
282 
283 	if (star_start && star_end)
284 		return strstr(text, copy);
285 
286 	if (star_end)
287 		return strstr(text, copy) == text;
288 
289 	if (star_start) {
290 		size_t text_len = strlen(text);
291 		const char *suffix;
292 
293 		if (n > text_len)
294 			return false;
295 		suffix = text + text_len - n;
296 		return !strcmp(suffix, copy);
297 	}
298 
299 	return !strcmp(text, copy);
300 }
301