feat(userspace/libc): implement all <string.h> functions

Implement all string.h functions except some which require locale which is not implemented yet

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
This commit is contained in:
EnderIce2 2025-02-14 22:15:20 +02:00
parent 6dfefc90c4
commit 0f9a1915d1
No known key found for this signature in database
GPG Key ID: 2EE20AF089811A5A
2 changed files with 459 additions and 46 deletions

View File

@ -26,43 +26,43 @@ extern "C"
#include <stddef.h> #include <stddef.h>
#include <locale.h> #include <locale.h>
void *memccpy(void *restrict, const void *restrict, int, size_t); void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n);
void *memchr(const void *, int, size_t); void *memchr(const void *s, int c, size_t n);
int memcmp(const void *, const void *, size_t); int memcmp(const void *s1, const void *s2, size_t n);
void *memcpy(void *restrict s1, const void *restrict 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 *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
void *memmove(void *, const void *, size_t); void *memmove(void *s1, const void *s2, size_t n);
void *memset(void *, int, size_t); void *memset(void *s, int c, size_t n);
char *stpcpy(char *restrict, const char *restrict); char *stpcpy(char *restrict s1, const char *restrict s2);
char *stpncpy(char *restrict, const char *restrict, size_t); char *stpncpy(char *restrict s1, const char *restrict s2, size_t n);
char *strcat(char *restrict, const char *restrict); char *strcat(char *restrict s1, const char *restrict s2);
char *strchr(const char *s, int c); char *strchr(const char *s, int c);
int strcmp(const char *s1, const char *s2); int strcmp(const char *s1, const char *s2);
int strcoll(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); char *strcpy(char *restrict s1, const char *restrict s2);
size_t strcspn(const char *s1, const char *s2); size_t strcspn(const char *s1, const char *s2);
char *strdup(const char *); char *strdup(const char *s);
char *strerror(int); char *strerror(int errnum);
char *strerror_l(int, locale_t); char *strerror_l(int errnum, locale_t locale);
int strerror_r(int, char *, size_t); int strerror_r(int errnum, char *strerrbuf, size_t buflen);
size_t strlcat(char *restrict, const char *restrict, size_t); size_t strlcat(char *restrict dst, const char *restrict src, size_t dstsize);
size_t strlcpy(char *restrict, const char *restrict, size_t); size_t strlcpy(char *restrict dst, const char *restrict src, size_t dstsize);
size_t strlen(const char *s); 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); int strncmp(const char *s1, const char *s2, size_t n);
char *strncpy(char *restrict s1, const char *restrict s2, size_t n); char *strncpy(char *restrict s1, const char *restrict s2, size_t n);
char *strndup(const char *, size_t); char *strndup(const char *s, size_t size);
size_t strnlen(const char *, size_t); size_t strnlen(const char *s, size_t maxlen);
char *strpbrk(const char *s1, const char *s2); char *strpbrk(const char *s1, const char *s2);
char *strrchr(const char *, int); char *strrchr(const char *s, int c);
char *strsignal(int signum); char *strsignal(int signum);
size_t strspn(const char *s1, const char *s2); 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(char *restrict s, const char *restrict sep);
char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state); 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(char *restrict s1, const char *restrict s2, size_t n);
size_t strxfrm_l(char *restrict, const char *restrict, size_t, locale_t); size_t strxfrm_l(char *restrict s1, const char *restrict s2, size_t n, locale_t locale);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -18,10 +18,53 @@
#include <sys/types.h> #include <sys/types.h>
#include <string.h> #include <string.h>
#include <fennix/syscalls.h> #include <fennix/syscalls.h>
#include <errno.h>
export void *memccpy(void *restrict, const void *restrict, int, size_t); export void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n)
export void *memchr(const void *, int, size_t); {
export int memcmp(const void *, const void *, size_t); 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) 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; return s1;
} }
export void *memmem(const void *, size_t, const void *, size_t); export void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen)
export void *memmove(void *, const void *, size_t); {
export void *memset(void *, int, size_t); const unsigned char *h = (const unsigned char *)haystack;
export char *stpcpy(char *restrict, const char *restrict); const unsigned char *n = (const unsigned char *)needle;
export char *stpncpy(char *restrict, const char *restrict, size_t);
export char *strcat(char *restrict, const char *restrict); 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) 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; 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) 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; return p - 1 - s1;
} }
export char *strdup(const char *); export char *strdup(const char *s)
export char *strerror(int); {
export char *strerror_l(int, locale_t); size_t len = strlen(s) + 1;
export int strerror_r(int, char *, size_t); char *new_str = (char *)malloc(len);
export size_t strlcat(char *restrict, const char *restrict, size_t); if (!new_str)
export size_t strlcpy(char *restrict, const char *restrict, size_t); 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) export size_t strlen(const char *s)
{ {
@ -126,7 +468,18 @@ export size_t strlen(const char *s)
return s - start; 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) 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; return s1;
} }
export char *strndup(const char *, size_t); export char *strndup(const char *s, size_t size)
export size_t strnlen(const char *, size_t); {
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) export char *strpbrk(const char *s1, const char *s2)
{ {
@ -174,7 +543,16 @@ export char *strpbrk(const char *s1, const char *s2)
return NULL; 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) export char *strsignal(int signum)
{ {
@ -259,7 +637,28 @@ cont:
return p - 1 - s1; 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) 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; return start;
} }
export size_t strxfrm(char *restrict, const char *restrict, size_t); export size_t strxfrm(char *restrict s1, const char *restrict s2, size_t n)
export size_t strxfrm_l(char *restrict, const char *restrict, size_t, locale_t); {
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);