feat(userspace/libc): complete <string.h> implementation

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
This commit is contained in:
EnderIce2 2025-02-19 18:54:20 +02:00
parent 2ae18af9a0
commit 4bb8ce6d00
No known key found for this signature in database
GPG Key ID: 2EE20AF089811A5A

View File

@ -19,6 +19,8 @@
#include <string.h> #include <string.h>
#include <fennix/syscalls.h> #include <fennix/syscalls.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h>
#include <stdio.h>
export void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n) export void *memccpy(void *restrict s1, const void *restrict s2, int c, size_t n)
{ {
@ -145,15 +147,17 @@ export char *stpcpy(char *restrict s1, const char *restrict s2)
export char *stpncpy(char *restrict s1, const char *restrict s2, size_t n) export char *stpncpy(char *restrict s1, const char *restrict s2, size_t n)
{ {
char *dest = s1; for (int i = 0; i < n; ++i)
while (n && (*dest++ = *s2++)) {
n--; char buf = s2[i];
s1[i] = buf;
if (n) if (buf != '\0')
while (--n) continue;
*dest++ = '\0'; for (int j = i + 1; j < n; ++j)
s1[j] = '\0';
return dest - 1; return s1 + i;
}
return s1 + n;
} }
export char *strcat(char *restrict s1, const char *restrict s2) export char *strcat(char *restrict s1, const char *restrict s2)
@ -239,172 +243,173 @@ export char *strdup(const char *s)
return new_str; return new_str;
} }
export char *strerror(int errnum) /* already defined in src/std/errno.c */
{ // export char *strerror(int errnum)
static char unknown_error[32]; // {
switch (errnum) // static char unknown_error[32];
{ // switch (errnum)
case 0: // {
return "No error"; // case 0:
case E2BIG: // return "No error";
return "Argument list too long"; // case E2BIG:
case EACCES: // return "Argument list too long";
return "Permission denied"; // case EACCES:
case EADDRINUSE: // return "Permission denied";
return "Address in use"; // case EADDRINUSE:
case EADDRNOTAVAIL: // return "Address in use";
return "Address not available"; // case EADDRNOTAVAIL:
case EAFNOSUPPORT: // return "Address not available";
return "Address family not supported"; // case EAFNOSUPPORT:
case EAGAIN: // return "Address family not supported";
return "Resource temporarily unavailable"; // case EAGAIN:
case EALREADY: // return "Resource temporarily unavailable";
return "Connection already in progress"; // case EALREADY:
case EBADF: // return "Connection already in progress";
return "Bad file descriptor"; // case EBADF:
case EBADMSG: // return "Bad file descriptor";
return "Bad message"; // case EBADMSG:
case EBUSY: // return "Bad message";
return "Resource busy"; // case EBUSY:
case ECANCELED: // return "Resource busy";
return "Operation canceled"; // case ECANCELED:
case ECHILD: // return "Operation canceled";
return "No child process"; // case ECHILD:
case ECONNABORTED: // return "No child process";
return "Connection aborted"; // case ECONNABORTED:
case ECONNREFUSED: // return "Connection aborted";
return "Connection refused"; // case ECONNREFUSED:
case ECONNRESET: // return "Connection refused";
return "Connection reset"; // case ECONNRESET:
case EDEADLK: // return "Connection reset";
return "Resource deadlock would occur"; // case EDEADLK:
case EDESTADDRREQ: // return "Resource deadlock would occur";
return "Destination address required"; // case EDESTADDRREQ:
case EDOM: // return "Destination address required";
return "Domain error"; // case EDOM:
case EEXIST: // return "Domain error";
return "File exists"; // case EEXIST:
case EFAULT: // return "File exists";
return "Bad address"; // case EFAULT:
case EFBIG: // return "Bad address";
return "File too large"; // case EFBIG:
case EHOSTUNREACH: // return "File too large";
return "Host is unreachable"; // case EHOSTUNREACH:
case EIDRM: // return "Host is unreachable";
return "Identifier removed"; // case EIDRM:
case EILSEQ: // return "Identifier removed";
return "Illegal byte sequence"; // case EILSEQ:
case EINPROGRESS: // return "Illegal byte sequence";
return "Operation in progress"; // case EINPROGRESS:
case EINTR: // return "Operation in progress";
return "Interrupted function call"; // case EINTR:
case EINVAL: // return "Interrupted function call";
return "Invalid argument"; // case EINVAL:
case EIO: // return "Invalid argument";
return "Input/output error"; // case EIO:
case EISCONN: // return "Input/output error";
return "Socket is connected"; // case EISCONN:
case EISDIR: // return "Socket is connected";
return "Is a directory"; // case EISDIR:
case ELOOP: // return "Is a directory";
return "Symbolic link loop"; // case ELOOP:
case EMFILE: // return "Symbolic link loop";
return "File descriptor value too large or too many open streams"; // case EMFILE:
case EMLINK: // return "File descriptor value too large or too many open streams";
return "Too many links"; // case EMLINK:
case EMSGSIZE: // return "Too many links";
return "Message too large"; // case EMSGSIZE:
case ENAMETOOLONG: // return "Message too large";
return "Filename too long"; // case ENAMETOOLONG:
case ENETDOWN: // return "Filename too long";
return "Network is down"; // case ENETDOWN:
case ENETRESET: // return "Network is down";
return "The connection was aborted by the network"; // case ENETRESET:
case ENETUNREACH: // return "The connection was aborted by the network";
return "Network unreachable"; // case ENETUNREACH:
case ENFILE: // return "Network unreachable";
return "Too many files open in system"; // case ENFILE:
case ENOBUFS: // return "Too many files open in system";
return "No buffer space available"; // case ENOBUFS:
case ENODATA: // return "No buffer space available";
return "No message available"; // case ENODATA:
case ENODEV: // return "No message available";
return "No such device"; // case ENODEV:
case ENOENT: // return "No such device";
return "No such file or directory"; // case ENOENT:
case ENOEXEC: // return "No such file or directory";
return "Executable file format error"; // case ENOEXEC:
case ENOLCK: // return "Executable file format error";
return "No locks available"; // case ENOLCK:
case ENOMEM: // return "No locks available";
return "Not enough space"; // case ENOMEM:
case ENOMSG: // return "Not enough space";
return "No message of the desired type"; // case ENOMSG:
case ENOPROTOOPT: // return "No message of the desired type";
return "Protocol not available"; // case ENOPROTOOPT:
case ENOSPC: // return "Protocol not available";
return "No space left on device"; // case ENOSPC:
case ENOSR: // return "No space left on device";
return "No STREAM resources"; // case ENOSR:
case ENOSTR: // return "No STREAM resources";
return "Not a STREAM"; // case ENOSTR:
case ENOSYS: // return "Not a STREAM";
return "Functionality not supported"; // case ENOSYS:
case ENOTCONN: // return "Functionality not supported";
return "Socket not connected"; // case ENOTCONN:
case ENOTDIR: // return "Socket not connected";
return "Not a directory"; // case ENOTDIR:
case ENOTEMPTY: // return "Not a directory";
return "Directory not empty"; // case ENOTEMPTY:
case ENOTRECOVERABLE: // return "Directory not empty";
return "State not recoverable"; // case ENOTRECOVERABLE:
case ENOTSOCK: // return "State not recoverable";
return "Not a socket"; // case ENOTSOCK:
case ENOTSUP: // return "Not a socket";
return "Not supported"; // case ENOTSUP:
case ENOTTY: // return "Not supported";
return "Inappropriate I/O control operation"; // case ENOTTY:
case ENXIO: // return "Inappropriate I/O control operation";
return "No such device or address"; // case ENXIO:
case EOPNOTSUPP: // return "No such device or address";
return "Operation not supported on socket"; // case EOPNOTSUPP:
case EOVERFLOW: // return "Operation not supported on socket";
return "Value too large to be stored in data type"; // case EOVERFLOW:
case EOWNERDEAD: // return "Value too large to be stored in data type";
return "Previous owner died"; // case EOWNERDEAD:
case EPERM: // return "Previous owner died";
return "Operation not permitted"; // case EPERM:
case EPIPE: // return "Operation not permitted";
return "Broken pipe"; // case EPIPE:
case EPROTO: // return "Broken pipe";
return "Protocol error"; // case EPROTO:
case EPROTONOSUPPORT: // return "Protocol error";
return "Protocol not supported"; // case EPROTONOSUPPORT:
case EPROTOTYPE: // return "Protocol not supported";
return "Protocol wrong type for socket"; // case EPROTOTYPE:
case ERANGE: // return "Protocol wrong type for socket";
return "Result too large"; // case ERANGE:
case EROFS: // return "Result too large";
return "Read-only file system"; // case EROFS:
case ESPIPE: // return "Read-only file system";
return "Invalid seek"; // case ESPIPE:
case ESRCH: // return "Invalid seek";
return "No such process"; // case ESRCH:
case ETIME: // return "No such process";
return "STREAM ioctl() timeout"; // case ETIME:
case ETIMEDOUT: // return "STREAM ioctl() timeout";
return "Connection timed out"; // case ETIMEDOUT:
case ETXTBSY: // return "Connection timed out";
return "Text file busy"; // case ETXTBSY:
case EWOULDBLOCK: // return "Text file busy";
return "Operation would block"; // case EWOULDBLOCK:
case EXDEV: // return "Operation would block";
return "Improper link"; // case EXDEV:
default: // return "Improper link";
snprintf(unknown_error, sizeof(unknown_error), "Unknown error %d", errnum); // default:
return unknown_error; // snprintf(unknown_error, sizeof(unknown_error), "Unknown error %d", errnum);
} // return unknown_error;
} // }
// }
export char *strerror_l(int errnum, locale_t locale); export char *strerror_l(int errnum, locale_t locale);
@ -558,66 +563,66 @@ export char *strsignal(int signum)
{ {
switch (signum) switch (signum)
{ {
case __SYS_SIGNULL: case SIGNULL:
return "NULL signal"; return "NULL signal";
case __SYS_SIGABRT: case SIGABRT:
return "Aborted"; return "Aborted";
case __SYS_SIGALRM: case SIGALRM:
return "Alarm clock"; return "Alarm clock";
case __SYS_SIGBUS: case SIGBUS:
return "Bus error"; return "Bus error";
case __SYS_SIGCHLD: case SIGCHLD:
return "Child status changed"; return "Child status changed";
case __SYS_SIGCONT: case SIGCONT:
return "Continued"; return "Continued";
case __SYS_SIGFPE: case SIGFPE:
return "Arithmetic exception"; return "Arithmetic exception";
case __SYS_SIGHUP: case SIGHUP:
return "Hangup"; return "Hangup";
case __SYS_SIGILL: case SIGILL:
return "Illegal instruction"; return "Illegal instruction";
case __SYS_SIGINT: case SIGINT:
return "Interrupt"; return "Interrupt";
case __SYS_SIGKILL: case SIGKILL:
return "Killed"; return "Killed";
case __SYS_SIGPIPE: case SIGPIPE:
return "Broken pipe"; return "Broken pipe";
case __SYS_SIGQUIT: case SIGQUIT:
return "Quit"; return "Quit";
case __SYS_SIGSEGV: case SIGSEGV:
return "Segmentation fault"; return "Segmentation fault";
case __SYS_SIGSTOP: case SIGSTOP:
return "Stopped (signal)"; return "Stopped (signal)";
case __SYS_SIGTERM: case SIGTERM:
return "Terminated"; return "Terminated";
case __SYS_SIGTSTP: case SIGTSTP:
return "Stopped (user)"; return "Stopped (user)";
case __SYS_SIGTTIN: case SIGTTIN:
return "Stopped (tty input)"; return "Stopped (tty input)";
case __SYS_SIGTTOU: case SIGTTOU:
return "Stopped (tty output)"; return "Stopped (tty output)";
case __SYS_SIGUSR1: case SIGUSR1:
return "User defined signal 1"; return "User defined signal 1";
case __SYS_SIGUSR2: case SIGUSR2:
return "User defined signal 2"; return "User defined signal 2";
case __SYS_SIGPOLL: case SIGPOLL:
return "Pollable event occurred"; return "Pollable event occurred";
case __SYS_SIGPROF: case SIGPROF:
return "Profiling timer expired"; return "Profiling timer expired";
case __SYS_SIGSYS: case SIGSYS:
return "Bad system call"; return "Bad system call";
case __SYS_SIGTRAP: case SIGTRAP:
return "Trace/breakpoint trap"; return "Trace/breakpoint trap";
case __SYS_SIGURG: case SIGURG:
return "Urgent I/O condition"; return "Urgent I/O condition";
case __SYS_SIGVTALRM: case SIGVTALRM:
return "Virtual timer expired"; return "Virtual timer expired";
case __SYS_SIGXCPU: case SIGXCPU:
return "CPU time limit exceeded"; return "CPU time limit exceeded";
case __SYS_SIGXFSZ: case SIGXFSZ:
return "File size limit exceeded"; return "File size limit exceeded";
default: default:
return NULL; return "Unknown signal";
} }
} }