diff options
author | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
commit | 4e09bca9e34c226b6d7e34b4fa11248405fd988e (patch) | |
tree | 80f156b7940d9d19971395f335530170c69516c7 /userland/libc |
Move everything into a new repo.
Diffstat (limited to 'userland/libc')
213 files changed, 4633 insertions, 0 deletions
diff --git a/userland/libc/Makefile b/userland/libc/Makefile new file mode 100644 index 0000000..98d81d4 --- /dev/null +++ b/userland/libc/Makefile @@ -0,0 +1,26 @@ +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +AR="/home/anton/prj/osdev/sysroot/bin/i686-sb-ar" +AS="/home/anton/prj/osdev/sysroot/bin/i686-sb-as" +#CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough -I./include/ -static -fsanitize=shift,signed-integer-overflow,bounds +CFLAGS = -ggdb -ffreestanding -O2 -Wall -pedantic -Wimplicit-fallthrough -I./include/ -static +#BINS=c.a libc.o crt0.o malloc.o pty.o mmap.o +OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/stdout.o stdio/stderr.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o libgen/basename.o string/strdup.o string/strndup.o string/strlcpy.o stdlib/atexit.o stdio/open_memstream.o libgen/dirname.o unistd/unlink.o string/strstr.o string/strcasecmp.o string/strncasecmp.o stdlib/mkstemp.o string/strtok.o unistd/execvp.o unistd/_exit.o ctype/isalnum.o time/ctime_r.o stdlib/strtold.o sys/time/gettimeofday.o stdio/fgetpos.o stdio/fsetpos.o ctype/isprint.o stdlib/system.o stdio/tmpnam.o unistd/msleep.o stdlib/atof.o stdlib/strtod.o stdio/rename.o sys/stat/mkdir.o unistd/uptime.o +#OBJ=crt0.o libc.o malloc/malloc.o pty.o sys/mman/mmap.o memset.o assert.o stdio/snprintf.o stdio/vfprintf.o string/memcpy.o string/memcmp.o string/strcmp.o ubsan.o string/strcpy.o isspace.o stdio/puts.o stdio/putchar.o dirent/opendir.o dirent/readdir.o dirent/closedir.o unistd/getopt.o dirent/scandir.o dirent/alphasort.o stdio/printf.o stdio/vdprintf.o stdio/vprintf.o stdio/dprintf.o stdio/vprintf.o string/strlen.o string/strnlen.o stdio/stdin.o stdio/stdout.o stdio/stderr.o stdio/getchar.o stdio/fgetc.o arpa/inet/htons.o arpa/inet/htonl.o stdio/fread.o stdio/fwrite.o stdio/fopen.o stdio/fclose.o stdio/fseek.o ctype/isascii.o stdio/fprintf.o stdlib/atoi.o stdlib/strtol.o ctype/toupper.o ctype/tolower.o string/strcat.o string/strchr.o string/sscanf.o sys/stat/stat.o stdlib/getenv.o string/strrchr.o stdio/ftell.o stdio/tmpfile.o stdio/fgets.o stdio/feof.o stdio/fscanf.o stdio/ungetc.o string/strncmp.o stdio/fputc.o string/strncpy.o stdio/remove.o stdio/ferror.o stdio/fputs.o stdlib/rand.o stdlib/srand.o unistd/getpid.o stdlib/strtoul.o stdio/fflush.o stdlib/abort.o string/strcspn.o time/localtime.o time/time.o time/clock_gettime.o time/gmtime.o time/strftime.o string/strpbrk.o ctype/isdigit.o ctype/isalpha.o ctype/isxdigit.o ctype/ispunct.o stdio/setvbuf.o stdio/fileno.o stdio/putc.o stdio/sprintf.o stdlib/abs.o string/strspn.o stdlib/qsort.o string/memmove.o setjmp/longjmp.o setjmp/setjmp.o +all: libc.a + +%.o: %.c + $(CC) $(CFLAGS) -O0 -I. -o $@ -c $< -lgcc + +%.o: %.s + $(AS) $< -o $@ + +libc.a: $(OBJ) + $(AR) rcs libc.a $(OBJ) + +install: + cp crt0.o /home/anton/prj/osdev/sysroot/lib/ + cp libc.a /home/anton/prj/osdev/sysroot/lib/ + cp -r include /home/anton/prj/osdev/sysroot/usr/ + +clean: + rm libc.a *.o */*.o */*/*.o diff --git a/userland/libc/arpa/inet.h b/userland/libc/arpa/inet.h new file mode 100644 index 0000000..7a033f2 --- /dev/null +++ b/userland/libc/arpa/inet.h @@ -0,0 +1,4 @@ +#include <stdint.h> + +uint32_t htonl(uint32_t hostlong); +uint16_t htons(uint16_t hostlong); diff --git a/userland/libc/arpa/inet/htonl.c b/userland/libc/arpa/inet/htonl.c new file mode 100644 index 0000000..4b66747 --- /dev/null +++ b/userland/libc/arpa/inet/htonl.c @@ -0,0 +1,11 @@ +#include <arpa/inet.h> +#include <endian.h> +#include <stdint.h> + +uint32_t htonl(uint32_t hostlong) { +#if BYTE_ORDER == LITTLE_ENDIAN + hostlong = (uint32_t)(htons(hostlong >> 16)) | + (uint32_t)(htons(hostlong & 0xFFFF) << 16); +#endif + return hostlong; +} diff --git a/userland/libc/arpa/inet/htons.c b/userland/libc/arpa/inet/htons.c new file mode 100644 index 0000000..798a64a --- /dev/null +++ b/userland/libc/arpa/inet/htons.c @@ -0,0 +1,10 @@ +#include <arpa/inet.h> +#include <endian.h> +#include <stdint.h> + +uint16_t htons(uint16_t hostlong) { +#if BYTE_ORDER == LITTLE_ENDIAN + hostlong = ((hostlong & 0xFF00) >> 8) | ((hostlong & 0x00FF) << 8); +#endif + return hostlong; +} diff --git a/userland/libc/assert.c b/userland/libc/assert.c new file mode 100644 index 0000000..4082f64 --- /dev/null +++ b/userland/libc/assert.c @@ -0,0 +1,9 @@ +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +void aFailed(char *f, int l) { + printf("Assert failed\n"); + printf("%s : %d\n", f, l); + exit(1); +} diff --git a/userland/libc/assert.h b/userland/libc/assert.h new file mode 100644 index 0000000..a009e5f --- /dev/null +++ b/userland/libc/assert.h @@ -0,0 +1,10 @@ +#ifndef ASSERT_H +#define ASSERT_H + +#define assert(expr) \ + { \ + if (!(expr)) \ + aFailed(__FILE__, __LINE__); \ + } +void aFailed(char *f, int l); +#endif diff --git a/userland/libc/crt0.s b/userland/libc/crt0.s new file mode 100644 index 0000000..05144d4 --- /dev/null +++ b/userland/libc/crt0.s @@ -0,0 +1,13 @@ +.global _start +.extern main +_start: + call main + mov %eax, %ebx + mov $8, %eax + int $0x80 +l: + nop + nop + nop + nop + jmp l diff --git a/userland/libc/ctype.h b/userland/libc/ctype.h new file mode 100644 index 0000000..5be4a89 --- /dev/null +++ b/userland/libc/ctype.h @@ -0,0 +1,12 @@ +#ifndef CTYPE_H +#define CTYPE_H + +int isspace(int c); +int isascii(int c); +int toupper(int c); +int tolower(int c); +int isdigit(int c); +int isalpha(int c); +int isxdigit(int c); +int ispunct(int c); +#endif diff --git a/userland/libc/ctype/isalnum.c b/userland/libc/ctype/isalnum.c new file mode 100644 index 0000000..870728d --- /dev/null +++ b/userland/libc/ctype/isalnum.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +// This is probably the most useless libc function I have seen so far. +int isalnum(int c) { + return isalpha(c) || isdigit(c); +} diff --git a/userland/libc/ctype/isalpha.c b/userland/libc/ctype/isalpha.c new file mode 100644 index 0000000..130f493 --- /dev/null +++ b/userland/libc/ctype/isalpha.c @@ -0,0 +1,4 @@ +#include <ctype.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/isalpha.html +int isalpha(int c) { return (('A' <= toupper(c)) && ('Z' >= toupper(c))); } diff --git a/userland/libc/ctype/isascii.c b/userland/libc/ctype/isascii.c new file mode 100644 index 0000000..660c8bb --- /dev/null +++ b/userland/libc/ctype/isascii.c @@ -0,0 +1,4 @@ +#include <ctype.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/isascii.html +int isascii(int c) { return (c < 128); } diff --git a/userland/libc/ctype/isdigit.c b/userland/libc/ctype/isdigit.c new file mode 100644 index 0000000..790b9f1 --- /dev/null +++ b/userland/libc/ctype/isdigit.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/isdigit.html +int isdigit(int c) { + return ('0' <= c && c <= '9'); +} diff --git a/userland/libc/ctype/isprint.c b/userland/libc/ctype/isprint.c new file mode 100644 index 0000000..e6a3d0e --- /dev/null +++ b/userland/libc/ctype/isprint.c @@ -0,0 +1,3 @@ +#include <ctype.h> + +int isprint(int c) { return c > 0x20 && 0x7F != c; } diff --git a/userland/libc/ctype/ispunct.c b/userland/libc/ctype/ispunct.c new file mode 100644 index 0000000..18dc7d8 --- /dev/null +++ b/userland/libc/ctype/ispunct.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/ispunct.html +int ispunct(int c) { + return (c == '.'); +} diff --git a/userland/libc/ctype/isxdigit.c b/userland/libc/ctype/isxdigit.c new file mode 100644 index 0000000..c843725 --- /dev/null +++ b/userland/libc/ctype/isxdigit.c @@ -0,0 +1,6 @@ +#include <ctype.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/isxdigit.html +int isxdigit(int c) { + return isdigit(c) || ('A' >= toupper(c) && 'Z' <= toupper(c)); +} diff --git a/userland/libc/ctype/tolower.c b/userland/libc/ctype/tolower.c new file mode 100644 index 0000000..f1bb163 --- /dev/null +++ b/userland/libc/ctype/tolower.c @@ -0,0 +1,7 @@ +#include <ctype.h> + +int tolower(int c) { + if (c >= 'A' && c <= 'Z') + return c - 'A' + 'a'; + return c; +} diff --git a/userland/libc/ctype/toupper.c b/userland/libc/ctype/toupper.c new file mode 100644 index 0000000..0f33886 --- /dev/null +++ b/userland/libc/ctype/toupper.c @@ -0,0 +1,7 @@ +#include <ctype.h> + +int toupper(int c) { + if (c >= 'a' && c <= 'z') + return c - 'a' + 'A'; + return c; +} diff --git a/userland/libc/dirent.h b/userland/libc/dirent.h new file mode 100644 index 0000000..f190a7c --- /dev/null +++ b/userland/libc/dirent.h @@ -0,0 +1,28 @@ +#ifndef DIRENT_H +#define DIRENT_H +#include <fcntl.h> +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> + +struct dirent { + ino_t d_ino; // File serial number. + char d_name[PATH_MAX]; // Filename string of entry. +}; + +typedef struct { + int fd; + struct dirent internal_direntry; + int dir_num; +} DIR; + +DIR *opendir(const char *dirname); +struct dirent *readdir(DIR *dir); +int closedir(DIR *dirp); +int alphasort(const struct dirent **d1, const struct dirent **d2); +int scandir(const char *dir, struct dirent ***namelist, + int (*sel)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)); +#endif diff --git a/userland/libc/dirent/alphasort.c b/userland/libc/dirent/alphasort.c new file mode 100644 index 0000000..43a4b5f --- /dev/null +++ b/userland/libc/dirent/alphasort.c @@ -0,0 +1,7 @@ +#include <dirent.h> + +int alphasort(const struct dirent **d1, const struct dirent **d2) { + // TODO: Actually sort it + *d2 = *d1; + return 0; +} diff --git a/userland/libc/dirent/closedir.c b/userland/libc/dirent/closedir.c new file mode 100644 index 0000000..e216d7c --- /dev/null +++ b/userland/libc/dirent/closedir.c @@ -0,0 +1,7 @@ +#include <dirent.h> + +int closedir(DIR *dir) { + close(dir->fd); + free(dir); + return 0; +} diff --git a/userland/libc/dirent/opendir.c b/userland/libc/dirent/opendir.c new file mode 100644 index 0000000..7bfa562 --- /dev/null +++ b/userland/libc/dirent/opendir.c @@ -0,0 +1,11 @@ +#include <dirent.h> + +DIR *opendir(const char *dirname) { + int fd = open(dirname, O_RDONLY, 0); + if (-1 == fd) + return NULL; + DIR *rc = malloc(sizeof(DIR)); + rc->fd = fd; + rc->dir_num = 0; + return rc; +} diff --git a/userland/libc/dirent/readdir.c b/userland/libc/dirent/readdir.c new file mode 100644 index 0000000..88aff48 --- /dev/null +++ b/userland/libc/dirent/readdir.c @@ -0,0 +1,14 @@ +#include <dirent.h> + +struct dirent *readdir(DIR *dir) { + size_t offset = dir->dir_num * sizeof(struct dirent); + int rc; + if (-1 == (rc = pread(dir->fd, &dir->internal_direntry, sizeof(struct dirent), + offset))) + return NULL; + if (rc < sizeof(struct dirent)) + return NULL; + + dir->dir_num++; + return &(dir->internal_direntry); +} diff --git a/userland/libc/dirent/scandir.c b/userland/libc/dirent/scandir.c new file mode 100644 index 0000000..1520140 --- /dev/null +++ b/userland/libc/dirent/scandir.c @@ -0,0 +1,43 @@ +#include <dirent.h> +#include <stdlib.h> +#include <string.h> + +int nop_sel(const struct dirent *unused) { + (void)unused; + return 1; +} + +int nop_compar(const struct dirent **d1, const struct dirent **d2) { + *d2 = *d1; + return 0; +} + +int scandir(const char *dir, struct dirent ***namelist, + int (*sel)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)) { + if (!sel) + sel = nop_sel; + + if (!compar) + compar = nop_compar; + + DIR *d = opendir(dir); + struct dirent **list = NULL; + struct dirent *e; + int rc = 0; + for (; (e = readdir(d));) { + if (!sel(e)) + continue; + struct dirent *p = malloc(sizeof(struct dirent)); + memcpy(p, e, sizeof(struct dirent)); + list = realloc(list, (rc + 1) * sizeof(struct dirent *)); + list[rc] = p; + rc++; + } + // struct dirent **new_list; + // compar((const struct dirent **)list, (const struct dirent **)new_list); + // *namelist = new_list; + *namelist = list; + // closedir(d); + return rc; +} diff --git a/userland/libc/endian.h b/userland/libc/endian.h new file mode 100644 index 0000000..f265a67 --- /dev/null +++ b/userland/libc/endian.h @@ -0,0 +1,2 @@ +#define LITTLE_ENDIAN 0 +#define BYTE_ORDER LITTLE_ENDIAN diff --git a/userland/libc/errno.h b/userland/libc/errno.h new file mode 100644 index 0000000..ec9a25e --- /dev/null +++ b/userland/libc/errno.h @@ -0,0 +1,87 @@ +#ifndef ERRNO_H +#define ERRNO_H +// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html +#define E2BIG 1 // Argument list too long. +#define EACCES 2 // Permission denied. +#define EADDRINUSE 3 // Address in use. +#define EADDRNOTAVAIL 4 // Address not available. +#define EAFNOSUPPORT 5 // Address family not supported. +#define EAGAIN 6 // Resource unavailable, try again. +#define EALREADY 7 // Connection already in progress. +#define EBADF 8 // Bad file descriptor. +#define EBADMSG 9 // Bad message. +#define EBUSY 10 // Device or resource busy. +#define ECANCELED 11 // Operation canceled. +#define ECHILD 12 // No child processes. +#define ECONNABORTED 13 // Connection aborted. +#define ECONNREFUSED 14 // Connection refused. +#define ECONNRESET 15 // Connection reset. +#define EDEADLK 16 // Resource deadlock would occur. +#define EDESTADDRREQ 17 // Destination address required. +#define EDOM 18 // Mathematics argument out of domain of function. +#define EDQUOT 19 // Reserved. +#define EEXIST 20 // File exists. +#define EFAULT 21 // Bad address. +#define EFBIG 22 // File too large. +#define EHOSTUNREACH 23 // Host is unreachable. +#define EIDRM 24 // Identifier removed. +#define EILSEQ 25 // Illegal byte sequence. +#define EINPROGRESS 26 // Operation in progress. +#define EINTR 27 // Interrupted function. +#define EINVAL 28 // Invalid argument. +#define EIO 29 // I/O error. +#define EISCONN 30 // Socket is connected. +#define EISDIR 31 // Is a directory. +#define ELOOP 32 // Too many levels of symbolic links. +#define EMFILE 33 // File descriptor value too large. +#define EMLINK 34 // Too many links. +#define EMSGSIZE 35 // Message too large. +#define EMULTIHOP 36 // Reserved. +#define ENAMETOOLONG 37 // Filename too long. +#define ENETDOWN 38 // Network is down. +#define ENETRESET 39 // Connection aborted by network. +#define ENETUNREACH 40 // Network unreachable. +#define ENFILE 41 // Too many files open in system. +#define ENOBUFS 42 // No buffer space available. +#define ENODATA 43 // No message is available on the STREAM head read queue. +#define ENODEV 44 // No such device. +#define ENOENT 45 // No such file or directory. +#define ENOEXEC 46 // Executable file format error. +#define ENOLCK 47 // No locks available. +#define ENOLINK 48 // Reserved. +#define ENOMEM 49 // Not enough space. +#define ENOMSG 50 // No message of the desired type. +#define ENOPROTOOPT 51 // Protocol not available. +#define ENOSPC 52 // No space left on device. +#define ENOSR 53 // No STREAM resources. +#define ENOSTR 54 // Not a STREAM. +#define ENOSYS 55 // Functionality not supported. +#define ENOTCONN 56 // The socket is not connected. +#define ENOTDIR 57 // Not a directory or a symbolic link to a directory. +#define ENOTEMPTY 58 // Directory not empty. +#define ENOTRECOVERABLE 59 // State not recoverable. +#define ENOTSOCK 60 // Not a socket. +#define ENOTSUP 61 // Not supported (may be the same value as. +#define ENOTTY 62 // Inappropriate I/O control operation. +#define ENXIO 63 // No such device or address. +#define EOPNOTSUPP ENOTSUP // Operation not supported on socket. +#define EOVERFLOW 65 // Value too large to be stored in data type. +#define EOWNERDEAD 66 // Previous owner died. +#define EPERM 67 // Operation not permitted. +#define EPIPE 68 // Broken pipe. +#define EPROTO 69 // Protocol error. +#define EPROTONOSUPPORT 70 // Protocol not supported. +#define EPROTOTYPE 71 // Protocol wrong type for socket. +#define ERANGE 72 // Result too large. +#define EROFS 73 // Read-only file system. +#define ESPIPE 74 // Invalid seek. +#define ESRCH 75 // No such process. +#define ESTALE 76 // Reserved. +#define ETIME 77 // Stream ioctl() timeout. +#define ETIMEDOUT 78 // Connection timed out. +#define ETXTBSY 79 // Text file busy. +#define EWOULDBLOCK EAGAIN // Operation would block. +#define EXDEV 81 // Cross-device link. + +extern int errno; +#endif diff --git a/userland/libc/fcntl.h b/userland/libc/fcntl.h new file mode 100644 index 0000000..4c1eb9c --- /dev/null +++ b/userland/libc/fcntl.h @@ -0,0 +1,10 @@ +// FIXME: Is there some standard value for this? +#define O_NONBLOCK (1 << 0) +#define O_READ (1 << 1) +#define O_WRITE (1 << 2) +#define O_CREAT (1 << 3) +#define O_RDONLY O_READ +#define O_WRONLY O_WRITE +#define O_RDWR (O_WRITE | O_READ) + +int open(const char *file, int flags, int mode); diff --git a/userland/libc/include/arpa/inet.h b/userland/libc/include/arpa/inet.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/arpa/inet.h diff --git a/userland/libc/include/assert.h b/userland/libc/include/assert.h new file mode 100644 index 0000000..a009e5f --- /dev/null +++ b/userland/libc/include/assert.h @@ -0,0 +1,10 @@ +#ifndef ASSERT_H +#define ASSERT_H + +#define assert(expr) \ + { \ + if (!(expr)) \ + aFailed(__FILE__, __LINE__); \ + } +void aFailed(char *f, int l); +#endif diff --git a/userland/libc/include/byteswap.h b/userland/libc/include/byteswap.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/byteswap.h diff --git a/userland/libc/include/ctype.h b/userland/libc/include/ctype.h new file mode 100644 index 0000000..7c8c311 --- /dev/null +++ b/userland/libc/include/ctype.h @@ -0,0 +1,14 @@ +#ifndef CTYPE_H +#define CTYPE_H + +int isspace(int c); +int isascii(int c); +int toupper(int c); +int tolower(int c); +int isdigit(int c); +int isalpha(int c); +int isxdigit(int c); +int ispunct(int c); +int isalnum(int c); +int isprint(int c); +#endif diff --git a/userland/libc/include/dirent.h b/userland/libc/include/dirent.h new file mode 100644 index 0000000..f190a7c --- /dev/null +++ b/userland/libc/include/dirent.h @@ -0,0 +1,28 @@ +#ifndef DIRENT_H +#define DIRENT_H +#include <fcntl.h> +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> + +struct dirent { + ino_t d_ino; // File serial number. + char d_name[PATH_MAX]; // Filename string of entry. +}; + +typedef struct { + int fd; + struct dirent internal_direntry; + int dir_num; +} DIR; + +DIR *opendir(const char *dirname); +struct dirent *readdir(DIR *dir); +int closedir(DIR *dirp); +int alphasort(const struct dirent **d1, const struct dirent **d2); +int scandir(const char *dir, struct dirent ***namelist, + int (*sel)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)); +#endif diff --git a/userland/libc/include/endian.h b/userland/libc/include/endian.h new file mode 100644 index 0000000..f265a67 --- /dev/null +++ b/userland/libc/include/endian.h @@ -0,0 +1,2 @@ +#define LITTLE_ENDIAN 0 +#define BYTE_ORDER LITTLE_ENDIAN diff --git a/userland/libc/include/err.h b/userland/libc/include/err.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/err.h diff --git a/userland/libc/include/errno.h b/userland/libc/include/errno.h new file mode 100644 index 0000000..ec9a25e --- /dev/null +++ b/userland/libc/include/errno.h @@ -0,0 +1,87 @@ +#ifndef ERRNO_H +#define ERRNO_H +// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html +#define E2BIG 1 // Argument list too long. +#define EACCES 2 // Permission denied. +#define EADDRINUSE 3 // Address in use. +#define EADDRNOTAVAIL 4 // Address not available. +#define EAFNOSUPPORT 5 // Address family not supported. +#define EAGAIN 6 // Resource unavailable, try again. +#define EALREADY 7 // Connection already in progress. +#define EBADF 8 // Bad file descriptor. +#define EBADMSG 9 // Bad message. +#define EBUSY 10 // Device or resource busy. +#define ECANCELED 11 // Operation canceled. +#define ECHILD 12 // No child processes. +#define ECONNABORTED 13 // Connection aborted. +#define ECONNREFUSED 14 // Connection refused. +#define ECONNRESET 15 // Connection reset. +#define EDEADLK 16 // Resource deadlock would occur. +#define EDESTADDRREQ 17 // Destination address required. +#define EDOM 18 // Mathematics argument out of domain of function. +#define EDQUOT 19 // Reserved. +#define EEXIST 20 // File exists. +#define EFAULT 21 // Bad address. +#define EFBIG 22 // File too large. +#define EHOSTUNREACH 23 // Host is unreachable. +#define EIDRM 24 // Identifier removed. +#define EILSEQ 25 // Illegal byte sequence. +#define EINPROGRESS 26 // Operation in progress. +#define EINTR 27 // Interrupted function. +#define EINVAL 28 // Invalid argument. +#define EIO 29 // I/O error. +#define EISCONN 30 // Socket is connected. +#define EISDIR 31 // Is a directory. +#define ELOOP 32 // Too many levels of symbolic links. +#define EMFILE 33 // File descriptor value too large. +#define EMLINK 34 // Too many links. +#define EMSGSIZE 35 // Message too large. +#define EMULTIHOP 36 // Reserved. +#define ENAMETOOLONG 37 // Filename too long. +#define ENETDOWN 38 // Network is down. +#define ENETRESET 39 // Connection aborted by network. +#define ENETUNREACH 40 // Network unreachable. +#define ENFILE 41 // Too many files open in system. +#define ENOBUFS 42 // No buffer space available. +#define ENODATA 43 // No message is available on the STREAM head read queue. +#define ENODEV 44 // No such device. +#define ENOENT 45 // No such file or directory. +#define ENOEXEC 46 // Executable file format error. +#define ENOLCK 47 // No locks available. +#define ENOLINK 48 // Reserved. +#define ENOMEM 49 // Not enough space. +#define ENOMSG 50 // No message of the desired type. +#define ENOPROTOOPT 51 // Protocol not available. +#define ENOSPC 52 // No space left on device. +#define ENOSR 53 // No STREAM resources. +#define ENOSTR 54 // Not a STREAM. +#define ENOSYS 55 // Functionality not supported. +#define ENOTCONN 56 // The socket is not connected. +#define ENOTDIR 57 // Not a directory or a symbolic link to a directory. +#define ENOTEMPTY 58 // Directory not empty. +#define ENOTRECOVERABLE 59 // State not recoverable. +#define ENOTSOCK 60 // Not a socket. +#define ENOTSUP 61 // Not supported (may be the same value as. +#define ENOTTY 62 // Inappropriate I/O control operation. +#define ENXIO 63 // No such device or address. +#define EOPNOTSUPP ENOTSUP // Operation not supported on socket. +#define EOVERFLOW 65 // Value too large to be stored in data type. +#define EOWNERDEAD 66 // Previous owner died. +#define EPERM 67 // Operation not permitted. +#define EPIPE 68 // Broken pipe. +#define EPROTO 69 // Protocol error. +#define EPROTONOSUPPORT 70 // Protocol not supported. +#define EPROTOTYPE 71 // Protocol wrong type for socket. +#define ERANGE 72 // Result too large. +#define EROFS 73 // Read-only file system. +#define ESPIPE 74 // Invalid seek. +#define ESRCH 75 // No such process. +#define ESTALE 76 // Reserved. +#define ETIME 77 // Stream ioctl() timeout. +#define ETIMEDOUT 78 // Connection timed out. +#define ETXTBSY 79 // Text file busy. +#define EWOULDBLOCK EAGAIN // Operation would block. +#define EXDEV 81 // Cross-device link. + +extern int errno; +#endif diff --git a/userland/libc/include/fcntl.h b/userland/libc/include/fcntl.h new file mode 100644 index 0000000..7f0906d --- /dev/null +++ b/userland/libc/include/fcntl.h @@ -0,0 +1,12 @@ +// FIXME: Is there some standard value for this? +#define O_NONBLOCK (1 << 0) +#define O_READ (1 << 1) +#define O_WRITE (1 << 2) +#define O_CREAT (1 << 3) +#define O_TRUNC (1 << 4) + +#define O_RDONLY O_READ +#define O_WRONLY O_WRITE +#define O_RDWR (O_WRITE | O_READ) + +int open(const char *file, int flags, int mode); diff --git a/userland/libc/include/fnmatch.h b/userland/libc/include/fnmatch.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/fnmatch.h diff --git a/userland/libc/include/glob.h b/userland/libc/include/glob.h new file mode 100644 index 0000000..f9e9c57 --- /dev/null +++ b/userland/libc/include/glob.h @@ -0,0 +1,10 @@ +#ifndef GLOB_H +#define GLOB_H +#include <stddef.h> + +typedef struct { + size_t gl_pathc; // Count of paths matched by pattern. + char **gl_pathv; // Pointer to a list of matched pathnames + size_t gl_offs; // Slots to reserve at the beginning of gl_pathv. +} glob_t; +#endif diff --git a/userland/libc/include/grp.h b/userland/libc/include/grp.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/grp.h diff --git a/userland/libc/include/input.h b/userland/libc/include/input.h new file mode 100644 index 0000000..a6602f5 --- /dev/null +++ b/userland/libc/include/input.h @@ -0,0 +1,9 @@ +#ifndef INPUT_H +#define INPUT_H +#include <stdint.h> + +struct input_event { + uint16_t key; + uint8_t status; +}; +#endif diff --git a/userland/libc/include/inttypes.h b/userland/libc/include/inttypes.h new file mode 100644 index 0000000..adde7c8 --- /dev/null +++ b/userland/libc/include/inttypes.h @@ -0,0 +1,19 @@ +#include <stdint.h> + +// FIXME: These are not correct +#define PRId8 "d" +#define PRId16 "d" +#define PRId32 "d" +#define PRId64 "d" +#define PRIu8 "d" +#define PRIu16 "d" +#define PRIu32 "d" +#define PRIu64 "d" +#define PRIx8 "x" +#define PRIx16 "x" +#define PRIx32 "x" +#define PRIx64 "x" +#define PRIX8 "x" +#define PRIX16 "x" +#define PRIX32 "x" +#define PRIX64 "x" diff --git a/userland/libc/include/langinfo.h b/userland/libc/include/langinfo.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/langinfo.h diff --git a/userland/libc/include/libgen.h b/userland/libc/include/libgen.h new file mode 100644 index 0000000..16dc3ed --- /dev/null +++ b/userland/libc/include/libgen.h @@ -0,0 +1,6 @@ +#ifndef LIBGEN_H +#define LIBGEN_H + +char *basename(char *path); +char *dirname(char *path); +#endif diff --git a/userland/libc/include/limits.h b/userland/libc/include/limits.h new file mode 100644 index 0000000..6d0abe0 --- /dev/null +++ b/userland/libc/include/limits.h @@ -0,0 +1,4 @@ +#define PATH_MAX 256 +#define FILENAME_MAX PATH_MAX +#define ULONG_MAX 0xFFFFFFFFUL +#define LONG_MAX 2147483647 diff --git a/userland/libc/include/locale.h b/userland/libc/include/locale.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/locale.h diff --git a/userland/libc/include/math.h b/userland/libc/include/math.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/math.h diff --git a/userland/libc/include/net/if.h b/userland/libc/include/net/if.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/net/if.h diff --git a/userland/libc/include/netdb.h b/userland/libc/include/netdb.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/netdb.h diff --git a/userland/libc/include/netinet/in.h b/userland/libc/include/netinet/in.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/netinet/in.h diff --git a/userland/libc/include/netinet/tcp.h b/userland/libc/include/netinet/tcp.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/netinet/tcp.h diff --git a/userland/libc/include/paths.h b/userland/libc/include/paths.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/paths.h diff --git a/userland/libc/include/poll.h b/userland/libc/include/poll.h new file mode 100644 index 0000000..e3c6d8d --- /dev/null +++ b/userland/libc/include/poll.h @@ -0,0 +1,17 @@ +#ifndef POLL_H +#define POLL_H +#include <stddef.h> + +#define POLLIN (1 << 0) +#define POLLPRI (1 << 1) +#define POLLOUT (1 << 2) +#define POLLHUP (1 << 3) + +struct pollfd { + int fd; + short events; + short revents; +}; + +int poll(struct pollfd *fds, size_t nfds, int timeout); +#endif diff --git a/userland/libc/include/pty.h b/userland/libc/include/pty.h new file mode 100644 index 0000000..b8ce978 --- /dev/null +++ b/userland/libc/include/pty.h @@ -0,0 +1,6 @@ +#ifndef PTY_H +#define PTY_H +int openpty(int *amaster, int *aslave, char *name, + /*const struct termios*/ void *termp, + /*const struct winsize*/ void *winp); +#endif diff --git a/userland/libc/include/pwd.h b/userland/libc/include/pwd.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/pwd.h diff --git a/userland/libc/include/regex.h b/userland/libc/include/regex.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/regex.h diff --git a/userland/libc/include/sched.h b/userland/libc/include/sched.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sched.h diff --git a/userland/libc/include/setjmp.h b/userland/libc/include/setjmp.h new file mode 100644 index 0000000..ea15cf3 --- /dev/null +++ b/userland/libc/include/setjmp.h @@ -0,0 +1,14 @@ +#ifndef SETJMP_H +#define SETJMP_H +typedef unsigned long __jmp_buf[6]; +typedef struct __jmp_buf_tag { + __jmp_buf __jb; + unsigned long __fl; + unsigned long __ss[128/sizeof(long)]; +} jmp_buf[1]; +typedef jmp_buf sigjmp_buf; + +void _longjmp(jmp_buf, int); +void longjmp(jmp_buf, int); +void siglongjmp(sigjmp_buf, int); +#endif diff --git a/userland/libc/include/signal.h b/userland/libc/include/signal.h new file mode 100644 index 0000000..2e6566d --- /dev/null +++ b/userland/libc/include/signal.h @@ -0,0 +1,9 @@ +#ifndef SIGNAL_H +#define SIGNAL_H +#define SIGHUP 0 +#define SIGINT 1 +#define SIGWINCH 2 +#define SIGQUIT 3 +#define SIG_IGN 4 +typedef int sig_atomic_t; +#endif // SIGNAL_H diff --git a/userland/libc/include/socket.h b/userland/libc/include/socket.h new file mode 100644 index 0000000..5e86b45 --- /dev/null +++ b/userland/libc/include/socket.h @@ -0,0 +1,41 @@ +#include <stddef.h> +#include <stdint.h> + +#define AF_UNIX 0 +#define AF_LOCAL AF_UNIX + +#define INADDR_ANY 0 + +typedef struct { + int domain; + int type; + int protocol; + + // UNIX socket + char *path; + int incoming_fd; +} SOCKET; + +typedef struct { + char *path; + SOCKET *s; +} OPEN_UNIX_SOCKET; + +typedef uint32_t in_addr_t; +typedef uint16_t in_port_t; +typedef unsigned int sa_family_t; +typedef uint32_t socklen_t; + +struct sockaddr { + sa_family_t sa_family; /* Address family */ + char *sa_data; /* Socket address */ +}; + +struct sockaddr_un { + sa_family_t sun_family; /* Address family */ + char *sun_path; /* Socket pathname */ +}; + +int socket(int domain, int type, int protocol); +int accept(int socket, struct sockaddr *address, socklen_t *address_len); +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); diff --git a/userland/libc/include/stdio.h b/userland/libc/include/stdio.h new file mode 100644 index 0000000..014e2ac --- /dev/null +++ b/userland/libc/include/stdio.h @@ -0,0 +1,116 @@ +#ifndef STDIO_H +#define STDIO_H +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> + +// FIXME: Most of these should probably not be here. But I am too lazy +// to fix it right now. This is futures mees problem to deal wth. + +#define EOF (-1) + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define BUFSIZ 4096 + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/setvbuf.html +#define _IOFBF 1 // shall cause input/output to be fully buffered. +#define _IOLBF 2 // shall cause input/output to be line buffered. +#define _IONBF 3 // shall cause input/output to be unbuffered. + +typedef long fpos_t; + +typedef struct __IO_FILE FILE; +struct __IO_FILE { + size_t (*write)(FILE *, const unsigned char *, size_t); + size_t (*read)(FILE *, unsigned char *, size_t); + int (*seek)(FILE *, long, int); + long offset_in_file; + int buffered_char; + int has_buffered_char; + int fd; + uint8_t is_eof; + uint8_t has_error; + uint64_t file_size; + void *cookie; +}; + +size_t write_fd(FILE *f, const unsigned char *s, size_t l); +size_t read_fd(FILE *f, unsigned char *s, size_t l); +int seek_fd(FILE *stream, long offset, int whence); + +typedef struct { + int fd; +} FILE_FD_COOKIE; + +extern FILE __stdin_FILE; +extern FILE __stdout_FILE; +extern FILE __stderr_FILE; + +#define stdin (&__stdin_FILE) +#define stdout (&__stdout_FILE) +//#define stderr (&__stderr_FILE) +#define stderr (&__stdout_FILE) + +typedef int mode_t; + +void perror(const char *s); + +int putchar(int c); +int puts(const char *s); +int brk(void *addr); +void *sbrk(intptr_t increment); +int write(int fd, const char *buf, size_t count); +int pwrite(int fd, const char *buf, size_t count, size_t offset); +int printf(const char *format, ...); +int pread(int fd, void *buf, size_t count, size_t offset); +int read(int fd, void *buf, size_t count); +int fork(void); +int memcmp(const void *s1, const void *s2, size_t n); +int wait(int *stat_loc); +void exit(int status); +void *memcpy(void *dest, const void *src, uint32_t n); +int shm_open(const char *name, int oflag, mode_t mode); +int dprintf(int fd, const char *format, ...); +int vdprintf(int fd, const char *format, va_list ap); +int vprintf(const char *format, va_list ap); +int snprintf(char *str, size_t size, const char *format, ...); +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +int vfprintf(FILE *f, const char *fmt, va_list ap); +int fgetc(FILE *stream); +int getchar(void); +#define getc(_a) fgetc(_a) +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +FILE *fopen(const char *pathname, const char *mode); +int fclose(FILE *stream); +int fseek(FILE *stream, long offset, int whence); +int fprintf(FILE *f, const char *fmt, ...); +int atoi(const char *str); +long strtol(const char *nptr, char **endptr, int base); +char *strchr(const char *s, int c); +char *strcat(char *s1, const char *s2); +char *fgets(char *s, int n, FILE *stream); +FILE *tmpfile(void); +int feof(FILE *stream); +int fscanf(FILE *stream, const char *format, ...); +int ungetc(int c, FILE *stream); +long ftell(FILE *stream); +int fputc(int c, FILE *stream); +int remove(const char *path); +int ferror(FILE *stream); +int fputs(const char *s, FILE *stream); +int fflush(FILE *stream); +int setvbuf(FILE *stream, char *restrict buf, int type, size_t size); +int fileno(FILE *stream); +int putc(int c, FILE *stream); +int vsprintf(char *str, const char *format, va_list ap); +int sprintf(char *str, const char *format, ...); +FILE *open_memstream(char **bufp, size_t *sizep); +int fsetpos(FILE *stream, const fpos_t *pos); +int fgetpos(FILE *restrict stream, fpos_t *restrict pos); +char *tmpnam(char *s); +int rename(const char *old, const char *new); +#endif diff --git a/userland/libc/include/stdlib.h b/userland/libc/include/stdlib.h new file mode 100644 index 0000000..c88f2f3 --- /dev/null +++ b/userland/libc/include/stdlib.h @@ -0,0 +1,32 @@ +#ifndef STDLIB_H +#define STDLIB_H +#include <limits.h> +#include <stddef.h> +#define RAND_MAX (UINT32_MAX) +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +typedef size_t size_t; // only for 32 bit + +void *malloc(size_t s); +void *calloc(size_t nelem, size_t elsize); +void *realloc(void *ptr, size_t size); +void free(void *p); +char *getenv(const char *name); +int rand(void); +void srand(unsigned int seed); +unsigned long strtoul(const char *restrict str, char **restrict endptr, + int base); +long strtol(const char *str, char **restrict endptr, int base); +void abort(void); +int abs(int i); +void qsort(void *base, size_t nel, size_t width, + int (*compar)(const void *, const void *)); +int atexit(void (*func)(void)); +int mkstemp(char *template); +long double strtold(const char *restrict nptr, char **restrict endptr); +int system(const char *command); +double atof(const char *str); +double strtod(const char *restrict nptr, char **restrict endptr); +int atoi(const char *str); +#endif diff --git a/userland/libc/include/string.h b/userland/libc/include/string.h new file mode 100644 index 0000000..0c61efa --- /dev/null +++ b/userland/libc/include/string.h @@ -0,0 +1,29 @@ +#ifndef STRING_H +#define STRING_H +#include <stddef.h> +#include <stdint.h> + +char *strerror(int errnum); +void *memset(void *s, int c, size_t n); +void *memcpy(void *dest, const void *src, uint32_t n); +int strcmp(const char *s1, const char *s2); +char *strcpy(char *dest, const char *src); +size_t strlen(const char *s); +size_t strnlen(const char *s, size_t maxlen); +int sscanf(const char *s, const char *restrict format, ...); +char *strrchr(const char *s, int c); +int strncmp(const char *s1, const char *s2, size_t n); +char *strncpy(char *s1, const char *s2, size_t n); +size_t *strlcpy(char *s1, const char *s2, size_t n); +size_t strcspn(const char *s1, const char *s2); +char *strpbrk(const char *s1, const char *s2); +size_t strspn(const char *s1, const char *s2); +void *memmove(void *s1, const void *s2, size_t n); +char *strdup(const char *s); +char *strndup(const char *s, size_t size); +char *strstr(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, size_t n); +int strcasecmp(const char *s1, const char *s2); +char *strtok(char *restrict s, const char *restrict sep); +char *strcat(char *restrict s1, const char *restrict s2); +#endif diff --git a/userland/libc/include/strings.h b/userland/libc/include/strings.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/strings.h diff --git a/userland/libc/include/sys/ioctl.h b/userland/libc/include/sys/ioctl.h new file mode 100644 index 0000000..a373a4b --- /dev/null +++ b/userland/libc/include/sys/ioctl.h @@ -0,0 +1,10 @@ +#ifndef IOCTL_H +#define IOCTL_H +#define TIOCGWINSZ 0 +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; +#endif // IOCTL_H diff --git a/userland/libc/include/sys/mman.h b/userland/libc/include/sys/mman.h new file mode 100644 index 0000000..7dfe29a --- /dev/null +++ b/userland/libc/include/sys/mman.h @@ -0,0 +1,15 @@ +#ifndef MMAP_H +#define MMAP_H +#include <stdint.h> +#include <stddef.h> + +#define PROT_READ (1 << 0) +#define PROT_WRITE (1 << 1) + +#define MAP_PRIVATE (1 << 0) +#define MAP_ANONYMOUS (1<< 1) +#define MAP_SHARED (1<< 2) + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, + size_t offset); +#endif diff --git a/userland/libc/include/sys/mount.h b/userland/libc/include/sys/mount.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/mount.h diff --git a/userland/libc/include/sys/resource.h b/userland/libc/include/sys/resource.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/resource.h diff --git a/userland/libc/include/sys/socket.h b/userland/libc/include/sys/socket.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/socket.h diff --git a/userland/libc/include/sys/stat.h b/userland/libc/include/sys/stat.h new file mode 100644 index 0000000..178d014 --- /dev/null +++ b/userland/libc/include/sys/stat.h @@ -0,0 +1,31 @@ +#ifndef STAT_H +#define STAT_H +#include <sys/types.h> +#include <time.h> + +struct stat { + dev_t st_dev; // Device ID of device containing file. + ino_t st_ino; // File serial number. + mode_t st_mode; // Mode of file (see below). + nlink_t st_nlink; // Number of hard links to the file. + uid_t st_uid; // User ID of file. + gid_t st_gid; // Group ID of file. + dev_t st_rdev; // Device ID (if file is character or block special). + off_t st_size; // For regular files, the file size in bytes. + // For symbolic links, the length in bytes of the + // pathname contained in the symbolic link. + // For a shared memory object, the length in bytes. + // For a typed memory object, the length in bytes. + // For other file types, the use of this field is + // unspecified. + struct timespec st_atime; // Last data access timestamp. + struct timespec st_mtime; // Last data modification timestamp. + struct timespec st_ctime; // Last file status change timestamp. + blksize_t st_blksize; // A file system-specific preferred I/O block size + // for this object. In some file system types, this + // may vary from file to file. + blkcnt_t st_blocks; // Number of blocks allocated for this object. +}; +int stat(const char *path, struct stat *buf); +int mkdir(const char *path, mode_t mode); +#endif diff --git a/userland/libc/include/sys/statvfs.h b/userland/libc/include/sys/statvfs.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/statvfs.h diff --git a/userland/libc/include/sys/syscall.h b/userland/libc/include/sys/syscall.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/syscall.h diff --git a/userland/libc/include/sys/time.h b/userland/libc/include/sys/time.h new file mode 100644 index 0000000..a675d9e --- /dev/null +++ b/userland/libc/include/sys/time.h @@ -0,0 +1,41 @@ +#ifndef TIME_H +#define TIME_H +#include <stddef.h> +#include <sys/types.h> +#include <time.h> + +#define CLOCK_REALTIME 0 + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long __tm_gmtoff; + const char *__tm_zone; +}; + +typedef int clockid_t; +struct timespec { + time_t tv_sec; // Seconds. + long tv_nsec; // Nanoseconds. +}; + +struct timeval { + time_t tv_sec; + suseconds_t tv_usec; +}; + +time_t time(time_t *tloc); +int clock_gettime(clockid_t clock_id, struct timespec *tp); +struct tm *localtime(const time_t *timer); +struct tm *gmtime(const time_t *timer); +size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, + const struct tm *restrict timeptr); +int gettimeofday(struct timeval *tp, void *tzp); +#endif diff --git a/userland/libc/include/sys/times.h b/userland/libc/include/sys/times.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/times.h diff --git a/userland/libc/include/sys/types.h b/userland/libc/include/sys/types.h new file mode 100644 index 0000000..48c57f9 --- /dev/null +++ b/userland/libc/include/sys/types.h @@ -0,0 +1,28 @@ +#ifndef TYPES_H +#define TYPES_H +typedef unsigned int ino_t; + +typedef int mode_t; + +typedef int nlink_t; +typedef int uid_t; +typedef int gid_t; +typedef int id_t; + +typedef int blkcnt_t; +typedef int off_t; + +typedef int dev_t; +typedef unsigned int fsblkcnt_t; +typedef unsigned int fsfilcnt_t; +typedef unsigned int ino_t; +//typedef unsigned int size_t; + +typedef int blksize_t; +typedef int pid_t; +typedef int ssize_t; + +//typedef int clock_t; +typedef int time_t; +typedef unsigned int suseconds_t; +#endif diff --git a/userland/libc/include/sys/ucontext.h b/userland/libc/include/sys/ucontext.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/ucontext.h diff --git a/userland/libc/include/sys/un.h b/userland/libc/include/sys/un.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/un.h diff --git a/userland/libc/include/sys/utsname.h b/userland/libc/include/sys/utsname.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/utsname.h diff --git a/userland/libc/include/sys/wait.h b/userland/libc/include/sys/wait.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/sys/wait.h diff --git a/userland/libc/include/syscall.h b/userland/libc/include/syscall.h new file mode 100644 index 0000000..caa7779 --- /dev/null +++ b/userland/libc/include/syscall.h @@ -0,0 +1,150 @@ +#ifndef SYSCALL_H +#define SYSCALL_H +#include "socket.h" +#include <stddef.h> +#include <stdint.h> +#include <sys/types.h> + +#define SYS_OPEN 0 +#define SYS_READ 1 +#define SYS_WRITE 2 +#define SYS_PREAD 3 +#define SYS_PWRITE 4 +#define SYS_FORK 5 +#define SYS_EXEC 6 +#define SYS_GETPID 7 +#define SYS_EXIT 8 +#define SYS_WAIT 9 +#define SYS_BRK 10 +#define SYS_SBRK 11 +#define SYS_PIPE 12 +#define SYS_DUP2 13 +#define SYS_CLOSE 14 +#define SYS_OPENPTY 15 +#define SYS_POLL 16 +#define SYS_MMAP 17 +#define SYS_ACCEPT 18 +#define SYS_BIND 19 +#define SYS_SOCKET 20 +#define SYS_SHM_OPEN 21 +#define SYS_FTRUNCATE 22 +#define SYS_STAT 23 +#define SYS_MSLEEP 24 +#define SYS_UPTIME 25 + +int syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx, + uint32_t esi, uint32_t edi); +int s_syscall(int sys); + +extern int errno; +#define RC_ERRNO(_rc) \ + { \ + int c = _rc; \ + if (c < 0) { \ + errno = -(c); \ + return -1; \ + } \ + return c; \ + } + +typedef int mode_t; + +typedef struct SYS_OPEN_PARAMS { + const char *file; + int flags; + int mode; +} __attribute__((packed)) SYS_OPEN_PARAMS; + +typedef struct SYS_PREAD_PARAMS { + int fd; + void *buf; + size_t count; + size_t offset; +} __attribute__((packed)) SYS_PREAD_PARAMS; + +typedef struct SYS_READ_PARAMS { + int fd; + void *buf; + size_t count; +} __attribute__((packed)) SYS_READ_PARAMS; + +typedef struct SYS_PWRITE_PARAMS { + int fd; + const void *buf; + size_t count; + size_t offset; +} __attribute__((packed)) SYS_PWRITE_PARAMS; + +typedef struct SYS_WRITE_PARAMS { + int fd; + const void *buf; + size_t count; +} __attribute__((packed)) SYS_WRITE_PARAMS; + +typedef struct SYS_EXEC_PARAMS { + const char *path; + char **argv; +} __attribute__((packed)) SYS_EXEC_PARAMS; + +typedef struct SYS_DUP2_PARAMS { + int org_fd; + int new_fd; +} __attribute__((packed)) SYS_DUP2_PARAMS; + +typedef struct SYS_OPENPTY_PARAMS { + int *amaster; + int *aslave; + char *name; + /*const struct termios*/ void *termp; + /*const struct winsize*/ void *winp; +} __attribute__((packed)) SYS_OPENPTY_PARAMS; + +typedef struct SYS_POLL_PARAMS { + struct pollfd *fds; + size_t nfds; + int timeout; +} __attribute__((packed)) SYS_POLL_PARAMS; + +typedef struct SYS_MMAP_PARAMS { + void *addr; + size_t length; + int prot; + int flags; + int fd; + size_t offset; +} __attribute__((packed)) SYS_MMAP_PARAMS; + +typedef struct SYS_SOCKET_PARAMS { + int domain; + int type; + int protocol; +} __attribute__((packed)) SYS_SOCKET_PARAMS; + +typedef struct SYS_BIND_PARAMS { + int sockfd; + const struct sockaddr *addr; + socklen_t addrlen; +} __attribute__((packed)) SYS_BIND_PARAMS; + +typedef struct SYS_ACCEPT_PARAMS { + int socket; + struct sockaddr *address; + socklen_t *address_len; +} __attribute__((packed)) SYS_ACCEPT_PARAMS; + +typedef struct SYS_SHM_OPEN_PARAMS { + const char *name; + int oflag; + mode_t mode; +} __attribute__((packed)) SYS_SHM_OPEN_PARAMS; + +typedef struct SYS_FTRUNCATE_PARAMS { + int fildes; + size_t length; +} __attribute__((packed)) SYS_FTRUNCATE_PARAMS; + +typedef struct SYS_STAT_PARAMS { + const char *pathname; + struct stat *statbuf; +} __attribute__((packed)) SYS_STAT_PARAMS; +#endif diff --git a/userland/libc/include/syslog.h b/userland/libc/include/syslog.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/syslog.h diff --git a/userland/libc/include/termios.h b/userland/libc/include/termios.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/termios.h diff --git a/userland/libc/include/time.h b/userland/libc/include/time.h new file mode 100644 index 0000000..567e9ef --- /dev/null +++ b/userland/libc/include/time.h @@ -0,0 +1,35 @@ +#ifndef TIME_H +#define TIME_H +#include <sys/types.h> +#include <stddef.h> + +#define CLOCK_REALTIME 0 + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long __tm_gmtoff; + const char *__tm_zone; +}; + +typedef int clockid_t; +struct timespec { + time_t tv_sec; // Seconds. + long tv_nsec; // Nanoseconds. +}; + +time_t time(time_t *tloc); +int clock_gettime(clockid_t clock_id, struct timespec *tp); +struct tm *localtime(const time_t *timer); +struct tm *gmtime(const time_t *timer); +size_t strftime(char *restrict s, size_t maxsize, + const char *restrict format, const struct tm *restrict timeptr); +char *ctime_r(const time_t *clock, char *buf); +#endif diff --git a/userland/libc/include/ubsan.h b/userland/libc/include/ubsan.h new file mode 100644 index 0000000..dac5407 --- /dev/null +++ b/userland/libc/include/ubsan.h @@ -0,0 +1,79 @@ +#include <stdint.h> + +enum { type_kind_int = 0, type_kind_float = 1, type_unknown = 0xffff }; + +struct type_descriptor { + uint16_t type_kind; + uint16_t type_info; + char type_name[1]; +}; + +struct source_location { + const char *file_name; + union { + unsigned long reported; + struct { + uint32_t line; + uint32_t column; + }; + }; +}; + +struct OverflowData { + struct source_location location; + struct type_descriptor *type; +}; + +struct type_mismatch_data { + struct source_location location; + struct type_descriptor *type; + unsigned long alignment; + unsigned char type_check_kind; +}; + +struct type_mismatch_data_v1 { + struct source_location location; + struct type_descriptor *type; + unsigned char log_alignment; + unsigned char type_check_kind; +}; + +struct type_mismatch_data_common { + struct source_location *location; + struct type_descriptor *type; + unsigned long alignment; + unsigned char type_check_kind; +}; + +struct nonnull_arg_data { + struct source_location location; + struct source_location attr_location; + int arg_index; +}; + +struct OutOfBoundsData { + struct source_location location; + struct type_descriptor *array_type; + struct type_descriptor *index_type; +}; + +struct ShiftOutOfBoundsData { + struct source_location location; + struct type_descriptor *lhs_type; + struct type_descriptor *rhs_type; +}; + +struct unreachable_data { + struct source_location location; +}; + +struct invalid_value_data { + struct source_location location; + struct type_descriptor *type; +}; + +struct alignment_assumption_data { + struct source_location location; + struct source_location assumption_location; + struct type_descriptor *type; +}; diff --git a/userland/libc/include/unistd.h b/userland/libc/include/unistd.h new file mode 100644 index 0000000..e43dc33 --- /dev/null +++ b/userland/libc/include/unistd.h @@ -0,0 +1,24 @@ +#ifndef UNISTD_H +#define UNISTD_H +#include <stddef.h> +#include <stdint.h> +#include <sys/types.h> + +#define STDIN_FILENO 0 + +extern int opterr, optind, optopt; +extern char *optarg; + +int close(int fildes); +int ftruncate(int fildes, uint64_t length); +int execv(char *path, char **argv); +int pipe(int fd[2]); +int dup2(int org_fd, int new_fd); +int getopt(int argc, char *const argv[], const char *optstring); +pid_t getpid(void); +int unlink(const char *path); +int execvp(const char *file, char *const argv[]); +void _exit(int status); +void msleep(uint32_t ms); // not standard +uint32_t uptime(void); // not standard +#endif diff --git a/userland/libc/include/utime.h b/userland/libc/include/utime.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/utime.h diff --git a/userland/libc/include/wchar.h b/userland/libc/include/wchar.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/wchar.h diff --git a/userland/libc/include/wctype.h b/userland/libc/include/wctype.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/include/wctype.h diff --git a/userland/libc/input.h b/userland/libc/input.h new file mode 100644 index 0000000..a6602f5 --- /dev/null +++ b/userland/libc/input.h @@ -0,0 +1,9 @@ +#ifndef INPUT_H +#define INPUT_H +#include <stdint.h> + +struct input_event { + uint16_t key; + uint8_t status; +}; +#endif diff --git a/userland/libc/inttypes.h b/userland/libc/inttypes.h new file mode 100644 index 0000000..0bf39d1 --- /dev/null +++ b/userland/libc/inttypes.h @@ -0,0 +1,5 @@ +#include <stdint.h> + +// FIXME: These are not correct +#define PRId64 "d" +#define PRId32 "d" diff --git a/userland/libc/isspace.c b/userland/libc/isspace.c new file mode 100644 index 0000000..9ba2766 --- /dev/null +++ b/userland/libc/isspace.c @@ -0,0 +1,5 @@ +#include <ctype.h> + +int isspace(int c) { + return c == ' ' || (unsigned)c-'\t' < 5; +} diff --git a/userland/libc/libc.c b/userland/libc/libc.c new file mode 100644 index 0000000..259ef0c --- /dev/null +++ b/userland/libc/libc.c @@ -0,0 +1,287 @@ +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <syscall.h> + +int errno; + +char *errno_strings[] = { + "", + "Argument list too long.", + "Permission denied.", + "Address in use.", + "Address not available.", + "Address family not supported.", + "Resource unavailable, try again (may be the same value as [EWOULDBLOCK]).", + "Connection already in progress.", + "Bad file descriptor.", + "Bad message.", + "Device or resource busy.", + "Operation canceled.", + "No child processes.", + "Connection aborted.", + "Connection refused.", + "Connection reset.", + "Resource deadlock would occur.", + "Destination address required.", + "Mathematics argument out of domain of function.", + "Reserved.", + "File exists.", + "Bad address.", + "File too large.", + "Host is unreachable.", + "Identifier removed.", + "Illegal byte sequence.", + "Operation in progress.", + "Interrupted function.", + "Invalid argument.", + "I/O error.", + "Socket is connected.", + "Is a directory.", + "Too many levels of symbolic links.", + "File descriptor value too large.", + "Too many links.", + "Message too large.", + "Reserved.", + "Filename too long.", + "Network is down.", + "Connection aborted by network.", + "Network unreachable.", + "Too many files open in system.", + "No buffer space available.", + "No message is available on the STREAM head read " + "queue. [Option End]", + "No such device.", + "No such file or directory.", + "Executable file format error.", + "No locks available.", + "Reserved.", + "Not enough space.", + "No message of the desired type.", + "Protocol not available.", + "No space left on device.", + "No STREAM resources.", + "Not a STREAM.", + "Functionality not supported.", + "The socket is not connected.", + "Not a directory or a symbolic link to a directory.", + "Directory not empty.", + "State not recoverable.", + "Not a socket.", + "Not supported (may be the same value as [EOPNOTSUPP]).", + "Inappropriate I/O control operation.", + "No such device or address.", + "Operation not supported on socket (may be the same value as [ENOTSUP]).", + "Value too large to be stored in data type.", + "Previous owner died.", + "Operation not permitted.", + "Broken pipe.", + "Protocol error.", + "Protocol not supported.", + "Protocol wrong type for socket.", + "Result too large.", + "Read-only file system.", + "Invalid seek.", + "No such process.", + "Reserved.", + "Stream ioctl() timeout. [Option End]", + "Connection timed out.", + "Text file busy.", + "Operation would block (may be the same value as [EAGAIN]).", + "Cross-device link. ", +}; + +#define ASSERT_NOT_REACHED assert(0) + +#define TAB_SIZE 8 + +// Functions preserve the registers ebx, esi, edi, ebp, and esp; while +// eax, ecx, edx are scratch registers. + +// Syscall: eax ebx ecx edx esi edi +int syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx, + uint32_t esi, uint32_t edi) { + asm volatile("push %edi\n" + "push %esi\n" + "push %ebx\n" + "mov 0x1C(%ebp), %edi\n" + "mov 0x18(%ebp), %esi\n" + "mov 0x14(%ebp), %edx\n" + "mov 0x10(%ebp), %ecx\n" + "mov 0xc(%ebp), %ebx\n" + "mov 0x8(%ebp), %eax\n" + "int $0x80\n" + "pop %ebx\n" + "pop %esi\n" + "pop %edi\n"); +} + +int pipe(int fd[2]) { return syscall(SYS_PIPE, fd, 0, 0, 0, 0); } + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html +char *strerror(int errnum) { + // The strerror() function shall map the error number in errnum to a + // locale-dependent error message string and shall return a pointer to it. + return errno_strings[errnum]; +} + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/perror.html +void perror(const char *s) { + // The perror() function shall map the error number accessed through the + // symbol errno to a language-dependent error message, which shall be written + // to the standard error stream as follows: + + // (First (if s is not a null pointer and the character pointed to + // by s is not the null byte), + if (s && *s != '\0') { + // the string pointed to by s + // followed by a <colon> and a <space>. + printf("%s: ", s); + } + + // Then an error message string followed by a <newline>. + // The contents of the error message strings shall be the same as those + // returned by strerror() with argument errno. + printf("%s\n", strerror(errno)); +} + +int open(const char *file, int flags, int mode) { + struct SYS_OPEN_PARAMS args = { + .file = file, + .flags = flags, + .mode = mode, + }; + RC_ERRNO(syscall(SYS_OPEN, &args, 0, 0, 0, 0)); +} + +int close(int fd) { return syscall(SYS_CLOSE, (void *)fd, 0, 0, 0, 0); } + +int execv(char *path, char **argv) { + struct SYS_EXEC_PARAMS args = {.path = path, .argv = argv}; + return syscall(SYS_EXEC, &args, 0, 0, 0, 0); +} +/* +int syscall(int sys, void *args) { + asm volatile("push %ebx\n" + "mov 0xc(%ebp), %ebx\n" + "mov 0x8(%ebp), %eax\n" + "int $0x80\n" + "pop %ebx\n"); +}*/ + +int s_syscall(int sys) { + asm volatile("movl %0, %%eax\n" + "int $0x80\n" ::"r"((uint32_t)sys)); +} + +int write(int fd, const char *buf, size_t count) { + /* + struct SYS_WRITE_PARAMS args = { + .fd = fd, + .buf = buf, + .count = count, + };*/ + return syscall(SYS_WRITE, fd, buf, count, 0, 0); +} + +int pwrite(int fd, const char *buf, size_t count, size_t offset) { + struct SYS_PWRITE_PARAMS args = { + .fd = fd, + .buf = buf, + .count = count, + .offset = offset, + }; + return syscall(SYS_PWRITE, &args, 0, 0, 0, 0); +} + +int wait(int *stat_loc) { return syscall(SYS_WAIT, stat_loc, 0, 0, 0, 0); } + +void exit(int status) { syscall(SYS_EXIT, (void *)status, 0, 0, 0, 0); } + +int pread(int fd, void *buf, size_t count, size_t offset) { + struct SYS_PREAD_PARAMS args = { + .fd = fd, + .buf = buf, + .count = count, + .offset = offset, + }; + RC_ERRNO(syscall(SYS_PREAD, &args, 0, 0, 0, 0)); +} + +int read(int fd, void *buf, size_t count) { + struct SYS_READ_PARAMS args = { + .fd = fd, + .buf = buf, + .count = count, + }; + RC_ERRNO(syscall(SYS_READ, &args, 0, 0, 0, 0)); +} + +int dup2(int org_fd, int new_fd) { + struct SYS_DUP2_PARAMS args = { + .org_fd = org_fd, + .new_fd = new_fd, + }; + RC_ERRNO(syscall(SYS_DUP2, &args, 0, 0, 0, 0)); +} + +int fork(void) { return s_syscall(SYS_FORK); } + +void dputc(int fd, const char c) { pwrite(fd, &c, 1, 0); } + +int brk(void *addr) { return syscall(SYS_BRK, addr, 0, 0, 0, 0); } + +void *sbrk(intptr_t increment) { + return (void *)syscall(SYS_SBRK, (void *)increment, 0, 0, 0, 0); +} + +int poll(struct pollfd *fds, size_t nfds, int timeout) { + SYS_POLL_PARAMS args = { + .fds = fds, + .nfds = nfds, + .timeout = timeout, + }; + RC_ERRNO(syscall(SYS_POLL, &args, 0, 0, 0, 0)); +} + +int socket(int domain, int type, int protocol) { + SYS_SOCKET_PARAMS args = { + .domain = domain, + .type = type, + .protocol = protocol, + }; + RC_ERRNO(syscall(SYS_SOCKET, &args, 0, 0, 0, 0)); +} + +int accept(int socket, struct sockaddr *address, socklen_t *address_len) { + SYS_ACCEPT_PARAMS args = { + .socket = socket, + .address = address, + .address_len = address_len, + }; + RC_ERRNO(syscall(SYS_ACCEPT, &args, 0, 0, 0, 0)); +} + +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + SYS_BIND_PARAMS args = { + .sockfd = sockfd, + .addr = addr, + .addrlen = addrlen, + }; + RC_ERRNO(syscall(SYS_BIND, &args, 0, 0, 0, 0)); +} + +int shm_open(const char *name, int oflag, mode_t mode) { + SYS_SHM_OPEN_PARAMS args = { + .name = name, + .oflag = oflag, + .mode = mode, + }; + RC_ERRNO(syscall(SYS_SHM_OPEN, &args, 0, 0, 0, 0)); +} + +int ftruncate(int fildes, uint64_t length) { + SYS_FTRUNCATE_PARAMS args = {.fildes = fildes, .length = length}; + RC_ERRNO(syscall(SYS_FTRUNCATE, &args, 0, 0, 0, 0)); +} diff --git a/userland/libc/libgen/basename.c b/userland/libc/libgen/basename.c new file mode 100644 index 0000000..a0a8adb --- /dev/null +++ b/userland/libc/libgen/basename.c @@ -0,0 +1,45 @@ +#include <libgen.h> +#include <stddef.h> + +/* +The basename() function shall take the pathname pointed to by path and +return a pointer to the final component of the pathname, deleting any +trailing '/' characters. + + +The basename() function may modify the string pointed to by path, and +may return a pointer to internal storage. The returned pointer might be +invalidated or the storage might be overwritten by a subsequent call to +basename(). The returned pointer might also be invalidated if the +calling thread is terminated. +*/ + +char *basename_empty_return_value = "."; +char *basename_slash_return_value = "/"; +char *basename(char *path) { + // If path is a null pointer or points to an empty string, basename() + // shall return a pointer to the string ".". + if (NULL == path || '\0' == *path) + return basename_empty_return_value; + + char *start = path; + // Move the string to the end + for (; *path; path++) + ; + if (start == path) + return start; + path--; + if ('/' == *path) // Trailing slash + *path = '\0'; + // Loop until next slash is found + for (; path != start && '/' != *path; path--) + ; + // If the string pointed to by path consists entirely of the '/' character, + // basename() shall return a pointer to the string "/". If the string + // pointed to by path is exactly "//", it is implementation-defined whether + //'/' or "//" is returned. + path++; + if ('\0' == *path) + return basename_slash_return_value; + return path; +} diff --git a/userland/libc/libgen/dirname.c b/userland/libc/libgen/dirname.c new file mode 100644 index 0000000..fb3c813 --- /dev/null +++ b/userland/libc/libgen/dirname.c @@ -0,0 +1,44 @@ +#include <libgen.h> + +char *dirname_empty_return_value = "."; +char *dirname_slash_return_value = "/"; +char *dirname(char *path) { + // If path is a null pointer or points to an empty string, + // dirname() shall return a pointer to the string "." + if (!path) + return dirname_empty_return_value; + if ('\0' == *path) + return dirname_empty_return_value; + + char *start = path; + for (; *path; path++) + ; + path--; + if ('/' == *path) { + if (start == path) + return path; + path--; + } + + for (; path != start && '/' != *path; path--) + ; + // If path does not contain a '/', then dirname() shall return a pointer to + // the string ".". + if ('/' != *path) + return dirname_empty_return_value; + + if (path == start) + return dirname_slash_return_value; + + *path = '\0'; + path--; + + for (; path != start && '/' != *path; path--) + ; + + if ('/' != *path) + return dirname_empty_return_value; + + path++; + return path; +} diff --git a/userland/libc/limits.h b/userland/libc/limits.h new file mode 100644 index 0000000..0c9389a --- /dev/null +++ b/userland/libc/limits.h @@ -0,0 +1,2 @@ +#define PATH_MAX 256 +#define FILENAME_MAX PATH_MAX diff --git a/userland/libc/malloc/malloc.c b/userland/libc/malloc/malloc.c new file mode 100644 index 0000000..f351291 --- /dev/null +++ b/userland/libc/malloc/malloc.c @@ -0,0 +1,232 @@ +#include <assert.h> +#include <errno.h> +#include <malloc/malloc.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#define NEW_ALLOC_SIZE 0x20000 +#define MALLOC_HEADER_MAGIC 0x1337F00D +#define MALLOC_HEADER_PAD 0x11223344 + +#define IS_FREE (1 << 0) +#define IS_FINAL (1 << 1) + +typedef struct MallocHeader { + uint32_t magic; + uint32_t size; + uint8_t flags; + struct MallocHeader *n; +} MallocHeader; + +size_t max(size_t a, size_t b) { return (a > b) ? a : b; } + +//;size_t min(size_t a, size_t b) { return (a < b) ? a : b; } + +uint64_t delta_page(uint64_t a) { return 0x1000 - (a % 0x1000); } + +MallocHeader *head = NULL; +MallocHeader *final = NULL; +uint32_t total_heap_size = 0; + +int init_heap(void) { + head = (MallocHeader *)sbrk(NEW_ALLOC_SIZE); + if ((void *)-1 == head) { + perror("sbrk"); + exit(1); + } + total_heap_size += NEW_ALLOC_SIZE - sizeof(MallocHeader); + head->magic = MALLOC_HEADER_MAGIC; + head->size = NEW_ALLOC_SIZE - sizeof(MallocHeader); + head->flags = IS_FREE | IS_FINAL; + head->n = NULL; + final = head; + return 1; +} + +int add_heap_memory(size_t min_desired) { + min_desired += sizeof(MallocHeader) + 0x1000; + size_t allocation_size = max(min_desired, NEW_ALLOC_SIZE); + allocation_size += delta_page(allocation_size); + void *p; + if ((void *)(-1) == (p = (void *)sbrk(allocation_size))) { + perror("sbrk"); + return 0; + } + total_heap_size += allocation_size - sizeof(MallocHeader); + void *e = final; + e = (void *)((uint32_t)e + final->size); + if (p == e) { + final->size += allocation_size - sizeof(MallocHeader); + return 1; + } + MallocHeader *new_entry = p; + new_entry->magic = MALLOC_HEADER_MAGIC; + new_entry->size = allocation_size - sizeof(MallocHeader); + new_entry->flags = IS_FREE | IS_FINAL; + new_entry->n = NULL; + final->n = new_entry; + final = new_entry; + return 1; +} + +MallocHeader *next_header(MallocHeader *a) { return a->n; } + +MallocHeader *next_close_header(MallocHeader *a) { + if (!a) { + printf("next close header fail\n"); + for (;;) + ; + } + if (a->flags & IS_FINAL) + return NULL; + return next_header(a); +} + +MallocHeader *find_free_entry(uint32_t s, int align) { + // A new header is required as well as the newly allocated chunk + if (!head) + init_heap(); + MallocHeader *p = head; + for (; p; p = next_header(p)) { + if (!(p->flags & IS_FREE)) + continue; + uint64_t required_size = s; + if (align) { + void *addy = p; + addy = (void *)((uint32_t)addy + sizeof(MallocHeader)); + uint64_t d = delta_page((uint32_t)addy); + if (d < sizeof(MallocHeader) && d != 0) + continue; + required_size += d; + } + if (p->size < required_size) + continue; + return p; + } + return NULL; +} + +void merge_headers(MallocHeader *b) { + if (!(b->flags & IS_FREE)) + return; + + MallocHeader *n = next_close_header(b); + if (!n) + return; + + if (n > 0xf58c0820 - 0x8 && n < 0xf58c0820 + 0x8) { + printf("b: %x\n", b); + printf("b->n: %x\n", b->n); + asm("hlt"); + assert(0); + } + if (!(n->flags & IS_FREE)) + return; + + // Remove the next header and just increase the newly freed header + b->size += n->size; + b->flags |= n->flags & IS_FINAL; + b->n = n->n; + if (n == final) + final = b; +} + +extern int errno; +// https://pubs.opengroup.org/onlinepubs/9699919799/ +void *int_malloc(size_t s, int align) { + if (!head) + init_heap(); + size_t n = s; + MallocHeader *free_entry = find_free_entry(s, align); + if (!free_entry) { + if (!add_heap_memory(s)) { + errno = ENOMEM; + printf("ENOMEM\n"); + return NULL; + } + return int_malloc(s, align); + } + + void *rc = (void *)((uint32_t)free_entry + sizeof(MallocHeader)); + + if (align) { + uint64_t d = delta_page((uint32_t)rc); + n = d; + n -= sizeof(MallocHeader); + } + + // Create a new header + MallocHeader *new_entry = + (MallocHeader *)((uint32_t)free_entry + n + sizeof(MallocHeader)); + new_entry->magic = MALLOC_HEADER_MAGIC; + new_entry->flags = free_entry->flags; + new_entry->n = free_entry->n; + new_entry->size = free_entry->size - n - sizeof(MallocHeader); + if (free_entry == final) + final = new_entry; + merge_headers(new_entry); + + // Modify the free entry + free_entry->size = n; + free_entry->flags = 0; + free_entry->n = new_entry; + + if (align && ((uint32_t)rc % 0x1000) != 0) { + void *c = int_malloc(s, 1); + free(rc); + rc = c; + return rc; + } + return rc; +} + +void *malloc(size_t s) { return int_malloc(s + 1, 0); } + +// https://pubs.opengroup.org/onlinepubs/9699919799/ +void *calloc(size_t nelem, size_t elsize) { + // The calloc() function shall allocate unused space for an array of + // nelem elements each of whose size in bytes is elsize. + size_t alloc_size = nelem * elsize; + void *rc = malloc(alloc_size); + // The space shall be initialized to all bits 0. + memset(rc, 0, alloc_size); + return rc; +} + +size_t get_mem_size(void *ptr) { + if (!ptr) + return 0; + return ((MallocHeader *)(ptr - sizeof(MallocHeader)))->size; +} + +void *realloc(void *ptr, size_t size) { + void *rc = malloc(size); + if (!rc) + return NULL; + size_t l = get_mem_size(ptr); + size_t to_copy = min(l, size); + memcpy(rc, ptr, to_copy); + free(ptr); + return rc; +} + +void free(void *p) { + if (!p) + return; + // FIXME: This assumes that p is at the start of a allocated area. + // Is this a assumption that can be made? + MallocHeader *h = (MallocHeader *)((uint32_t)p - sizeof(MallocHeader)); + if (MALLOC_HEADER_MAGIC != h->magic) { + printf("h->magic: %x\n", h->magic); + printf("&h->magic: %x\n", &(h->magic)); + assert(0); + } + if (h->flags & IS_FREE) + return; + + h->flags |= IS_FREE; + merge_headers(h); +} diff --git a/userland/libc/malloc/malloc.h b/userland/libc/malloc/malloc.h new file mode 100644 index 0000000..082d8ad --- /dev/null +++ b/userland/libc/malloc/malloc.h @@ -0,0 +1,9 @@ +#ifndef MALLOC_H +#define MALLOC_H +#include <stdint.h> +#include <stddef.h> + +void *malloc(size_t s); +void *calloc(size_t nelem, size_t elsize); +void free(void *p); +#endif diff --git a/userland/libc/malloc/oldmalloc.c b/userland/libc/malloc/oldmalloc.c new file mode 100644 index 0000000..042049d --- /dev/null +++ b/userland/libc/malloc/oldmalloc.c @@ -0,0 +1,136 @@ +#include "stdio.h" +#include "stdlib.h" +#include "../errno.h" +#include <stdint.h> +#include <stddef.h> +#include <string.h> + +#define NEW_ALLOC_SIZE 0x1000 + +#define IS_FREE (1 << 0) +#define IS_FINAL (1 << 1) + +typedef struct MallocHeader { + uint32_t size; + uint8_t flags; +} MallocHeader; + +MallocHeader *head = NULL; +MallocHeader *final = NULL; +uint32_t total_heap_size = 0; + +int init_heap(void) { + head = sbrk(NEW_ALLOC_SIZE); + if ((void *)-1 == head) { + // perror("sbrk"); + return 0; + } + total_heap_size += NEW_ALLOC_SIZE; + head->size = NEW_ALLOC_SIZE; + head->flags = IS_FREE | IS_FINAL; + final = head; + return 1; +} + +int add_heap_memory(void) { + if ((void *)-1 == sbrk(NEW_ALLOC_SIZE)) { + // perror("sbrk"); + return 0; + } + total_heap_size += NEW_ALLOC_SIZE; + final->size += NEW_ALLOC_SIZE; + return 1; +} + +MallocHeader *next_header(MallocHeader *a) { + if (a->flags & IS_FINAL) + return NULL; + return ((void *)a) + a->size; +} + +MallocHeader *find_free_entry(uint32_t s) { + // A new header is required as well as the newly allocated chunk + s += sizeof(MallocHeader); + if (!head) + init_heap(); + MallocHeader *p = head; + for (; p; p = next_header(p)) { + if (!(p->flags & IS_FREE)) + continue; + if (p->size < s) + continue; + return p; + } + return NULL; +} + +void merge_headers(MallocHeader *b) { + if (!(b->flags & IS_FREE)) + return; + + MallocHeader *n = next_header(b); + if (!n) + return; + + if (!(n->flags & IS_FREE)) + return; + + // Remove the next header and just increase the newly freed header + b->size += n->size; + b->flags |= n->flags & IS_FINAL; + if (b->flags & IS_FINAL) + final = b; +} + +extern int errno; +// https://pubs.opengroup.org/onlinepubs/9699919799/ +void *malloc(size_t s) { + if(s == 0) + s = 1; + + MallocHeader *free_entry = find_free_entry(s); + if (!free_entry) { + if (!add_heap_memory()) { + errno = ENOMEM; + return NULL; + } + return malloc(s); + } + + // Create a new header + MallocHeader *new_entry = ((void *)free_entry) + s; + new_entry->flags |= IS_FREE; + new_entry->size = free_entry->size - s - sizeof(MallocHeader); + new_entry->flags |= free_entry->flags & IS_FINAL; + if (new_entry->flags & IS_FINAL) + final = new_entry; + merge_headers(new_entry); + + // Modify the free entry + free_entry->size = s; + free_entry->flags = 0; + + return ((void *)free_entry) + sizeof(MallocHeader); +} + +// https://pubs.opengroup.org/onlinepubs/9699919799/ +void *calloc(size_t nelem, size_t elsize) { + // The calloc() function shall allocate unused space for an array of + // nelem elements each of whose size in bytes is elsize. + size_t alloc_size = nelem*elsize; + void *rc = malloc(alloc_size); + // The space shall be initialized to all bits 0. + memset(rc, 0, alloc_size); + return rc; +} + +void free(void *p) { + // FIXME: This assumes that p is at the start of a allocated area. + // Is this a assumption that can be made? + MallocHeader *h = p - sizeof(MallocHeader); + if (h->flags & IS_FREE) + return; + + h->flags |= IS_FREE; + merge_headers(h); +} diff --git a/userland/libc/math.h b/userland/libc/math.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/math.h diff --git a/userland/libc/memset.c b/userland/libc/memset.c new file mode 100644 index 0000000..51910e9 --- /dev/null +++ b/userland/libc/memset.c @@ -0,0 +1,15 @@ +#include <stddef.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/ +void *memset(void *s, int c, size_t n) { + // The memset() function shall copy c (converted to an unsigned + // char) into each of the first n bytes of the object pointed to by + // s. + + unsigned char *p = s; + for (; n > 0; n--, p++) + *p = (unsigned char)c; + + // The memset() function shall return s + return s; +} diff --git a/userland/libc/mmap.c b/userland/libc/mmap.c new file mode 100644 index 0000000..06b79bd --- /dev/null +++ b/userland/libc/mmap.c @@ -0,0 +1,19 @@ +#include <syscall.h> +#include <errno.h> +#include <sys/mman.h> + +extern int errno; + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, + size_t offset) { + SYS_MMAP_PARAMS args = { + .addr = addr, + .length = length, + .prot = prot, + .flags = flags, + .fd = fd, + .offset = offset, + }; +// return (void*)syscall(SYS_MMAP, &args); + RC_ERRNO(syscall(SYS_MMAP, &args)); +} diff --git a/userland/libc/poll.h b/userland/libc/poll.h new file mode 100644 index 0000000..88e98b3 --- /dev/null +++ b/userland/libc/poll.h @@ -0,0 +1,16 @@ +#ifndef POLL_H +#define POLL_H +#include <stddef.h> + +#define POLLIN (1 << 0) +#define POLLPRI (1 << 1) +#define POLLOUT (1 << 2) + +struct pollfd { + int fd; + short events; + short revents; +}; + +int poll(struct pollfd *fds, size_t nfds, int timeout); +#endif diff --git a/userland/libc/pty.c b/userland/libc/pty.c new file mode 100644 index 0000000..b7ddf00 --- /dev/null +++ b/userland/libc/pty.c @@ -0,0 +1,15 @@ +#include "pty.h" +#include "syscall.h" + +int openpty(int *amaster, int *aslave, char *name, + /*const struct termios*/ void *termp, + /*const struct winsize*/ void *winp) { + SYS_OPENPTY_PARAMS args = { + .amaster = amaster, + .aslave = aslave, + .name = name, + .termp = termp, + .winp = winp, + }; + syscall(SYS_OPENPTY, &args, 0, 0, 0, 0); +} diff --git a/userland/libc/pty.h b/userland/libc/pty.h new file mode 100644 index 0000000..b8ce978 --- /dev/null +++ b/userland/libc/pty.h @@ -0,0 +1,6 @@ +#ifndef PTY_H +#define PTY_H +int openpty(int *amaster, int *aslave, char *name, + /*const struct termios*/ void *termp, + /*const struct winsize*/ void *winp); +#endif diff --git a/userland/libc/setjmp/longjmp.s b/userland/libc/setjmp/longjmp.s new file mode 100644 index 0000000..8188f06 --- /dev/null +++ b/userland/libc/setjmp/longjmp.s @@ -0,0 +1,16 @@ +.global _longjmp +.global longjmp +.type _longjmp,@function +.type longjmp,@function +_longjmp: +longjmp: + mov 4(%esp),%edx + mov 8(%esp),%eax + cmp $1,%eax + adc $0, %al + mov (%edx),%ebx + mov 4(%edx),%esi + mov 8(%edx),%edi + mov 12(%edx),%ebp + mov 16(%edx),%esp + jmp *20(%edx) diff --git a/userland/libc/setjmp/setjmp.s b/userland/libc/setjmp/setjmp.s new file mode 100644 index 0000000..4d19cf8 --- /dev/null +++ b/userland/libc/setjmp/setjmp.s @@ -0,0 +1,23 @@ +.global ___setjmp +.hidden ___setjmp +.global __setjmp +.global _setjmp +.global setjmp +.type __setjmp,@function +.type _setjmp,@function +.type setjmp,@function +___setjmp: +__setjmp: +_setjmp: +setjmp: + mov 4(%esp), %eax + mov %ebx, (%eax) + mov %esi, 4(%eax) + mov %edi, 8(%eax) + mov %ebp, 12(%eax) + lea 4(%esp), %ecx + mov %ecx, 16(%eax) + mov (%esp), %ecx + mov %ecx, 20(%eax) + xor %eax, %eax + ret diff --git a/userland/libc/socket.h b/userland/libc/socket.h new file mode 100644 index 0000000..5e86b45 --- /dev/null +++ b/userland/libc/socket.h @@ -0,0 +1,41 @@ +#include <stddef.h> +#include <stdint.h> + +#define AF_UNIX 0 +#define AF_LOCAL AF_UNIX + +#define INADDR_ANY 0 + +typedef struct { + int domain; + int type; + int protocol; + + // UNIX socket + char *path; + int incoming_fd; +} SOCKET; + +typedef struct { + char *path; + SOCKET *s; +} OPEN_UNIX_SOCKET; + +typedef uint32_t in_addr_t; +typedef uint16_t in_port_t; +typedef unsigned int sa_family_t; +typedef uint32_t socklen_t; + +struct sockaddr { + sa_family_t sa_family; /* Address family */ + char *sa_data; /* Socket address */ +}; + +struct sockaddr_un { + sa_family_t sun_family; /* Address family */ + char *sun_path; /* Socket pathname */ +}; + +int socket(int domain, int type, int protocol); +int accept(int socket, struct sockaddr *address, socklen_t *address_len); +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); diff --git a/userland/libc/stdio.h b/userland/libc/stdio.h new file mode 100644 index 0000000..38aaf22 --- /dev/null +++ b/userland/libc/stdio.h @@ -0,0 +1,95 @@ +#ifndef STDIO_H +#define STDIO_H +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> + +// FIXME: Most of these should probably not be here. But I am too lazy +// to fix it right now. This is futures mees problem to deal wth. + +#define EOF (-1) + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +typedef struct __IO_FILE FILE; +struct __IO_FILE { + size_t (*write)(FILE *, const unsigned char *, size_t); + size_t (*read)(FILE *, unsigned char *, size_t); + int (*seek)(FILE *, long, int); + long offset_in_file; + int buffered_char; + int has_buffered_char; + uint8_t is_eof; + uint8_t has_error; + uint64_t file_size; + void *cookie; +}; + +size_t write_fd(FILE *f, const unsigned char *s, size_t l); +size_t read_fd(FILE *f, unsigned char *s, size_t l); +int seek_fd(FILE *stream, long offset, int whence); + +typedef struct { + int fd; +} FILE_FD_COOKIE; + +extern FILE __stdin_FILE; +extern FILE __stdout_FILE; +extern FILE __stderr_FILE; + +#define stdin (&__stdin_FILE) +#define stdout (&__stdout_FILE) +//#define stderr (&__stderr_FILE) +#define stderr (&__stdout_FILE) + +typedef int mode_t; + +void perror(const char *s); + +int putchar(int c); +int puts(const char *s); +int brk(void *addr); +void *sbrk(intptr_t increment); +int write(int fd, const char *buf, size_t count); +int pwrite(int fd, const char *buf, size_t count, size_t offset); +int printf(const char *format, ...); +int pread(int fd, void *buf, size_t count, size_t offset); +int read(int fd, void *buf, size_t count); +int fork(void); +int memcmp(const void *s1, const void *s2, size_t n); +int wait(int *stat_loc); +void exit(int status); +void *memcpy(void *dest, const void *src, uint32_t n); +int shm_open(const char *name, int oflag, mode_t mode); +int dprintf(int fd, const char *format, ...); +int vdprintf(int fd, const char *format, va_list ap); +int vprintf(const char *format, va_list ap); +int snprintf(char *str, size_t size, const char *format, ...); +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +int vfprintf(FILE *f, const char *fmt, va_list ap); +int fgetc(FILE *stream); +int getchar(void); +#define getc(_a) fgetc(_a) +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +FILE *fopen(const char *pathname, const char *mode); +int fclose(FILE *stream); +int fseek(FILE *stream, long offset, int whence); +int fprintf(FILE *f, const char *fmt, ...); +long strtol(const char *nptr, char **endptr, int base); +char *strchr(const char *s, int c); +char *strcat(char *s1, const char *s2); +char *fgets(char *s, int n, FILE *stream); +FILE *tmpfile(void); +int feof(FILE *stream); +int fscanf(FILE *stream, const char *format, ...); +int ungetc(int c, FILE *stream); +long ftell(FILE *stream); +int fputc(int c, FILE *stream); +int remove(const char *path); +int ferror(FILE *stream); +int fputs(const char *s, FILE *stream); +int fflush(FILE *stream); +#endif diff --git a/userland/libc/stdio/dprintf.c b/userland/libc/stdio/dprintf.c new file mode 100644 index 0000000..2f2aadb --- /dev/null +++ b/userland/libc/stdio/dprintf.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int dprintf(int fd, const char *format, ...) { + va_list ap; + va_start(ap, format); + int rc = vdprintf(fd, format, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/fclose.c b/userland/libc/stdio/fclose.c new file mode 100644 index 0000000..02d93ae --- /dev/null +++ b/userland/libc/stdio/fclose.c @@ -0,0 +1,10 @@ +#include <stdio.h> +#include <stdlib.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fclose.html +// FIXME: Do some actual error checking. +int fclose(FILE *stream) { + free(stream->cookie); + free(stream); + return 0; +} diff --git a/userland/libc/stdio/feof.c b/userland/libc/stdio/feof.c new file mode 100644 index 0000000..7f46301 --- /dev/null +++ b/userland/libc/stdio/feof.c @@ -0,0 +1,5 @@ +#include <stdio.h> + +int feof(FILE *stream) { + return stream->is_eof; +} diff --git a/userland/libc/stdio/ferror.c b/userland/libc/stdio/ferror.c new file mode 100644 index 0000000..8cb46cf --- /dev/null +++ b/userland/libc/stdio/ferror.c @@ -0,0 +1,5 @@ +#include <stdio.h> + +int ferror(FILE *stream) { + return stream->has_error; +} diff --git a/userland/libc/stdio/fflush.c b/userland/libc/stdio/fflush.c new file mode 100644 index 0000000..7a37c79 --- /dev/null +++ b/userland/libc/stdio/fflush.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fflush.html +int fflush(FILE *stream) { + // FIXME: Implement + return 0; +} diff --git a/userland/libc/stdio/fgetc.c b/userland/libc/stdio/fgetc.c new file mode 100644 index 0000000..c69211f --- /dev/null +++ b/userland/libc/stdio/fgetc.c @@ -0,0 +1,20 @@ +#include <assert.h> +#include <stdio.h> + +int fgetc(FILE *stream) { + if (stream->has_buffered_char) { + stream->has_buffered_char = 0; + return stream->buffered_char; + } + char c; + if (1 == fread(&c, 1, 1, stream)) + return (int)c; + // FIXME: Should use feof and ferror + if (stream->has_error) + return EOF; + if (stream->is_eof) + return EOF; + // How did we get here? + assert(0); + return EOF; +} diff --git a/userland/libc/stdio/fgetpos.c b/userland/libc/stdio/fgetpos.c new file mode 100644 index 0000000..7f34d6a --- /dev/null +++ b/userland/libc/stdio/fgetpos.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +// FIXME: Error handling +int fgetpos(FILE *restrict stream, fpos_t *restrict pos) { + *pos = (fpos_t)stream->offset_in_file; + return 0; +} diff --git a/userland/libc/stdio/fgets.c b/userland/libc/stdio/fgets.c new file mode 100644 index 0000000..8e21501 --- /dev/null +++ b/userland/libc/stdio/fgets.c @@ -0,0 +1,16 @@ +#include <stdio.h> + +char *fgets(char *s, int n, FILE *stream) { + for (int i = 0; i < n; i++) { + char c; + fread(&c, 1, 1, stream); + if (stream->has_error) + return NULL; + if (stream->is_eof) + return NULL; + s[i] = c; + if (c == '\n') + break; + } + return s; +} diff --git a/userland/libc/stdio/fileno.c b/userland/libc/stdio/fileno.c new file mode 100644 index 0000000..246cc51 --- /dev/null +++ b/userland/libc/stdio/fileno.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <errno.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fileno.html +// The fileno() function shall return the integer file descriptor associated +// with the stream pointed to by stream. +int fileno(FILE *stream) { + if (-1 == stream->fd) { + errno = EBADF; + return -1; + } + return stream->fd; +} diff --git a/userland/libc/stdio/fopen.c b/userland/libc/stdio/fopen.c new file mode 100644 index 0000000..a29c7ef --- /dev/null +++ b/userland/libc/stdio/fopen.c @@ -0,0 +1,57 @@ +#include <fcntl.h> +#include <sys/stat.h> +#include <stdint.h> +#include <stdio.h> + +// FIXME: All modes not implemented +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html +FILE *fopen(const char *pathname, const char *mode) { + uint8_t read = 0; + uint8_t write = 0; + uint8_t append = 0; + // FIXME: Not parsed correctly + for (; *mode; mode++) { + // r or rb + // Open file for reading. + // w or wb + // Truncate to zero length or create file for writing. + // a or ab + // Append; open or create file for writing at + // end-of-file. + switch (*mode) { + case 'r': + read = 1; + break; + case 'w': + write = 1; + break; + case 'a': + append = 1; + break; + } + } + int flag = 0; + if (read) + flag |= O_READ; + if (write) + flag |= O_WRITE; + + int fd = open(pathname, flag, 0); + if (-1 == fd) + return NULL; + + struct stat s; + stat(pathname, &s); + + FILE *r = malloc(sizeof(FILE)); + r->read = read_fd; + r->write = write_fd; + r->seek = seek_fd; + r->has_error = 0; + r->is_eof = 0; + r->offset_in_file = 0; + r->file_size = s.st_size; + r->cookie = NULL; + r->fd = fd; + return r; +} diff --git a/userland/libc/stdio/fprintf.c b/userland/libc/stdio/fprintf.c new file mode 100644 index 0000000..f983065 --- /dev/null +++ b/userland/libc/stdio/fprintf.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int fprintf(FILE *f, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int rc = vfprintf(f, fmt, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/fputc.c b/userland/libc/stdio/fputc.c new file mode 100644 index 0000000..7c8fa7c --- /dev/null +++ b/userland/libc/stdio/fputc.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +int fputc(int c, FILE *stream) { + if (fwrite(&c, 1, 1, stream) > 0) + return c; + return EOF; +} diff --git a/userland/libc/stdio/fputs.c b/userland/libc/stdio/fputs.c new file mode 100644 index 0000000..1b70c66 --- /dev/null +++ b/userland/libc/stdio/fputs.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int fputs(const char *s, FILE *stream) { + const char *b = s; + for (; *s; s++) + if (0 == fwrite(s, 1, 1, stream)) + return EOF; + return s - b; +} diff --git a/userland/libc/stdio/fread.c b/userland/libc/stdio/fread.c new file mode 100644 index 0000000..1a27afa --- /dev/null +++ b/userland/libc/stdio/fread.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <sys/types.h> + +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { + // FIXME: Check for overflow + ssize_t bytes_to_read = nmemb * size; + size_t rc = stream->read(stream, ptr, bytes_to_read); + // On success, fread() return the number of items read + rc /= size; + return rc; +} diff --git a/userland/libc/stdio/fscanf.c b/userland/libc/stdio/fscanf.c new file mode 100644 index 0000000..785ce4b --- /dev/null +++ b/userland/libc/stdio/fscanf.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <assert.h> + +int fscanf(FILE *stream, const char *format, ...) { + // FIXME + assert(0); +} diff --git a/userland/libc/stdio/fseek.c b/userland/libc/stdio/fseek.c new file mode 100644 index 0000000..fb891ec --- /dev/null +++ b/userland/libc/stdio/fseek.c @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <assert.h> + +int fseek(FILE *stream, long offset, int whence) { + return stream->seek(stream, offset, whence); + /* + switch (whence) { + case SEEK_SET: + stream->offset_in_file = offset; + break; + case SEEK_CUR: + stream->offset_in_file += offset; + break; + case SEEK_END: + // FIXME + assert(0); + break; + } + // FIXME: Error checking + return 0;*/ +} diff --git a/userland/libc/stdio/fsetpos.c b/userland/libc/stdio/fsetpos.c new file mode 100644 index 0000000..c39c545 --- /dev/null +++ b/userland/libc/stdio/fsetpos.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +// FIXME: Error handling +int fsetpos(FILE *stream, const fpos_t *pos) { + stream->offset_in_file = (long)(*pos); + return 0; +} diff --git a/userland/libc/stdio/ftell.c b/userland/libc/stdio/ftell.c new file mode 100644 index 0000000..35076d0 --- /dev/null +++ b/userland/libc/stdio/ftell.c @@ -0,0 +1,5 @@ +#include <stdio.h> + +long ftell(FILE *stream) { + return stream->offset_in_file; +} diff --git a/userland/libc/stdio/fwrite.c b/userland/libc/stdio/fwrite.c new file mode 100644 index 0000000..552bbd6 --- /dev/null +++ b/userland/libc/stdio/fwrite.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include <sys/types.h> + +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { + // FIXME: Check for overflow + ssize_t bytes_to_write = nmemb * size; + size_t rc = stream->write(stream, ptr, bytes_to_write); + // On success, fwrite() return the number of items + // written. + rc /= size; + return rc; +} diff --git a/userland/libc/stdio/getchar.c b/userland/libc/stdio/getchar.c new file mode 100644 index 0000000..dad2263 --- /dev/null +++ b/userland/libc/stdio/getchar.c @@ -0,0 +1,4 @@ +#include <stdio.h> + +// The getchar() function shall be equivalent to getc(stdin). +int getchar(void) { return fgetc(stdin); } diff --git a/userland/libc/stdio/open_memstream.c b/userland/libc/stdio/open_memstream.c new file mode 100644 index 0000000..8f359b9 --- /dev/null +++ b/userland/libc/stdio/open_memstream.c @@ -0,0 +1,108 @@ +#include <assert.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +/* +struct __IO_FILE { + size_t (*write)(FILE *, const unsigned char *, size_t); + size_t (*read)(FILE *, unsigned char *, size_t); + int (*seek)(FILE *, long, int); + long offset_in_file; + int buffered_char; + int has_buffered_char; + int fd; + uint8_t is_eof; + uint8_t has_error; + uint64_t file_size; + void *cookie; +}; +*/ + +struct Memstream { + size_t buffer_usage; + char *buffer; +}; + +#define MEMSTREAM_DEF_SIZE 4096 + +size_t memstream_write(FILE *fp, const unsigned char *buf, size_t n) { + struct Memstream *c = fp->cookie; + // FIXME: Do a reallocation + if (c->buffer_usage + n >= fp->file_size) { + n = fp->file_size - c->buffer_usage; + } + + memcpy(c->buffer + fp->offset_in_file, buf, n); + fp->offset_in_file += n; + if (fp->offset_in_file > c->buffer_usage) + c->buffer_usage = fp->offset_in_file; + return n; +} + +size_t memstream_read(FILE *fp, unsigned char *buf, size_t n) { + struct Memstream *c = fp->cookie; + size_t length_left = c->buffer_usage - fp->offset_in_file; + n = min(length_left, n); + memcpy(buf, c->buffer + fp->offset_in_file, n); + fp->offset_in_file += n; + if (0 == n) + fp->is_eof = 1; + return n; +} + +int memstream_seek(FILE *stream, long offset, int whence) { + switch (whence) { + case SEEK_SET: + stream->offset_in_file = offset; + break; + case SEEK_CUR: + stream->offset_in_file += offset; + break; + case SEEK_END: + stream->offset_in_file = stream->file_size + offset; + break; + default: + assert(0); + break; + } + // FIXME: Error checking + return 0; +} + +FILE *open_memstream(char **bufp, size_t *sizep) { + struct Memstream *c = NULL; + FILE *fp = malloc(sizeof(FILE)); + if (!fp) + return NULL; + + fp->offset_in_file = 0; + fp->buffered_char = 0; + fp->has_buffered_char = 0; + fp->seek = memstream_seek; + fp->fd = -1; + fp->is_eof = 0; + fp->has_error = 0; + fp->file_size = MEMSTREAM_DEF_SIZE; + + fp->write = memstream_write; + fp->read = memstream_read; + + c = malloc(sizeof(struct Memstream)); + if (!c) { + goto _exit_memstream_fail; + } + + fp->cookie = (void *)c; + + c->buffer = *bufp = malloc(MEMSTREAM_DEF_SIZE); + if (!bufp) { + goto _exit_memstream_fail; + } + c->buffer_usage = 0; + + return fp; +_exit_memstream_fail: + free(c); + free(fp); + return NULL; +} diff --git a/userland/libc/stdio/printf.c b/userland/libc/stdio/printf.c new file mode 100644 index 0000000..d26568a --- /dev/null +++ b/userland/libc/stdio/printf.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int printf(const char *format, ...) { + va_list ap; + va_start(ap, format); + int rc = vprintf(format, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/putc.c b/userland/libc/stdio/putc.c new file mode 100644 index 0000000..a468a95 --- /dev/null +++ b/userland/libc/stdio/putc.c @@ -0,0 +1,3 @@ +#include <stdio.h> + +int putc(int c, FILE *stream) { return fputc(c, stream);} diff --git a/userland/libc/stdio/putchar.c b/userland/libc/stdio/putchar.c new file mode 100644 index 0000000..3fcf7ca --- /dev/null +++ b/userland/libc/stdio/putchar.c @@ -0,0 +1,7 @@ +#include <stdio.h> +#include <unistd.h> + +int putchar(int c) { + printf("%c", (char)c); + return c; +} diff --git a/userland/libc/stdio/puts.c b/userland/libc/stdio/puts.c new file mode 100644 index 0000000..4a72e66 --- /dev/null +++ b/userland/libc/stdio/puts.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int puts(const char *s) { + int rc = printf("%s\n", s); + return rc; +} diff --git a/userland/libc/stdio/remove.c b/userland/libc/stdio/remove.c new file mode 100644 index 0000000..35b41ad --- /dev/null +++ b/userland/libc/stdio/remove.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <errno.h> + +extern int errno; +int remove(const char *path) { + // FIXME + errno = ENAMETOOLONG; + return -1; +} diff --git a/userland/libc/stdio/rename.c b/userland/libc/stdio/rename.c new file mode 100644 index 0000000..15d4bf5 --- /dev/null +++ b/userland/libc/stdio/rename.c @@ -0,0 +1,8 @@ +#include <stdio.h> +#include <assert.h> + +int rename(const char *old, const char *new) { + (void)old; + (void)new; + assert(0); // TODO: Implement + } diff --git a/userland/libc/stdio/setvbuf.c b/userland/libc/stdio/setvbuf.c new file mode 100644 index 0000000..7f91518 --- /dev/null +++ b/userland/libc/stdio/setvbuf.c @@ -0,0 +1,6 @@ +#include <stdio.h> + +int setvbuf(FILE *restrict stream, char *restrict buf, int type, size_t size) { + // TODO + return 0; +} diff --git a/userland/libc/stdio/snprintf.c b/userland/libc/stdio/snprintf.c new file mode 100644 index 0000000..328442a --- /dev/null +++ b/userland/libc/stdio/snprintf.c @@ -0,0 +1,42 @@ +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +struct sn_cookie { + char *s; + size_t n; +}; + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +size_t sn_write(FILE *f, const unsigned char *s, const size_t l) { + struct sn_cookie *c = f->cookie; + size_t k = MIN(l, c->n); + memcpy(c->s, s, k); + c->s += k; + c->n -= k; + *(c->s) = '\0'; + // Upon successful completion, the snprintf() function shall return the number + // of bytes that would be written to s had n been sufficiently large excluding + // the terminating null byte. + return l; +} + +int vsnprintf(char *str, size_t size, const char *format, va_list ap) { + char dummy[1]; + struct sn_cookie c = {.s = (size ? str : dummy), .n = (size ? size - 1 : 0)}; + FILE f = { + .write = sn_write, + .cookie = &c, + }; + return vfprintf(&f, format, ap); +} + +int snprintf(char *str, size_t size, const char *format, ...) { + va_list ap; + va_start(ap, format); + int rc = vsnprintf(str, size, format, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/sprintf.c b/userland/libc/stdio/sprintf.c new file mode 100644 index 0000000..deffbbe --- /dev/null +++ b/userland/libc/stdio/sprintf.c @@ -0,0 +1,33 @@ +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +struct s_cookie { + char *s; +}; + +size_t s_write(FILE *f, const unsigned char *s, size_t l) { + struct s_cookie *c = f->cookie; + memcpy(c->s, s, l); + c->s += l; + *(c->s) = '\0'; + return l; +} + +int vsprintf(char *str, const char *format, va_list ap) { + struct s_cookie c = {.s = str}; + FILE f = { + .write = s_write, + .cookie = &c, + }; + return vfprintf(&f, format, ap); +} + +int sprintf(char *str, const char *format, ...) { + va_list ap; + va_start(ap, format); + int rc = vsprintf(str, format, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/stdio/stderr.c b/userland/libc/stdio/stderr.c new file mode 100644 index 0000000..76597e2 --- /dev/null +++ b/userland/libc/stdio/stderr.c @@ -0,0 +1,11 @@ +#include <stdio.h> +#include <unistd.h> + +FILE __stderr_FILE = { + .write = write_fd, + .read = read_fd, + .is_eof = 0, + .has_error = 0, + .cookie = NULL, + .fd = 2, +}; diff --git a/userland/libc/stdio/stdin.c b/userland/libc/stdio/stdin.c new file mode 100644 index 0000000..ae3ab8d --- /dev/null +++ b/userland/libc/stdio/stdin.c @@ -0,0 +1,54 @@ +#include <assert.h> +#include <stdio.h> +#include <unistd.h> + +size_t write_fd(FILE *f, const unsigned char *s, size_t l) { + int rc = pwrite(f->fd, s, l, f->offset_in_file); + if (rc == -1) { + f->has_error = 1; + return 0; + } + f->offset_in_file += rc; + return rc; +} + +size_t read_fd(FILE *f, unsigned char *s, size_t l) { + int rc = pread(f->fd, s, l, f->offset_in_file); + if (rc == 0) + f->is_eof = 1; + if (rc == -1) { + f->has_error = 1; + return 0; + } + f->offset_in_file += rc; + return rc; +} + +int seek_fd(FILE *stream, long offset, int whence) { + switch (whence) { + case SEEK_SET: + stream->offset_in_file = offset; + break; + case SEEK_CUR: + stream->offset_in_file += offset; + break; + case SEEK_END: + stream->offset_in_file = stream->file_size + offset; + break; + default: + assert(0); + break; + } + // FIXME: Error checking + return 0; +} + +FILE __stdin_FILE = { + .write = write_fd, + .read = read_fd, + .seek = NULL, + .is_eof = 0, + .has_error = 0, + .cookie = NULL, + .fd = 0, +}; diff --git a/userland/libc/stdio/stdout.c b/userland/libc/stdio/stdout.c new file mode 100644 index 0000000..7f4edf0 --- /dev/null +++ b/userland/libc/stdio/stdout.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <unistd.h> + +FILE __stdout_FILE = { + .write = write_fd, + .read = read_fd, + .is_eof = 0, + .has_error = 0, + .seek = NULL, + .cookie = NULL, + .fd = 1, +}; +FILE __stderr_FILE; diff --git a/userland/libc/stdio/tmpfile.c b/userland/libc/stdio/tmpfile.c new file mode 100644 index 0000000..cee6e0a --- /dev/null +++ b/userland/libc/stdio/tmpfile.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <assert.h> + +FILE *tmpfile(void) { + // TODO + printf("TODO: Implement tmpfile()\n"); + assert(0); + return NULL; +} diff --git a/userland/libc/stdio/tmpnam.c b/userland/libc/stdio/tmpnam.c new file mode 100644 index 0000000..aafe67d --- /dev/null +++ b/userland/libc/stdio/tmpnam.c @@ -0,0 +1,10 @@ +#include <assert.h> +#include <stdio.h> + +char *tmpnam(char *s) { + assert(!s); + s = malloc(100); + strcpy(s, "/tmp.XXXXXX"); + mkstemp(s); + return s; +} diff --git a/userland/libc/stdio/ungetc.c b/userland/libc/stdio/ungetc.c new file mode 100644 index 0000000..8d649bc --- /dev/null +++ b/userland/libc/stdio/ungetc.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +int ungetc(int c, FILE *stream) { + if (stream->has_buffered_char) + return EOF; + stream->buffered_char = c; + stream->has_buffered_char = 1; + return c; +} diff --git a/userland/libc/stdio/vdprintf.c b/userland/libc/stdio/vdprintf.c new file mode 100644 index 0000000..b3fa065 --- /dev/null +++ b/userland/libc/stdio/vdprintf.c @@ -0,0 +1,77 @@ +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +struct vd_cookie { + int fd; + char *buffer; + uint8_t buf_len; + uint8_t buf_used; + int sent_bytes; +}; + +size_t min(size_t a, size_t b) { return (a < b) ? a : b; } + +size_t vd_write(FILE *f, const unsigned char *s, size_t l) { + struct vd_cookie *c = f->cookie; + + int clear_buffer = 0; + size_t b_copy = min(l, c->buf_len - (c->buf_used)); + for (int i = 0; i < b_copy; i++) { + c->buffer[c->buf_used + i] = s[i]; + if (s[i] == '\n') + clear_buffer = 1; + } + c->buf_used += b_copy; + + if (clear_buffer) { + int rc = write(c->fd, c->buffer, c->buf_used); + c->buf_used = 0; + if (-1 == rc) { + return (size_t)-1; + } + c->sent_bytes += rc; + } + return l; +} + +int vdprintf(int fd, const char *format, va_list ap) { + FILE f = { + .write = write_fd, + .fd = fd, + }; + return vfprintf(&f, format, ap); + // return -1; + /* +char buffer[32]; +struct vd_cookie c = {.fd = fd, + .buffer = buffer, + .buf_len = 32, + .buf_used = 0, + .sent_bytes = 0}; +FILE f = { +.write = vd_write, +.cookie = &c, +}; + +// If an output error was encountered, these functions shall return a +// negative value and set errno to indicate the error. +if (-1 == vfprintf(&f, format, ap)) +return -1; + +// Upon successful completion, the dprintf(), +// fprintf(), and printf() functions shall return the number of bytes +// transmitted. + +if(0 == c.buf_used) +return c.sent_bytes; + +// First the current buffer needs to be cleared +int rc = write(fd, buffer, c.buf_used); +if (-1 == rc) { +return -1; +} +c.sent_bytes += rc; +return c.sent_bytes;*/ +} diff --git a/userland/libc/stdio/vfprintf.c b/userland/libc/stdio/vfprintf.c new file mode 100644 index 0000000..79a22fb --- /dev/null +++ b/userland/libc/stdio/vfprintf.c @@ -0,0 +1,243 @@ +#include <assert.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +const char HEX_SET[0x10] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + +#define FILE_WRITE(_f, _s, _l, _r) \ + { \ + size_t _rc = _f->write(_f, (const unsigned char *)_s, _l); \ + if ((size_t)-1 == _rc) \ + assert(0); \ + *(int *)(_r) += _rc; \ + } +// if ((size_t)0 == _rc) \ +// assert(0); \ + +int fprint_num(FILE *f, int n, int base, char *char_set, int prefix, + int zero_padding, int right_padding) { + int c = 0; + if (0 == n) { + zero_padding = 1; + prefix = 1; + } + char str[32]; + int i = 0; + for (; n != 0 && i < 32; i++, n /= base) + // str[i] = (n % base) + '0'; + str[i] = char_set[(n % base)]; + + char t = (zero_padding) ? '0' : ' '; + int orig_i = i; + + if (!right_padding) { + for (; prefix - orig_i > 0; prefix--) + FILE_WRITE(f, &t, 1, &c); + } + + for (i--; i >= 0; i--) + FILE_WRITE(f, &(str[i]), 1, &c); + + if (right_padding) { + for (; prefix - orig_i > 0; prefix--) + FILE_WRITE(f, &t, 1, &c); + } + return c; +} + +int fprint_int(FILE *f, int n, int prefix, int zero_padding, + int right_padding) { + return fprint_num(f, n, 10, "0123456789", prefix, zero_padding, + right_padding); +} + +int fprint_hex(FILE *f, int n, int prefix, int zero_padding, + int right_padding) { + return fprint_num(f, n, 16, "0123456789abcdef", prefix, zero_padding, + right_padding); +} + +int fprint_octal(FILE *f, int n, int prefix, int zero_padding, + int right_padding) { + return fprint_num(f, n, 8, "012345678", prefix, zero_padding, right_padding); +} + +int print_string(FILE *f, const char *s, int *rc, int prefix, int right_padding, + int precision) { + int l = strlen(s); + char t = ' '; + int c = 0; + if (!right_padding) { + if (prefix) + assert(-1 == precision); // FIXME: Is this correct? + for (; prefix - l > 0; prefix--) + FILE_WRITE(f, &t, 1, &c); + } + int bl = precision; + for (; *s; s++, (*rc)++) { + if (precision != -1) { + if (0 == bl) + break; + bl--; + } + int r; + FILE_WRITE(f, (const unsigned char *)s, 1, &r); + assert(r != 0); + } + if (right_padding) { + assert(-1 == precision); // FIXME: Is this correct? + for (; prefix - l > 0; prefix--) + FILE_WRITE(f, &t, 1, &c); + } + (*rc) += c; + return 0; +} + +int parse_precision(const char **fmt) { + const char *s = *fmt; + int rc = 0; + for (int i = 0;; i++, s++) { + if ('\0' == *s) + break; + const char c = *s; + if ('*' == c) { + assert(i == 0); + return -1; + } else if (!(c >= '0' && c <= '9')) { + s--; + break; + } + rc *= 10; + rc += c - '0'; + } + *fmt = s; + return rc; +} + +int vfprintf(FILE *f, const char *fmt, va_list ap) { + int rc = 0; + const char *s = fmt; + int prefix = 0; + + int zero_padding = 0; + int right_padding = 0; + + int cont = 0; + int precision = -1; + for (; *s; s++) { + if (!cont && '%' != *s) { + FILE_WRITE(f, (const unsigned char *)s, 1, &rc); + continue; + } + if (!cont) { + cont = 1; + continue; + } + + if ('\0' == *s) + break; + + switch (*s) { + case '.': + s++; + assert('\0' != *s); + precision = parse_precision(&s); + assert('\0' != *s); + if (-1 == precision) + precision = va_arg(ap, int); + cont = 1; + break; + case '0': + prefix *= 10; + if (0 == prefix) + zero_padding = 1; + cont = 1; + break; + case '-': + assert(0 == prefix); + right_padding = 1; + cont = 1; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + prefix *= 10; + prefix += (*s) - '0'; + cont = 1; + break; + case 'i': + case 'd': + if(-1 != precision) { + zero_padding = 1; + prefix = precision; + right_padding = 0; + } + rc += fprint_int(f, va_arg(ap, int), prefix, zero_padding, right_padding); + cont = 0; + break; + case 'u': + assert(-1 == precision); + rc += fprint_int(f, va_arg(ap, unsigned int), prefix, zero_padding, + right_padding); + cont = 0; + break; + case 's': { + assert(!zero_padding); // this is not supported to strings + char *a = va_arg(ap, char *); + if (!a) { + if (-1 == + print_string(f, "(NULL)", &rc, prefix, right_padding, precision)) + return -1; + cont = 0; + break; + } + if (-1 == print_string(f, a, &rc, prefix, right_padding, precision)) + return -1; + cont = 0; + break; + } + case 'p': // TODO: Print this out in a nicer way + case 'x': + assert(-1 == precision); + rc += fprint_hex(f, va_arg(ap, const uint32_t), prefix, zero_padding, + right_padding); + cont = 0; + break; + case 'o': + assert(-1 == precision); + rc += fprint_octal(f, va_arg(ap, const uint32_t), prefix, zero_padding, + right_padding); + cont = 0; + break; + case '%': { + FILE_WRITE(f, (const unsigned char *)"%", 1, &rc); + cont = 0; + break; + } + case 'c': { + char c = va_arg(ap, const int); + FILE_WRITE(f, (const unsigned char *)&c, 1, &rc); + cont = 0; + break; + } + default: + printf("got %c but that is not supported by printf\n", *s); + assert(0); + break; + } + if (!cont) { + prefix = 0; + zero_padding = right_padding = 0; + precision = -1; + } + } + return rc; +} diff --git a/userland/libc/stdio/vprintf.c b/userland/libc/stdio/vprintf.c new file mode 100644 index 0000000..8a8dc33 --- /dev/null +++ b/userland/libc/stdio/vprintf.c @@ -0,0 +1,3 @@ +#include <stdio.h> + +int vprintf(const char *format, va_list ap) { return vdprintf(1, format, ap); } diff --git a/userland/libc/stdlib.h b/userland/libc/stdlib.h new file mode 100644 index 0000000..bba5d84 --- /dev/null +++ b/userland/libc/stdlib.h @@ -0,0 +1,17 @@ +#ifndef STDLIB_H +#define STDLIB_H +#include <stddef.h> +#include <limits.h> +#define RAND_MAX (UINT32_MAX) + +void *malloc(size_t s); +void *calloc(size_t nelem, size_t elsize); +void *realloc(void *ptr, size_t size); +void free(void *p); +char *getenv(const char *name); +int rand(void); +void srand(unsigned int seed); +unsigned long strtoul(const char *restrict str, + char **restrict endptr, int base); +int atoi(const char *str); +#endif diff --git a/userland/libc/stdlib/abort.c b/userland/libc/stdlib/abort.c new file mode 100644 index 0000000..7fd747e --- /dev/null +++ b/userland/libc/stdlib/abort.c @@ -0,0 +1,10 @@ +#include <assert.h> +#include <stdlib.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/abort.html +void abort(void) { + printf("aborting!!!!\n"); + assert(0); + for (;;) + ; +} diff --git a/userland/libc/stdlib/abs.c b/userland/libc/stdlib/abs.c new file mode 100644 index 0000000..1079beb --- /dev/null +++ b/userland/libc/stdlib/abs.c @@ -0,0 +1,3 @@ +#include <stdlib.h> + +int abs(int i) { return (i < 0) ? (-i) : (i); } diff --git a/userland/libc/stdlib/atexit.c b/userland/libc/stdlib/atexit.c new file mode 100644 index 0000000..0e401ff --- /dev/null +++ b/userland/libc/stdlib/atexit.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +int atexit(void (*func)(void)) { + //TODO + return 0; +} diff --git a/userland/libc/stdlib/atof.c b/userland/libc/stdlib/atof.c new file mode 100644 index 0000000..8524f8b --- /dev/null +++ b/userland/libc/stdlib/atof.c @@ -0,0 +1,5 @@ +#include <stdlib.h> + +double atof(const char *str) { + return strtod(str,(char **)NULL); +} diff --git a/userland/libc/stdlib/atoi.c b/userland/libc/stdlib/atoi.c new file mode 100644 index 0000000..2183306 --- /dev/null +++ b/userland/libc/stdlib/atoi.c @@ -0,0 +1,4 @@ +#include <stdlib.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/ +int atoi(const char *str) { return (int)strtol(str, (char **)NULL, 10); } diff --git a/userland/libc/stdlib/getenv.c b/userland/libc/stdlib/getenv.c new file mode 100644 index 0000000..9a6a4e5 --- /dev/null +++ b/userland/libc/stdlib/getenv.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +char *getenv(const char *name) { + // FIXME + return NULL; +} diff --git a/userland/libc/stdlib/mkstemp.c b/userland/libc/stdlib/mkstemp.c new file mode 100644 index 0000000..1ea8790 --- /dev/null +++ b/userland/libc/stdlib/mkstemp.c @@ -0,0 +1,14 @@ +#include <fcntl.h> +#include <stdlib.h> + +char rand_char(void) { return 'A' + (rand() % 10); } + +int mkstemp(char *template) { + // FIXME: Incomplete + const char *s = template; + for (; *template; template ++) { + if ('X' == *template) + *template = rand_char(); + } + return open(s, O_RDWR, O_CREAT); +} diff --git a/userland/libc/stdlib/qsort.c b/userland/libc/stdlib/qsort.c new file mode 100644 index 0000000..3f87db5 --- /dev/null +++ b/userland/libc/stdlib/qsort.c @@ -0,0 +1,29 @@ +#include <stdlib.h> +#include <string.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/qsort.html +void qsort(void *base, size_t nel, size_t width, + int (*compar)(const void *, const void *)) { + // If the nel argument has the value zero, the comparison function pointed to + // by compar shall not be called and no rearrangement shall take place. + if (0 == nel) + return; + + // AB + // Results in negative + // BA + // Results in positive + + // Using bubblesort + unsigned char *p = base; + for (size_t i = 1; i < nel; i++) { + for (size_t j = 0; j < nel; j++) { + if (compar((p + i * width), (p + j * width)) < 0) { + unsigned char tmp[width]; + memcpy(tmp, (p + i * width), width); + memcpy((p + i * width), (p + j * width), width); + memcpy((p + j * width), tmp, width); + } + } + } +} diff --git a/userland/libc/stdlib/rand.c b/userland/libc/stdlib/rand.c new file mode 100644 index 0000000..e186af7 --- /dev/null +++ b/userland/libc/stdlib/rand.c @@ -0,0 +1,17 @@ +#include <stdint.h> +#include <stdlib.h> + +uint32_t xorshift(uint32_t x) { + uint32_t f = x; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return f + x; +} + +extern uint32_t __INTERNAL_RNG_STATE; +int rand(void) { + uint32_t x = xorshift(__INTERNAL_RNG_STATE); + __INTERNAL_RNG_STATE++; + return x; +} diff --git a/userland/libc/stdlib/srand.c b/userland/libc/stdlib/srand.c new file mode 100644 index 0000000..a35185a --- /dev/null +++ b/userland/libc/stdlib/srand.c @@ -0,0 +1,8 @@ +#include <stdint.h> +#include <stdlib.h> + +uint32_t __INTERNAL_RNG_STATE; +void srand(unsigned int seed) { + __INTERNAL_RNG_STATE = seed; + __INTERNAL_RNG_STATE = rand(); // rand() used the internal rng state +} diff --git a/userland/libc/stdlib/strtod.c b/userland/libc/stdlib/strtod.c new file mode 100644 index 0000000..2c83879 --- /dev/null +++ b/userland/libc/stdlib/strtod.c @@ -0,0 +1,70 @@ +#include <ctype.h> +#include <stdlib.h> +#include <assert.h> + +int ctoi(char c) { return c - '0'; } + +double strtod(const char *restrict nptr, char **restrict endptr) { + double r = 0; + // An initial, possibly empty, sequence of white-space characters (as + // specified by isspace()) + for (; isspace(*nptr); nptr++) + ; + + // A subject sequence interpreted as a floating-point constant or representing + // infinity or NaN + + { + // The expected form of the subject sequence is an optional '+' or '-' sign + int sign = 0; + int exp_sign = 0; + if ('+' == *nptr) { + sign = 0; + nptr++; + } else if ('-' == *nptr) { + sign = 1; + nptr++; + } + + // A non-empty sequence of decimal digits optionally containing a radix + // character + double exp = 0; + for (; isdigit(*nptr); nptr++) { + r *= 10; + r += ctoi(*nptr); + } + if ('.' == *nptr) { + double div = 10; + for (; isdigit(*nptr); nptr++) { + r += ctoi(*nptr) / div; + div *= 10; + } + } + r *= (sign) ? (-1) : (1); + + // then an optional exponent part consisting of the character 'e' or + // the character 'E' + if ('e' == tolower(*nptr)) { + // optionally followed by a '+' or '-' character + if ('+' == *nptr) { + exp_sign = 0; + nptr++; + } else if ('-' == *nptr) { + exp_sign = 1; + nptr++; + } + // and then followed by one or more decimal digits + for (; isdigit(*nptr); nptr++) { + exp *= 10; + exp += ctoi(*nptr); + } + exp *= (exp_sign) ? (-1) : (1); + } + assert(0 == exp); // TODO + } + + // A final string of one or more unrecognized characters, including the + // terminating NUL character of the input string + ; + return r; +} diff --git a/userland/libc/stdlib/strtol.c b/userland/libc/stdlib/strtol.c new file mode 100644 index 0000000..7aa7760 --- /dev/null +++ b/userland/libc/stdlib/strtol.c @@ -0,0 +1,52 @@ +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <assert.h> + +extern int errno; +extern int get_value(char c, long base); + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html +long strtol(const char *str, char **restrict endptr, int base) { + long ret_value = 0; + if (endptr) + *endptr = str; + // Ignore inital white-space sequence + for (; *str && isspace(*str); str++) + ; + if (!*str) + return ret_value; + + int sign = 0; + if ('-' == *str) { + // FIXME + sign = 1; + str++; + assert(0); + } else if ('+' == *str) { + str++; + } + + if (0 == base) { + // FIXME + assert(0); + } + + if (2 <= base && 36 >= base) { + for (; *str; str++) { + ret_value *= base; + int val = get_value(*str, base); + if (ret_value > LONG_MAX - val) { + errno = ERANGE; + return 0; + } + ret_value += val; + } + } else { + errno = EINVAL; + return 0; + } + if (endptr) + *endptr = str; + return ret_value; +} diff --git a/userland/libc/stdlib/strtold.c b/userland/libc/stdlib/strtold.c new file mode 100644 index 0000000..222464e --- /dev/null +++ b/userland/libc/stdlib/strtold.c @@ -0,0 +1,9 @@ +#include <assert.h> +#include <stdlib.h> + +long double strtold(const char *restrict nptr, char **restrict endptr) { + // TODO + // I will do this some other day + assert(NULL); + return 0; +} diff --git a/userland/libc/stdlib/strtoul.c b/userland/libc/stdlib/strtoul.c new file mode 100644 index 0000000..4d9a51d --- /dev/null +++ b/userland/libc/stdlib/strtoul.c @@ -0,0 +1,72 @@ +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <limits.h> + +extern int errno; +int get_value(char c, long base) { + int r; + if (c >= '0' && c <= '9') + r = c - '0'; + else if (c >= 'A' && c <= 'Z') + r = c - 'A'; + else if (c >= 'a' && c <= 'z') + r = c - 'a'; + else + return -1; + if (r >= base) + return -1; + return r; +} + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtoul.html +unsigned long strtoul(const char *restrict str, char **restrict endptr, + int base) { + unsigned long ret_value = 0; + if (endptr) + *endptr = str; + // Ignore inital white-space sequence + for (; *str && isspace(*str); str++) + ; + if (!*str) + return ret_value; + + int sign = 0; + if ('-' == *str) { + // FIXME + sign = 1; + str++; + assert(0); + } else if ('+' == *str) { + str++; + } + + if (0 == base) { + // FIXME + assert(0); + } + + if (2 <= base && 36 >= base) { + for (; *str; str++) { + ret_value *= base; + int val = get_value(*str, base); + /* + if (-1 == val) { + errno = ERANGE; + return 0; + }*/ + if (ret_value > ULONG_MAX - val) { + errno = ERANGE; + return 0; + } + + ret_value += val; + } + } else { + errno = EINVAL; + return 0; + } + if (endptr) + *endptr = str; + return ret_value; +} diff --git a/userland/libc/stdlib/system.c b/userland/libc/stdlib/system.c new file mode 100644 index 0000000..d951c5c --- /dev/null +++ b/userland/libc/stdlib/system.c @@ -0,0 +1,17 @@ +#include <stdlib.h> + +int system(const char *command) { + if (!command) + return NULL; + int pid = fork(); + if (0 == pid) { + char *argv[2]; + argv[0] = "/sh"; + argv[1] = command; + execv("/sh", argv); + } + // FIXME: Use waitpid + int rc; + (void)wait(&rc); + return rc; +} diff --git a/userland/libc/string.h b/userland/libc/string.h new file mode 100644 index 0000000..f811dba --- /dev/null +++ b/userland/libc/string.h @@ -0,0 +1,17 @@ +#ifndef STRING_H +#define STRING_H +#include <stddef.h> +#include <stdint.h> + +char *strerror(int errnum); +void *memset(void *s, int c, size_t n); +void *memcpy(void *dest, const void *src, uint32_t n); +int strcmp(const char *s1, const char *s2); +char *strcpy(char *dest, const char *src); +size_t strlen(const char *s); +size_t strnlen(const char *s, size_t maxlen); +int sscanf(const char *s, const char *restrict format, ...); +char *strrchr(const char *s, int c); +int strncmp(const char *s1, const char *s2, size_t n); +char *strncpy(char *s1, const char *s2, size_t n); +#endif diff --git a/userland/libc/string/memcmp.c b/userland/libc/string/memcmp.c new file mode 100644 index 0000000..01109b8 --- /dev/null +++ b/userland/libc/string/memcmp.c @@ -0,0 +1,11 @@ +#include <string.h> + +int memcmp(const void *s1, const void *s2, size_t n) { + int return_value = 0; + + for (uint32_t i = 0; i < n; i++) + if (((unsigned char *)(s1))[i] != ((unsigned char *)(s2))[i]) + return_value++; + + return return_value; +} diff --git a/userland/libc/string/memcpy.c b/userland/libc/string/memcpy.c new file mode 100644 index 0000000..e19dec9 --- /dev/null +++ b/userland/libc/string/memcpy.c @@ -0,0 +1,9 @@ +#include <string.h> + +void *memcpy(void *dest, const void *src, uint32_t n) { + unsigned char *d = dest; + const unsigned char *s = src; + for (; n; n--) + *d++ = *s++; + return dest; +} diff --git a/userland/libc/string/memmove.c b/userland/libc/string/memmove.c new file mode 100644 index 0000000..5fc49f7 --- /dev/null +++ b/userland/libc/string/memmove.c @@ -0,0 +1,14 @@ +#include <string.h> + +// copy bytes in memory with overlapping areas +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/memmove.html +void *memmove(void *s1, const void *s2, size_t n) { + // Copying takes place as if the n bytes from the object pointed to by s2 are + // first copied into a temporary array of n bytes that does not overlap the + // objects pointed to by s1 and s2, and then the n bytes from the temporary + // array are copied into the object pointed to by s1. + unsigned char tmp[n]; + memcpy(tmp, s2, n); + memcpy(s1, tmp, n); + return s1; +} diff --git a/userland/libc/string/sscanf.c b/userland/libc/string/sscanf.c new file mode 100644 index 0000000..28e1ce1 --- /dev/null +++ b/userland/libc/string/sscanf.c @@ -0,0 +1,193 @@ +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +extern int errno; +extern int get_value(char c, long base); + +long ftnum(FILE *stream, int base, int *error) { + char c; + long ret_value = 0; + *error = 0; + // Ignore inital white-space sequence + for (;;) { + if (EOF == (c = fgetc(stream))) { + *error = 1; + return 0; + } + + if (!isspace(c)) { + ungetc(c, stream); + break; + } + } + if (c == '\0') { + *error = 1; + return 0; + } + if (!isdigit(c)) { + *error = 1; + return 0; + } + if (!(2 <= base && 36 >= base)) { + *error = 1; + return 0; + } + for (;;) { + if (EOF == (c = fgetc(stream))) + break; + if (c == '\0') { + ungetc(c, stream); + break; + } + int val = get_value(c, base); + if (-1 == val) { + ungetc(c, stream); + break; + } + if (ret_value * base > LONG_MAX - val) { + ungetc(c, stream); + errno = ERANGE; + *error = 1; + return 0; + } + ret_value *= base; + ret_value += val; + } + return ret_value; +} + +int vfscanf(FILE *stream, const char *format, va_list ap) { + int rc = 0; // Upon successful completion, these functions shall return the + // number of successfully matched and assigned input items + int cont = 0; + int suppress = 0; + for (; *format; format++) { + if (*format != '%' && !cont) { + char c; + if (isspace(*format)) + continue; + if (EOF == (c = fgetc(stream))) { + break; + } + if (*format == c) // TODO: Make sure this is the correct behaviour + continue; + // TODO: Make sure this is the correct behaviour + errno = EINVAL; + assert(0); + break; + } + + if (*format == '%' && !cont) { + cont = 1; + continue; + } + + int is_long = 0; + switch (*format) { + case 'l': + is_long++; + assert(is_long < 3); + cont = 1; + break; + case 'i': // Matches an optionally signed integer, whose format is the same + // as expected for the subject sequence of strtol() with 0 for the + // base argument. + case 'd': { + // Matches an optionally signed decimal integer, whose format is the + // same as expected for the subject sequence of strtol() with the value + // 10 for the base argument. In the absence of a size modifier, the + // application shall ensure that the corresponding argument is a pointer + // to int. + int err = 0; + int result = ftnum(stream, 10, &err); + if (err) { + cont = 0; + break; + } + if (!suppress) { + if (2 == is_long) { + *((long long *)va_arg(ap, long long *)) = result; + } else if (1 == is_long) { + *((long *)va_arg(ap, long *)) = result; + } else { + *((int *)va_arg(ap, int *)) = result; + } + rc++; + } + assert(0 == err); + cont = 0; + break; + } + case 'c': { + char result = fgetc(stream); + if (!suppress) { + *((char *)va_arg(ap, char *)) = result; + rc++; + } + cont = 0; + break; + } + case '*': // Assignment suppression + suppress = 1; + cont = 1; + break; + default: + printf("vfscanf: Got %c but not supported.\n", *format); + assert(0); + break; + } + if (!cont) { + suppress = 0; + } + } + return rc; +} + +struct sscanf_cookie { + const char *s; +}; + +size_t sscanf_read(FILE *f, unsigned char *s, size_t l) { + struct sscanf_cookie *c = f->cookie; + if (!*(c->s)) { + return 0; + } + size_t r = 0; + for (; l && *(c->s); l--, c->s += 1) { + *s = *(c->s); + s++; + r++; + } + if (!(*(c->s))) + f->is_eof = 1; + /* + memcpy(s, c->s, l); + c->s += l;*/ + return r; +} + +int vsscanf(const char *s, const char *restrict format, va_list ap) { + struct sscanf_cookie c = {.s = s}; + FILE f = { + .read = sscanf_read, + .cookie = &c, + .has_buffered_char = 0, + .is_eof = 0, + .has_error = 0, + .offset_in_file = 0, + }; + return vfscanf(&f, format, ap); +} + +int sscanf(const char *s, const char *restrict format, ...) { + va_list ap; + va_start(ap, format); + int rc = vsscanf(s, format, ap); + va_end(ap); + return rc; +} diff --git a/userland/libc/string/strcasecmp.c b/userland/libc/string/strcasecmp.c new file mode 100644 index 0000000..eed337b --- /dev/null +++ b/userland/libc/string/strcasecmp.c @@ -0,0 +1,28 @@ +#include <strings.h> + +int strcasecmp(const char *s1, const char *s2) { + // The strcmp() function shall compare the string pointed to by s1 + // to the string pointed to by s2. + int l1, l2, rc; + l1 = l2 = rc = 0; + for (; (*s1 || *s2);) { + if (tolower(*s1) != tolower(*s2)) + rc++; + if (*s1) { + l1++; + s1++; + } + if (*s2) { + l2++; + s2++; + } + } + + // Upon completion, strcmp() shall return an integer greater than, + // equal to, or less than 0, if the string pointed to by s1 is + // greater than, equal to, or less than the string pointed to by + // s2, respectively. + if (l2 > l1) + return -rc; + return rc; +} diff --git a/userland/libc/string/strcat.c b/userland/libc/string/strcat.c new file mode 100644 index 0000000..c430698 --- /dev/null +++ b/userland/libc/string/strcat.c @@ -0,0 +1,13 @@ +#include <string.h> + +char *strcat(char *s1, const char *s2) { + strcpy(s1 + strlen(s1), s2); + return s1; + /* +char *r = s1; +for (; *s1; s1++) +; +for (; *s2; s2++, s1++) +*s1 = *s2; +return r;*/ +} diff --git a/userland/libc/string/strchr.c b/userland/libc/string/strchr.c new file mode 100644 index 0000000..1995547 --- /dev/null +++ b/userland/libc/string/strchr.c @@ -0,0 +1,11 @@ +#include <string.h> + +char *strchr(const char *s, int c) { + for (; *s; s++) { + if (*s == (char)c) + return (char*)s; + } + if ((char)c == '\0') + return (char *)s; + return NULL; +} diff --git a/userland/libc/string/strcmp.c b/userland/libc/string/strcmp.c new file mode 100644 index 0000000..368b8fb --- /dev/null +++ b/userland/libc/string/strcmp.c @@ -0,0 +1,29 @@ +#include <string.h> + +// https://pubs.opengroup.org/onlinepubs/9699919799/ +int strcmp(const char *s1, const char *s2) { + // The strcmp() function shall compare the string pointed to by s1 + // to the string pointed to by s2. + int l1, l2, rc; + l1 = l2 = rc = 0; + for (; *s1 || *s2;) { + if (*s1 != *s2) + rc++; + if (*s1) { + l1++; + s1++; + } + if (*s2) { + l2++; + s2++; + } + } + + // Upon completion, strcmp() shall return an integer greater than, + // equal to, or less than 0, if the string pointed to by s1 is + // greater than, equal to, or less than the string pointed to by + // s2, respectively. + if (l2 > l1) + return -rc; + return rc; +} diff --git a/userland/libc/string/strcpy.c b/userland/libc/string/strcpy.c new file mode 100644 index 0000000..9023fd1 --- /dev/null +++ b/userland/libc/string/strcpy.c @@ -0,0 +1,7 @@ +#include <string.h> + +char *strcpy(char *dest, const char *src) { + for (; (*dest = *src); dest++, src++) + ; + return dest; +} diff --git a/userland/libc/string/strcspn.c b/userland/libc/string/strcspn.c new file mode 100644 index 0000000..2ad38d5 --- /dev/null +++ b/userland/libc/string/strcspn.c @@ -0,0 +1,14 @@ +#include <string.h> + +size_t strcspn(const char *s1, const char *s2) { + size_t r = 0; + for (; *s1; s1++) { + for (const char *t = s2; *t; t++) { + if (*s1 == *s2) { + r++; + break; + } + } + } + return r; +} diff --git a/userland/libc/string/strdup.c b/userland/libc/string/strdup.c new file mode 100644 index 0000000..9e22f94 --- /dev/null +++ b/userland/libc/string/strdup.c @@ -0,0 +1,15 @@ +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +// The strdup() function shall return a pointer to a new string, which is a +// duplicate of the string pointed to by s. The returned pointer can be passed +// to free(). A null pointer is returned if the new string cannot be created. +char *strdup(const char *s) { + size_t l = strlen(s); + char *r = malloc(l + 1); + if (!r) + return NULL; + strcpy(r, s); + return r; +} diff --git a/userland/libc/string/strlcpy.c b/userland/libc/string/strlcpy.c new file mode 100644 index 0000000..a2d3dd9 --- /dev/null +++ b/userland/libc/string/strlcpy.c @@ -0,0 +1,20 @@ +#include <string.h> + +// Copy string s2 to buffer s1 of size n. At most n-1 +// chars will be copied. Always NUL terminates (unless n == 0). +// Returns strlen(s2); if retval >= n, truncation occurred. +size_t *strlcpy(char *s1, const char *s2, size_t n) { + size_t tmp_n = n; + const char *os2 = s2; + for (; tmp_n; tmp_n--) { + if ((*s1++ = *s2++) == '\0') + break; + } + if (tmp_n == 0) { + if (n != 0) + *s1 = '\0'; /* NUL-terminate s1 */ + while (*s2++) + ; + } + return s2 - os2 - 1; +} diff --git a/userland/libc/string/strlen.c b/userland/libc/string/strlen.c new file mode 100644 index 0000000..8e3e77a --- /dev/null +++ b/userland/libc/string/strlen.c @@ -0,0 +1,8 @@ +#include <string.h> + +size_t strlen(const char *s) { + const char *d = s; + for (; *s; s++) + ; + return s - d; +} diff --git a/userland/libc/string/strncasecmp.c b/userland/libc/string/strncasecmp.c new file mode 100644 index 0000000..9ce8c04 --- /dev/null +++ b/userland/libc/string/strncasecmp.c @@ -0,0 +1,29 @@ +#include <strings.h> +#include <stddef.h> + +int strncasecmp(const char *s1, const char *s2, size_t n) { + // The strcmp() function shall compare the string pointed to by s1 + // to the string pointed to by s2. + int l1, l2, rc; + l1 = l2 = rc = 0; + for (; (*s1 || *s2) && n > 0; n--) { + if (tolower(*s1) != tolower(*s2)) + rc++; + if (*s1) { + l1++; + s1++; + } + if (*s2) { + l2++; + s2++; + } + } + + // Upon completion, strcmp() shall return an integer greater than, + // equal to, or less than 0, if the string pointed to by s1 is + // greater than, equal to, or less than the string pointed to by + // s2, respectively. + if (l2 > l1) + return -rc; + return rc; +} diff --git a/userland/libc/string/strncmp.c b/userland/libc/string/strncmp.c new file mode 100644 index 0000000..fd46189 --- /dev/null +++ b/userland/libc/string/strncmp.c @@ -0,0 +1,28 @@ +#include <string.h> + +int strncmp(const char *s1, const char *s2, size_t n) { + // The strcmp() function shall compare the string pointed to by s1 + // to the string pointed to by s2. + int l1, l2, rc; + l1 = l2 = rc = 0; + for (; (*s1 || *s2) && n > 0; n--) { + if (*s1 != *s2) + rc++; + if (*s1) { + l1++; + s1++; + } + if (*s2) { + l2++; + s2++; + } + } + + // Upon completion, strcmp() shall return an integer greater than, + // equal to, or less than 0, if the string pointed to by s1 is + // greater than, equal to, or less than the string pointed to by + // s2, respectively. + if (l2 > l1) + return -rc; + return rc; +} diff --git a/userland/libc/string/strncpy.c b/userland/libc/string/strncpy.c new file mode 100644 index 0000000..0e88c63 --- /dev/null +++ b/userland/libc/string/strncpy.c @@ -0,0 +1,13 @@ +#include <string.h> + +char *strncpy(char *s1, const char *s2, size_t n) { + char *rc = s1; + for (; n > 0; s1++, s2++, n--) { + *s1 = *s2; + if (!*s2) + break; + } + for (; n > 0; n--,s1++) + *s1 = '\0'; + return rc; +} diff --git a/userland/libc/string/strndup.c b/userland/libc/string/strndup.c new file mode 100644 index 0000000..ffb2088 --- /dev/null +++ b/userland/libc/string/strndup.c @@ -0,0 +1,22 @@ +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +// The strndup() function shall be equivalent to the strdup() function, +// duplicating the provided s in a new block of memory allocated as if +// by using malloc(), with the exception being that strndup() copies at +// most size plus one bytes into the newly allocated memory, terminating +// the new string with a NUL character. If the length of s is larger +// than size, only size bytes shall be duplicated. If size is larger +// than the length of s, all bytes in s shall be copied into the new +// memory buffer, including the terminating NUL character. The newly +// created string shall always be properly terminated. +char *strndup(const char *s, size_t size) { + size_t l = strlen(s); + size_t real_l = min(l, size); + char *r = malloc(real_l + 1); + if (!r) + return NULL; + strlcpy(r, s, real_l); + return r; +} diff --git a/userland/libc/string/strnlen.c b/userland/libc/string/strnlen.c new file mode 100644 index 0000000..86df42e --- /dev/null +++ b/userland/libc/string/strnlen.c @@ -0,0 +1,9 @@ +#include <string.h> + +size_t strnlen(const char *s, size_t maxlen) { + size_t i; + for (i = 0; i < maxlen; i++) + if (s[i] == 0) + break; + return i; +} diff --git a/userland/libc/string/strpbrk.c b/userland/libc/string/strpbrk.c new file mode 100644 index 0000000..fb16b0c --- /dev/null +++ b/userland/libc/string/strpbrk.c @@ -0,0 +1,12 @@ +#include <string.h> + +char *strpbrk(const char *s1, const char *s2) { + for (; *s1; s1++) { + for (const char *t = s2; *t; t++) { + if (*s1 == *t) { + return s1; + } + } + } + return NULL; +} diff --git a/userland/libc/string/strrchr.c b/userland/libc/string/strrchr.c new file mode 100644 index 0000000..a44199a --- /dev/null +++ b/userland/libc/string/strrchr.c @@ -0,0 +1,12 @@ +#include <string.h> + +char *strrchr(const char *s, int c) { + char *last = NULL; + for (; *s; s++) { + if (*s == (char)c) + last = (char *)s; + } + if ((char)c == '\0') + last = (char*)s; + return last; +} diff --git a/userland/libc/string/strspn.c b/userland/libc/string/strspn.c new file mode 100644 index 0000000..2a7d3ae --- /dev/null +++ b/userland/libc/string/strspn.c @@ -0,0 +1,18 @@ +#include <string.h> + +size_t strspn(const char *s1, const char *s2) { + size_t r = 0; + for (; *s1; s1++) { + int e = 0; + for (const char *t = s2; *t; t++) { + if (*s1 == *t) { + e = 1; + break; + } + } + if (!e) + break; + r++; + } + return r; +} diff --git a/userland/libc/string/strstr.c b/userland/libc/string/strstr.c new file mode 100644 index 0000000..20b9dc2 --- /dev/null +++ b/userland/libc/string/strstr.c @@ -0,0 +1,21 @@ +#include <string.h> + +char *strstr(const char *s1, const char *s2) { + // If s2 points to a string with zero length, the function shall return s1. + if ('\0' == *s2) + return s1; + for (; *s1; s1++) { + const char *t1 = s1; + const char *t2 = s2; + int is_dif = 0; + for (; *t2 && *t1; t1++, t2++) { + if (*t2 != *t1) { + is_dif = 1; + break; + } + } + if (!is_dif) + return s1; + } + return NULL; +} diff --git a/userland/libc/string/strtok.c b/userland/libc/string/strtok.c new file mode 100644 index 0000000..7b8d0e3 --- /dev/null +++ b/userland/libc/string/strtok.c @@ -0,0 +1,26 @@ +#include <string.h> + +char *strtok_s; + +char *strtok(char *restrict s, const char *restrict sep) { + if (s) { + strtok_s = s; + return strtok(NULL, sep); + } + if(!strtok_s) + return NULL; + char *e = strpbrk(strtok_s, sep); + if (!e) { + char *r = strtok_s; + strtok_s = NULL; + return r; + } + *e = '\0'; + e--; + for (; *sep; sep++) + e++; + e++; + char *r = strtok_s; + strtok_s = e; + return r; +} diff --git a/userland/libc/strings.h b/userland/libc/strings.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/strings.h diff --git a/userland/libc/sys/mman.h b/userland/libc/sys/mman.h new file mode 100644 index 0000000..e3ff734 --- /dev/null +++ b/userland/libc/sys/mman.h @@ -0,0 +1,8 @@ +#ifndef MMAP_H +#define MMAP_H +#include <stdint.h> +#include <stddef.h> + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, + size_t offset); +#endif diff --git a/userland/libc/sys/mman/mmap.c b/userland/libc/sys/mman/mmap.c new file mode 100644 index 0000000..b9ad3a2 --- /dev/null +++ b/userland/libc/sys/mman/mmap.c @@ -0,0 +1,19 @@ +#include <syscall.h> +#include <errno.h> +#include <sys/mman.h> + +extern int errno; + +void *mmap(void *addr, size_t length, int prot, int flags, int fd, + size_t offset) { + SYS_MMAP_PARAMS args = { + .addr = addr, + .length = length, + .prot = prot, + .flags = flags, + .fd = fd, + .offset = offset, + }; +// return (void*)syscall(SYS_MMAP, &args, 0, 0, 0, 0); + RC_ERRNO(syscall(SYS_MMAP, &args, 0, 0, 0, 0)); +} diff --git a/userland/libc/sys/stat.h b/userland/libc/sys/stat.h new file mode 100644 index 0000000..2fe6cdc --- /dev/null +++ b/userland/libc/sys/stat.h @@ -0,0 +1,30 @@ +#ifndef STAT_H +#define STAT_H +#include <sys/types.h> +#include <time.h> + +struct stat { + dev_t st_dev; // Device ID of device containing file. + ino_t st_ino; // File serial number. + mode_t st_mode; // Mode of file (see below). + nlink_t st_nlink; // Number of hard links to the file. + uid_t st_uid; // User ID of file. + gid_t st_gid; // Group ID of file. + dev_t st_rdev; // Device ID (if file is character or block special). + off_t st_size; // For regular files, the file size in bytes. + // For symbolic links, the length in bytes of the + // pathname contained in the symbolic link. + // For a shared memory object, the length in bytes. + // For a typed memory object, the length in bytes. + // For other file types, the use of this field is + // unspecified. + struct timespec st_atime; // Last data access timestamp. + struct timespec st_mtime; // Last data modification timestamp. + struct timespec st_ctime; // Last file status change timestamp. + blksize_t st_blksize; // A file system-specific preferred I/O block size + // for this object. In some file system types, this + // may vary from file to file. + blkcnt_t st_blocks; // Number of blocks allocated for this object. +}; +int stat(const char *path, struct stat *buf); +#endif diff --git a/userland/libc/sys/stat/mkdir.c b/userland/libc/sys/stat/mkdir.c new file mode 100644 index 0000000..c057fa7 --- /dev/null +++ b/userland/libc/sys/stat/mkdir.c @@ -0,0 +1,9 @@ +#include <sys/stat.h> +#include <assert.h> + +int mkdir(const char *path, mode_t mode) { + (void)path; + (void)mode; + assert(0); // TODO: Implement + return 0; +} diff --git a/userland/libc/sys/stat/stat.c b/userland/libc/sys/stat/stat.c new file mode 100644 index 0000000..e37223e --- /dev/null +++ b/userland/libc/sys/stat/stat.c @@ -0,0 +1,13 @@ +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <sys/stat.h> +#include <syscall.h> + +int stat(const char *path, struct stat *buf) { + SYS_STAT_PARAMS args = { + .pathname = path, + .statbuf = buf, + }; + RC_ERRNO(syscall(SYS_STAT, &args, 0, 0, 0, 0)); +} diff --git a/userland/libc/sys/time/gettimeofday.c b/userland/libc/sys/time/gettimeofday.c new file mode 100644 index 0000000..e172cf2 --- /dev/null +++ b/userland/libc/sys/time/gettimeofday.c @@ -0,0 +1,5 @@ +#include <sys/time.h> +#include <time.h> + +static int return_tod =0; +int gettimeofday(struct timeval *tp, void *tzp) {return return_tod++;} diff --git a/userland/libc/sys/types.h b/userland/libc/sys/types.h new file mode 100644 index 0000000..ffcf281 --- /dev/null +++ b/userland/libc/sys/types.h @@ -0,0 +1,27 @@ +#ifndef TYPES_H +#define TYPES_H +typedef unsigned int ino_t; + +typedef int mode_t; + +typedef int nlink_t; +typedef int uid_t; +typedef int gid_t; +typedef int id_t; + +typedef int blkcnt_t; +typedef int off_t; + +typedef int dev_t; +typedef unsigned int fsblkcnt_t; +typedef unsigned int fsfilcnt_t; +typedef unsigned int ino_t; +//typedef unsigned int size_t; + +typedef int blksize_t; +typedef int pid_t; +typedef int ssize_t; + +//typedef int clock_t; +typedef int time_t; +#endif diff --git a/userland/libc/syscall.h b/userland/libc/syscall.h new file mode 100644 index 0000000..952492f --- /dev/null +++ b/userland/libc/syscall.h @@ -0,0 +1,149 @@ +#ifndef SYSCALL_H +#define SYSCALL_H +#include "socket.h" +#include <stddef.h> +#include <stdint.h> + +#define SYS_OPEN 0 +#define SYS_READ 1 +#define SYS_WRITE 2 +#define SYS_PREAD 3 +#define SYS_PWRITE 4 +#define SYS_FORK 5 +#define SYS_EXEC 6 +#define SYS_GETPID 7 +#define SYS_EXIT 8 +#define SYS_WAIT 9 +#define SYS_BRK 10 +#define SYS_SBRK 11 +#define SYS_PIPE 12 +#define SYS_DUP2 13 +#define SYS_CLOSE 14 +#define SYS_OPENPTY 15 +#define SYS_POLL 16 +#define SYS_MMAP 17 +#define SYS_ACCEPT 18 +#define SYS_BIND 19 +#define SYS_SOCKET 20 +#define SYS_SHM_OPEN 21 +#define SYS_FTRUNCATE 22 +#define SYS_STAT 23 +#define SYS_MSLEEP 24 +#define SYS_UPTIME 25 + +int syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx, + uint32_t esi, uint32_t edi); +int s_syscall(int sys); + +extern int errno; +#define RC_ERRNO(_rc) \ + { \ + int c = _rc; \ + if (c < 0) { \ + errno = -(c); \ + return -1; \ + } \ + return c; \ + } + +typedef int mode_t; + +typedef struct SYS_OPEN_PARAMS { + char *file; + int flags; + int mode; +} __attribute__((packed)) SYS_OPEN_PARAMS; + +typedef struct SYS_PREAD_PARAMS { + int fd; + void *buf; + size_t count; + size_t offset; +} __attribute__((packed)) SYS_PREAD_PARAMS; + +typedef struct SYS_READ_PARAMS { + int fd; + void *buf; + size_t count; +} __attribute__((packed)) SYS_READ_PARAMS; + +typedef struct SYS_PWRITE_PARAMS { + int fd; + void *buf; + size_t count; + size_t offset; +} __attribute__((packed)) SYS_PWRITE_PARAMS; + +typedef struct SYS_WRITE_PARAMS { + int fd; + void *buf; + size_t count; +} __attribute__((packed)) SYS_WRITE_PARAMS; + +typedef struct SYS_EXEC_PARAMS { + char *path; + char **argv; +} __attribute__((packed)) SYS_EXEC_PARAMS; + +typedef struct SYS_DUP2_PARAMS { + int org_fd; + int new_fd; +} __attribute__((packed)) SYS_DUP2_PARAMS; + +typedef struct SYS_OPENPTY_PARAMS { + int *amaster; + int *aslave; + char *name; + /*const struct termios*/ void *termp; + /*const struct winsize*/ void *winp; +} __attribute__((packed)) SYS_OPENPTY_PARAMS; + +typedef struct SYS_POLL_PARAMS { + struct pollfd *fds; + size_t nfds; + int timeout; +} __attribute__((packed)) SYS_POLL_PARAMS; + +typedef struct SYS_MMAP_PARAMS { + void *addr; + size_t length; + int prot; + int flags; + int fd; + size_t offset; +} __attribute__((packed)) SYS_MMAP_PARAMS; + +typedef struct SYS_SOCKET_PARAMS { + int domain; + int type; + int protocol; +} __attribute__((packed)) SYS_SOCKET_PARAMS; + +typedef struct SYS_BIND_PARAMS { + int sockfd; + const struct sockaddr *addr; + socklen_t addrlen; +} __attribute__((packed)) SYS_BIND_PARAMS; + +typedef struct SYS_ACCEPT_PARAMS { + int socket; + struct sockaddr *address; + socklen_t *address_len; +} __attribute__((packed)) SYS_ACCEPT_PARAMS; + +typedef struct SYS_SHM_OPEN_PARAMS { + const char *name; + int oflag; + mode_t mode; +} __attribute__((packed)) SYS_SHM_OPEN_PARAMS; + +typedef struct SYS_FTRUNCATE_PARAMS { + int fildes; + uint64_t length; +} __attribute__((packed)) SYS_FTRUNCATE_PARAMS; + +typedef struct SYS_STAT_PARAMS { + const char *pathname; + struct stat *statbuf; +} __attribute__((packed)) SYS_STAT_PARAMS; +#endif diff --git a/userland/libc/time.h b/userland/libc/time.h new file mode 100644 index 0000000..771e430 --- /dev/null +++ b/userland/libc/time.h @@ -0,0 +1,20 @@ +#include <sys/types.h> + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + long __tm_gmtoff; + const char *__tm_zone; +}; + +struct timespec { + time_t tv_sec; // Seconds. + long tv_nsec; // Nanoseconds. +}; diff --git a/userland/libc/time/clock_gettime.c b/userland/libc/time/clock_gettime.c new file mode 100644 index 0000000..15f0cb7 --- /dev/null +++ b/userland/libc/time/clock_gettime.c @@ -0,0 +1,14 @@ +#include <syscall.h> +#include <time.h> + +int clock_gettime(clockid_t clock_id, struct timespec *tp) { + tp->tv_sec = 0; + tp->tv_nsec = 0; + return 0; + /* +SYS_CLOCK_GETTIME_PARAMS args = { +.clk = clock_id, +.ts = tp, +}; +return syscall(SYS_CLOCK_GETTIME, &args);*/ +} diff --git a/userland/libc/time/ctime_r.c b/userland/libc/time/ctime_r.c new file mode 100644 index 0000000..66e6416 --- /dev/null +++ b/userland/libc/time/ctime_r.c @@ -0,0 +1,13 @@ +#include <string.h> +#include <time.h> + +// TODO: Implement this + +// Time, formatting and parsing are some of the most annoying parts of +// programming. Lets just hope this function is not important +char *ctime_r(const time_t *clock, char *buf) { + (void)clock; + size_t l = strlen(buf); + memset(buf, '0', l); + return buf; +} diff --git a/userland/libc/time/gmtime.c b/userland/libc/time/gmtime.c new file mode 100644 index 0000000..44e0ff3 --- /dev/null +++ b/userland/libc/time/gmtime.c @@ -0,0 +1,21 @@ +#include <time.h> + +struct tm gmtime_r = { + .tm_sec = 0, + .tm_min = 0, + .tm_hour = 0, + .tm_mday = 0, + .tm_mon = 0, + .tm_year = 0, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = 0, + .__tm_gmtoff = 0, + .__tm_zone = 0, +}; + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/gmtime.html +struct tm *gmtime(const time_t *timer) { + // TODO: Implement + return &gmtime_r; +} diff --git a/userland/libc/time/localtime.c b/userland/libc/time/localtime.c new file mode 100644 index 0000000..40ca351 --- /dev/null +++ b/userland/libc/time/localtime.c @@ -0,0 +1,21 @@ +#include <time.h> + + struct tm localtime_r = { + .tm_sec = 0, + .tm_min = 0, + .tm_hour = 0, + .tm_mday = 0, + .tm_mon = 0, + .tm_year = 0, + .tm_wday = 0, + .tm_yday = 0, + .tm_isdst = 0, + .__tm_gmtoff = 0, + .__tm_zone = 0, + }; + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/localtime.html +struct tm *localtime(const time_t *timer) { + // TODO: Implement + return &localtime_r; +} diff --git a/userland/libc/time/strftime.c b/userland/libc/time/strftime.c new file mode 100644 index 0000000..30a080d --- /dev/null +++ b/userland/libc/time/strftime.c @@ -0,0 +1,7 @@ +#include <time.h> +#include <stddef.h> + +size_t strftime(char *restrict s, size_t maxsize, + const char *restrict format, const struct tm *restrict timeptr) { + return 0; +} diff --git a/userland/libc/time/time.c b/userland/libc/time/time.c new file mode 100644 index 0000000..9931b71 --- /dev/null +++ b/userland/libc/time/time.c @@ -0,0 +1,9 @@ +#include <time.h> + +time_t time(time_t *tloc) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + if (tloc) + *tloc = ts.tv_sec; + return ts.tv_sec; +} diff --git a/userland/libc/ubsan.c b/userland/libc/ubsan.c new file mode 100644 index 0000000..9ac9879 --- /dev/null +++ b/userland/libc/ubsan.c @@ -0,0 +1,49 @@ +#include <stdio.h> +#include <ubsan.h> + +void ubsan_log(const char *cause, struct source_location source) { + printf("UBSAN\n"); + printf("%s: %s : %d\n", cause, source.file_name, source.line); + for (;;) + ; +} + +void __ubsan_handle_shift_out_of_bounds(struct ShiftOutOfBoundsData *data, + unsigned long lhs, unsigned long rhs) { + (void)lhs; + (void)rhs; + ubsan_log("handle_shift_out_of_bounds", data->location); +} + +void __ubsan_handle_add_overflow(struct OverflowData *data, unsigned long lhs, + unsigned long rhs) { + (void)lhs; + (void)rhs; + ubsan_log("handle_add_overflow", data->location); +} + +void __ubsan_handle_sub_overflow(struct OverflowData *data, unsigned long lhs, + unsigned long rhs) { + (void)lhs; + (void)rhs; + ubsan_log("handle_sub_overflow", data->location); +} + +void __ubsan_handle_negate_overflow(struct OverflowData *data, unsigned long lhs, + unsigned long rhs) { + (void)lhs; + (void)rhs; + ubsan_log("handle_negate_overflow", data->location); +} + +void __ubsan_handle_mul_overflow(struct OverflowData *data, unsigned long lhs, + unsigned long rhs) { + (void)lhs; + (void)rhs; + ubsan_log("handle_mul_overflow", data->location); +} + +void __ubsan_handle_out_of_bounds(struct OutOfBoundsData *data, void *index) { + (void)index; + ubsan_log("handle_out_of_bounds", data->location); +} diff --git a/userland/libc/ubsan.h b/userland/libc/ubsan.h new file mode 100644 index 0000000..dac5407 --- /dev/null +++ b/userland/libc/ubsan.h @@ -0,0 +1,79 @@ +#include <stdint.h> + +enum { type_kind_int = 0, type_kind_float = 1, type_unknown = 0xffff }; + +struct type_descriptor { + uint16_t type_kind; + uint16_t type_info; + char type_name[1]; +}; + +struct source_location { + const char *file_name; + union { + unsigned long reported; + struct { + uint32_t line; + uint32_t column; + }; + }; +}; + +struct OverflowData { + struct source_location location; + struct type_descriptor *type; +}; + +struct type_mismatch_data { + struct source_location location; + struct type_descriptor *type; + unsigned long alignment; + unsigned char type_check_kind; +}; + +struct type_mismatch_data_v1 { + struct source_location location; + struct type_descriptor *type; + unsigned char log_alignment; + unsigned char type_check_kind; +}; + +struct type_mismatch_data_common { + struct source_location *location; + struct type_descriptor *type; + unsigned long alignment; + unsigned char type_check_kind; +}; + +struct nonnull_arg_data { + struct source_location location; + struct source_location attr_location; + int arg_index; +}; + +struct OutOfBoundsData { + struct source_location location; + struct type_descriptor *array_type; + struct type_descriptor *index_type; +}; + +struct ShiftOutOfBoundsData { + struct source_location location; + struct type_descriptor *lhs_type; + struct type_descriptor *rhs_type; +}; + +struct unreachable_data { + struct source_location location; +}; + +struct invalid_value_data { + struct source_location location; + struct type_descriptor *type; +}; + +struct alignment_assumption_data { + struct source_location location; + struct source_location assumption_location; + struct type_descriptor *type; +}; diff --git a/userland/libc/unistd.h b/userland/libc/unistd.h new file mode 100644 index 0000000..b1e3434 --- /dev/null +++ b/userland/libc/unistd.h @@ -0,0 +1,14 @@ +#ifndef UNISTD_H +#define UNISTD_H +#include <stddef.h> + +extern int opterr, optind, optopt; +extern char *optarg; + +int close(int fildes); +int ftruncate(int fildes, size_t length); +int execv(char *path, char **argv); +int pipe(int fd[2]); +int dup2(int org_fd, int new_fd); +int getopt(int argc, char * const argv[], const char *optstring); +#endif diff --git a/userland/libc/unistd/_exit.c b/userland/libc/unistd/_exit.c new file mode 100644 index 0000000..c6d64be --- /dev/null +++ b/userland/libc/unistd/_exit.c @@ -0,0 +1,8 @@ +#include <syscall.h> +#include <unistd.h> + +// FIXME: Technically exit and _exit are different but this +// stackoverflow answer says that it does not usually matter. So lets +// hope that is the case. +// https://stackoverflow.com/a/5423108 +void _exit(int status) { syscall(SYS_EXIT, (void *)status, 0, 0, 0, 0); } diff --git a/userland/libc/unistd/execvp.c b/userland/libc/unistd/execvp.c new file mode 100644 index 0000000..573e822 --- /dev/null +++ b/userland/libc/unistd/execvp.c @@ -0,0 +1,8 @@ +#include <unistd.h> +#include <syscall.h> + +// FIXME: Path resolution +int execvp(const char *file, char *const argv[]) { + struct SYS_EXEC_PARAMS args = {.path = file, .argv = argv}; + return syscall(SYS_EXEC, &args, 0, 0, 0, 0); +} diff --git a/userland/libc/unistd/getopt.c b/userland/libc/unistd/getopt.c new file mode 100644 index 0000000..a026b59 --- /dev/null +++ b/userland/libc/unistd/getopt.c @@ -0,0 +1,14 @@ +#include <assert.h> +#include <unistd.h> + +int opterr, optind, optopt; +char *optarg; + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html +int getopt(int argc, char *const argv[], const char *optstring) { + // TODO + optind = 1; + optarg = NULL; + // assert(0); + return -1; +} diff --git a/userland/libc/unistd/getpid.c b/userland/libc/unistd/getpid.c new file mode 100644 index 0000000..8aeef10 --- /dev/null +++ b/userland/libc/unistd/getpid.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include <syscall.h> +#include <sys/types.h> + +pid_t getpid(void) { + return s_syscall(SYS_GETPID); +} diff --git a/userland/libc/unistd/msleep.c b/userland/libc/unistd/msleep.c new file mode 100644 index 0000000..0b016c6 --- /dev/null +++ b/userland/libc/unistd/msleep.c @@ -0,0 +1,6 @@ +// Not standard, but it feels like it should be. +#include <syscall.h> +#include <unistd.h> +#include <stdint.h> + +void msleep(uint32_t ms) { syscall(SYS_MSLEEP, (void *)ms, 0, 0, 0, 0); } diff --git a/userland/libc/unistd/unlink.c b/userland/libc/unistd/unlink.c new file mode 100644 index 0000000..ccac0df --- /dev/null +++ b/userland/libc/unistd/unlink.c @@ -0,0 +1,7 @@ +#include <unistd.h> + +int unlink(const char *path) { + // TODO + printf("TODO: Implement unlink"); + return 0; +} diff --git a/userland/libc/unistd/uptime.c b/userland/libc/unistd/uptime.c new file mode 100644 index 0000000..090a0e5 --- /dev/null +++ b/userland/libc/unistd/uptime.c @@ -0,0 +1,6 @@ +// Not standard, but it feels like it should be. +#include <stdint.h> +#include <syscall.h> +#include <unistd.h> + +uint32_t uptime(void) { return syscall(SYS_UPTIME, 0, 0, 0, 0, 0); } diff --git a/userland/libc/wchar.h b/userland/libc/wchar.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/wchar.h diff --git a/userland/libc/wctype.h b/userland/libc/wctype.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/userland/libc/wctype.h |