From 0f9a1915d1ecf701bfe91d1274f0052592a671dd Mon Sep 17 00:00:00 2001 From: EnderIce2 Date: Fri, 14 Feb 2025 22:15:20 +0200 Subject: [PATCH] feat(userspace/libc): implement all functions Implement all string.h functions except some which require locale which is not implemented yet Signed-off-by: EnderIce2 --- Userspace/libc/include/string.h | 46 ++-- Userspace/libc/src/std/string.c | 459 ++++++++++++++++++++++++++++++-- 2 files changed, 459 insertions(+), 46 deletions(-) diff --git a/Userspace/libc/include/string.h b/Userspace/libc/include/string.h index 59ce07c4..014f5c79 100644 --- a/Userspace/libc/include/string.h +++ b/Userspace/libc/include/string.h @@ -26,43 +26,43 @@ extern "C" #include #include - void *memccpy(void *restrict, const void *restrict, int, size_t); - void *memchr(const void *, int, size_t); - int memcmp(const void *, const void *, size_t); + void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n); + void *memchr(const void *s, int c, size_t n); + int memcmp(const void *s1, const void *s2, size_t n); void *memcpy(void *restrict s1, const void *restrict s2, size_t n); - void *memmem(const void *, size_t, const void *, size_t); - void *memmove(void *, const void *, size_t); - void *memset(void *, int, size_t); - char *stpcpy(char *restrict, const char *restrict); - char *stpncpy(char *restrict, const char *restrict, size_t); - char *strcat(char *restrict, const char *restrict); + void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); + void *memmove(void *s1, const void *s2, size_t n); + void *memset(void *s, int c, size_t n); + char *stpcpy(char *restrict s1, const char *restrict s2); + char *stpncpy(char *restrict s1, const char *restrict s2, size_t n); + char *strcat(char *restrict s1, const char *restrict s2); char *strchr(const char *s, int c); int strcmp(const char *s1, const char *s2); int strcoll(const char *s1, const char *s2); - int strcoll_l(const char *, const char *, locale_t); + int strcoll_l(const char *s1, const char *s2, locale_t locale); char *strcpy(char *restrict s1, const char *restrict s2); size_t strcspn(const char *s1, const char *s2); - char *strdup(const char *); - char *strerror(int); - char *strerror_l(int, locale_t); - int strerror_r(int, char *, size_t); - size_t strlcat(char *restrict, const char *restrict, size_t); - size_t strlcpy(char *restrict, const char *restrict, size_t); + char *strdup(const char *s); + char *strerror(int errnum); + char *strerror_l(int errnum, locale_t locale); + int strerror_r(int errnum, char *strerrbuf, size_t buflen); + size_t strlcat(char *restrict dst, const char *restrict src, size_t dstsize); + size_t strlcpy(char *restrict dst, const char *restrict src, size_t dstsize); size_t strlen(const char *s); - char *strncat(char *restrict, const char *restrict, size_t); + char *strncat(char *restrict s1, const char *restrict s2, size_t n); int strncmp(const char *s1, const char *s2, size_t n); char *strncpy(char *restrict s1, const char *restrict s2, size_t n); - char *strndup(const char *, size_t); - size_t strnlen(const char *, size_t); + char *strndup(const char *s, size_t size); + size_t strnlen(const char *s, size_t maxlen); char *strpbrk(const char *s1, const char *s2); - char *strrchr(const char *, int); + char *strrchr(const char *s, int c); char *strsignal(int signum); size_t strspn(const char *s1, const char *s2); - char *strstr(const char *, const char *); + char *strstr(const char *s1, const char *s2); char *strtok(char *restrict s, const char *restrict sep); char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state); - size_t strxfrm(char *restrict, const char *restrict, size_t); - size_t strxfrm_l(char *restrict, const char *restrict, size_t, locale_t); + size_t strxfrm(char *restrict s1, const char *restrict s2, size_t n); + size_t strxfrm_l(char *restrict s1, const char *restrict s2, size_t n, locale_t locale); #ifdef __cplusplus } diff --git a/Userspace/libc/src/std/string.c b/Userspace/libc/src/std/string.c index c24cc099..e5fe327d 100644 --- a/Userspace/libc/src/std/string.c +++ b/Userspace/libc/src/std/string.c @@ -18,10 +18,53 @@ #include #include #include +#include -export void *memccpy(void *restrict, const void *restrict, int, size_t); -export void *memchr(const void *, int, size_t); -export int memcmp(const void *, const void *, size_t); +export void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n) +{ + unsigned char *dest = (unsigned char *)s1; + const unsigned char *src = (const unsigned char *)s2; + unsigned char uc = (unsigned char)c; + + while (n--) + { + *dest = *src; + if (*src == uc) + return (void *)(dest + 1); + dest++; + src++; + } + return NULL; +} + +export void *memchr(const void *s, int c, size_t n) +{ + const unsigned char *src = (const unsigned char *)s; + unsigned char uc = (unsigned char)c; + + while (n--) + { + if (*src == uc) + return (void *)src; + src++; + } + return NULL; +} + +export int memcmp(const void *s1, const void *s2, size_t n) +{ + const unsigned char *p1 = (const unsigned char *)s1; + const unsigned char *p2 = (const unsigned char *)s2; + + while (n--) + { + if (*p1 != *p2) + return *p1 - *p2; + p1++; + p2++; + } + return 0; +} export void *memcpy(void *restrict s1, const void *restrict s2, size_t n) { @@ -41,12 +84,87 @@ export void *memcpy(void *restrict s1, const void *restrict s2, size_t n) return s1; } -export void *memmem(const void *, size_t, const void *, size_t); -export void *memmove(void *, const void *, size_t); -export void *memset(void *, int, size_t); -export char *stpcpy(char *restrict, const char *restrict); -export char *stpncpy(char *restrict, const char *restrict, size_t); -export char *strcat(char *restrict, const char *restrict); +export void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) +{ + const unsigned char *h = (const unsigned char *)haystack; + const unsigned char *n = (const unsigned char *)needle; + + if (needlelen == 0) + return (void *)haystack; + + if (haystacklen < needlelen) + return NULL; + + for (size_t i = 0; i <= haystacklen - needlelen; i++) + { + if (memcmp(h + i, n, needlelen) == 0) + return (void *)(h + i); + } + + return NULL; +} + +export void *memmove(void *s1, const void *s2, size_t n) +{ + unsigned char *dest = (unsigned char *)s1; + const unsigned char *src = (const unsigned char *)s2; + + if (dest < src) + { + while (n--) + *dest++ = *src++; + } + else + { + dest += n; + src += n; + while (n--) + *--dest = *--src; + } + + return s1; +} + +export void *memset(void *s, int c, size_t n) +{ + unsigned char *p = (unsigned char *)s; + while (n--) + *p++ = (unsigned char)c; + return s; +} + +export char *stpcpy(char *restrict s1, const char *restrict s2) +{ + while ((*s1 = *s2) != '\0') + { + s1++; + s2++; + } + return s1; +} + +export char *stpncpy(char *restrict s1, const char *restrict s2, size_t n) +{ + char *dest = s1; + while (n && (*dest++ = *s2++)) + n--; + + if (n) + while (--n) + *dest++ = '\0'; + + return dest - 1; +} + +export char *strcat(char *restrict s1, const char *restrict s2) +{ + char *dest = s1; + while (*dest) + dest++; + while ((*dest++ = *s2++)) + ; + return s1; +} export char *strchr(const char *s, int c) { @@ -83,7 +201,7 @@ export int strcoll(const char *s1, const char *s2) return *(unsigned char *)s1 - *(unsigned char *)s2; } -export int strcoll_l(const char *, const char *, locale_t); +export int strcoll_l(const char *s1, const char *s2, locale_t locale); export char *strcpy(char *restrict s1, const char *restrict s2) { @@ -111,12 +229,236 @@ export size_t strcspn(const char *s1, const char *s2) return p - 1 - s1; } -export char *strdup(const char *); -export char *strerror(int); -export char *strerror_l(int, locale_t); -export int strerror_r(int, char *, size_t); -export size_t strlcat(char *restrict, const char *restrict, size_t); -export size_t strlcpy(char *restrict, const char *restrict, size_t); +export char *strdup(const char *s) +{ + size_t len = strlen(s) + 1; + char *new_str = (char *)malloc(len); + if (!new_str) + return NULL; + memcpy(new_str, s, len); + return new_str; +} + +export char *strerror(int errnum) +{ + static char unknown_error[32]; + switch (errnum) + { + case 0: + return "No error"; + case E2BIG: + return "Argument list too long"; + case EACCES: + return "Permission denied"; + case EADDRINUSE: + return "Address in use"; + case EADDRNOTAVAIL: + return "Address not available"; + case EAFNOSUPPORT: + return "Address family not supported"; + case EAGAIN: + return "Resource temporarily unavailable"; + case EALREADY: + return "Connection already in progress"; + case EBADF: + return "Bad file descriptor"; + case EBADMSG: + return "Bad message"; + case EBUSY: + return "Resource busy"; + case ECANCELED: + return "Operation canceled"; + case ECHILD: + return "No child process"; + case ECONNABORTED: + return "Connection aborted"; + case ECONNREFUSED: + return "Connection refused"; + case ECONNRESET: + return "Connection reset"; + case EDEADLK: + return "Resource deadlock would occur"; + case EDESTADDRREQ: + return "Destination address required"; + case EDOM: + return "Domain error"; + case EEXIST: + return "File exists"; + case EFAULT: + return "Bad address"; + case EFBIG: + return "File too large"; + case EHOSTUNREACH: + return "Host is unreachable"; + case EIDRM: + return "Identifier removed"; + case EILSEQ: + return "Illegal byte sequence"; + case EINPROGRESS: + return "Operation in progress"; + case EINTR: + return "Interrupted function call"; + case EINVAL: + return "Invalid argument"; + case EIO: + return "Input/output error"; + case EISCONN: + return "Socket is connected"; + case EISDIR: + return "Is a directory"; + case ELOOP: + return "Symbolic link loop"; + case EMFILE: + return "File descriptor value too large or too many open streams"; + case EMLINK: + return "Too many links"; + case EMSGSIZE: + return "Message too large"; + case ENAMETOOLONG: + return "Filename too long"; + case ENETDOWN: + return "Network is down"; + case ENETRESET: + return "The connection was aborted by the network"; + case ENETUNREACH: + return "Network unreachable"; + case ENFILE: + return "Too many files open in system"; + case ENOBUFS: + return "No buffer space available"; + case ENODATA: + return "No message available"; + case ENODEV: + return "No such device"; + case ENOENT: + return "No such file or directory"; + case ENOEXEC: + return "Executable file format error"; + case ENOLCK: + return "No locks available"; + case ENOMEM: + return "Not enough space"; + case ENOMSG: + return "No message of the desired type"; + case ENOPROTOOPT: + return "Protocol not available"; + case ENOSPC: + return "No space left on device"; + case ENOSR: + return "No STREAM resources"; + case ENOSTR: + return "Not a STREAM"; + case ENOSYS: + return "Functionality not supported"; + case ENOTCONN: + return "Socket not connected"; + case ENOTDIR: + return "Not a directory"; + case ENOTEMPTY: + return "Directory not empty"; + case ENOTRECOVERABLE: + return "State not recoverable"; + case ENOTSOCK: + return "Not a socket"; + case ENOTSUP: + return "Not supported"; + case ENOTTY: + return "Inappropriate I/O control operation"; + case ENXIO: + return "No such device or address"; + case EOPNOTSUPP: + return "Operation not supported on socket"; + case EOVERFLOW: + return "Value too large to be stored in data type"; + case EOWNERDEAD: + return "Previous owner died"; + case EPERM: + return "Operation not permitted"; + case EPIPE: + return "Broken pipe"; + case EPROTO: + return "Protocol error"; + case EPROTONOSUPPORT: + return "Protocol not supported"; + case EPROTOTYPE: + return "Protocol wrong type for socket"; + case ERANGE: + return "Result too large"; + case EROFS: + return "Read-only file system"; + case ESPIPE: + return "Invalid seek"; + case ESRCH: + return "No such process"; + case ETIME: + return "STREAM ioctl() timeout"; + case ETIMEDOUT: + return "Connection timed out"; + case ETXTBSY: + return "Text file busy"; + case EWOULDBLOCK: + return "Operation would block"; + case EXDEV: + return "Improper link"; + default: + snprintf(unknown_error, sizeof(unknown_error), "Unknown error %d", errnum); + return unknown_error; + } +} + +export char *strerror_l(int errnum, locale_t locale); + +export int strerror_r(int errnum, char *strerrbuf, size_t buflen) +{ + const char *errmsg = strerror(errnum); + if (strlen(errmsg) >= buflen) + { + if (buflen > 0) + { + strncpy(strerrbuf, errmsg, buflen - 1); + strerrbuf[buflen - 1] = '\0'; + } + return ERANGE; + } + else + { + strcpy(strerrbuf, errmsg); + return 0; + } +} + +size_t strlcat(char *restrict dst, const char *restrict src, size_t dstsize) +{ + size_t dst_len = strnlen(dst, dstsize); + size_t src_len = strlen(src); + + if (dst_len == dstsize) + return dstsize + src_len; + + if (src_len < dstsize - dst_len) + memcpy(dst + dst_len, src, src_len + 1); + else + { + memcpy(dst + dst_len, src, dstsize - dst_len - 1); + dst[dstsize - 1] = '\0'; + } + + return dst_len + src_len; +} + +size_t strlcpy(char *restrict dst, const char *restrict src, size_t dstsize) +{ + size_t src_len = strlen(src); + + if (dstsize != 0) + { + size_t copy_len = (src_len >= dstsize) ? dstsize - 1 : src_len; + memcpy(dst, src, copy_len); + dst[copy_len] = '\0'; + } + + return src_len; +} export size_t strlen(const char *s) { @@ -126,7 +468,18 @@ export size_t strlen(const char *s) return s - start; } -export char *strncat(char *restrict, const char *restrict, size_t); +export char *strncat(char *restrict s1, const char *restrict s2, size_t n) +{ + char *dest = s1; + while (*dest) + dest++; + + while (n-- && *s2) + *dest++ = *s2++; + + *dest = '\0'; + return s1; +} export int strncmp(const char *s1, const char *s2, size_t n) { @@ -155,8 +508,24 @@ export char *strncpy(char *restrict s1, const char *restrict s2, size_t n) return s1; } -export char *strndup(const char *, size_t); -export size_t strnlen(const char *, size_t); +export char *strndup(const char *s, size_t size) +{ + size_t len = strnlen(s, size); + char *new_str = (char *)malloc(len + 1); + if (!new_str) + return NULL; + memcpy(new_str, s, len); + new_str[len] = '\0'; + return new_str; +} + +export size_t strnlen(const char *s, size_t maxlen) +{ + size_t len = 0; + while (len < maxlen && s[len] != '\0') + len++; + return len; +} export char *strpbrk(const char *s1, const char *s2) { @@ -174,7 +543,16 @@ export char *strpbrk(const char *s1, const char *s2) return NULL; } -export char *strrchr(const char *, int); +export char *strrchr(const char *s, int c) +{ + const char *last = NULL; + do + { + if (*s == (char)c) + last = s; + } while (*s++); + return (char *)last; +} export char *strsignal(int signum) { @@ -259,7 +637,28 @@ cont: return p - 1 - s1; } -export char *strstr(const char *, const char *); +export char *strstr(const char *s1, const char *s2) +{ + if (!*s2) + return (char *)s1; + + for (; *s1; s1++) + { + const char *h = s1; + const char *n = s2; + + while (*h && *n && *h == *n) + { + h++; + n++; + } + + if (!*n) + return (char *)s1; + } + + return NULL; +} export char *strtok(char *restrict s, const char *restrict sep) { @@ -295,5 +694,19 @@ export char *strtok_r(char *restrict s, const char *restrict sep, char **restric return start; } -export size_t strxfrm(char *restrict, const char *restrict, size_t); -export size_t strxfrm_l(char *restrict, const char *restrict, size_t, locale_t); +export size_t strxfrm(char *restrict s1, const char *restrict s2, size_t n) +{ + size_t len = 0; + while (s2[len] != '\0' && len < n - 1) + { + s1[len] = s2[len]; + len++; + } + if (n > 0) + s1[len] = '\0'; + while (s2[len] != '\0') + len++; + return len; +} + +export size_t strxfrm_l(char *restrict s1, const char *restrict s2, size_t n, locale_t locale);