mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-28 15:34:31 +00:00
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:
parent
6dfefc90c4
commit
0f9a1915d1
@ -26,43 +26,43 @@ extern "C"
|
||||
#include <stddef.h>
|
||||
#include <locale.h>
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -18,10 +18,53 @@
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <fennix/syscalls.h>
|
||||
#include <errno.h>
|
||||
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user