1#include <errno.h>
2#include <limits.h>
3#include <mem/alloc.h>
4#include <stdarg.h>
5#include <stdbool.h>
6#include <stddef.h>
7#include <stdint.h>
8#include <string.h>
9
10#undef memset
11#undef memcpy
12#undef memmove
13#undef memcmp
14
15void *memcpy(void *dest, const void *src, size_t n) {
16 return __memcpy_inline(dest, src, n);
17}
18
19void *memset(void *s, int c, size_t n) {
20 return __memset_inline(s, c, n);
21}
22
23void *memmove(void *dest, const void *src, size_t n) {
24 return __memmove_inline(dest, src, n);
25}
26
27int memcmp(const void *s1, const void *s2, size_t n) {
28 return __memcmp_inline(s1, s2, n);
29}
30size_t strlen(const char *str) {
31 size_t length = 0;
32
33 while (str[length] != '\0')
34 length++;
35
36 return length;
37}
38
39char *strcpy(char *dest, const char *src) {
40 char *original_dest = dest;
41 while ((*dest++ = *src++))
42 ;
43 return original_dest;
44}
45
46char *strcat(char *dest, const char *src) {
47 char *original_dest = dest;
48 while (*dest)
49 dest++;
50
51 while ((*dest++ = *src++))
52 ;
53
54 return original_dest;
55}
56
57int strncmp(const char *s1, const char *s2, size_t n) {
58 for (size_t i = 0; i < n; i++) {
59 if (s1[i] != s2[i] || s1[i] == '\0')
60 return s1[i] < s2[i] ? -1 : 1;
61 }
62 return 0;
63}
64
65char *strncpy(char *dest, const char *src, size_t n) {
66 char *original_dest = dest;
67 size_t i;
68 for (i = 0; i < n && src[i] != '\0'; i++)
69 dest[i] = src[i];
70
71 for (; i < n; i++)
72 dest[i] = '\0';
73
74 return original_dest;
75}
76
77void *memchr(const void *s, int c, size_t n) {
78 const uint8_t *p = (const uint8_t *) s;
79 for (size_t i = 0; i < n; i++) {
80 if (p[i] == (uint8_t) c)
81 return (void *) (p + i);
82 }
83 return NULL;
84}
85
86void *memrchr(const void *s, int c, size_t n) {
87 const uint8_t *p = (const uint8_t *) s;
88 for (size_t i = n; i > 0; i--) {
89 if (p[i - 1] == (uint8_t) c)
90 return (void *) (p + (i - 1));
91 }
92 return NULL;
93}
94
95int strcmp(const char *str1, const char *str2) {
96 while (*str1 != '\0' && *str2 != '\0') {
97 if (*str1 != *str2)
98 return (unsigned char) (*str1) - (unsigned char) (*str2);
99
100 str1++;
101 str2++;
102 }
103 return (unsigned char) (*str1) - (unsigned char) (*str2);
104}
105
106char *strchr(const char *s, int c) {
107 do {
108 if (*s == c)
109 return (char *) s;
110
111 } while (*s++);
112 return (0);
113}
114
115int islower(int c) {
116 return (unsigned) c - 'a' < 26;
117}
118
119int isupper(int c) {
120 return (unsigned) c - 'A' < 26;
121}
122
123int isdigit(int c) {
124 return (unsigned) c - '0' < 10;
125}
126
127int isalpha(int c) {
128 return islower(c) || isupper(c);
129}
130
131int isalnum(int c) {
132 return isalpha(c) || isdigit(c);
133}
134
135int isspace(int c) {
136 return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' ||
137 c == '\v';
138}
139
140int isprint(int c) {
141 return (unsigned) c - 0x20 < 0x5f;
142}
143
144int toupper(int c) {
145 if (islower(c))
146 return c & 0x5f;
147 return c;
148}
149
150int tolower(int c) {
151 if (isupper(c))
152 return c | 0x20;
153 return c;
154}
155
156char *strdup(const char *str) {
157 if (!str)
158 return NULL;
159
160 size_t len = 0;
161 while (str[len] != '\0')
162 len++;
163
164 char *copy = (char *) kmalloc(len + 1);
165 if (!copy)
166 return NULL;
167
168 for (size_t i = 0; i <= len; i++)
169 copy[i] = str[i];
170
171 return copy;
172}
173
174char *strrchr(const char *s, int c) {
175 const char *last = NULL;
176 do {
177 if (*s == (char) c)
178 last = s;
179 } while (*s++);
180 return (char *) last;
181}
182
183size_t strspn(const char *s, const char *accept) {
184 size_t i = 0;
185 while (s[i]) {
186 const char *a = accept;
187 bool found = false;
188 while (*a) {
189 if (s[i] == *a++) {
190 found = true;
191 break;
192 }
193 }
194 if (!found)
195 break;
196 i++;
197 }
198 return i;
199}
200
201size_t strcspn(const char *s, const char *reject) {
202 size_t i = 0;
203 while (s[i]) {
204 const char *r = reject;
205 while (*r) {
206 if (s[i] == *r++)
207 goto done;
208 }
209 i++;
210 }
211done:
212 return i;
213}
214
215char *strpbrk(const char *s, const char *accept) {
216 while (*s) {
217 const char *a = accept;
218 while (*a) {
219 if (*s == *a++)
220 return (char *) s;
221 }
222 s++;
223 }
224 return NULL;
225}
226
227char *strstr(const char *haystack, const char *needle) {
228 if (!*needle)
229 return (char *) haystack;
230 size_t nlen = strlen(str: needle);
231 size_t hlen = strlen(str: haystack);
232 if (nlen > hlen)
233 return NULL;
234
235 /* KMP failure table */
236 int64_t table[nlen];
237 table[0] = -1;
238 int64_t k = -1;
239 for (size_t i = 1; i < nlen; i++) {
240 while (k >= 0 && needle[k + 1] != needle[i])
241 k = table[k];
242 if (needle[k + 1] == needle[i])
243 k++;
244 table[i] = k;
245 }
246
247 int64_t q = -1;
248 for (size_t i = 0; i < hlen; i++) {
249 while (q >= 0 && needle[q + 1] != haystack[i])
250 q = table[q];
251 if (needle[q + 1] == haystack[i])
252 q++;
253 if (q == (int64_t) nlen - 1)
254 return (char *) (haystack + i - nlen + 1);
255 }
256 return NULL;
257}
258
259char *strtok(char *str, const char *delim) {
260 static char *saved = NULL;
261 if (str)
262 saved = str;
263 if (!saved || !*saved)
264 return NULL;
265
266 saved += strspn(s: saved, accept: delim);
267 if (!*saved) {
268 saved = NULL;
269 return NULL;
270 }
271
272 char *token_start = saved;
273 saved += strcspn(s: saved, reject: delim);
274 if (*saved)
275 *saved++ = '\0';
276 else
277 saved = NULL;
278 return token_start;
279}
280
281char *strtok_r(char *str, const char *delim, char **saveptr) {
282 if (str)
283 *saveptr = str;
284 if (!*saveptr || !**saveptr)
285 return NULL;
286
287 *saveptr += strspn(s: *saveptr, accept: delim);
288 if (!**saveptr) {
289 *saveptr = NULL;
290 return NULL;
291 }
292
293 char *token_start = *saveptr;
294 *saveptr += strcspn(s: *saveptr, reject: delim);
295 if (**saveptr)
296 *(*saveptr)++ = '\0';
297 else
298 *saveptr = NULL;
299 return token_start;
300}
301
302char *strncat(char *dest, const char *src, size_t n) {
303 char *d = dest;
304 while (*d)
305 d++;
306 while (n-- && *src)
307 *d++ = *src++;
308 *d = '\0';
309 return dest;
310}
311
312size_t strnlen(const char *s, size_t maxlen) {
313 size_t i = 0;
314 while (i < maxlen && s[i] != '\0')
315 i++;
316 return i;
317}
318
319int64_t atoi(const char *str) {
320 while (isspace(c: (unsigned char) *str))
321 str++;
322 int64_t sign = 1;
323 if (*str == '-') {
324 sign = -1;
325 str++;
326 } else if (*str == '+')
327 str++;
328 int64_t result = 0;
329 while (isdigit(c: (unsigned char) *str))
330 result = result * 10 + (*str++ - '0');
331 return sign * result;
332}
333
334size_t atoui(const char *str) {
335 while (isspace(c: (unsigned char) *str))
336 str++;
337 if (*str == '+')
338 str++;
339 size_t result = 0;
340 while (isdigit(c: (unsigned char) *str))
341 result = result * 10 + (*str++ - '0');
342 return result;
343}
344
345size_t atohex(const char *str) {
346 while (isspace(c: (unsigned char) *str))
347 str++;
348 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
349 str += 2;
350 size_t result = 0;
351 while (1) {
352 char c = *str++;
353 if (c >= '0' && c <= '9')
354 result = result * 16 + (c - '0');
355 else if (c >= 'a' && c <= 'f')
356 result = result * 16 + (c - 'a' + 10);
357 else if (c >= 'A' && c <= 'F')
358 result = result * 16 + (c - 'A' + 10);
359 else
360 break;
361 }
362 return result;
363}
364
365char *itoa(int64_t value, char *buf, int base) {
366 static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
367 if (base < 2 || base > 36) {
368 buf[0] = '\0';
369 return buf;
370 }
371
372 char *p = buf;
373 char *start;
374 bool negative = (base == 10 && value < 0);
375 size_t uval = negative ? -(size_t) value : (size_t) value;
376
377 do {
378 *p++ = digits[uval % base];
379 uval /= base;
380 } while (uval);
381
382 if (negative)
383 *p++ = '-';
384 *p = '\0';
385
386 start = buf;
387 char *end = p - 1;
388 while (start < end) {
389 char tmp = *start;
390 *start++ = *end;
391 *end-- = tmp;
392 }
393 return buf;
394}
395
396char *utoa(size_t value, char *buf, int base) {
397 static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
398 if (base < 2 || base > 36) {
399 buf[0] = '\0';
400 return buf;
401 }
402
403 char *p = buf;
404 char *start;
405 do {
406 *p++ = digits[value % base];
407 value /= base;
408 } while (value);
409 *p = '\0';
410
411 start = buf;
412 char *end = p - 1;
413 while (start < end) {
414 char tmp = *start;
415 *start++ = *end;
416 *end-- = tmp;
417 }
418 return buf;
419}
420
421int strcasecmp(const char *s1, const char *s2) {
422 while (*s1 && *s2) {
423 int d = tolower(c: (unsigned char) *s1) - tolower(c: (unsigned char) *s2);
424 if (d)
425 return d;
426 s1++;
427 s2++;
428 }
429 return tolower(c: (unsigned char) *s1) - tolower(c: (unsigned char) *s2);
430}
431
432int strncasecmp(const char *s1, const char *s2, size_t n) {
433 while (n-- && *s1 && *s2) {
434 int d = tolower(c: (unsigned char) *s1) - tolower(c: (unsigned char) *s2);
435 if (d)
436 return d;
437 s1++;
438 s2++;
439 }
440 if (n == (size_t) -1)
441 return 0;
442 return tolower(c: (unsigned char) *s1) - tolower(c: (unsigned char) *s2);
443}
444
445char *strrev(char *s) {
446 char *l = s, *r = s + strlen(str: s) - 1;
447 while (l < r) {
448 char t = *l;
449 *l++ = *r;
450 *r-- = t;
451 }
452 return s;
453}
454
455char *strtoupper(char *s) {
456 for (char *p = s; *p; p++)
457 *p = (char) toupper(c: (unsigned char) *p);
458 return s;
459}
460
461char *strtolower(char *s) {
462 for (char *p = s; *p; p++)
463 *p = (char) tolower(c: (unsigned char) *p);
464 return s;
465}
466
467char *strndup(const char *str, size_t n) {
468 if (!str)
469 return NULL;
470 size_t len = strnlen(s: str, maxlen: n);
471 char *copy = (char *) kmalloc(len + 1);
472 if (!copy)
473 return NULL;
474 memcpy(dest: copy, src: str, n: len);
475 copy[len] = '\0';
476 return copy;
477}
478
479long strtol(const char *nptr, char **endptr, int base) {
480 const char *s = nptr;
481
482 while (*s && isspace(c: (unsigned char) *s))
483 s++;
484
485 int neg = 0;
486 if (*s == '+' || *s == '-') {
487 neg = (*s == '-');
488 s++;
489 }
490
491 if (base != 0 && (base < 2 || base > 36)) {
492 if (endptr)
493 *endptr = (char *) nptr;
494 return 0;
495 }
496
497 if (base == 0) {
498 if (*s == '0') {
499 if (s[1] == 'x' || s[1] == 'X') {
500 base = 16;
501 s += 2;
502 } else {
503 base = 8;
504 s += 1;
505 }
506 } else {
507 base = 10;
508 }
509 } else {
510 if (base == 16 && *s == '0' && (s[1] == 'x' || s[1] == 'X'))
511 s += 2;
512 }
513
514 const char *start_digits = s;
515
516 unsigned long acc = 0;
517
518 unsigned long limit =
519 neg ? (unsigned long) LONG_MAX + 1UL : (unsigned long) LONG_MAX;
520
521 for (;;) {
522 int digit;
523
524 char c = *s;
525 if (c >= '0' && c <= '9')
526 digit = c - '0';
527 else if (c >= 'a' && c <= 'z')
528 digit = 10 + (c - 'a');
529 else if (c >= 'A' && c <= 'Z')
530 digit = 10 + (c - 'A');
531 else
532 break;
533
534 if (digit >= base)
535 break;
536
537 if (acc > (limit - (unsigned long) digit) / (unsigned long) base) {
538 while (1) {
539 s++;
540 char dch = *s;
541 if (dch >= '0' && dch <= '9')
542 digit = dch - '0';
543 else if (dch >= 'a' && dch <= 'z')
544 digit = 10 + (dch - 'a');
545 else if (dch >= 'A' && dch <= 'Z')
546 digit = 10 + (dch - 'A');
547 else
548 break;
549 if (digit >= base)
550 break;
551 }
552 break;
553 }
554
555 acc = acc * (unsigned long) base + (unsigned long) digit;
556 s++;
557 }
558
559 if (endptr)
560 *endptr = (char *) s;
561
562 if (s == start_digits)
563 return 0;
564
565 if (neg) {
566 if (acc == (unsigned long) LONG_MAX + 1UL)
567 return LONG_MIN;
568 return -(long) acc;
569 } else {
570 return (long) acc;
571 }
572}
573
574unsigned long long strtoull(const char *nptr, char **endptr, int base) {
575 const char *s = nptr;
576
577 while (*s && isspace(c: (unsigned char) *s))
578 s++;
579
580 int neg = 0;
581 if (*s == '+' || *s == '-') {
582 neg = (*s == '-');
583 s++;
584 }
585
586 if (base != 0 && (base < 2 || base > 36)) {
587 if (endptr)
588 *endptr = (char *) nptr;
589 return 0;
590 }
591
592 if (base == 0) {
593 if (*s == '0' && (s[1] == 'x' || s[1] == 'X')) {
594 base = 16;
595 s += 2;
596 } else if (*s == '0') {
597 base = 8;
598 } else {
599 base = 10;
600 }
601 } else if (base == 16 && *s == '0' && (s[1] == 'x' || s[1] == 'X')) {
602 s += 2;
603 }
604
605 const char *start_digits = s;
606 unsigned long long acc = 0;
607 int overflow = 0;
608
609 for (;;) {
610 int digit;
611 char c = *s;
612 if (c >= '0' && c <= '9')
613 digit = c - '0';
614 else if (c >= 'a' && c <= 'z')
615 digit = 10 + (c - 'a');
616 else if (c >= 'A' && c <= 'Z')
617 digit = 10 + (c - 'A');
618 else
619 break;
620
621 if (digit >= base)
622 break;
623
624 if (overflow || acc > (ULLONG_MAX - (unsigned long long) digit) /
625 (unsigned long long) base)
626 overflow = 1; /* keep consuming digits so endptr stays correct */
627 else
628 acc = acc * (unsigned long long) base + (unsigned long long) digit;
629
630 s++;
631 }
632
633 if (endptr)
634 *endptr = (char *) (s == start_digits ? nptr : s);
635
636 if (s == start_digits)
637 return 0;
638
639 if (overflow)
640 return ULLONG_MAX;
641
642 return neg ? (0ULL - acc) : acc;
643}
644
645unsigned long strtoul(const char *nptr, char **endptr, int base) {
646 return (unsigned long) strtoull(nptr, endptr, base);
647}
648
649long long strtoll(const char *nptr, char **endptr, int base) {
650 return (long long) strtol(nptr, endptr, base);
651}
652
653size_t strlcpy(char *dst, const char *src, size_t size) {
654 size_t srclen = strlen(str: src);
655 if (size) {
656 size_t n = (srclen < size - 1) ? srclen : size - 1;
657 memcpy(dest: dst, src, n);
658 dst[n] = '\0';
659 }
660 return srclen;
661}
662
663size_t strlcat(char *dst, const char *src, size_t size) {
664 size_t dstlen = strnlen(s: dst, maxlen: size);
665 size_t srclen = strlen(str: src);
666
667 if (dstlen == size)
668 return size + srclen;
669
670 size_t avail = size - dstlen;
671 size_t n = (srclen < avail - 1) ? srclen : avail - 1;
672 memcpy(dest: dst + dstlen, src, n);
673 dst[dstlen + n] = '\0';
674 return dstlen + srclen;
675}
676
677char *strsep(char **stringp, const char *delim) {
678 char *start = *stringp;
679 if (!start)
680 return NULL;
681
682 char *p = strpbrk(s: start, accept: delim);
683 if (p) {
684 *p = '\0';
685 *stringp = p + 1;
686 } else {
687 *stringp = NULL;
688 }
689 return start;
690}
691
692char *strchrnul(const char *s, int c) {
693 while (*s && *s != (char) c)
694 s++;
695 return (char *) s;
696}
697
698int vasprintf(char **strp, const char *fmt, va_list args) {
699 if (!strp || !fmt)
700 return ERR_INVAL;
701
702 va_list args_copy;
703 va_copy(args_copy, args);
704
705 int needed = vsnprintf(NULL, buffer_len: 0, format: fmt, args: args_copy);
706 va_end(args_copy);
707
708 if (needed < 0)
709 return ERR_INVAL;
710
711 size_t size = (size_t) needed + 1;
712
713 char *buf = (char *) kmalloc(size, ALLOC_FLAGS_ZERO);
714 if (!buf)
715 return ERR_NO_MEM;
716
717 va_copy(args_copy, args);
718 int written = vsnprintf(buffer: buf, buffer_len: size, format: fmt, args: args_copy);
719 va_end(args_copy);
720
721 if (written < 0) {
722 kfree(buf);
723 return ERR_INVAL;
724 }
725
726 *strp = buf;
727 return written;
728}
729
730int asprintf(char **strp, const char *fmt, ...) {
731 if (!strp || !fmt)
732 return ERR_INVAL;
733
734 va_list args;
735 va_start(args, fmt);
736 int ret = vasprintf(strp, fmt, args);
737 va_end(args);
738
739 return ret;
740}
741