1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mos_string.h" |
4 | |
5 | #include <mos/moslib_global.h> |
6 | #include <mos_stdlib.h> |
7 | |
8 | size_t strlen(const char *str) |
9 | { |
10 | size_t len = 0; |
11 | while (str[len]) |
12 | len++; |
13 | return len; |
14 | } |
15 | |
16 | size_t strnlen(const char *str, size_t n) |
17 | { |
18 | size_t len = 0; |
19 | while (len < n && str[len]) |
20 | len++; |
21 | return len; |
22 | } |
23 | |
24 | s32 strcmp(const char *s1, const char *s2) |
25 | { |
26 | size_t i = 0; |
27 | while (s1[i] && s2[i] && s1[i] == s2[i]) |
28 | i++; |
29 | return s1[i] - s2[i]; |
30 | } |
31 | |
32 | s32 strncmp(const char *str1, const char *str2, size_t n) |
33 | { |
34 | u8 c1, c2; |
35 | while (n-- > 0) |
36 | { |
37 | c1 = (u8) *str1++; |
38 | c2 = (u8) *str2++; |
39 | if (c1 != c2) |
40 | return c1 - c2; |
41 | if (c1 == '\0') |
42 | return 0; |
43 | } |
44 | return 0; |
45 | } |
46 | |
47 | s32 strncasecmp(const char *a, const char *b, size_t n) |
48 | { |
49 | for (size_t i = 0; i < n; i++) |
50 | { |
51 | unsigned char a_byte = tolower(c: a[i]); |
52 | unsigned char b_byte = tolower(c: b[i]); |
53 | if (!a_byte && !b_byte) |
54 | return 0; |
55 | // If only one char is null, one of the following cases applies. |
56 | if (a_byte < b_byte) |
57 | return -1; |
58 | if (a_byte > b_byte) |
59 | return 1; |
60 | } |
61 | return 0; |
62 | } |
63 | |
64 | void *memcpy(void *__restrict _dst, const void *__restrict _src, size_t n) |
65 | { |
66 | // https://github.com/eblot/newlib/blob/master/newlib/libc/string/memcpy.c |
67 | |
68 | #define UNALIGNED(X, Y) (((long) X & (sizeof(long) - 1)) | ((long) Y & (sizeof(long) - 1))) // Nonzero if either X or Y is not aligned on a "long" boundary. |
69 | #define BIGBLOCKSIZE (sizeof(long) << 2) // How many bytes are copied each iteration of the 4X unrolled loop. |
70 | #define LITTLEBLOCKSIZE (sizeof(long)) // How many bytes are copied each iteration of the word copy loop. |
71 | #define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE) // Threshold for punting to the byte copier. |
72 | |
73 | char *dst = _dst; |
74 | const char *src = _src; |
75 | |
76 | /* If the size is small, or either SRC or DST is unaligned, |
77 | then punt into the byte copy loop. This should be rare. */ |
78 | if (!TOO_SMALL(n) && !UNALIGNED(src, dst)) |
79 | { |
80 | long *aligned_dst = (long *) dst; |
81 | const long *aligned_src = (long *) src; |
82 | |
83 | /* Copy 4X long words at a time if possible. */ |
84 | while (n >= BIGBLOCKSIZE) |
85 | { |
86 | *aligned_dst++ = *aligned_src++; |
87 | *aligned_dst++ = *aligned_src++; |
88 | *aligned_dst++ = *aligned_src++; |
89 | *aligned_dst++ = *aligned_src++; |
90 | n -= BIGBLOCKSIZE; |
91 | } |
92 | |
93 | /* Copy one long word at a time if possible. */ |
94 | while (n >= LITTLEBLOCKSIZE) |
95 | { |
96 | *aligned_dst++ = *aligned_src++; |
97 | n -= LITTLEBLOCKSIZE; |
98 | } |
99 | |
100 | /* Pick up any residual with a byte copier. */ |
101 | dst = (char *) aligned_dst; |
102 | src = (char *) aligned_src; |
103 | } |
104 | |
105 | while (n--) |
106 | *dst++ = *src++; |
107 | |
108 | return _dst; |
109 | } |
110 | |
111 | void *memmove(void *dest, const void *source, size_t length) |
112 | { |
113 | // https://github.com/eblot/newlib/blob/master/newlib/libc/string/memmove.c |
114 | char *dst = dest; |
115 | const char *src = source; |
116 | |
117 | if (src < dst && dst < src + length) |
118 | { |
119 | /* Have to copy backwards */ |
120 | src += length; |
121 | dst += length; |
122 | while (length--) |
123 | *--dst = *--src; |
124 | } |
125 | else |
126 | { |
127 | while (length--) |
128 | *dst++ = *src++; |
129 | } |
130 | |
131 | return dest; |
132 | } |
133 | |
134 | void *memset(void *s, int c, size_t n) |
135 | { |
136 | u8 *d = s; |
137 | for (size_t i = 0; i < n; i++) |
138 | d[i] = c; |
139 | return s; |
140 | } |
141 | |
142 | int memcmp(const void *s1, const void *s2, size_t n) |
143 | { |
144 | const u8 *p1 = s1, *p2 = s2; |
145 | for (size_t i = 0; i < n; i++) |
146 | { |
147 | if (p1[i] != p2[i]) |
148 | return p1[i] - p2[i]; |
149 | } |
150 | return 0; |
151 | } |
152 | |
153 | void memzero(void *s, size_t n) |
154 | { |
155 | typedef u64 largeint_t; |
156 | largeint_t *lsrc = (largeint_t *) s; |
157 | |
158 | while (n >= sizeof(largeint_t)) |
159 | { |
160 | *lsrc++ = 0; |
161 | n -= sizeof(largeint_t); |
162 | } |
163 | |
164 | char *csrc = (char *) lsrc; |
165 | |
166 | while (n > 0) |
167 | { |
168 | *csrc++ = 0; |
169 | n--; |
170 | } |
171 | } |
172 | |
173 | void *memchr(const void *m, int c, size_t n) |
174 | { |
175 | const u8 *s = m; |
176 | for (size_t i = 0; i < n; i++) |
177 | { |
178 | if (s[i] == c) |
179 | return (void *) &s[i]; |
180 | } |
181 | return NULL; |
182 | } |
183 | |
184 | char *strcpy(char *__restrict dest, const char *__restrict src) |
185 | { |
186 | while (*src) |
187 | *dest++ = *src++; |
188 | *dest = 0; |
189 | return dest; |
190 | } |
191 | |
192 | char *strcat(char *__restrict dest, const char *__restrict src) |
193 | { |
194 | while (*dest) |
195 | dest++; |
196 | while (*src) |
197 | *dest++ = *src++; |
198 | *dest = 0; |
199 | return dest; |
200 | } |
201 | |
202 | char *strncpy(char *__restrict dest, const char *__restrict src, size_t n) |
203 | { |
204 | char *ret = dest; |
205 | while (n > 0 && *src) |
206 | { |
207 | *dest++ = *src++; |
208 | n--; |
209 | } |
210 | while (n > 0) |
211 | { |
212 | *dest++ = 0; |
213 | n--; |
214 | } |
215 | return ret; |
216 | } |
217 | |
218 | // not available for minimal libc |
219 | #ifdef __MOS_KERNEL__ |
220 | char *strdup(const char *src) |
221 | { |
222 | char *dst = malloc(strlen(src) + 1); |
223 | strcpy(dest: dst, src); |
224 | return dst; |
225 | } |
226 | |
227 | char *strndup(const char *src, size_t len) |
228 | { |
229 | char *dst = malloc(len + 1); |
230 | strncpy(dest: dst, src, n: len); |
231 | dst[len] = '\0'; |
232 | return dst; |
233 | } |
234 | #endif |
235 | |
236 | char *strchr(const char *s, int c) |
237 | { |
238 | while (*s) |
239 | { |
240 | if (*s == c) |
241 | return (char *) s; |
242 | s++; |
243 | } |
244 | return NULL; |
245 | } |
246 | |
247 | char *strrchr(const char *s, int c) |
248 | { |
249 | const char *last = NULL; |
250 | do |
251 | { |
252 | if (*s == c) |
253 | last = s; |
254 | } while (*s++); |
255 | return (char *) last; |
256 | } |
257 | |
258 | size_t strspn(const char *s, const char *accept) |
259 | { |
260 | size_t i = 0; |
261 | while (s[i]) |
262 | { |
263 | if (!strchr(s: accept, c: s[i])) |
264 | break; |
265 | i++; |
266 | } |
267 | return i; |
268 | } |
269 | |
270 | char *strpbrk(const char *s, const char *accept) |
271 | { |
272 | while (*s) |
273 | { |
274 | if (strchr(s: accept, c: *s)) |
275 | return (char *) s; |
276 | s++; |
277 | } |
278 | return NULL; |
279 | } |
280 | |
281 | char *strtok(char *str, const char *delim) |
282 | { |
283 | static char *last; |
284 | if (str == NULL) |
285 | str = last; |
286 | if (str == NULL) |
287 | return NULL; |
288 | str += strspn(s: str, accept: delim); |
289 | if (*str == '\0') |
290 | return last = NULL; |
291 | char *token = str; |
292 | str = strpbrk(s: token, accept: delim); |
293 | if (str == NULL) |
294 | last = NULL; |
295 | else |
296 | { |
297 | *str = '\0'; |
298 | last = str + 1; |
299 | } |
300 | return token; |
301 | } |
302 | |
303 | char *strtok_r(char *str, const char *delim, char **saveptr) |
304 | { |
305 | if (str == NULL) |
306 | str = *saveptr; |
307 | |
308 | if (str == NULL) |
309 | return NULL; |
310 | |
311 | str += strspn(s: str, accept: delim); |
312 | |
313 | if (*str == '\0') |
314 | return *saveptr = NULL; |
315 | |
316 | char *token = str; |
317 | str = strpbrk(s: token, accept: delim); |
318 | |
319 | if (str == NULL) |
320 | *saveptr = NULL; |
321 | else |
322 | { |
323 | *str = '\0'; |
324 | *saveptr = str + 1; |
325 | } |
326 | return token; |
327 | } |
328 | |