From 0d8c65e44b4f0128bf179334f65694cd58351a3f Mon Sep 17 00:00:00 2001 From: EnderIce2 Date: Mon, 24 Mar 2025 00:40:07 +0000 Subject: [PATCH] feat(userspace/libc): implement functions for porting apps Signed-off-by: EnderIce2 --- .../libc/abis/fennix/generic/bits/socket.h | 4 + .../libc/abis/fennix/generic/bits/syscalls.h | 2 +- Userspace/libc/include/bits/libc.h | 5 + Userspace/libc/include/iconv.h | 29 ++++ Userspace/libc/include/stddef.h | 2 + Userspace/libc/include/stdio.h | 10 +- Userspace/libc/include/stdlib.h | 3 +- Userspace/libc/include/sys/select.h | 41 +++++ Userspace/libc/include/sys/time.h | 51 ++++++ Userspace/libc/include/sys/un.h | 31 ++++ Userspace/libc/include/time.h | 10 +- Userspace/libc/include/unistd.h | 4 +- Userspace/libc/libs/CMakeLists.txt | 2 + Userspace/libc/libs/libpthread/CMakeLists.txt | 15 ++ Userspace/libc/libs/libpthread/libpthread.c | 18 ++ Userspace/libc/libs/librt/CMakeLists.txt | 15 ++ Userspace/libc/libs/librt/librt.c | 18 ++ Userspace/libc/src/std/stdio.c | 142 +++++++++++++++- Userspace/libc/src/std/stdlib.c | 156 +++++++++++++++++- Userspace/libc/src/std/time.c | 40 ++++- Userspace/libc/src/std/unistd.c | 14 +- .../libc/sysdeps/fennix/generic/syscalls.c | 28 ++++ 22 files changed, 615 insertions(+), 25 deletions(-) create mode 100644 Userspace/libc/include/iconv.h create mode 100644 Userspace/libc/include/sys/select.h create mode 100644 Userspace/libc/include/sys/time.h create mode 100644 Userspace/libc/include/sys/un.h create mode 100644 Userspace/libc/libs/libpthread/CMakeLists.txt create mode 100644 Userspace/libc/libs/libpthread/libpthread.c create mode 100644 Userspace/libc/libs/librt/CMakeLists.txt create mode 100644 Userspace/libc/libs/librt/librt.c diff --git a/Userspace/libc/abis/fennix/generic/bits/socket.h b/Userspace/libc/abis/fennix/generic/bits/socket.h index 017dfa38..33b966bb 100644 --- a/Userspace/libc/abis/fennix/generic/bits/socket.h +++ b/Userspace/libc/abis/fennix/generic/bits/socket.h @@ -31,4 +31,8 @@ struct sockaddr char sa_data[14]; }; +#ifdef _GNU_SOURCE +#define SO_PEERCRED 0x1029 +#endif + #endif // _BITS_SOCKET_H diff --git a/Userspace/libc/abis/fennix/generic/bits/syscalls.h b/Userspace/libc/abis/fennix/generic/bits/syscalls.h index 1d75bd71..a80a58c4 100644 --- a/Userspace/libc/abis/fennix/generic/bits/syscalls.h +++ b/Userspace/libc/abis/fennix/generic/bits/syscalls.h @@ -1807,7 +1807,7 @@ typedef enum /* Time */ /** @copydoc SYS_TIME */ -#define call_time(t) syscall1(SYS_TIME, t) +#define call_time(t) syscall1(SYS_TIME, (scarg)t) /** @copydoc SYS_CLOCK_GETTIME */ #define call_clock_gettime(clockid, tp) syscall2(SYS_CLOCK_GETTIME, (scarg)clockid, (scarg)tp) diff --git a/Userspace/libc/include/bits/libc.h b/Userspace/libc/include/bits/libc.h index 4c0d0bd2..219b1d29 100644 --- a/Userspace/libc/include/bits/libc.h +++ b/Userspace/libc/include/bits/libc.h @@ -70,5 +70,10 @@ int sysdep(ChangeDirectory)(const char *Pathname); char *sysdep(GetWorkingDirectory)(char *Buffer, size_t Size); int sysdep(Brk)(void *Address); int sysdep(FileControl)(int Descriptor, int Command, void *Arg); +int sysdep(ClockGetTime)(clockid_t ClockID, struct timespec *TP); +time_t sysdep(Time)(void); +clock_t sysdep(Clock)(void); +int sysdep(RemoveDirectory)(const char *Pathname); +int sysdep(Unlink)(const char *Pathname); #endif // FENNIX_BITS_LIBC_H diff --git a/Userspace/libc/include/iconv.h b/Userspace/libc/include/iconv.h new file mode 100644 index 00000000..55e06c45 --- /dev/null +++ b/Userspace/libc/include/iconv.h @@ -0,0 +1,29 @@ +/* + This file is part of Fennix C Library. + + Fennix C Library is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix C Library. If not, see . +*/ + +#ifndef _ICONV_H +#define _ICONV_H + +#include + +typedef void *iconv_t; + +iconv_t iconv_open(const char *tocode, const char *fromcode); +size_t iconv(iconv_t cd, char **restrict inbuf, size_t *restrict inbytesleft, char **restrict outbuf, size_t *restrict outbytesleft); +int iconv_close(iconv_t cd); + +#endif // _ICONV_H diff --git a/Userspace/libc/include/stddef.h b/Userspace/libc/include/stddef.h index 70c953c8..75fcf593 100644 --- a/Userspace/libc/include/stddef.h +++ b/Userspace/libc/include/stddef.h @@ -27,6 +27,8 @@ extern "C" #define NULL ((void *)0) #endif +#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) + typedef struct { long long __a; diff --git a/Userspace/libc/include/stdio.h b/Userspace/libc/include/stdio.h index de19ab42..f82199f8 100644 --- a/Userspace/libc/include/stdio.h +++ b/Userspace/libc/include/stdio.h @@ -106,7 +106,7 @@ extern "C" int fputs(const char *restrict s, FILE *restrict stream); size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream); FILE *freopen(const char *restrict, const char *restrict, FILE *restrict); - int fscanf(FILE *restrict, const char *restrict, ...); + int fscanf(FILE *restrict stream, const char *restrict format, ...); int fseek(FILE *stream, long offset, int whence); int fseeko(FILE *, off_t, int); int fsetpos(FILE *, const fpos_t *); @@ -131,16 +131,16 @@ extern "C" int putc_unlocked(int c, FILE *stream); int putchar_unlocked(int c); int puts(const char *s); - int remove(const char *); + int remove(const char *path); int rename(const char *, const char *); int renameat(int, const char *, int, const char *); void rewind(FILE *); - int scanf(const char *restrict, ...); + int scanf(const char *restrict format, ...); void setbuf(FILE *restrict, char *restrict); int setvbuf(FILE *restrict, char *restrict, int, size_t); int snprintf(char *restrict s, size_t n, const char *restrict format, ...); int sprintf(char *restrict s, const char *restrict format, ...); - int sscanf(const char *restrict, const char *restrict, ...); + int sscanf(const char *restrict s, const char *restrict format, ...); FILE *tmpfile(void); char *tmpnam(char *); int ungetc(int, FILE *); @@ -149,7 +149,7 @@ extern "C" int vfscanf(FILE *restrict, const char *restrict, va_list); int vprintf(const char *restrict, va_list); int vscanf(const char *restrict, va_list); - int vsnprintf(char *restrict, size_t, const char *restrict, va_list); + int vsnprintf(char *restrict s, size_t n, const char *restrict format, va_list ap); int vsprintf(char *restrict, const char *restrict, va_list); int vsscanf(const char *restrict, const char *restrict, va_list); diff --git a/Userspace/libc/include/stdlib.h b/Userspace/libc/include/stdlib.h index fb156d9f..f383de9d 100644 --- a/Userspace/libc/include/stdlib.h +++ b/Userspace/libc/include/stdlib.h @@ -102,7 +102,8 @@ extern "C" double strtod(const char *, char **); long strtol(const char *restrict nptr, char **restrict endptr, int base); long long strtoll(const char *restrict nptr, char **restrict endptr, int base); - unsigned long int strtoul(const char *, char **, int); + unsigned long int strtoul(const char *restrict str, char **restrict endptr, int base); + unsigned long long strtoull(const char *restrict str, char **restrict endptr, int base); int system(const char *command); int ttyslot(void); int unlockpt(int); diff --git a/Userspace/libc/include/sys/select.h b/Userspace/libc/include/sys/select.h new file mode 100644 index 00000000..5461b957 --- /dev/null +++ b/Userspace/libc/include/sys/select.h @@ -0,0 +1,41 @@ +/* + This file is part of Fennix C Library. + + Fennix C Library is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix C Library. If not, see . +*/ + +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H + +#include +#include +#include +#include + +#define FD_SETSIZE 1024 + +typedef struct +{ + unsigned long fds_bits[(FD_SETSIZE + (8 * sizeof(unsigned long) - 1)) / (8 * sizeof(unsigned long))]; +} fd_set; + +#define FD_CLR(fd, fdset) ((fdset)->fds_bits[(fd) / (8 * sizeof(unsigned long))] &= ~(1UL << ((fd) % (8 * sizeof(unsigned long))))) +#define FD_ISSET(fd, fdset) (((fdset)->fds_bits[(fd) / (8 * sizeof(unsigned long))] & (1UL << ((fd) % (8 * sizeof(unsigned long))))) != 0) +#define FD_SET(fd, fdset) ((fdset)->fds_bits[(fd) / (8 * sizeof(unsigned long))] |= (1UL << ((fd) % (8 * sizeof(unsigned long))))) +#define FD_ZERO(fdset) (memset((fdset), 0, sizeof(fd_set))) + +int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct timeval *restrict timeout); +int pselect(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, const struct timespec *restrict timeout, const sigset_t *restrict sigmask); + +#endif // _SYS_SELECT_H diff --git a/Userspace/libc/include/sys/time.h b/Userspace/libc/include/sys/time.h new file mode 100644 index 00000000..91d2b4ce --- /dev/null +++ b/Userspace/libc/include/sys/time.h @@ -0,0 +1,51 @@ +/* + This file is part of Fennix C Library. + + Fennix C Library is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix C Library. If not, see . +*/ + +#ifndef _SYS_TIME_H +#define _SYS_TIME_H + +#include +#include +#include + +typedef long time_t; +typedef long suseconds_t; + +struct timeval +{ + time_t tv_sec; /* Seconds */ + suseconds_t tv_usec; /* Microseconds */ +}; + +struct itimerval +{ + struct timeval it_interval; /* Timer interval */ + struct timeval it_value; /* Current value */ +}; + +/* Values for the which argument of getitimer() and setitimer() */ +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +int getitimer(int which, struct itimerval *value); +int gettimeofday(struct timeval *restrict tp, void *restrict tzp); +// int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct timeval *restrict timeout); +int setitimer(int which, const struct itimerval *restrict new_value, struct itimerval *restrict old_value); +int utimes(const char *filename, const struct timeval times[2]); + +#endif // _SYS_TIME_H diff --git a/Userspace/libc/include/sys/un.h b/Userspace/libc/include/sys/un.h new file mode 100644 index 00000000..6bc1d4b9 --- /dev/null +++ b/Userspace/libc/include/sys/un.h @@ -0,0 +1,31 @@ +/* + This file is part of Fennix C Library. + + Fennix C Library is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix C Library. If not, see . +*/ + +#ifndef _SYS_UN_H +#define _SYS_UN_H + +#include + +#define SUN_PATH_SIZE 108 + +struct sockaddr_un +{ + sa_family_t sun_family; /* Address family */ + char sun_path[SUN_PATH_SIZE]; /* Socket pathname storage */ +}; + +#endif // _SYS_UN_H diff --git a/Userspace/libc/include/time.h b/Userspace/libc/include/time.h index 00dc6d0d..4974bd2f 100644 --- a/Userspace/libc/include/time.h +++ b/Userspace/libc/include/time.h @@ -49,7 +49,7 @@ extern "C" struct timespec it_value; /* Timer expiration. */ } itimerspec; -#define CLOCKS_PER_SEC +#define CLOCKS_PER_SEC 1000000 #define TIME_UTC #define CLOCK_MONOTONIC __SYS_CLOCK_MONOTONIC #define CLOCK_PROCESS_CPUTIME_ID __SYS_CLOCK_PROCESS_CPUTIME_ID @@ -64,10 +64,10 @@ extern "C" char *asctime(const struct tm *); clock_t clock(void); int clock_getcpuclockid(pid_t, clockid_t *); - int clock_getres(clockid_t, struct timespec *); - int clock_gettime(clockid_t, struct timespec *); + int clock_getres(clockid_t clock_id, struct timespec *res); + int clock_gettime(clockid_t clock_id, struct timespec *tp); int clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *); - int clock_settime(clockid_t, const struct timespec *); + int clock_settime(clockid_t clock_id, const struct timespec *tp); char *ctime(const time_t *); double difftime(time_t, time_t); struct tm *getdate(const char *); @@ -81,7 +81,7 @@ extern "C" size_t strftime(char *restrict, size_t, const char *restrict, const struct tm *restrict); size_t strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t); char *strptime(const char *restrict, const char *restrict, struct tm *restrict); - time_t time(time_t *); + time_t time(time_t *tloc); int timer_create(clockid_t, struct sigevent *restrict, timer_t *restrict); int timer_delete(timer_t); int timer_getoverrun(timer_t); diff --git a/Userspace/libc/include/unistd.h b/Userspace/libc/include/unistd.h index 0ce82788..8ee77c8d 100644 --- a/Userspace/libc/include/unistd.h +++ b/Userspace/libc/include/unistd.h @@ -121,7 +121,7 @@ extern "C" ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset); ssize_t read(int fildes, void *buf, size_t nbyte); int readlink(const char *, char *, size_t); - int rmdir(const char *); + int rmdir(const char *path); void *sbrk(intptr_t incr); int setgid(gid_t); int setpgid(pid_t, pid_t); @@ -141,7 +141,7 @@ extern "C" char *ttyname(int); int ttyname_r(int, char *, size_t); useconds_t ualarm(useconds_t, useconds_t); - int unlink(const char *); + int unlink(const char *path); int usleep(useconds_t); pid_t vfork(void); ssize_t write(int fildes, const void *buf, size_t nbyte); diff --git a/Userspace/libc/libs/CMakeLists.txt b/Userspace/libc/libs/CMakeLists.txt index fa561e76..df329a43 100644 --- a/Userspace/libc/libs/CMakeLists.txt +++ b/Userspace/libc/libs/CMakeLists.txt @@ -2,4 +2,6 @@ cmake_minimum_required(VERSION 3.10) project(FennixStandardLibraries) add_subdirectory(libm) +add_subdirectory(librt) +add_subdirectory(libpthread) add_subdirectory(libstdc++) diff --git a/Userspace/libc/libs/libpthread/CMakeLists.txt b/Userspace/libc/libs/libpthread/CMakeLists.txt new file mode 100644 index 00000000..b9385d74 --- /dev/null +++ b/Userspace/libc/libs/libpthread/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.10) +project(FennixRealTimeLibrary) + +set(SOURCES libpthread.c) + +add_library(pthread STATIC ${SOURCES}) +add_library(pthread_shared SHARED ${SOURCES}) + +target_link_options(pthread_shared PRIVATE -nostdlib) +set_target_properties(pthread_shared PROPERTIES OUTPUT_NAME "pthread") + +install(TARGETS pthread pthread_shared + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + PUBLIC_HEADER DESTINATION include) diff --git a/Userspace/libc/libs/libpthread/libpthread.c b/Userspace/libc/libs/libpthread/libpthread.c new file mode 100644 index 00000000..183ad690 --- /dev/null +++ b/Userspace/libc/libs/libpthread/libpthread.c @@ -0,0 +1,18 @@ +/* + This file is part of Fennix Userspace. + + Fennix Userspace is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Userspace is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Userspace. If not, see . +*/ + +/* dummy file */ diff --git a/Userspace/libc/libs/librt/CMakeLists.txt b/Userspace/libc/libs/librt/CMakeLists.txt new file mode 100644 index 00000000..06b8f9d1 --- /dev/null +++ b/Userspace/libc/libs/librt/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.10) +project(FennixRealTimeLibrary) + +set(SOURCES librt.c) + +add_library(rt STATIC ${SOURCES}) +add_library(rt_shared SHARED ${SOURCES}) + +target_link_options(rt_shared PRIVATE -nostdlib) +set_target_properties(rt_shared PROPERTIES OUTPUT_NAME "rt") + +install(TARGETS rt rt_shared + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + PUBLIC_HEADER DESTINATION include) diff --git a/Userspace/libc/libs/librt/librt.c b/Userspace/libc/libs/librt/librt.c new file mode 100644 index 00000000..183ad690 --- /dev/null +++ b/Userspace/libc/libs/librt/librt.c @@ -0,0 +1,18 @@ +/* + This file is part of Fennix Userspace. + + Fennix Userspace is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Userspace is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Userspace. If not, see . +*/ + +/* dummy file */ diff --git a/Userspace/libc/src/std/stdio.c b/Userspace/libc/src/std/stdio.c index f1edb812..68738eb1 100644 --- a/Userspace/libc/src/std/stdio.c +++ b/Userspace/libc/src/std/stdio.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include "../print/printf.h" @@ -466,7 +467,24 @@ export int puts(const char *s) return 0; } -export int remove(const char *); +export int remove(const char *path) +{ + if (!path) + { + errno = EINVAL; + return -1; + } + + struct stat path_stat; + if (sysdep(Stat)(path, &path_stat) < 0) + return -1; + + if (S_ISDIR(path_stat.st_mode)) + return sysdep(RemoveDirectory)(path); + else + return sysdep(Unlink)(path); +} + export int rename(const char *, const char *); export int renameat(int, const char *, int, const char *); export void rewind(FILE *); @@ -492,7 +510,117 @@ export int sprintf(char *restrict s, const char *restrict format, ...) return ret; } -export int sscanf(const char *restrict, const char *restrict, ...); +export int sscanf(const char *restrict s, const char *restrict format, ...) +{ + va_list args; + va_start(args, format); + + const char *p = format; + int matchedItems = 0; + + while (*p) + { + if (isspace(*p)) + { + while (isspace(*p)) + p++; + while (isspace(*s)) + s++; + } + else if (*p == '%') + { + p++; + if (*p == '\0') + break; + + int suppress_assignment = 0; + if (*p == '*') + { + suppress_assignment = 1; + p++; + } + + int width = 0; + while (isdigit(*p)) + { + width = width * 10 + (*p - '0'); + p++; + } + + char specifier = *p++; + if (specifier == '\0') + break; + + if (specifier == 'd' || specifier == 'i') + { + int value = 0; + while (isdigit(*s) || (*s == '-' && value == 0)) + { + if (*s == '-') + { + s++; + continue; + } + value = value * 10 + (*s - '0'); + s++; + } + if (!suppress_assignment) + { + int *arg = va_arg(args, int *); + *arg = value; + matchedItems++; + } + } + else if (specifier == 's') + { + char *str = va_arg(args, char *); + while (*s && !isspace(*s) && (width == 0 || width-- > 0)) + { + if (!suppress_assignment) + *str++ = *s; + s++; + } + if (!suppress_assignment) + *str = '\0'; + matchedItems++; + } + else if (specifier == 'c') + { + char *ch = va_arg(args, char *); + if (*s && (width == 0 || width-- > 0)) + { + if (!suppress_assignment) + *ch = *s; + s++; + matchedItems++; + } + } + else if (specifier == '%') + { + if (*s == '%') + s++; + else + break; + } + else + break; + } + else + { + if (*s == *p) + { + s++; + p++; + } + else + break; + } + } + + va_end(args); + return matchedItems; +} + export FILE *tmpfile(void); export char *tmpnam(char *); export int ungetc(int, FILE *); @@ -526,6 +654,14 @@ export int vfprintf(FILE *restrict stream, const char *restrict format, va_list export int vfscanf(FILE *restrict, const char *restrict, va_list); export int vprintf(const char *restrict, va_list); export int vscanf(const char *restrict, va_list); -export int vsnprintf(char *restrict, size_t, const char *restrict, va_list); + +export int vsnprintf(char *restrict s, size_t n, const char *restrict format, va_list ap) +{ + int ret = vsnprintf_(s, n, format, ap); + if (ret < 0) + return ret; + return ret; +} + export int vsprintf(char *restrict, const char *restrict, va_list); export int vsscanf(const char *restrict, const char *restrict, va_list); diff --git a/Userspace/libc/src/std/stdlib.c b/Userspace/libc/src/std/stdlib.c index 6ca365ea..3d7704a6 100644 --- a/Userspace/libc/src/std/stdlib.c +++ b/Userspace/libc/src/std/stdlib.c @@ -334,7 +334,161 @@ export long long strtoll(const char *restrict nptr, char **restrict endptr, int return acc; } -export unsigned long int strtoul(const char *, char **, int); +export unsigned long int strtoul(const char *restrict str, char **restrict endptr, int base) +{ + const char *s = str; + unsigned long acc = 0; + int c; + unsigned long cutoff; + int any, cutlim; + + if (base < 0 || base == 1 || base > 36) + { + errno = EINVAL; + if (endptr) + *endptr = (char *)str; + return 0; + } + + while (isspace((unsigned char)*s)) + s++; + + if (*s == '+') + s++; + else if (*s == '-') + { + errno = EINVAL; + if (endptr) + *endptr = (char *)str; + return 0; + } + + if ((base == 0 || base == 16) && *s == '0' && (s[1] == 'x' || s[1] == 'X')) + { + s += 2; + base = 16; + } + else if (base == 0) + base = *s == '0' ? 8 : 10; + + cutoff = ULONG_MAX / base; + cutlim = ULONG_MAX % base; + + for (acc = 0, any = 0;; c = *s++) + { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + + if (c >= base) + break; + + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else + { + any = 1; + acc *= base; + acc += c; + } + } + + if (any < 0) + { + acc = ULONG_MAX; + errno = ERANGE; + } + else if (any == 0) + { + errno = EINVAL; + } + + if (endptr) + *endptr = (char *)(any ? s - 1 : str); + + return acc; +} + +export unsigned long long strtoull(const char *restrict str, char **restrict endptr, int base) +{ + const char *s = str; + unsigned long long acc = 0; + int c; + unsigned long long cutoff; + int any, cutlim; + + if (base < 0 || base == 1 || base > 36) + { + errno = EINVAL; + if (endptr) + *endptr = (char *)str; + return 0; + } + + while (isspace((unsigned char)*s)) + s++; + + if (*s == '+') + s++; + else if (*s == '-') + { + errno = EINVAL; + if (endptr) + *endptr = (char *)str; + return 0; + } + + if ((base == 0 || base == 16) && *s == '0' && (s[1] == 'x' || s[1] == 'X')) + { + s += 2; + base = 16; + } + else if (base == 0) + base = *s == '0' ? 8 : 10; + + cutoff = ULLONG_MAX / base; + cutlim = ULLONG_MAX % base; + + for (acc = 0, any = 0;; c = *s++) + { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + + if (c >= base) + break; + + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else + { + any = 1; + acc *= base; + acc += c; + } + } + + if (any < 0) + { + acc = ULLONG_MAX; + errno = ERANGE; + } + else if (any == 0) + { + errno = EINVAL; + } + + if (endptr) + *endptr = (char *)(any ? s - 1 : str); + + return acc; +} export int system(const char *command) { diff --git a/Userspace/libc/src/std/time.c b/Userspace/libc/src/std/time.c index 88abd75f..e4a9cfcb 100644 --- a/Userspace/libc/src/std/time.c +++ b/Userspace/libc/src/std/time.c @@ -30,12 +30,29 @@ export long timezone; export char *tzname[2]; export char *asctime(const struct tm *); -export clock_t clock(void); + +export clock_t clock(void) +{ + clock_t processor_time = sysdep(Clock)(); + if (processor_time == (clock_t)-1) + { + errno = EOVERFLOW; + return (clock_t)-1; + } + return processor_time; +} + export int clock_getcpuclockid(pid_t, clockid_t *); -export int clock_getres(clockid_t, struct timespec *); -export int clock_gettime(clockid_t, struct timespec *); +export int clock_getres(clockid_t clock_id, struct timespec *res); + +export int clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + return sysdep(ClockGetTime)(clock_id, tp); +} + export int clock_nanosleep(clockid_t, int, const struct timespec *, struct timespec *); -export int clock_settime(clockid_t, const struct timespec *); +export int clock_settime(clockid_t clock_id, const struct timespec *tp); +; export char *ctime(const time_t *); export double difftime(time_t, time_t); export struct tm *getdate(const char *); @@ -193,7 +210,20 @@ export int nanosleep(const struct timespec *, struct timespec *); export size_t strftime(char *restrict, size_t, const char *restrict, const struct tm *restrict); export size_t strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t); export char *strptime(const char *restrict, const char *restrict, struct tm *restrict); -export time_t time(time_t *); + +export time_t time(time_t *tloc) +{ + time_t current_time = sysdep(Time)(); + if (current_time == (time_t)-1) + { + errno = EOVERFLOW; + return (time_t)-1; + } + if (tloc) + *tloc = current_time; + return current_time; +} + export int timer_create(clockid_t, struct sigevent *restrict, timer_t *restrict); export int timer_delete(timer_t); export int timer_getoverrun(timer_t); diff --git a/Userspace/libc/src/std/unistd.c b/Userspace/libc/src/std/unistd.c index a7682d43..0fed008b 100644 --- a/Userspace/libc/src/std/unistd.c +++ b/Userspace/libc/src/std/unistd.c @@ -293,7 +293,12 @@ export ssize_t read(int fildes, void *buf, size_t nbyte) } export int readlink(const char *, char *, size_t); -export int rmdir(const char *); + +export int rmdir(const char *path) +{ + return __check_errno(sysdep(RemoveDirectory)(path), -1); +} + export void *sbrk(intptr_t incr); export int setgid(gid_t); export int setpgid(pid_t, pid_t); @@ -334,7 +339,12 @@ export int truncate(const char *, off_t); export char *ttyname(int); export int ttyname_r(int, char *, size_t); export useconds_t ualarm(useconds_t, useconds_t); -export int unlink(const char *); + +export int unlink(const char *path) +{ + return __check_errno(sysdep(Unlink)(path), -1); +} + export int usleep(useconds_t); export pid_t vfork(void); diff --git a/Userspace/libc/sysdeps/fennix/generic/syscalls.c b/Userspace/libc/sysdeps/fennix/generic/syscalls.c index 6d57d26a..b57d4018 100644 --- a/Userspace/libc/sysdeps/fennix/generic/syscalls.c +++ b/Userspace/libc/sysdeps/fennix/generic/syscalls.c @@ -19,6 +19,8 @@ #include #include +extern int printf(const char *restrict format, ...); + void sysdep(Exit)(int Status) { call_exit(Status); @@ -209,3 +211,29 @@ int sysdep(FileControl)(int Descriptor, int Command, void *Arg) { return call_fcntl(Descriptor, Command, Arg); } + +int sysdep(ClockGetTime)(clockid_t ClockID, struct timespec *TP) +{ + return call_clock_gettime(ClockID, TP); +} + +time_t sysdep(Time)(void) +{ + return call_time(NULL); +} + +clock_t sysdep(Clock)() +{ + printf("sysdep(Clock): unimplemented\n"); + return 0; +} + +int sysdep(RemoveDirectory)(const char *Pathname) +{ + return call_rmdir(Pathname); +} + +int sysdep(Unlink)(const char *Pathname) +{ + return call_unlink(Pathname); +}