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
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 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
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 = 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
134void *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
142int 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
155void 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
175void *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
186char *strcpy(char *__restrict dest, const char *__restrict src)
187{
188 while (*src)
189 *dest++ = *src++;
190 *dest = 0;
191 return dest;
192}
193
194char *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
204char *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__
222char *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
229char *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
238char *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
249char *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
260size_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
272char *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
283char *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
305char *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