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
8size_t strlen(const char *str)
9{
10 size_t len = 0;
11 while (str[len])
12 len++;
13 return len;
14}
15
16size_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
24s32 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
32s32 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
47s32 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
64void *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
111void *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
134void *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
142int 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
153void 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
173void *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
184char *strcpy(char *__restrict dest, const char *__restrict src)
185{
186 while (*src)
187 *dest++ = *src++;
188 *dest = 0;
189 return dest;
190}
191
192char *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
202char *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__
220char *strdup(const char *src)
221{
222 char *dst = malloc(strlen(src) + 1);
223 strcpy(dest: dst, src);
224 return dst;
225}
226
227char *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
236char *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
247char *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
258size_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
270char *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
281char *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
303char *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