summaryrefslogtreecommitdiff
path: root/userland/libc/string
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2023-10-22 19:50:38 +0200
committerAnton Kling <anton@kling.gg>2023-10-22 19:50:38 +0200
commit4e09bca9e34c226b6d7e34b4fa11248405fd988e (patch)
tree80f156b7940d9d19971395f335530170c69516c7 /userland/libc/string
Move everything into a new repo.
Diffstat (limited to 'userland/libc/string')
-rw-r--r--userland/libc/string/memcmp.c11
-rw-r--r--userland/libc/string/memcpy.c9
-rw-r--r--userland/libc/string/memmove.c14
-rw-r--r--userland/libc/string/sscanf.c193
-rw-r--r--userland/libc/string/strcasecmp.c28
-rw-r--r--userland/libc/string/strcat.c13
-rw-r--r--userland/libc/string/strchr.c11
-rw-r--r--userland/libc/string/strcmp.c29
-rw-r--r--userland/libc/string/strcpy.c7
-rw-r--r--userland/libc/string/strcspn.c14
-rw-r--r--userland/libc/string/strdup.c15
-rw-r--r--userland/libc/string/strlcpy.c20
-rw-r--r--userland/libc/string/strlen.c8
-rw-r--r--userland/libc/string/strncasecmp.c29
-rw-r--r--userland/libc/string/strncmp.c28
-rw-r--r--userland/libc/string/strncpy.c13
-rw-r--r--userland/libc/string/strndup.c22
-rw-r--r--userland/libc/string/strnlen.c9
-rw-r--r--userland/libc/string/strpbrk.c12
-rw-r--r--userland/libc/string/strrchr.c12
-rw-r--r--userland/libc/string/strspn.c18
-rw-r--r--userland/libc/string/strstr.c21
-rw-r--r--userland/libc/string/strtok.c26
23 files changed, 562 insertions, 0 deletions
diff --git a/userland/libc/string/memcmp.c b/userland/libc/string/memcmp.c
new file mode 100644
index 0000000..01109b8
--- /dev/null
+++ b/userland/libc/string/memcmp.c
@@ -0,0 +1,11 @@
+#include <string.h>
+
+int memcmp(const void *s1, const void *s2, size_t n) {
+ int return_value = 0;
+
+ for (uint32_t i = 0; i < n; i++)
+ if (((unsigned char *)(s1))[i] != ((unsigned char *)(s2))[i])
+ return_value++;
+
+ return return_value;
+}
diff --git a/userland/libc/string/memcpy.c b/userland/libc/string/memcpy.c
new file mode 100644
index 0000000..e19dec9
--- /dev/null
+++ b/userland/libc/string/memcpy.c
@@ -0,0 +1,9 @@
+#include <string.h>
+
+void *memcpy(void *dest, const void *src, uint32_t n) {
+ unsigned char *d = dest;
+ const unsigned char *s = src;
+ for (; n; n--)
+ *d++ = *s++;
+ return dest;
+}
diff --git a/userland/libc/string/memmove.c b/userland/libc/string/memmove.c
new file mode 100644
index 0000000..5fc49f7
--- /dev/null
+++ b/userland/libc/string/memmove.c
@@ -0,0 +1,14 @@
+#include <string.h>
+
+// copy bytes in memory with overlapping areas
+// https://pubs.opengroup.org/onlinepubs/9699919799/functions/memmove.html
+void *memmove(void *s1, const void *s2, size_t n) {
+ // Copying takes place as if the n bytes from the object pointed to by s2 are
+ // first copied into a temporary array of n bytes that does not overlap the
+ // objects pointed to by s1 and s2, and then the n bytes from the temporary
+ // array are copied into the object pointed to by s1.
+ unsigned char tmp[n];
+ memcpy(tmp, s2, n);
+ memcpy(s1, tmp, n);
+ return s1;
+}
diff --git a/userland/libc/string/sscanf.c b/userland/libc/string/sscanf.c
new file mode 100644
index 0000000..28e1ce1
--- /dev/null
+++ b/userland/libc/string/sscanf.c
@@ -0,0 +1,193 @@
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+extern int errno;
+extern int get_value(char c, long base);
+
+long ftnum(FILE *stream, int base, int *error) {
+ char c;
+ long ret_value = 0;
+ *error = 0;
+ // Ignore inital white-space sequence
+ for (;;) {
+ if (EOF == (c = fgetc(stream))) {
+ *error = 1;
+ return 0;
+ }
+
+ if (!isspace(c)) {
+ ungetc(c, stream);
+ break;
+ }
+ }
+ if (c == '\0') {
+ *error = 1;
+ return 0;
+ }
+ if (!isdigit(c)) {
+ *error = 1;
+ return 0;
+ }
+ if (!(2 <= base && 36 >= base)) {
+ *error = 1;
+ return 0;
+ }
+ for (;;) {
+ if (EOF == (c = fgetc(stream)))
+ break;
+ if (c == '\0') {
+ ungetc(c, stream);
+ break;
+ }
+ int val = get_value(c, base);
+ if (-1 == val) {
+ ungetc(c, stream);
+ break;
+ }
+ if (ret_value * base > LONG_MAX - val) {
+ ungetc(c, stream);
+ errno = ERANGE;
+ *error = 1;
+ return 0;
+ }
+ ret_value *= base;
+ ret_value += val;
+ }
+ return ret_value;
+}
+
+int vfscanf(FILE *stream, const char *format, va_list ap) {
+ int rc = 0; // Upon successful completion, these functions shall return the
+ // number of successfully matched and assigned input items
+ int cont = 0;
+ int suppress = 0;
+ for (; *format; format++) {
+ if (*format != '%' && !cont) {
+ char c;
+ if (isspace(*format))
+ continue;
+ if (EOF == (c = fgetc(stream))) {
+ break;
+ }
+ if (*format == c) // TODO: Make sure this is the correct behaviour
+ continue;
+ // TODO: Make sure this is the correct behaviour
+ errno = EINVAL;
+ assert(0);
+ break;
+ }
+
+ if (*format == '%' && !cont) {
+ cont = 1;
+ continue;
+ }
+
+ int is_long = 0;
+ switch (*format) {
+ case 'l':
+ is_long++;
+ assert(is_long < 3);
+ cont = 1;
+ break;
+ case 'i': // Matches an optionally signed integer, whose format is the same
+ // as expected for the subject sequence of strtol() with 0 for the
+ // base argument.
+ case 'd': {
+ // Matches an optionally signed decimal integer, whose format is the
+ // same as expected for the subject sequence of strtol() with the value
+ // 10 for the base argument. In the absence of a size modifier, the
+ // application shall ensure that the corresponding argument is a pointer
+ // to int.
+ int err = 0;
+ int result = ftnum(stream, 10, &err);
+ if (err) {
+ cont = 0;
+ break;
+ }
+ if (!suppress) {
+ if (2 == is_long) {
+ *((long long *)va_arg(ap, long long *)) = result;
+ } else if (1 == is_long) {
+ *((long *)va_arg(ap, long *)) = result;
+ } else {
+ *((int *)va_arg(ap, int *)) = result;
+ }
+ rc++;
+ }
+ assert(0 == err);
+ cont = 0;
+ break;
+ }
+ case 'c': {
+ char result = fgetc(stream);
+ if (!suppress) {
+ *((char *)va_arg(ap, char *)) = result;
+ rc++;
+ }
+ cont = 0;
+ break;
+ }
+ case '*': // Assignment suppression
+ suppress = 1;
+ cont = 1;
+ break;
+ default:
+ printf("vfscanf: Got %c but not supported.\n", *format);
+ assert(0);
+ break;
+ }
+ if (!cont) {
+ suppress = 0;
+ }
+ }
+ return rc;
+}
+
+struct sscanf_cookie {
+ const char *s;
+};
+
+size_t sscanf_read(FILE *f, unsigned char *s, size_t l) {
+ struct sscanf_cookie *c = f->cookie;
+ if (!*(c->s)) {
+ return 0;
+ }
+ size_t r = 0;
+ for (; l && *(c->s); l--, c->s += 1) {
+ *s = *(c->s);
+ s++;
+ r++;
+ }
+ if (!(*(c->s)))
+ f->is_eof = 1;
+ /*
+ memcpy(s, c->s, l);
+ c->s += l;*/
+ return r;
+}
+
+int vsscanf(const char *s, const char *restrict format, va_list ap) {
+ struct sscanf_cookie c = {.s = s};
+ FILE f = {
+ .read = sscanf_read,
+ .cookie = &c,
+ .has_buffered_char = 0,
+ .is_eof = 0,
+ .has_error = 0,
+ .offset_in_file = 0,
+ };
+ return vfscanf(&f, format, ap);
+}
+
+int sscanf(const char *s, const char *restrict format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ int rc = vsscanf(s, format, ap);
+ va_end(ap);
+ return rc;
+}
diff --git a/userland/libc/string/strcasecmp.c b/userland/libc/string/strcasecmp.c
new file mode 100644
index 0000000..eed337b
--- /dev/null
+++ b/userland/libc/string/strcasecmp.c
@@ -0,0 +1,28 @@
+#include <strings.h>
+
+int strcasecmp(const char *s1, const char *s2) {
+ // The strcmp() function shall compare the string pointed to by s1
+ // to the string pointed to by s2.
+ int l1, l2, rc;
+ l1 = l2 = rc = 0;
+ for (; (*s1 || *s2);) {
+ if (tolower(*s1) != tolower(*s2))
+ rc++;
+ if (*s1) {
+ l1++;
+ s1++;
+ }
+ if (*s2) {
+ l2++;
+ s2++;
+ }
+ }
+
+ // Upon completion, strcmp() shall return an integer greater than,
+ // equal to, or less than 0, if the string pointed to by s1 is
+ // greater than, equal to, or less than the string pointed to by
+ // s2, respectively.
+ if (l2 > l1)
+ return -rc;
+ return rc;
+}
diff --git a/userland/libc/string/strcat.c b/userland/libc/string/strcat.c
new file mode 100644
index 0000000..c430698
--- /dev/null
+++ b/userland/libc/string/strcat.c
@@ -0,0 +1,13 @@
+#include <string.h>
+
+char *strcat(char *s1, const char *s2) {
+ strcpy(s1 + strlen(s1), s2);
+ return s1;
+ /*
+char *r = s1;
+for (; *s1; s1++)
+;
+for (; *s2; s2++, s1++)
+*s1 = *s2;
+return r;*/
+}
diff --git a/userland/libc/string/strchr.c b/userland/libc/string/strchr.c
new file mode 100644
index 0000000..1995547
--- /dev/null
+++ b/userland/libc/string/strchr.c
@@ -0,0 +1,11 @@
+#include <string.h>
+
+char *strchr(const char *s, int c) {
+ for (; *s; s++) {
+ if (*s == (char)c)
+ return (char*)s;
+ }
+ if ((char)c == '\0')
+ return (char *)s;
+ return NULL;
+}
diff --git a/userland/libc/string/strcmp.c b/userland/libc/string/strcmp.c
new file mode 100644
index 0000000..368b8fb
--- /dev/null
+++ b/userland/libc/string/strcmp.c
@@ -0,0 +1,29 @@
+#include <string.h>
+
+// https://pubs.opengroup.org/onlinepubs/9699919799/
+int strcmp(const char *s1, const char *s2) {
+ // The strcmp() function shall compare the string pointed to by s1
+ // to the string pointed to by s2.
+ int l1, l2, rc;
+ l1 = l2 = rc = 0;
+ for (; *s1 || *s2;) {
+ if (*s1 != *s2)
+ rc++;
+ if (*s1) {
+ l1++;
+ s1++;
+ }
+ if (*s2) {
+ l2++;
+ s2++;
+ }
+ }
+
+ // Upon completion, strcmp() shall return an integer greater than,
+ // equal to, or less than 0, if the string pointed to by s1 is
+ // greater than, equal to, or less than the string pointed to by
+ // s2, respectively.
+ if (l2 > l1)
+ return -rc;
+ return rc;
+}
diff --git a/userland/libc/string/strcpy.c b/userland/libc/string/strcpy.c
new file mode 100644
index 0000000..9023fd1
--- /dev/null
+++ b/userland/libc/string/strcpy.c
@@ -0,0 +1,7 @@
+#include <string.h>
+
+char *strcpy(char *dest, const char *src) {
+ for (; (*dest = *src); dest++, src++)
+ ;
+ return dest;
+}
diff --git a/userland/libc/string/strcspn.c b/userland/libc/string/strcspn.c
new file mode 100644
index 0000000..2ad38d5
--- /dev/null
+++ b/userland/libc/string/strcspn.c
@@ -0,0 +1,14 @@
+#include <string.h>
+
+size_t strcspn(const char *s1, const char *s2) {
+ size_t r = 0;
+ for (; *s1; s1++) {
+ for (const char *t = s2; *t; t++) {
+ if (*s1 == *s2) {
+ r++;
+ break;
+ }
+ }
+ }
+ return r;
+}
diff --git a/userland/libc/string/strdup.c b/userland/libc/string/strdup.c
new file mode 100644
index 0000000..9e22f94
--- /dev/null
+++ b/userland/libc/string/strdup.c
@@ -0,0 +1,15 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+// The strdup() function shall return a pointer to a new string, which is a
+// duplicate of the string pointed to by s. The returned pointer can be passed
+// to free(). A null pointer is returned if the new string cannot be created.
+char *strdup(const char *s) {
+ size_t l = strlen(s);
+ char *r = malloc(l + 1);
+ if (!r)
+ return NULL;
+ strcpy(r, s);
+ return r;
+}
diff --git a/userland/libc/string/strlcpy.c b/userland/libc/string/strlcpy.c
new file mode 100644
index 0000000..a2d3dd9
--- /dev/null
+++ b/userland/libc/string/strlcpy.c
@@ -0,0 +1,20 @@
+#include <string.h>
+
+// Copy string s2 to buffer s1 of size n. At most n-1
+// chars will be copied. Always NUL terminates (unless n == 0).
+// Returns strlen(s2); if retval >= n, truncation occurred.
+size_t *strlcpy(char *s1, const char *s2, size_t n) {
+ size_t tmp_n = n;
+ const char *os2 = s2;
+ for (; tmp_n; tmp_n--) {
+ if ((*s1++ = *s2++) == '\0')
+ break;
+ }
+ if (tmp_n == 0) {
+ if (n != 0)
+ *s1 = '\0'; /* NUL-terminate s1 */
+ while (*s2++)
+ ;
+ }
+ return s2 - os2 - 1;
+}
diff --git a/userland/libc/string/strlen.c b/userland/libc/string/strlen.c
new file mode 100644
index 0000000..8e3e77a
--- /dev/null
+++ b/userland/libc/string/strlen.c
@@ -0,0 +1,8 @@
+#include <string.h>
+
+size_t strlen(const char *s) {
+ const char *d = s;
+ for (; *s; s++)
+ ;
+ return s - d;
+}
diff --git a/userland/libc/string/strncasecmp.c b/userland/libc/string/strncasecmp.c
new file mode 100644
index 0000000..9ce8c04
--- /dev/null
+++ b/userland/libc/string/strncasecmp.c
@@ -0,0 +1,29 @@
+#include <strings.h>
+#include <stddef.h>
+
+int strncasecmp(const char *s1, const char *s2, size_t n) {
+ // The strcmp() function shall compare the string pointed to by s1
+ // to the string pointed to by s2.
+ int l1, l2, rc;
+ l1 = l2 = rc = 0;
+ for (; (*s1 || *s2) && n > 0; n--) {
+ if (tolower(*s1) != tolower(*s2))
+ rc++;
+ if (*s1) {
+ l1++;
+ s1++;
+ }
+ if (*s2) {
+ l2++;
+ s2++;
+ }
+ }
+
+ // Upon completion, strcmp() shall return an integer greater than,
+ // equal to, or less than 0, if the string pointed to by s1 is
+ // greater than, equal to, or less than the string pointed to by
+ // s2, respectively.
+ if (l2 > l1)
+ return -rc;
+ return rc;
+}
diff --git a/userland/libc/string/strncmp.c b/userland/libc/string/strncmp.c
new file mode 100644
index 0000000..fd46189
--- /dev/null
+++ b/userland/libc/string/strncmp.c
@@ -0,0 +1,28 @@
+#include <string.h>
+
+int strncmp(const char *s1, const char *s2, size_t n) {
+ // The strcmp() function shall compare the string pointed to by s1
+ // to the string pointed to by s2.
+ int l1, l2, rc;
+ l1 = l2 = rc = 0;
+ for (; (*s1 || *s2) && n > 0; n--) {
+ if (*s1 != *s2)
+ rc++;
+ if (*s1) {
+ l1++;
+ s1++;
+ }
+ if (*s2) {
+ l2++;
+ s2++;
+ }
+ }
+
+ // Upon completion, strcmp() shall return an integer greater than,
+ // equal to, or less than 0, if the string pointed to by s1 is
+ // greater than, equal to, or less than the string pointed to by
+ // s2, respectively.
+ if (l2 > l1)
+ return -rc;
+ return rc;
+}
diff --git a/userland/libc/string/strncpy.c b/userland/libc/string/strncpy.c
new file mode 100644
index 0000000..0e88c63
--- /dev/null
+++ b/userland/libc/string/strncpy.c
@@ -0,0 +1,13 @@
+#include <string.h>
+
+char *strncpy(char *s1, const char *s2, size_t n) {
+ char *rc = s1;
+ for (; n > 0; s1++, s2++, n--) {
+ *s1 = *s2;
+ if (!*s2)
+ break;
+ }
+ for (; n > 0; n--,s1++)
+ *s1 = '\0';
+ return rc;
+}
diff --git a/userland/libc/string/strndup.c b/userland/libc/string/strndup.c
new file mode 100644
index 0000000..ffb2088
--- /dev/null
+++ b/userland/libc/string/strndup.c
@@ -0,0 +1,22 @@
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+// The strndup() function shall be equivalent to the strdup() function,
+// duplicating the provided s in a new block of memory allocated as if
+// by using malloc(), with the exception being that strndup() copies at
+// most size plus one bytes into the newly allocated memory, terminating
+// the new string with a NUL character. If the length of s is larger
+// than size, only size bytes shall be duplicated. If size is larger
+// than the length of s, all bytes in s shall be copied into the new
+// memory buffer, including the terminating NUL character. The newly
+// created string shall always be properly terminated.
+char *strndup(const char *s, size_t size) {
+ size_t l = strlen(s);
+ size_t real_l = min(l, size);
+ char *r = malloc(real_l + 1);
+ if (!r)
+ return NULL;
+ strlcpy(r, s, real_l);
+ return r;
+}
diff --git a/userland/libc/string/strnlen.c b/userland/libc/string/strnlen.c
new file mode 100644
index 0000000..86df42e
--- /dev/null
+++ b/userland/libc/string/strnlen.c
@@ -0,0 +1,9 @@
+#include <string.h>
+
+size_t strnlen(const char *s, size_t maxlen) {
+ size_t i;
+ for (i = 0; i < maxlen; i++)
+ if (s[i] == 0)
+ break;
+ return i;
+}
diff --git a/userland/libc/string/strpbrk.c b/userland/libc/string/strpbrk.c
new file mode 100644
index 0000000..fb16b0c
--- /dev/null
+++ b/userland/libc/string/strpbrk.c
@@ -0,0 +1,12 @@
+#include <string.h>
+
+char *strpbrk(const char *s1, const char *s2) {
+ for (; *s1; s1++) {
+ for (const char *t = s2; *t; t++) {
+ if (*s1 == *t) {
+ return s1;
+ }
+ }
+ }
+ return NULL;
+}
diff --git a/userland/libc/string/strrchr.c b/userland/libc/string/strrchr.c
new file mode 100644
index 0000000..a44199a
--- /dev/null
+++ b/userland/libc/string/strrchr.c
@@ -0,0 +1,12 @@
+#include <string.h>
+
+char *strrchr(const char *s, int c) {
+ char *last = NULL;
+ for (; *s; s++) {
+ if (*s == (char)c)
+ last = (char *)s;
+ }
+ if ((char)c == '\0')
+ last = (char*)s;
+ return last;
+}
diff --git a/userland/libc/string/strspn.c b/userland/libc/string/strspn.c
new file mode 100644
index 0000000..2a7d3ae
--- /dev/null
+++ b/userland/libc/string/strspn.c
@@ -0,0 +1,18 @@
+#include <string.h>
+
+size_t strspn(const char *s1, const char *s2) {
+ size_t r = 0;
+ for (; *s1; s1++) {
+ int e = 0;
+ for (const char *t = s2; *t; t++) {
+ if (*s1 == *t) {
+ e = 1;
+ break;
+ }
+ }
+ if (!e)
+ break;
+ r++;
+ }
+ return r;
+}
diff --git a/userland/libc/string/strstr.c b/userland/libc/string/strstr.c
new file mode 100644
index 0000000..20b9dc2
--- /dev/null
+++ b/userland/libc/string/strstr.c
@@ -0,0 +1,21 @@
+#include <string.h>
+
+char *strstr(const char *s1, const char *s2) {
+ // If s2 points to a string with zero length, the function shall return s1.
+ if ('\0' == *s2)
+ return s1;
+ for (; *s1; s1++) {
+ const char *t1 = s1;
+ const char *t2 = s2;
+ int is_dif = 0;
+ for (; *t2 && *t1; t1++, t2++) {
+ if (*t2 != *t1) {
+ is_dif = 1;
+ break;
+ }
+ }
+ if (!is_dif)
+ return s1;
+ }
+ return NULL;
+}
diff --git a/userland/libc/string/strtok.c b/userland/libc/string/strtok.c
new file mode 100644
index 0000000..7b8d0e3
--- /dev/null
+++ b/userland/libc/string/strtok.c
@@ -0,0 +1,26 @@
+#include <string.h>
+
+char *strtok_s;
+
+char *strtok(char *restrict s, const char *restrict sep) {
+ if (s) {
+ strtok_s = s;
+ return strtok(NULL, sep);
+ }
+ if(!strtok_s)
+ return NULL;
+ char *e = strpbrk(strtok_s, sep);
+ if (!e) {
+ char *r = strtok_s;
+ strtok_s = NULL;
+ return r;
+ }
+ *e = '\0';
+ e--;
+ for (; *sep; sep++)
+ e++;
+ e++;
+ char *r = strtok_s;
+ strtok_s = e;
+ return r;
+}