diff options
Diffstat (limited to 'userland/libc/string')
-rw-r--r-- | userland/libc/string/memcmp.c | 11 | ||||
-rw-r--r-- | userland/libc/string/memcpy.c | 9 | ||||
-rw-r--r-- | userland/libc/string/memmove.c | 14 | ||||
-rw-r--r-- | userland/libc/string/sscanf.c | 193 | ||||
-rw-r--r-- | userland/libc/string/strcasecmp.c | 28 | ||||
-rw-r--r-- | userland/libc/string/strcat.c | 13 | ||||
-rw-r--r-- | userland/libc/string/strchr.c | 11 | ||||
-rw-r--r-- | userland/libc/string/strcmp.c | 29 | ||||
-rw-r--r-- | userland/libc/string/strcpy.c | 7 | ||||
-rw-r--r-- | userland/libc/string/strcspn.c | 14 | ||||
-rw-r--r-- | userland/libc/string/strdup.c | 15 | ||||
-rw-r--r-- | userland/libc/string/strlcpy.c | 20 | ||||
-rw-r--r-- | userland/libc/string/strlen.c | 8 | ||||
-rw-r--r-- | userland/libc/string/strncasecmp.c | 29 | ||||
-rw-r--r-- | userland/libc/string/strncmp.c | 28 | ||||
-rw-r--r-- | userland/libc/string/strncpy.c | 13 | ||||
-rw-r--r-- | userland/libc/string/strndup.c | 22 | ||||
-rw-r--r-- | userland/libc/string/strnlen.c | 9 | ||||
-rw-r--r-- | userland/libc/string/strpbrk.c | 12 | ||||
-rw-r--r-- | userland/libc/string/strrchr.c | 12 | ||||
-rw-r--r-- | userland/libc/string/strspn.c | 18 | ||||
-rw-r--r-- | userland/libc/string/strstr.c | 21 | ||||
-rw-r--r-- | userland/libc/string/strtok.c | 26 |
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; +} |