1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mos_string.hpp" |
4 | |
5 | #include <mos/moslib_global.hpp> |
6 | #include <mos_stdlib.hpp> |
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 | auto dst = (char *) _dst; |
74 | const char *src = (const char *) _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 = static_cast<char *>(dest); |
115 | const char *src = static_cast<const char *>(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 = static_cast<u8 *>(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 = static_cast<const u8 *>(s1); |
145 | const u8 *p2 = static_cast<const u8 *>(s2); |
146 | |
147 | for (size_t i = 0; i < n; i++) |
148 | { |
149 | if (p1[i] != p2[i]) |
150 | return p1[i] - p2[i]; |
151 | } |
152 | return 0; |
153 | } |
154 | |
155 | void memzero(void *s, size_t n) |
156 | { |
157 | typedef u64 largeint_t; |
158 | largeint_t *lsrc = (largeint_t *) s; |
159 | |
160 | while (n >= sizeof(largeint_t)) |
161 | { |
162 | *lsrc++ = 0; |
163 | n -= sizeof(largeint_t); |
164 | } |
165 | |
166 | char *csrc = (char *) lsrc; |
167 | |
168 | while (n > 0) |
169 | { |
170 | *csrc++ = 0; |
171 | n--; |
172 | } |
173 | } |
174 | |
175 | void *memchr(const void *m, int c, size_t n) |
176 | { |
177 | const u8 *s = static_cast<const u8 *>(m); |
178 | for (size_t i = 0; i < n; i++) |
179 | { |
180 | if (s[i] == c) |
181 | return (void *) &s[i]; |
182 | } |
183 | return NULL; |
184 | } |
185 | |
186 | char *strcpy(char *__restrict dest, const char *__restrict src) |
187 | { |
188 | while (*src) |
189 | *dest++ = *src++; |
190 | *dest = 0; |
191 | return dest; |
192 | } |
193 | |
194 | char *strcat(char *__restrict dest, const char *__restrict src) |
195 | { |
196 | while (*dest) |
197 | dest++; |
198 | while (*src) |
199 | *dest++ = *src++; |
200 | *dest = 0; |
201 | return dest; |
202 | } |
203 | |
204 | char *strncpy(char *__restrict dest, const char *__restrict src, size_t n) |
205 | { |
206 | char *ret = dest; |
207 | while (n > 0 && *src) |
208 | { |
209 | *dest++ = *src++; |
210 | n--; |
211 | } |
212 | while (n > 0) |
213 | { |
214 | *dest++ = 0; |
215 | n--; |
216 | } |
217 | return ret; |
218 | } |
219 | |
220 | // not available for minimal libc |
221 | #ifdef __MOS_KERNEL__ |
222 | char *strdup(const char *src) |
223 | { |
224 | char *dst = (char *) malloc(size: strlen(str: src) + 1); |
225 | strcpy(dest: dst, src); |
226 | return dst; |
227 | } |
228 | |
229 | char *strndup(const char *src, size_t len) |
230 | { |
231 | char *dst = (char *) malloc(size: len + 1); |
232 | strncpy(dest: dst, src, n: len); |
233 | dst[len] = '\0'; |
234 | return dst; |
235 | } |
236 | #endif |
237 | |
238 | char *strchr(const char *s, int c) |
239 | { |
240 | while (*s) |
241 | { |
242 | if (*s == c) |
243 | return (char *) s; |
244 | s++; |
245 | } |
246 | return NULL; |
247 | } |
248 | |
249 | char *strrchr(const char *s, int c) |
250 | { |
251 | const char *last = NULL; |
252 | do |
253 | { |
254 | if (*s == c) |
255 | last = s; |
256 | } while (*s++); |
257 | return (char *) last; |
258 | } |
259 | |
260 | size_t strspn(const char *s, const char *accept) |
261 | { |
262 | size_t i = 0; |
263 | while (s[i]) |
264 | { |
265 | if (!strchr(s: accept, c: s[i])) |
266 | break; |
267 | i++; |
268 | } |
269 | return i; |
270 | } |
271 | |
272 | char *strpbrk(const char *s, const char *accept) |
273 | { |
274 | while (*s) |
275 | { |
276 | if (strchr(s: accept, c: *s)) |
277 | return (char *) s; |
278 | s++; |
279 | } |
280 | return NULL; |
281 | } |
282 | |
283 | char *strtok(char *str, const char *delim) |
284 | { |
285 | static char *last; |
286 | if (str == NULL) |
287 | str = last; |
288 | if (str == NULL) |
289 | return NULL; |
290 | str += strspn(s: str, accept: delim); |
291 | if (*str == '\0') |
292 | return last = NULL; |
293 | char *token = str; |
294 | str = strpbrk(s: token, accept: delim); |
295 | if (str == NULL) |
296 | last = NULL; |
297 | else |
298 | { |
299 | *str = '\0'; |
300 | last = str + 1; |
301 | } |
302 | return token; |
303 | } |
304 | |
305 | char *strtok_r(char *str, const char *delim, char **saveptr) |
306 | { |
307 | if (str == NULL) |
308 | str = *saveptr; |
309 | |
310 | if (str == NULL) |
311 | return NULL; |
312 | |
313 | str += strspn(s: str, accept: delim); |
314 | |
315 | if (*str == '\0') |
316 | return *saveptr = NULL; |
317 | |
318 | char *token = str; |
319 | str = strpbrk(s: token, accept: delim); |
320 | |
321 | if (str == NULL) |
322 | *saveptr = NULL; |
323 | else |
324 | { |
325 | *str = '\0'; |
326 | *saveptr = str + 1; |
327 | } |
328 | return token; |
329 | } |
330 | |