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