From 4e09bca9e34c226b6d7e34b4fa11248405fd988e Mon Sep 17 00:00:00 2001 From: Anton Kling Date: Sun, 22 Oct 2023 19:50:38 +0200 Subject: Move everything into a new repo. --- userland/ante/Makefile | 15 + userland/ante/ante.c | 296 ++++++++++++++ userland/cat/Makefile | 10 + userland/cat/cat | Bin 0 -> 33852 bytes userland/cat/cat.c | 24 ++ userland/init/Makefile | 10 + userland/init/crt0_old.c | 12 + userland/init/init | Bin 0 -> 31476 bytes userland/init/init.c | 15 + userland/json/Makefile | 18 + userland/json/hashmap | 1 + userland/json/json.c | 360 +++++++++++++++++ userland/json/json.h | 39 ++ userland/json/libjson.a | Bin 0 -> 6304 bytes userland/libc/Makefile | 26 ++ userland/libc/arpa/inet.h | 4 + userland/libc/arpa/inet/htonl.c | 11 + userland/libc/arpa/inet/htons.c | 10 + userland/libc/assert.c | 9 + userland/libc/assert.h | 10 + userland/libc/crt0.s | 13 + userland/libc/ctype.h | 12 + userland/libc/ctype/isalnum.c | 6 + userland/libc/ctype/isalpha.c | 4 + userland/libc/ctype/isascii.c | 4 + userland/libc/ctype/isdigit.c | 6 + userland/libc/ctype/isprint.c | 3 + userland/libc/ctype/ispunct.c | 6 + userland/libc/ctype/isxdigit.c | 6 + userland/libc/ctype/tolower.c | 7 + userland/libc/ctype/toupper.c | 7 + userland/libc/dirent.h | 28 ++ userland/libc/dirent/alphasort.c | 7 + userland/libc/dirent/closedir.c | 7 + userland/libc/dirent/opendir.c | 11 + userland/libc/dirent/readdir.c | 14 + userland/libc/dirent/scandir.c | 43 ++ userland/libc/endian.h | 2 + userland/libc/errno.h | 87 ++++ userland/libc/fcntl.h | 10 + userland/libc/include/arpa/inet.h | 0 userland/libc/include/assert.h | 10 + userland/libc/include/byteswap.h | 0 userland/libc/include/ctype.h | 14 + userland/libc/include/dirent.h | 28 ++ userland/libc/include/endian.h | 2 + userland/libc/include/err.h | 0 userland/libc/include/errno.h | 87 ++++ userland/libc/include/fcntl.h | 12 + userland/libc/include/fnmatch.h | 0 userland/libc/include/glob.h | 10 + userland/libc/include/grp.h | 0 userland/libc/include/input.h | 9 + userland/libc/include/inttypes.h | 19 + userland/libc/include/langinfo.h | 0 userland/libc/include/libgen.h | 6 + userland/libc/include/limits.h | 4 + userland/libc/include/locale.h | 0 userland/libc/include/math.h | 0 userland/libc/include/net/if.h | 0 userland/libc/include/netdb.h | 0 userland/libc/include/netinet/in.h | 0 userland/libc/include/netinet/tcp.h | 0 userland/libc/include/paths.h | 0 userland/libc/include/poll.h | 17 + userland/libc/include/pty.h | 6 + userland/libc/include/pwd.h | 0 userland/libc/include/regex.h | 0 userland/libc/include/sched.h | 0 userland/libc/include/setjmp.h | 14 + userland/libc/include/signal.h | 9 + userland/libc/include/socket.h | 41 ++ userland/libc/include/stdio.h | 116 ++++++ userland/libc/include/stdlib.h | 32 ++ userland/libc/include/string.h | 29 ++ userland/libc/include/strings.h | 0 userland/libc/include/sys/ioctl.h | 10 + userland/libc/include/sys/mman.h | 15 + userland/libc/include/sys/mount.h | 0 userland/libc/include/sys/resource.h | 0 userland/libc/include/sys/socket.h | 0 userland/libc/include/sys/stat.h | 31 ++ userland/libc/include/sys/statvfs.h | 0 userland/libc/include/sys/syscall.h | 0 userland/libc/include/sys/time.h | 41 ++ userland/libc/include/sys/times.h | 0 userland/libc/include/sys/types.h | 28 ++ userland/libc/include/sys/ucontext.h | 0 userland/libc/include/sys/un.h | 0 userland/libc/include/sys/utsname.h | 0 userland/libc/include/sys/wait.h | 0 userland/libc/include/syscall.h | 150 +++++++ userland/libc/include/syslog.h | 0 userland/libc/include/termios.h | 0 userland/libc/include/time.h | 35 ++ userland/libc/include/ubsan.h | 79 ++++ userland/libc/include/unistd.h | 24 ++ userland/libc/include/utime.h | 0 userland/libc/include/wchar.h | 0 userland/libc/include/wctype.h | 0 userland/libc/input.h | 9 + userland/libc/inttypes.h | 5 + userland/libc/isspace.c | 5 + userland/libc/libc.c | 287 ++++++++++++++ userland/libc/libgen/basename.c | 45 +++ userland/libc/libgen/dirname.c | 44 +++ userland/libc/limits.h | 2 + userland/libc/malloc/malloc.c | 232 +++++++++++ userland/libc/malloc/malloc.h | 9 + userland/libc/malloc/oldmalloc.c | 136 +++++++ userland/libc/math.h | 0 userland/libc/memset.c | 15 + userland/libc/mmap.c | 19 + userland/libc/poll.h | 16 + userland/libc/pty.c | 15 + userland/libc/pty.h | 6 + userland/libc/setjmp/longjmp.s | 16 + userland/libc/setjmp/setjmp.s | 23 ++ userland/libc/socket.h | 41 ++ userland/libc/stdio.h | 95 +++++ userland/libc/stdio/dprintf.c | 9 + userland/libc/stdio/fclose.c | 10 + userland/libc/stdio/feof.c | 5 + userland/libc/stdio/ferror.c | 5 + userland/libc/stdio/fflush.c | 7 + userland/libc/stdio/fgetc.c | 20 + userland/libc/stdio/fgetpos.c | 7 + userland/libc/stdio/fgets.c | 16 + userland/libc/stdio/fileno.c | 13 + userland/libc/stdio/fopen.c | 57 +++ userland/libc/stdio/fprintf.c | 9 + userland/libc/stdio/fputc.c | 7 + userland/libc/stdio/fputs.c | 9 + userland/libc/stdio/fread.c | 11 + userland/libc/stdio/fscanf.c | 7 + userland/libc/stdio/fseek.c | 21 + userland/libc/stdio/fsetpos.c | 7 + userland/libc/stdio/ftell.c | 5 + userland/libc/stdio/fwrite.c | 12 + userland/libc/stdio/getchar.c | 4 + userland/libc/stdio/open_memstream.c | 108 +++++ userland/libc/stdio/printf.c | 9 + userland/libc/stdio/putc.c | 3 + userland/libc/stdio/putchar.c | 7 + userland/libc/stdio/puts.c | 6 + userland/libc/stdio/remove.c | 9 + userland/libc/stdio/rename.c | 8 + userland/libc/stdio/setvbuf.c | 6 + userland/libc/stdio/snprintf.c | 42 ++ userland/libc/stdio/sprintf.c | 33 ++ userland/libc/stdio/stderr.c | 11 + userland/libc/stdio/stdin.c | 54 +++ userland/libc/stdio/stdout.c | 13 + userland/libc/stdio/tmpfile.c | 9 + userland/libc/stdio/tmpnam.c | 10 + userland/libc/stdio/ungetc.c | 9 + userland/libc/stdio/vdprintf.c | 77 ++++ userland/libc/stdio/vfprintf.c | 243 ++++++++++++ userland/libc/stdio/vprintf.c | 3 + userland/libc/stdlib.h | 17 + userland/libc/stdlib/abort.c | 10 + userland/libc/stdlib/abs.c | 3 + userland/libc/stdlib/atexit.c | 6 + userland/libc/stdlib/atof.c | 5 + userland/libc/stdlib/atoi.c | 4 + userland/libc/stdlib/getenv.c | 6 + userland/libc/stdlib/mkstemp.c | 14 + userland/libc/stdlib/qsort.c | 29 ++ userland/libc/stdlib/rand.c | 17 + userland/libc/stdlib/srand.c | 8 + userland/libc/stdlib/strtod.c | 70 ++++ userland/libc/stdlib/strtol.c | 52 +++ userland/libc/stdlib/strtold.c | 9 + userland/libc/stdlib/strtoul.c | 72 ++++ userland/libc/stdlib/system.c | 17 + userland/libc/string.h | 17 + userland/libc/string/memcmp.c | 11 + userland/libc/string/memcpy.c | 9 + userland/libc/string/memmove.c | 14 + userland/libc/string/sscanf.c | 193 +++++++++ userland/libc/string/strcasecmp.c | 28 ++ userland/libc/string/strcat.c | 13 + userland/libc/string/strchr.c | 11 + userland/libc/string/strcmp.c | 29 ++ userland/libc/string/strcpy.c | 7 + userland/libc/string/strcspn.c | 14 + userland/libc/string/strdup.c | 15 + userland/libc/string/strlcpy.c | 20 + userland/libc/string/strlen.c | 8 + userland/libc/string/strncasecmp.c | 29 ++ userland/libc/string/strncmp.c | 28 ++ userland/libc/string/strncpy.c | 13 + userland/libc/string/strndup.c | 22 ++ userland/libc/string/strnlen.c | 9 + userland/libc/string/strpbrk.c | 12 + userland/libc/string/strrchr.c | 12 + userland/libc/string/strspn.c | 18 + userland/libc/string/strstr.c | 21 + userland/libc/string/strtok.c | 26 ++ userland/libc/strings.h | 0 userland/libc/sys/mman.h | 8 + userland/libc/sys/mman/mmap.c | 19 + userland/libc/sys/stat.h | 30 ++ userland/libc/sys/stat/mkdir.c | 9 + userland/libc/sys/stat/stat.c | 13 + userland/libc/sys/time/gettimeofday.c | 5 + userland/libc/sys/types.h | 27 ++ userland/libc/syscall.h | 149 +++++++ userland/libc/time.h | 20 + userland/libc/time/clock_gettime.c | 14 + userland/libc/time/ctime_r.c | 13 + userland/libc/time/gmtime.c | 21 + userland/libc/time/localtime.c | 21 + userland/libc/time/strftime.c | 7 + userland/libc/time/time.c | 9 + userland/libc/ubsan.c | 49 +++ userland/libc/ubsan.h | 79 ++++ userland/libc/unistd.h | 14 + userland/libc/unistd/_exit.c | 8 + userland/libc/unistd/execvp.c | 8 + userland/libc/unistd/getopt.c | 14 + userland/libc/unistd/getpid.c | 7 + userland/libc/unistd/msleep.c | 6 + userland/libc/unistd/unlink.c | 7 + userland/libc/unistd/uptime.c | 6 + userland/libc/wchar.h | 0 userland/libc/wctype.h | 0 userland/libgui/Makefile | 17 + userland/libgui/font.h | 3 + userland/libgui/libgui.c | 290 ++++++++++++++ userland/libgui/libgui.h | 34 ++ userland/minibox/Makefile | 12 + userland/minibox/minibox.c | 65 +++ userland/minibox/utilities/ascii.c | 30 ++ userland/minibox/utilities/cat.c | 54 +++ userland/minibox/utilities/echo.c | 30 ++ userland/minibox/utilities/ed.c | 145 +++++++ userland/minibox/utilities/include.h | 41 ++ userland/minibox/utilities/init.c | 72 ++++ userland/minibox/utilities/ls.c | 42 ++ userland/minibox/utilities/minibox.c | 15 + userland/minibox/utilities/pwd.c | 12 + userland/minibox/utilities/touch.c | 11 + userland/minibox/utilities/wc.c | 106 +++++ userland/minibox/utilities/yes.c | 13 + userland/sh/Makefile | 13 + userland/sh/sh | Bin 0 -> 44776 bytes userland/sh/sh.c | 224 +++++++++++ userland/sh/sh_a | Bin 0 -> 9200 bytes userland/sh/sh_bad | Bin 0 -> 9188 bytes userland/snake/Makefile | 15 + userland/snake/snake.c | 109 +++++ userland/terminal/Makefile | 15 + userland/terminal/term.c | 166 ++++++++ userland/test/Makefile | 16 + userland/test/linux.sh | 4 + userland/test/local/a.out | Bin 0 -> 35312 bytes userland/test/local/testfile | 1 + userland/test/test | Bin 0 -> 86144 bytes userland/test/test.c | 722 ++++++++++++++++++++++++++++++++++ userland/windowserver/Makefile | 16 + userland/windowserver/draw.c | 80 ++++ userland/windowserver/draw.h | 13 + userland/windowserver/font.h | 133 +++++++ userland/windowserver/ws.c | 375 ++++++++++++++++++ userland/windowserver/ws.h | 30 ++ 266 files changed, 8357 insertions(+) create mode 100644 userland/ante/Makefile create mode 100644 userland/ante/ante.c create mode 100644 userland/cat/Makefile create mode 100755 userland/cat/cat create mode 100644 userland/cat/cat.c create mode 100644 userland/init/Makefile create mode 100644 userland/init/crt0_old.c create mode 100755 userland/init/init create mode 100644 userland/init/init.c create mode 100644 userland/json/Makefile create mode 160000 userland/json/hashmap create mode 100644 userland/json/json.c create mode 100644 userland/json/json.h create mode 100644 userland/json/libjson.a create mode 100644 userland/libc/Makefile create mode 100644 userland/libc/arpa/inet.h create mode 100644 userland/libc/arpa/inet/htonl.c create mode 100644 userland/libc/arpa/inet/htons.c create mode 100644 userland/libc/assert.c create mode 100644 userland/libc/assert.h create mode 100644 userland/libc/crt0.s create mode 100644 userland/libc/ctype.h create mode 100644 userland/libc/ctype/isalnum.c create mode 100644 userland/libc/ctype/isalpha.c create mode 100644 userland/libc/ctype/isascii.c create mode 100644 userland/libc/ctype/isdigit.c create mode 100644 userland/libc/ctype/isprint.c create mode 100644 userland/libc/ctype/ispunct.c create mode 100644 userland/libc/ctype/isxdigit.c create mode 100644 userland/libc/ctype/tolower.c create mode 100644 userland/libc/ctype/toupper.c create mode 100644 userland/libc/dirent.h create mode 100644 userland/libc/dirent/alphasort.c create mode 100644 userland/libc/dirent/closedir.c create mode 100644 userland/libc/dirent/opendir.c create mode 100644 userland/libc/dirent/readdir.c create mode 100644 userland/libc/dirent/scandir.c create mode 100644 userland/libc/endian.h create mode 100644 userland/libc/errno.h create mode 100644 userland/libc/fcntl.h create mode 100644 userland/libc/include/arpa/inet.h create mode 100644 userland/libc/include/assert.h create mode 100644 userland/libc/include/byteswap.h create mode 100644 userland/libc/include/ctype.h create mode 100644 userland/libc/include/dirent.h create mode 100644 userland/libc/include/endian.h create mode 100644 userland/libc/include/err.h create mode 100644 userland/libc/include/errno.h create mode 100644 userland/libc/include/fcntl.h create mode 100644 userland/libc/include/fnmatch.h create mode 100644 userland/libc/include/glob.h create mode 100644 userland/libc/include/grp.h create mode 100644 userland/libc/include/input.h create mode 100644 userland/libc/include/inttypes.h create mode 100644 userland/libc/include/langinfo.h create mode 100644 userland/libc/include/libgen.h create mode 100644 userland/libc/include/limits.h create mode 100644 userland/libc/include/locale.h create mode 100644 userland/libc/include/math.h create mode 100644 userland/libc/include/net/if.h create mode 100644 userland/libc/include/netdb.h create mode 100644 userland/libc/include/netinet/in.h create mode 100644 userland/libc/include/netinet/tcp.h create mode 100644 userland/libc/include/paths.h create mode 100644 userland/libc/include/poll.h create mode 100644 userland/libc/include/pty.h create mode 100644 userland/libc/include/pwd.h create mode 100644 userland/libc/include/regex.h create mode 100644 userland/libc/include/sched.h create mode 100644 userland/libc/include/setjmp.h create mode 100644 userland/libc/include/signal.h create mode 100644 userland/libc/include/socket.h create mode 100644 userland/libc/include/stdio.h create mode 100644 userland/libc/include/stdlib.h create mode 100644 userland/libc/include/string.h create mode 100644 userland/libc/include/strings.h create mode 100644 userland/libc/include/sys/ioctl.h create mode 100644 userland/libc/include/sys/mman.h create mode 100644 userland/libc/include/sys/mount.h create mode 100644 userland/libc/include/sys/resource.h create mode 100644 userland/libc/include/sys/socket.h create mode 100644 userland/libc/include/sys/stat.h create mode 100644 userland/libc/include/sys/statvfs.h create mode 100644 userland/libc/include/sys/syscall.h create mode 100644 userland/libc/include/sys/time.h create mode 100644 userland/libc/include/sys/times.h create mode 100644 userland/libc/include/sys/types.h create mode 100644 userland/libc/include/sys/ucontext.h create mode 100644 userland/libc/include/sys/un.h create mode 100644 userland/libc/include/sys/utsname.h create mode 100644 userland/libc/include/sys/wait.h create mode 100644 userland/libc/include/syscall.h create mode 100644 userland/libc/include/syslog.h create mode 100644 userland/libc/include/termios.h create mode 100644 userland/libc/include/time.h create mode 100644 userland/libc/include/ubsan.h create mode 100644 userland/libc/include/unistd.h create mode 100644 userland/libc/include/utime.h create mode 100644 userland/libc/include/wchar.h create mode 100644 userland/libc/include/wctype.h create mode 100644 userland/libc/input.h create mode 100644 userland/libc/inttypes.h create mode 100644 userland/libc/isspace.c create mode 100644 userland/libc/libc.c create mode 100644 userland/libc/libgen/basename.c create mode 100644 userland/libc/libgen/dirname.c create mode 100644 userland/libc/limits.h create mode 100644 userland/libc/malloc/malloc.c create mode 100644 userland/libc/malloc/malloc.h create mode 100644 userland/libc/malloc/oldmalloc.c create mode 100644 userland/libc/math.h create mode 100644 userland/libc/memset.c create mode 100644 userland/libc/mmap.c create mode 100644 userland/libc/poll.h create mode 100644 userland/libc/pty.c create mode 100644 userland/libc/pty.h create mode 100644 userland/libc/setjmp/longjmp.s create mode 100644 userland/libc/setjmp/setjmp.s create mode 100644 userland/libc/socket.h create mode 100644 userland/libc/stdio.h create mode 100644 userland/libc/stdio/dprintf.c create mode 100644 userland/libc/stdio/fclose.c create mode 100644 userland/libc/stdio/feof.c create mode 100644 userland/libc/stdio/ferror.c create mode 100644 userland/libc/stdio/fflush.c create mode 100644 userland/libc/stdio/fgetc.c create mode 100644 userland/libc/stdio/fgetpos.c create mode 100644 userland/libc/stdio/fgets.c create mode 100644 userland/libc/stdio/fileno.c create mode 100644 userland/libc/stdio/fopen.c create mode 100644 userland/libc/stdio/fprintf.c create mode 100644 userland/libc/stdio/fputc.c create mode 100644 userland/libc/stdio/fputs.c create mode 100644 userland/libc/stdio/fread.c create mode 100644 userland/libc/stdio/fscanf.c create mode 100644 userland/libc/stdio/fseek.c create mode 100644 userland/libc/stdio/fsetpos.c create mode 100644 userland/libc/stdio/ftell.c create mode 100644 userland/libc/stdio/fwrite.c create mode 100644 userland/libc/stdio/getchar.c create mode 100644 userland/libc/stdio/open_memstream.c create mode 100644 userland/libc/stdio/printf.c create mode 100644 userland/libc/stdio/putc.c create mode 100644 userland/libc/stdio/putchar.c create mode 100644 userland/libc/stdio/puts.c create mode 100644 userland/libc/stdio/remove.c create mode 100644 userland/libc/stdio/rename.c create mode 100644 userland/libc/stdio/setvbuf.c create mode 100644 userland/libc/stdio/snprintf.c create mode 100644 userland/libc/stdio/sprintf.c create mode 100644 userland/libc/stdio/stderr.c create mode 100644 userland/libc/stdio/stdin.c create mode 100644 userland/libc/stdio/stdout.c create mode 100644 userland/libc/stdio/tmpfile.c create mode 100644 userland/libc/stdio/tmpnam.c create mode 100644 userland/libc/stdio/ungetc.c create mode 100644 userland/libc/stdio/vdprintf.c create mode 100644 userland/libc/stdio/vfprintf.c create mode 100644 userland/libc/stdio/vprintf.c create mode 100644 userland/libc/stdlib.h create mode 100644 userland/libc/stdlib/abort.c create mode 100644 userland/libc/stdlib/abs.c create mode 100644 userland/libc/stdlib/atexit.c create mode 100644 userland/libc/stdlib/atof.c create mode 100644 userland/libc/stdlib/atoi.c create mode 100644 userland/libc/stdlib/getenv.c create mode 100644 userland/libc/stdlib/mkstemp.c create mode 100644 userland/libc/stdlib/qsort.c create mode 100644 userland/libc/stdlib/rand.c create mode 100644 userland/libc/stdlib/srand.c create mode 100644 userland/libc/stdlib/strtod.c create mode 100644 userland/libc/stdlib/strtol.c create mode 100644 userland/libc/stdlib/strtold.c create mode 100644 userland/libc/stdlib/strtoul.c create mode 100644 userland/libc/stdlib/system.c create mode 100644 userland/libc/string.h create mode 100644 userland/libc/string/memcmp.c create mode 100644 userland/libc/string/memcpy.c create mode 100644 userland/libc/string/memmove.c create mode 100644 userland/libc/string/sscanf.c create mode 100644 userland/libc/string/strcasecmp.c create mode 100644 userland/libc/string/strcat.c create mode 100644 userland/libc/string/strchr.c create mode 100644 userland/libc/string/strcmp.c create mode 100644 userland/libc/string/strcpy.c create mode 100644 userland/libc/string/strcspn.c create mode 100644 userland/libc/string/strdup.c create mode 100644 userland/libc/string/strlcpy.c create mode 100644 userland/libc/string/strlen.c create mode 100644 userland/libc/string/strncasecmp.c create mode 100644 userland/libc/string/strncmp.c create mode 100644 userland/libc/string/strncpy.c create mode 100644 userland/libc/string/strndup.c create mode 100644 userland/libc/string/strnlen.c create mode 100644 userland/libc/string/strpbrk.c create mode 100644 userland/libc/string/strrchr.c create mode 100644 userland/libc/string/strspn.c create mode 100644 userland/libc/string/strstr.c create mode 100644 userland/libc/string/strtok.c create mode 100644 userland/libc/strings.h create mode 100644 userland/libc/sys/mman.h create mode 100644 userland/libc/sys/mman/mmap.c create mode 100644 userland/libc/sys/stat.h create mode 100644 userland/libc/sys/stat/mkdir.c create mode 100644 userland/libc/sys/stat/stat.c create mode 100644 userland/libc/sys/time/gettimeofday.c create mode 100644 userland/libc/sys/types.h create mode 100644 userland/libc/syscall.h create mode 100644 userland/libc/time.h create mode 100644 userland/libc/time/clock_gettime.c create mode 100644 userland/libc/time/ctime_r.c create mode 100644 userland/libc/time/gmtime.c create mode 100644 userland/libc/time/localtime.c create mode 100644 userland/libc/time/strftime.c create mode 100644 userland/libc/time/time.c create mode 100644 userland/libc/ubsan.c create mode 100644 userland/libc/ubsan.h create mode 100644 userland/libc/unistd.h create mode 100644 userland/libc/unistd/_exit.c create mode 100644 userland/libc/unistd/execvp.c create mode 100644 userland/libc/unistd/getopt.c create mode 100644 userland/libc/unistd/getpid.c create mode 100644 userland/libc/unistd/msleep.c create mode 100644 userland/libc/unistd/unlink.c create mode 100644 userland/libc/unistd/uptime.c create mode 100644 userland/libc/wchar.h create mode 100644 userland/libc/wctype.h create mode 100644 userland/libgui/Makefile create mode 100644 userland/libgui/font.h create mode 100644 userland/libgui/libgui.c create mode 100644 userland/libgui/libgui.h create mode 100644 userland/minibox/Makefile create mode 100644 userland/minibox/minibox.c create mode 100644 userland/minibox/utilities/ascii.c create mode 100644 userland/minibox/utilities/cat.c create mode 100644 userland/minibox/utilities/echo.c create mode 100644 userland/minibox/utilities/ed.c create mode 100644 userland/minibox/utilities/include.h create mode 100644 userland/minibox/utilities/init.c create mode 100644 userland/minibox/utilities/ls.c create mode 100644 userland/minibox/utilities/minibox.c create mode 100644 userland/minibox/utilities/pwd.c create mode 100644 userland/minibox/utilities/touch.c create mode 100644 userland/minibox/utilities/wc.c create mode 100644 userland/minibox/utilities/yes.c create mode 100644 userland/sh/Makefile create mode 100755 userland/sh/sh create mode 100644 userland/sh/sh.c create mode 100755 userland/sh/sh_a create mode 100755 userland/sh/sh_bad create mode 100644 userland/snake/Makefile create mode 100644 userland/snake/snake.c create mode 100644 userland/terminal/Makefile create mode 100644 userland/terminal/term.c create mode 100644 userland/test/Makefile create mode 100755 userland/test/linux.sh create mode 100755 userland/test/local/a.out create mode 100644 userland/test/local/testfile create mode 100755 userland/test/test create mode 100644 userland/test/test.c create mode 100644 userland/windowserver/Makefile create mode 100644 userland/windowserver/draw.c create mode 100644 userland/windowserver/draw.h create mode 100644 userland/windowserver/font.h create mode 100644 userland/windowserver/ws.c create mode 100644 userland/windowserver/ws.h (limited to 'userland') diff --git a/userland/ante/Makefile b/userland/ante/Makefile new file mode 100644 index 0000000..412b302 --- /dev/null +++ b/userland/ante/Makefile @@ -0,0 +1,15 @@ +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +CFLAGS = -ggdb -O2 -Wall -Wextra -pedantic -static +LIB=-L../libgui -lgui -lgcc +INC=-I../libgui/ +BINS=ante +all: $(BINS) + +ante.o: ante.c + $(CC) $(CFLAGS) $(INC) $(LIB) -o $@ -c $< + +ante: ante.o + $(CC) $(CFLAGS) -o $@ $^ $(LIB) + +clean: + rm $(BINS) *.o diff --git a/userland/ante/ante.c b/userland/ante/ante.c new file mode 100644 index 0000000..753e7f2 --- /dev/null +++ b/userland/ante/ante.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BACKGROUND_COLOR 0x000000 + +int file_fd; +char *file_buffer; +uint64_t file_buffer_size; +uint64_t file_size = 0; +uint64_t file_real_position = 0; +GUI_Window *global_w; + +typedef enum { + NORMAL, + INSERT, + COMMAND, +} editor_mode_t; + +editor_mode_t current_mode = NORMAL; +uint32_t cursor_pos_x = 0; +uint64_t cursor_pos_y = 0; +void draw_file(void); +void write_file(void); + +int clamp(int *x, int *y) { + int clamped = 0; + if (*x < 0) { + *x = 0; + clamped = 1; + } + if (*y < 0) { + *y = 0; + clamped = 1; + } + if (*x + 8 > global_w->sx) { + *x = (global_w->sx - 8) / 8; + clamped = 1; + } + if (*y + 8 > global_w->sy) { + *y = (global_w->sy - 8) / 8; + clamped = 1; + } + return clamped; +} + +void insert_char(int pos, char c) { + if (0 == file_size) { + file_size++; + file_buffer[0] = c; + return; + } + + // Shift the buffer at 'pos' to the right by one. + memmove(file_buffer + pos + 1, file_buffer + pos, file_size - pos); + + file_buffer[pos] = c; + file_size++; +} + +void delete_char(int pos, int *deleted_newline) { + if (0 == pos) { + return; + } + // Delete the characther at 'pos'. This makes sense if 'pos' is + // at the end of the file and as a result the shift operation done + // later in the function is not overwritting the characther. + if ('\n' == file_buffer[pos - 1]) + *deleted_newline = 1; + file_buffer[pos - 1] = 0; + + // Shift the buffer at 'pos' to the left by one + memmove(file_buffer + pos - 1, file_buffer + pos, file_size - pos); + file_size--; +} + +uint64_t cursor_to_real(int x, int y, int *is_valid) { + *is_valid = 0; + if (clamp(&x, &y)) + return file_real_position; + if (0 == file_size) { + if (0 == x && 0 == y) { + *is_valid = 1; + return 0; + } + return 0; + } + uint64_t p = 0; + int cx = 0; + int cy = 0; + for (; p < file_size; p++) { + if (cx == x && cy == y) { + *is_valid = 1; + break; + } + if ('\n' == file_buffer[p]) { + cx = 0; + cy++; + continue; + } + cx++; + } + if (*is_valid) + return p; + else + return file_real_position; +} + +void key_event(char c) { + int x = 0; + int y = 0; + if (COMMAND == current_mode) { + if ('w' == c) { + printf("wrote to file\n"); + write_file(); + current_mode = NORMAL; + return; + } + if ('q' == c) { + close(file_fd); + close(global_w->ws_socket); + current_mode = NORMAL; + exit(0); + return; + } + return; + } else if (NORMAL == current_mode) { + switch (c) { + case 'j': + y++; + break; + case 'k': + y--; + break; + case 'l': + x++; + break; + case 'h': + x--; + break; + case 'c': + printf("entering command mode\n"); + current_mode = COMMAND; + return; + break; + case 'i': + current_mode = INSERT; + return; + break; + default: + return; + } + } else { + if ('\x1B' == c) { + current_mode = NORMAL; + return; + } + if ('\b' == c) { + int deleted_newline = 0; + delete_char(file_real_position, &deleted_newline); + if (deleted_newline) { + y--; + } else { + x--; + } + GUI_ClearScreen(global_w, BACKGROUND_COLOR); + } else { + insert_char(file_real_position, c); + printf("inserting char: %c\n", c); + if ('\n' == c) { + cursor_pos_x = 0; + y++; + } else { + x++; + } + GUI_ClearScreen(global_w, BACKGROUND_COLOR); + } + } + + int is_valid_position = 0; + file_real_position = + cursor_to_real(cursor_pos_x + x, cursor_pos_y + y, &is_valid_position); + if (!is_valid_position) { + return; + } + GUI_OverwriteFont(global_w, cursor_pos_x * 8, cursor_pos_y * 8, + BACKGROUND_COLOR); + draw_file(); + cursor_pos_x += x; + cursor_pos_y += y; + GUI_OverwriteFont(global_w, cursor_pos_x * 8, cursor_pos_y * 8, 0xFFFFFF); + + GUI_UpdateWindow(global_w); +} + +void draw_file(void) { + assert(file_buffer); + uint32_t screen_pos_x = 0; + uint64_t screen_pos_y = 0; + for (uint64_t i = 0; i < file_size; i++) { + char c = file_buffer[i]; + if ('\n' == c) { + screen_pos_x = 0; + screen_pos_y += 8; + continue; + } + GUI_DrawFont(global_w, screen_pos_x, screen_pos_y, c); + screen_pos_x += 8; + } +} + +void write_file(void) { + assert(file_buffer); + pwrite(file_fd, file_buffer, file_size, 0); +} + +int open_file(const char *file) { + file_fd = open(file, O_RDWR, O_CREAT); + printf("file_fd: %d\n", file_fd); + if (0 > file_fd) { + perror("open"); + return 0; + } + + file_buffer_size = 0x1000; + file_buffer = malloc(file_buffer_size); + uint64_t index = 0; + assert(file_buffer); + for (;;) { + char buffer[4096]; + int rc = read(file_fd, buffer, 4096); + if (-1 == rc) { + perror("read"); + assert(0); + } + + if (0 == rc) + break; + + file_size += rc; + if (file_size > file_buffer_size) { + file_buffer_size = file_size; + file_buffer = realloc(file_buffer, file_buffer_size); + assert(file_buffer); + } + + for (int i = 0; i < rc; i++, index++) { + file_buffer[index] = buffer[i]; + } + } + return 1; +} + +void run() { + struct pollfd fds[1]; + fds[0].fd = global_w->ws_socket; + fds[0].events = POLLIN; + fds[0].revents = 0; + for (;; fds[0].revents = 0) { + poll(fds, 1, 0); + if (fds[0].revents & POLLIN) { + WS_EVENT e; + int rc; + if (0 >= (rc = read(global_w->ws_socket, &e, sizeof(e)))) + continue; + if (0 == e.c) + continue; + key_event(e.c); + } + } +} + +int main(int argc, char **argv) { + if (argc < 2) { + printf("File has to be specified.\n"); + return 1; + } + global_w = GUI_CreateWindow(10, 10, 150 * 4, 150 * 4); + assert(global_w); + GUI_ClearScreen(global_w, BACKGROUND_COLOR); + GUI_UpdateWindow(global_w); + + assert(open_file(argv[1])); + draw_file(); + run(); + return 0; +} diff --git a/userland/cat/Makefile b/userland/cat/Makefile new file mode 100644 index 0000000..b45fae9 --- /dev/null +++ b/userland/cat/Makefile @@ -0,0 +1,10 @@ +CC="/home/anton/opt/cross/bin/i686-elf-gcc" +CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough +BINS=cat +all: $(BINS) + +cat.o: cat.c + $(CC) $(CFLAGS) -L../libc/ -lc -c cat.c -I../libc/ + +cat: cat.o + $(CC) -shared -o cat -ffreestanding -nostdlib $(CFLAGS) cat.o -L../libc/ -lc -lgcc #-L../libc/c.a diff --git a/userland/cat/cat b/userland/cat/cat new file mode 100755 index 0000000..2ba0c4d Binary files /dev/null and b/userland/cat/cat differ diff --git a/userland/cat/cat.c b/userland/cat/cat.c new file mode 100644 index 0000000..b143581 --- /dev/null +++ b/userland/cat/cat.c @@ -0,0 +1,24 @@ +#include +#include +#include + +int main(int argc, char **argv) { + DIR *d = opendir("/"); + struct dirent *de = readdir(d); + printf("x : %x\n", de->d_name[0]); + for (;;) + ; + /* + int fd = 0; + if (argc < 2) + goto read_stdin; + for (int i = 1; i < argc; i++) { + if ((fd = open(argv[i], O_RDONLY, 0)) == -1) { + return 1; + } + read_stdin: + for (char c[4096], int rc; (rc = read(fd, c, 4096) > 0);) + write(1, c, rc); + }*/ + return 0; +} diff --git a/userland/init/Makefile b/userland/init/Makefile new file mode 100644 index 0000000..932fcd3 --- /dev/null +++ b/userland/init/Makefile @@ -0,0 +1,10 @@ +CC="/home/anton/opt/cross/bin/i686-elf-gcc" +CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough +BINS=init +all: $(BINS) + +init.o: init.c + $(CC) $(CFLAGS) -I../libc/ -L../libc/ -lc -c init.c + +init: init.o + $(CC) -shared -o init -ffreestanding -nostdlib $(CFLAGS) init.o -L../libc/ -lc -lgcc #-L../libc/c.a diff --git a/userland/init/crt0_old.c b/userland/init/crt0_old.c new file mode 100644 index 0000000..7d1e977 --- /dev/null +++ b/userland/init/crt0_old.c @@ -0,0 +1,12 @@ +#include +int main(int argc, char **argv); +//int main(); + +void _start(int a, int b, int argc, char** argv) +{ + (void)a; + kprintf("argc : %x\n", &argc); + kprintf("argv : %x\n", &argv); + for(;;); +// main(argc, t); +} diff --git a/userland/init/init b/userland/init/init new file mode 100755 index 0000000..3ae9020 Binary files /dev/null and b/userland/init/init differ diff --git a/userland/init/init.c b/userland/init/init.c new file mode 100644 index 0000000..78c4420 --- /dev/null +++ b/userland/init/init.c @@ -0,0 +1,15 @@ +#include +#include +#include +#include +#include + +int main(void) { + if (fork()) + for (;;) + wait(NULL); + + char *a[] = {NULL}; + execv("/term", a); + return 1; +} diff --git a/userland/json/Makefile b/userland/json/Makefile new file mode 100644 index 0000000..9fcb567 --- /dev/null +++ b/userland/json/Makefile @@ -0,0 +1,18 @@ +#CC="/home/anton/opt/cross/bin/i686-elf-gcc" +#AR="/home/anton/opt/cross/bin/i686-elf-ar" +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +AR="/home/anton/prj/osdev/sysroot/bin/i686-sb-ar" +CFLAGS = -O0 -Wall -Wextra -pedantic -Wimplicit-fallthrough -static -Wno-undef +BINS=libjson.a +all: $(BINS) +LIBS=-L./hashmap -lhashmap +OBJ=json.o + +json.o: json.c + $(CC) $(CFLAGS) $(LIBS) -c json.c + +libjson.a: $(OBJ) + $(AR) rcs libjson.a $^ + +clean: + rm libjson.a json.o diff --git a/userland/json/hashmap b/userland/json/hashmap new file mode 160000 index 0000000..07dfe3b --- /dev/null +++ b/userland/json/hashmap @@ -0,0 +1 @@ +Subproject commit 07dfe3b606e0d82b2e181b27344b5e4ce8849f31 diff --git a/userland/json/json.c b/userland/json/json.c new file mode 100644 index 0000000..6449193 --- /dev/null +++ b/userland/json/json.c @@ -0,0 +1,360 @@ +// +// Copyright (C) 2022 by Anton Kling +// +// SPDX-License-Identifier: BSD-2-Clause +// +#include "hashmap/hashmap.h" +#include +#include +#include +#include +#include +#include + +typedef enum JSON_TYPE { + NONE, + STRING, + NUMBER, + OBJECT, + ARRAY, // FIXME + BOOL, + JSON_NULL, +} JSON_TYPE; + +typedef struct JSON_ENTRY { + char *name; + JSON_TYPE type; + void *value; +} JSON_ENTRY; + +typedef struct JSON_OBJECT { + size_t size; + JSON_ENTRY *entries; + HashMap *hash_indexes; +} JSON_OBJECT; + +typedef struct JSON_CTX { + JSON_ENTRY global_object; +} JSON_CTX; + +void JSON_Init(JSON_CTX *ctx) { + ctx->global_object.name = NULL; + ctx->global_object.type = OBJECT; + ctx->global_object.value = malloc(sizeof(JSON_OBJECT)); + JSON_OBJECT *obj = ctx->global_object.value; + obj->size = 0; + obj->entries = NULL; +} + +const char *skip_whitespace(const char *str) { + for (; *str; str++) + switch (*str) { + case ' ': + case '\t': + case '\n': + case '\r': + break; + default: + goto _exit; + } +_exit: + return str; +} + +char to_lower(char c) { + if (c <= 'Z') + return c | 32; + return c; +} + +int low_strequ(const char *s1, const char *s2, size_t l) { + for (; 0 < l; l--, s2++, s1++) { + if (to_lower(*s2) != to_lower(*s1)) + return 0; + } + return 1; +} + +const char *find_name(const char *json, char *name_buffer, size_t buffer_len, + size_t *name_length, int *rc) { + *rc = 0; + json = skip_whitespace(json); + if ('"' != *json) + return json; + + // This *can* be the name + json++; + const char *tmp = json; + for (; *tmp && '"' != *tmp; tmp++) + ; + if (!(*tmp && ':' == *(tmp + 1))) { + // Invalid name + // FIXME: Do something better than this. + assert(0); + } + // The name was found. + *rc = 1; + size_t str_len; + if (tmp == json) + str_len = 0; + else + str_len = (tmp - json - 1); + if (str_len + 1 > buffer_len) { + // JSON string is too long for the buffer + // FIXME: Do something better than this. + assert(0); + } + memcpy(name_buffer, json, str_len + 1); + name_buffer[str_len + 1] = '\0'; + *name_length = str_len; + return tmp + 2; +} + +const char *find_entry(const char *json, char *name_buffer, size_t buffer_len, + size_t *name_length, JSON_TYPE *entry_type, int *rc) { + *rc = 0; + json = skip_whitespace(json); + json = find_name(json, name_buffer, 4096, name_length, rc); + json = skip_whitespace(json); + switch (*json) { + case '{': + *entry_type = OBJECT; + break; + case '"': + *entry_type = STRING; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + *entry_type = NUMBER; + break; + case '[': + *entry_type = ARRAY; + break; + case 'T': + case 'F': + case 't': + case 'f': + *entry_type = BOOL; + break; + case 'N': + case 'n': + *entry_type = JSON_NULL; + break; + case '}': + *rc = 2; + break; + default: + *entry_type = NONE; + break; + } + return json; +} + +const char *extract_int(const char *json, uint32_t **value, int *rc) { + *value = malloc(sizeof(uint32_t)); + *rc = 0; + json = skip_whitespace(json); + // FIXME: Do some checking to determine that this is a int. + **value = 0; + for (; *json && ',' != *json && '}' != *json;) { + **value *= 10; + **value += (uint32_t)(*json - '0'); + json++; + json = skip_whitespace(json); + } + if ('\0' != *json) + *rc = 1; + return json; +} + +const char *extract_string(const char *json, char **value, int *rc) { + *value = malloc(4096); + *rc = 0; + int escape = 0; + json++; + char *tmp = *value; + for (; *json; json++) { + if ('"' == *json && !escape) + break; + escape = 0; + + if ('\\' == *json && !escape) { + escape = 1; + continue; + } + *tmp = *json; + tmp++; + } + *tmp = '\0'; + if ('\0' != *json) + *rc = 1; + return json; +} + +const char *extract_bool(const char *json, uint8_t **value, int *rc) { + *value = malloc(sizeof(uint8_t)); + *rc = 0; + if (low_strequ(json, "true", 3)) { + **value = 1; + json += 4; + *rc = 1; + return json; + } else if (low_strequ(json, "false", 4)) { + **value = 0; + json += 5; + *rc = 1; + return json; + } + return json; +} + +const char *extract_null(const char *json, uint8_t **value, int *rc) { + *value = malloc(sizeof(uint8_t)); + *rc = 0; + + if (low_strequ(json, "null", 3)) { + **value = 0; + json += 4; + *rc = 1; + return json; + } + return json; +} + +void hashmap_free_value(char *key, void *value) { + (void)key; + free(value); +} + +JSON_ENTRY *JSON_at(JSON_ENTRY *entry, size_t i); + +void JSON_Parse(JSON_CTX *ctx, const char *json) { + int rc; + char name_buffer[4096]; + size_t name_length; + JSON_TYPE entry_type; + JSON_OBJECT *object_stack[64]; + memset(object_stack, 0, sizeof(JSON_OBJECT *[64])); + size_t parent_num = 0; + object_stack[parent_num] = ctx->global_object.value; + object_stack[parent_num]->size = 0; + + for (;; json++) { + json = find_entry(json, name_buffer, 4096, &name_length, &entry_type, &rc); + if ('\0' == *json) + return; + + if (2 == rc) { + if (0 == parent_num) + return; + parent_num--; + json++; + json = skip_whitespace(json); + if (',' == *json) + json++; + continue; + } + + if (NULL == object_stack[parent_num]->entries) { + object_stack[parent_num]->entries = malloc(sizeof(JSON_ENTRY[30])); + object_stack[parent_num]->size = 0; + object_stack[parent_num]->hash_indexes = hashmap_create(30); + } + + size_t entry_num = object_stack[parent_num]->size; + object_stack[parent_num]->size++; + + if (NULL == object_stack[parent_num]->entries) { + void *rc = object_stack[parent_num]->entries = + malloc(sizeof(JSON_ENTRY[30])); + object_stack[parent_num]->entries = rc; + object_stack[parent_num]->size = 0; + object_stack[parent_num]->hash_indexes = hashmap_create(30); + } + JSON_ENTRY *entry = &object_stack[parent_num]->entries[entry_num]; + if (1 == rc) { + name_length++; + entry->name = malloc(name_length + 2); + memcpy(entry->name, name_buffer, name_length); + entry->name[name_length] = '\0'; + size_t *b = malloc(sizeof(size_t)); + *b = entry_num; + hashmap_add_entry(object_stack[parent_num]->hash_indexes, entry->name, b, + hashmap_free_value, 1); + } else { + entry->name = NULL; + } + entry->type = entry_type; + if (OBJECT == entry_type) { + entry->value = malloc(sizeof(JSON_OBJECT)); + parent_num++; + object_stack[parent_num] = entry->value; + object_stack[parent_num]->entries = NULL; + continue; + } else if (NUMBER == entry_type) { + json = extract_int(json, (uint32_t **)&entry->value, &rc); + } else if (STRING == entry_type) { + json = extract_string(json, (char **)&entry->value, &rc); + } else if (BOOL == entry_type) { + json = extract_bool(json, (uint8_t **)&entry->value, &rc); + } else if (JSON_NULL == entry_type) { + json = extract_null(json, (uint8_t **)&entry->value, &rc); + } + json++; + } +} + +JSON_ENTRY *JSON_at(JSON_ENTRY *entry, size_t i) { + if (OBJECT != entry->type) + return NULL; + return &((JSON_OBJECT *)(entry->value))->entries[i]; +} + +JSON_ENTRY *JSON_search_name(JSON_ENTRY *entry, char *name) { + if (OBJECT != entry->type) + return NULL; + size_t *i = + hashmap_get_entry(((JSON_OBJECT *)(entry->value))->hash_indexes, name); + if (!i) + return NULL; + return JSON_at(entry, *i); +} + +void write_entry_content(int fd, size_t indent, JSON_ENTRY *entry) { +#define PLACE_TABS \ + { \ + for (size_t i = 0; i < indent; i++) \ + dprintf(fd, "\t"); \ + } + PLACE_TABS + if (entry->name) + dprintf(fd, "\"%s\": ", entry->name); + if (OBJECT == entry->type) { + JSON_OBJECT *object = entry->value; + dprintf(fd, "{\n"); + for (size_t i = 0; i < object->size; i++) + write_entry_content(fd, indent + 1, &object->entries[i]); + PLACE_TABS + dprintf(fd, "},\n"); + } else if (NUMBER == entry->type) + dprintf(fd, "%d,\n", *(uint32_t *)entry->value); + else if (STRING == entry->type) + dprintf(fd, "\"%s\",\n", (char *)entry->value); + else if (BOOL == entry->type) + dprintf(fd, "%s,\n", ((*(uint8_t *)entry->value) ? "true" : "false")); + else if (JSON_NULL == entry->type) + dprintf(fd, "null,\n"); +} + +void JSON_extract_fd(JSON_CTX *ctx, int fd) { + JSON_ENTRY *entry = &ctx->global_object; + write_entry_content(fd, 0, &((JSON_OBJECT *)entry->value)->entries[0]); +} diff --git a/userland/json/json.h b/userland/json/json.h new file mode 100644 index 0000000..642a878 --- /dev/null +++ b/userland/json/json.h @@ -0,0 +1,39 @@ +#ifndef JSON_H +#define JSON_H +#include "hashmap/hashmap.h" +#include +#include + +typedef enum JSON_TYPE { + NONE, + STRING, + NUMBER, + OBJECT, + ARRAY, // FIXME + BOOL, + JSON_NULL, +} JSON_TYPE; + +typedef struct JSON_ENTRY { + char *name; + JSON_TYPE type; + void *value; +} JSON_ENTRY; + +typedef struct JSON_OBJECT { + uint64_t size; + JSON_ENTRY *entries; + HashMap *hash_indexes; +} JSON_OBJECT; + +typedef struct JSON_CTX { + JSON_ENTRY global_object; +} JSON_CTX; + +void JSON_Init(JSON_CTX *ctx); +void JSON_Parse(JSON_CTX *ctx, const char *json); +void JSON_extract_fd(JSON_CTX *ctx, int whitespace, int fd); +uint64_t JSON_extract_length(JSON_CTX *ctx, int whitespace); +JSON_ENTRY *JSON_at(JSON_ENTRY *entry, uint64_t i); +JSON_ENTRY *JSON_search_name(JSON_ENTRY *entry, char *name); +#endif diff --git a/userland/json/libjson.a b/userland/json/libjson.a new file mode 100644 index 0000000..ca66650 Binary files /dev/null and b/userland/json/libjson.a differ 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 + +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 +#include +#include + +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 +#include +#include + +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 +#include +#include + +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 + +// 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 + +// 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 + +// 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 + +// 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 + +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 + +// 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 + +// 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 + +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 + +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 +#include +#include +#include +#include +#include + +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 + +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 + +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 + +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 + +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 +#include +#include + +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 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 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 +#include +#include +#include +#include +#include + +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 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 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 + +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 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 + +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 + +// 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 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 diff --git a/userland/libc/include/math.h b/userland/libc/include/math.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/net/if.h b/userland/libc/include/net/if.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/netdb.h b/userland/libc/include/netdb.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/netinet/in.h b/userland/libc/include/netinet/in.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/netinet/tcp.h b/userland/libc/include/netinet/tcp.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/paths.h b/userland/libc/include/paths.h new file mode 100644 index 0000000..e69de29 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 + +#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 diff --git a/userland/libc/include/regex.h b/userland/libc/include/regex.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/sched.h b/userland/libc/include/sched.h new file mode 100644 index 0000000..e69de29 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 +#include + +#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 +#include +#include + +// 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 +#include +#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 +#include + +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 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 +#include + +#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 diff --git a/userland/libc/include/sys/resource.h b/userland/libc/include/sys/resource.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/sys/socket.h b/userland/libc/include/sys/socket.h new file mode 100644 index 0000000..e69de29 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 +#include + +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 diff --git a/userland/libc/include/sys/syscall.h b/userland/libc/include/sys/syscall.h new file mode 100644 index 0000000..e69de29 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 +#include +#include + +#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 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 diff --git a/userland/libc/include/sys/un.h b/userland/libc/include/sys/un.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/sys/utsname.h b/userland/libc/include/sys/utsname.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/sys/wait.h b/userland/libc/include/sys/wait.h new file mode 100644 index 0000000..e69de29 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 +#include +#include + +#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 diff --git a/userland/libc/include/termios.h b/userland/libc/include/termios.h new file mode 100644 index 0000000..e69de29 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 +#include + +#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 + +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 +#include +#include + +#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 diff --git a/userland/libc/include/wchar.h b/userland/libc/include/wchar.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libc/include/wctype.h b/userland/libc/include/wctype.h new file mode 100644 index 0000000..e69de29 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 + +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 + +// 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 + +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 +#include +#include +#include +#include + +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 and a . + printf("%s: ", s); + } + + // Then an error message string followed by a . + // 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 +#include + +/* +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 + +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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include + +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 +#include +#include + +#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 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 + +// 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 +#include +#include + +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 + +#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 +#include + +#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 +#include +#include + +// 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 + +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 +#include + +// 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 + +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 + +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 + +// 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 +#include + +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 + +// 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 + +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 +#include + +// 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 +#include +#include +#include + +// 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 + +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 + +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 + +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 +#include + +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 +#include + +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 +#include + +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 + +// 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 + +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 +#include + +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 + +// 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 +#include +#include +#include +/* +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 + +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 + +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 +#include + +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 + +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 +#include + +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 +#include + +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 + +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 +#include +#include +#include + +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 +#include +#include +#include + +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 +#include + +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 +#include +#include + +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 +#include + +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 +#include + +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 +#include + +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 + +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 +#include +#include +#include + +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 +#include +#include +#include + +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 + +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 +#include +#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 +#include + +// 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 + +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 + +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 + +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 + +// 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 + +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 +#include + +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 +#include + +// 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 +#include + +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 +#include + +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 +#include +#include + +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 +#include +#include +#include + +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 +#include + +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 +#include +#include +#include + +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 + +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 +#include + +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 + +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 + +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 + +// 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 +#include +#include +#include +#include +#include +#include + +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 + +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 + +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 + +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 + +// 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 + +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 + +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 +#include +#include + +// 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 + +// 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 + +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 +#include + +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 + +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 + +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 +#include +#include + +// 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 + +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 + +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 + +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 + +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 + +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 + +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 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 +#include + +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 +#include +#include + +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 +#include + +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 +#include + +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 +#include +#include +#include +#include + +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 +#include + +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 +#include + +#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 + +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 +#include + +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 +#include + +// 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 + +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 + + 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 +#include + +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_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 +#include + +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 + +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 + +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 +#include + +// 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 +#include + +// 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 +#include + +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 +#include +#include + +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 +#include +#include + +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 + +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 +#include +#include + +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 diff --git a/userland/libc/wctype.h b/userland/libc/wctype.h new file mode 100644 index 0000000..e69de29 diff --git a/userland/libgui/Makefile b/userland/libgui/Makefile new file mode 100644 index 0000000..5a895c4 --- /dev/null +++ b/userland/libgui/Makefile @@ -0,0 +1,17 @@ +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +AR="/home/anton/prj/osdev/sysroot/bin/i686-sb-ar" +#CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough -nostdlib -static -Wno-undef -fsanitize=shift,signed-integer-overflow,bounds +CFLAGS = -O2 -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough -nostdlib -static -Wno-undef +BINS=libgui.a +all: $(BINS) +LIBS=-L../libc -lc -L../json -ljson -lgcc +OBJ=libgui.o + +libgui.o: libgui.c + $(CC) $(CFLAGS) -c libgui.c -I../libc/ -I../json/ $(LIBS) + +libgui.a: $(OBJ) + $(AR) rcs libgui.a $^ + +clean: + rm $(OBJ) $(BINS) diff --git a/userland/libgui/font.h b/userland/libgui/font.h new file mode 100644 index 0000000..763b438 --- /dev/null +++ b/userland/libgui/font.h @@ -0,0 +1,3 @@ +#ifndef FONT_H +#define FONT_H +#endif diff --git a/userland/libgui/libgui.c b/userland/libgui/libgui.c new file mode 100644 index 0000000..5f5526d --- /dev/null +++ b/userland/libgui/libgui.c @@ -0,0 +1,290 @@ +#include "libgui.h" +#include "font.h" +#include +#include +#include +#include +#include +#include +#include + +#define place_pixel_pos(_p, _pos) \ + { *(uint32_t *)(w->bitmap_ptr + _pos) = _p; } + +static const unsigned char font8x8_basic[128][8] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) + {0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) + {0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") + {0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) + {0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) + {0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) + {0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) + {0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') + {0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() + {0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) + {0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) + {0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) + {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) + {0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) + {0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) + {0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) + {0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) + {0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) + {0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) + {0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) + {0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) + {0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) + {0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) + {0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) + {0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) + {0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) + {0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) + {0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;) + {0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) + {0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) + {0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) + {0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) + {0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) + {0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) + {0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) + {0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) + {0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) + {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) + {0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) + {0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) + {0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) + {0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) + {0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) + {0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) + {0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) + {0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) + {0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) + {0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) + {0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) + {0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) + {0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) + {0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) + {0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) + {0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) + {0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) + {0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) + {0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) + {0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) + {0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) + {0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) + {0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) + {0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) + {0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) + {0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) + {0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) + {0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) + {0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) + {0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) + {0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) + {0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) + {0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) + {0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) + {0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) + {0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) + {0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) + {0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) + {0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) + {0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) + {0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) + {0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) + {0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) + {0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) + {0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) + {0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) + {0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) + {0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) + {0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) + {0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) + {0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) + {0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) + {0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) + {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) + {0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) + {0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F +}; + +#define pokeb(S, O, V) (*(unsigned char *)((S) + (O)) = (V)) + +// Very temporary +char *random_string(void) { + int fd = open("/dev/urandom", O_RDONLY, 0); + char *r = malloc(sizeof(char[10])); + for (int i = 0; i < 10 - 1; i++) { + char c; + read(fd, &c, 1); + r[i] = 'a' + (c & 0xF); + } + close(fd); + r[9] = '\0'; + printf("r: %s\n", r); + return r; +} + +int get_bitmap_value(const unsigned char bitmap[], int i) { + int array_index = i / 8; + int byte_index = i % 8; + int rc = (bitmap[array_index] >> byte_index) & 0x1; + return rc; +} + +void GUI_OverwriteFont(GUI_Window *w, uint32_t px, uint32_t py, + const uint32_t color) { + int sx, sy; + sx = 8; + sy = 8; + int x, y; + x = px; + y = py; + if (px + sx > w->sx) + return; + if (py + sy > w->sy) + return; + for (int i = 0; i < sx * sy; i++) { + int pos = x + y * w->sx; + place_pixel_pos(color, pos); + x++; + if (x >= sx + px) { + y++; + x = px; + } + if (y > py + sy) + break; + } +} + +void GUI_DrawFont(GUI_Window *w, uint32_t px, uint32_t py, const uint32_t c) { + int sx, sy; + sx = 8; + sy = 8; + int x, y; + x = px; + y = py; + if (px + sx > w->sx) + return; + if (py + sy > w->sy) + return; + const unsigned char *bitmap = font8x8_basic[c]; + for (int i = 0; i < sx * sy; i++) { + int pos = x + y * w->sx; + if (get_bitmap_value(bitmap, i)) { + place_pixel_pos(0xFFFFFF, pos); + } else { + place_pixel_pos(0x0, pos); + } + x++; + if (x >= sx + px) { + y++; + x = px; + } + if (y > py + sy) + break; + } +} + +typedef struct { + uint16_t px; + uint16_t py; + uint16_t sx; + uint16_t sy; + uint8_t name_len; +} WS_EVENT_CREATE; + +void GUI_ClearScreen(GUI_Window *w, uint32_t color) { + for (int i = 0; i < w->sx * w->sy; i++) + w->bitmap_ptr[i] =color; +} + +GUI_Window *GUI_CreateWindow(uint32_t x, uint32_t y, uint32_t sx, uint32_t sy) { + GUI_Window *w = malloc(sizeof(GUI_Window)); + if (!w) + return NULL; + w->x = x; + w->y = y; + w->sx = sx; + w->sy = sy; + + // Connect to the windowserver + int ws_fd = -1; + for (; - 1 == ws_fd;) { + ws_fd = open("/dev/windowserver", O_RDWR | O_NONBLOCK, 0); + } + w->ws_socket = ws_fd; + char *str = random_string(); + WS_EVENT_CREATE e; + e.px = x; + e.py = y; + e.sx = sx; + e.sy = sy; + e.name_len = (uint8_t)strlen(str) + 1; + + // Create bitmap + w->bitmap_fd = shm_open(str, O_RDWR, 0); + if (!((int)w->bitmap_fd >= 0)) { + printf("bitmap_fd: %x\n", w->bitmap_fd); + assert(0); + } + ftruncate(w->bitmap_fd, sx * sy * sizeof(uint32_t)); + void *rc = mmap(NULL, sx * sy * sizeof(uint32_t), 0, 0, w->bitmap_fd, 0); + if (!((int)rc >= 0)) { + printf("rc: %x\n", rc); + assert(0); + } + w->bitmap_ptr = rc; + + // Send the request to the windowserver + uint8_t l = 1; + uint8_t len = sizeof(l) + sizeof(e) + e.name_len; + char *buffer = malloc(len); + char *p = buffer; + memcpy(p, &l, sizeof(l)); + p += sizeof(l); + memcpy(p, &e, sizeof(e)); + p += sizeof(e); + strcpy(p, str); + write(ws_fd, buffer, len); + return w; +} + +void GUI_UpdateWindow(GUI_Window *w) { + uint8_t l = 0; + write(w->ws_socket, &l, sizeof(l)); +} diff --git a/userland/libgui/libgui.h b/userland/libgui/libgui.h new file mode 100644 index 0000000..d58c23c --- /dev/null +++ b/userland/libgui/libgui.h @@ -0,0 +1,34 @@ +#ifndef LIBGUI_H +#define LIBGUI_H +#include +#include + +typedef struct { + int ws_socket; + int bitmap_fd; + uint32_t *bitmap_ptr; + int x; + int y; + int sx; + int sy; +} GUI_Window; + +// Taken from drivers/keyboard.c +struct KEY_EVENT { + char c; + uint8_t mode; // (shift (0 bit)) (alt (1 bit)) + uint8_t release; // 0 pressed, 1 released +}; + +typedef struct { + int type; + struct KEY_EVENT ev; +} WS_EVENT; + +GUI_Window *GUI_CreateWindow(uint32_t x, uint32_t y, uint32_t sx, uint32_t sy); +void GUI_DrawFont(GUI_Window *w, uint32_t px, uint32_t py, const uint32_t c); +void GUI_UpdateWindow(GUI_Window *w); +void GUI_OverwriteFont(GUI_Window *w, uint32_t px, uint32_t py, + const uint32_t color); +void GUI_ClearScreen(GUI_Window *w, uint32_t color); +#endif diff --git a/userland/minibox/Makefile b/userland/minibox/Makefile new file mode 100644 index 0000000..5448f96 --- /dev/null +++ b/userland/minibox/Makefile @@ -0,0 +1,12 @@ +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +CFLAGS=-Wall -Wextra -pedantic -Wimplicit-fallthrough -g -O0 +OBJ=minibox.o utilities/cat.o utilities/echo.o utilities/yes.o utilities/minibox.o utilities/ascii.o utilities/wc.o utilities/init.o utilities/ls.o utilities/touch.o utilities/ed.o + +%.o: %.c + $(CC) $(CFLAGS) $(INCLUDE) $(LIBS) -c $< -o $@ + +minibox: $(OBJ) + $(CC) $(INCLUDE) -o $@ $^ $(CFLAGS) $(LIBS) + +clean: + rm minibox $(OBJ) diff --git a/userland/minibox/minibox.c b/userland/minibox/minibox.c new file mode 100644 index 0000000..63eaee8 --- /dev/null +++ b/userland/minibox/minibox.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: 0BSD +// TODO: Possibly use getprogname() instead of using argv[0] to get the +// utility name. +#include +#include +#include + +#include "utilities/include.h" + +#define ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0])) + +typedef struct Command { + char *name; + int (*function)(int, char **); +} Command; + +#define STR2(_x) #_x +#define STR(_x) STR2(_x) +#define COMMAND(NAME) \ + { STR(NAME), NAME##_main } + +Command utilities[] = {COMMAND(minibox), COMMAND(ascii), COMMAND(echo), + COMMAND(cat), COMMAND(yes), COMMAND(wc), + COMMAND(init), COMMAND(ls), COMMAND(touch), + COMMAND(ed)}; + +char *parse_filename(char *str) { + char *tmp = NULL, *is = str; + for (; *is++;) + if ('/' == *is) + tmp = is; + return tmp ? tmp + 1 : str; +} + +void usage(void) { + for (int i = 0; i < ARRAY_LENGTH(utilities); i++) { + printf("%s ", utilities[i].name); + } + printf("\n"); +} + +int main(int argc, char **argv) { + if (argc < 1) + return 1; +#ifdef SINGLE_MAIN + return utilities[0].function(argc, argv); +#endif + + // argv[0] will be checked to determine what utility + // is supposed to be ran. + // NOTE: "minibox" is a utility than can be ran. "minibox" + // will switch argv and argc so that argv[1] -> argv[0] + // then it will rerun main(). This allows utlities + // to be ran like "minibox " or + // even "minibox minibox " + const char *utility_name = parse_filename(argv[0]); + if (*utility_name == '/') + utility_name++; + for (int i = 0; i < ARRAY_LENGTH(utilities); i++) + if (0 == strcmp(utility_name, utilities[i].name)) + return utilities[i].function(argc, argv); + + usage(); + return 0; +} diff --git a/userland/minibox/utilities/ascii.c b/userland/minibox/utilities/ascii.c new file mode 100644 index 0000000..53429dc --- /dev/null +++ b/userland/minibox/utilities/ascii.c @@ -0,0 +1,30 @@ +#include + +const char * const ascii_table[] = +{ +"Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex", +" 0 00 NUL 16 10 DLE 32 20 48 30 0 64 40 @ 80 50 P 96 60 ` 112 70 p", +" 1 01 SOH 17 11 DC1 33 21 ! 49 31 1 65 41 A 81 51 Q 97 61 a 113 71 q", +" 2 02 STX 18 12 DC2 34 22 \" 50 32 2 66 42 B 82 52 R 98 62 b 114 72 r", +" 3 03 ETX 19 13 DC3 35 23 # 51 33 3 67 43 C 83 53 S 99 63 c 115 73 s", +" 4 04 EOT 20 14 DC4 36 24 $ 52 34 4 68 44 D 84 54 T 100 64 d 116 74 t", +" 5 05 ENQ 21 15 NAK 37 25 % 53 35 5 69 45 E 85 55 U 101 65 e 117 75 u", +" 6 06 ACK 22 16 SYN 38 26 & 54 36 6 70 46 F 86 56 V 102 66 f 118 76 v", +" 7 07 BEL 23 17 ETB 39 27 ' 55 37 7 71 47 G 87 57 W 103 67 g 119 77 w", +" 8 08 BS 24 18 CAN 40 28 ( 56 38 8 72 48 H 88 58 X 104 68 h 120 78 x", +" 9 09 HT 25 19 EM 41 29 ) 57 39 9 73 49 I 89 59 Y 105 69 i 121 79 y", +" 10 0A LF 26 1A SUB 42 2A * 58 3A : 74 4A J 90 5A Z 106 6A j 122 7A z", +" 11 0B VT 27 1B ESC 43 2B + 59 3B ; 75 4B K 91 5B [ 107 6B k 123 7B {", +" 12 0C FF 28 1C FS 44 2C , 60 3C < 76 4C L 92 5C \\ 108 6C l 124 7C |", +" 13 0D CR 29 1D GS 45 2D - 61 3D = 77 4D M 93 5D ] 109 6D m 125 7D }", +" 14 0E SO 30 1E RS 46 2E . 62 3E > 78 4E N 94 5E ^ 110 6E n 126 7E ~", +" 15 0F SI 31 1F US 47 2F / 63 3F ? 79 4F O 95 5F _ 111 6F o 127 7F DEL", +}; + +int ascii_main(int argc, char ** argv) +{ + for(int i = 0;i < sizeof(ascii_table)/sizeof(ascii_table[0]);i++) + puts(ascii_table[i]); + + return 0; +} diff --git a/userland/minibox/utilities/cat.c b/userland/minibox/utilities/cat.c new file mode 100644 index 0000000..c528d49 --- /dev/null +++ b/userland/minibox/utilities/cat.c @@ -0,0 +1,54 @@ +// cat - concatenate and print files +// https://pubs.opengroup.org/onlinepubs/9699919799/ +// +// TODO: Add -u flag "Write bytes from the input file to the standard +// output without delay as each is read." +#include "include.h" +#include +#include +#include +#include +#include + +int fd_to_stdout(int fd) { + int rc; + for (char buffer[CAT_BUFFER]; (rc = read(fd, &buffer, sizeof(buffer)));) { + if (-1 == rc) + return 0; + if (-1 == write(fd_stdout, buffer, rc)) + return 0; + } + return 1; +} + +int cat_main(int argc, char **argv) { + int fd = fd_stdin; + + // If no file operands are specified, the standard input shall be + // used. + if (argc < 2) { + return (fd_to_stdout(0)) ? 0 : 1; + } + + argv++; + for (; *argv; argv++) { + // If a file is '-', the cat utility shall read from the standard + // input at that point in the sequence. + if (0 == strcmp(*argv, "-")) { + if (!fd_to_stdout(0)) + return 1; + continue; + } + + if (-1 == (fd = open(*argv, O_RDONLY, 0))) { + printf("cat: "); + // fflush(stdout); + perror(*argv); + return 1; + } + if (!fd_to_stdout(fd)) + return 1; + close(fd); + } + return 0; +} diff --git a/userland/minibox/utilities/echo.c b/userland/minibox/utilities/echo.c new file mode 100644 index 0000000..5ec68a7 --- /dev/null +++ b/userland/minibox/utilities/echo.c @@ -0,0 +1,30 @@ +#include "include.h" +#include +#include +#include +#include + +int echo(char **str, int new_line) { + for (; *str;) { + printf("%s", *str); + if (*++str) + putchar(' '); + } + + if (new_line) + putchar('\n'); + return 0; +} + +int echo_main(int argc, char **argv) { + int new_line = 1; + + for (; *++argv && '-' == **argv;) + switch (*(*argv + 1)) { + case 'n': + new_line = 0; + break; + } + + return echo(argv, new_line); +} diff --git a/userland/minibox/utilities/ed.c b/userland/minibox/utilities/ed.c new file mode 100644 index 0000000..53270dc --- /dev/null +++ b/userland/minibox/utilities/ed.c @@ -0,0 +1,145 @@ +// ed - edit text +// ed [-p string] [-s] [file] +#include +#include +#include +#define COMMAND_MODE 0 +#define INPUT_MODE 1 + +int mode = COMMAND_MODE; + +FILE *fp = NULL; +FILE *mem_fp = NULL; +int line_number = 1; + +int getline(char *buffer, size_t s) { + (void)s; + int i = 0; + char c; + for (;; i++) { + int rc = read(0, &c, 1); + assert(rc > 0); + printf("%c", c); + buffer[i] = c; + if ('\n' == c) + break; + } + buffer[i] = '\0'; + return i; +} + +void goto_line(void) { + char c; + fseek(mem_fp, 0, SEEK_SET); + int line = 1; + if (1 != line_number) { + // Goto line + for (; fread(&c, 1, 1, mem_fp);) { + if ('\n' == c) + line++; + if (line == line_number) + return; + } + printf("got to line: %d\n", line); + assert(0); + } +} + +void read_line(void) { + char c; + goto_line(); + for (; fread(&c, 1, 1, mem_fp);) { + if ('\n' == c) + break; + printf("%c", c); + } + printf("\n"); +} + +void goto_end_of_line(void) { + char c; + for (; fread(&c, 1, 1, mem_fp);) { + if ('\n' == c) + break; + } +} + +void delete_line(void) { + long s = ftell(mem_fp); + printf("s: %d\n", s); + goto_end_of_line(); + long end = ftell(mem_fp); + printf("end: %d\n", end); + long offset = end - s; + for (char buffer[4096];;) { + int rc = fread(buffer, 1, 100, mem_fp); + long reset = ftell(mem_fp); + if (0 == rc) + break; + fseek(mem_fp, s, SEEK_SET); + fwrite(buffer, 1, rc, mem_fp); + s += rc; + fseek(mem_fp, reset, SEEK_SET); + } +} + +void read_command(void) { + char buffer[4096]; + char *s = buffer; + getline(buffer, 4096); + int a = -1; + int rc = sscanf(buffer, "%d", &a); + if (0 < rc) { + line_number = a; + } + for (; isdigit(*s); s++) + ; + if (0 == strcmp(s, "i")) { + mode = INPUT_MODE; + return; + } + if (0 == strcmp(s, ".")) { + read_line(); + return; + } + return; +} + +void read_input(void) { + char buffer[4096]; + int l = getline(buffer, 4096); + if (0 == strcmp(buffer, ".")) { + mode = COMMAND_MODE; + return; + } + goto_line(); + delete_line(); + goto_line(); + assert(fwrite(buffer, l, 1, mem_fp)); + return; +} + +int ed_main(char argc, char **argv) { + if (argc < 2) + return 1; + char *buffer; + size_t size; + mem_fp = open_memstream(&buffer, &size); + assert(mem_fp); + fp = fopen(argv[1], "r"); + assert(fp); + char r_buffer[4096]; + for (int rc; (rc = fread(buffer, 1, 4096, fp));) { + fwrite(r_buffer, 1, rc, mem_fp); + } + + for (;;) { + if (COMMAND_MODE == mode) + read_command(); + else + read_input(); + } + fclose(fp); + fclose(mem_fp); + return 0; +} diff --git a/userland/minibox/utilities/include.h b/userland/minibox/utilities/include.h new file mode 100644 index 0000000..7ffd136 --- /dev/null +++ b/userland/minibox/utilities/include.h @@ -0,0 +1,41 @@ +#include +/* General constants */ +#define fd_stdin 0 /* standard in file descriptor */ +#define fd_stdout 1 /* standard out file descriptor */ +#define ASSERT_NOT_REACHED assert(0); +/* END General constants */ + +/* CAT SETTINGS */ +#define CAT_BUFFER 4096 /* size of the read buffer */ +/* END CAT SETTINGS */ + +/* HTTP SETTINGS */ +#define HTTP_MAX_BUFFER 4096 /* size of the read buffer */ +#define HTTP_DEFAULT_PORT 1337 /* default port should -p not be supplied */ +#define HTTP_WEBSITE_ROOT "site/" /* default directory that it chroots into */ + +/* should xxx.html not exist these will be supplied instead */ +#define HTTP_DEFAULT_404_SITE "404 - Not Found" +#define HTTP_DEFAULT_400_SITE "400 - Bad Request" +/* END HTTP SETTINGS */ + +#define COND_PERROR_EXP(condition, function_name, expression) \ + if (condition) { \ + perror(function_name); \ + expression; \ + } + +int minibox_main(int argc, char **argv); +int ascii_main(int argc, char **argv); +int echo_main(int argc, char **argv); +int http_main(int argc, char **argv); +int lock_main(int argc, char **argv); +int yes_main(int argc, char **argv); +int cat_main(int argc, char **argv); +int pwd_main(int argc, char **argv); +int wc_main(int argc, char **argv); +int ls_main(int argc, char **argv); +int touch_main(int argc, char **argv); +int ed_main(int argc, char **argv); + +int init_main(void); diff --git a/userland/minibox/utilities/init.c b/userland/minibox/utilities/init.c new file mode 100644 index 0000000..35bedf2 --- /dev/null +++ b/userland/minibox/utilities/init.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int cmdfd; + +void execsh(void) { + char *argv[] = {NULL}; + execv("/sh", argv); +} + +void newtty(void) { + int m; + int s; + openpty(&m, &s, NULL, NULL, NULL); + int pid = fork(); + if (0 == pid) { + dup2(s, 0); + dup2(s, 1); + dup2(s, 2); + execsh(); + return; + } + close(s); + cmdfd = m; +} + +void shell() { + struct pollfd fds[2]; + fds[0].fd = cmdfd; + fds[0].events = POLLIN; + fds[0].revents = 0; + fds[1].fd = open("/dev/keyboard", O_RDONLY, 0); + fds[1].events = POLLIN; + fds[1].revents = 0; + for (;; fds[0].revents = fds[1].revents = 0) { + poll(fds, 2, 0); + if (fds[0].revents & POLLIN) { + char c[4096]; + int rc = read(fds[0].fd, c, 4096); + assert(rc > 0); + for (int i = 0; i < rc; i++) + putchar(c[i]); + } + if (fds[1].revents & POLLIN) { + char c; + int rc = read(fds[1].fd, &c, 1); + assert(rc > 0); + write(cmdfd, &c, 1); + // putchar(c); + } + } +} + +int init_main(void) { + if (1 != getpid()) { + printf("minibox init must be launched as pid1.\n"); + return 1; + } + if (fork()) + for (;;) + wait(NULL); + char *a[] = {NULL}; + execv("/term", a); + return 1; +} diff --git a/userland/minibox/utilities/ls.c b/userland/minibox/utilities/ls.c new file mode 100644 index 0000000..dc93d36 --- /dev/null +++ b/userland/minibox/utilities/ls.c @@ -0,0 +1,42 @@ +#include "include.h" +#include +#include +#include +#include +#include +#include + +int ls_main(int argc, char **argv) { + int list_hidden = 0; + int newline = 0; + /* + for (int ch;-1 != (ch = getopt(argc, argv, "a1"));) + switch ((char)ch) + { + case 'a': + list_hidden = 1; + break; + case '1': + newline = 1; + break; + }*/ + struct dirent **namelist; + int n; + COND_PERROR_EXP(-1 == (n = scandir("/", &namelist, 0, 0)), "scandir", + return 1); + + int prev = 0; + for (int i = 0; i < n; i++) { + if (!list_hidden) + if ('.' == *namelist[i]->d_name) + continue; + + if (prev) + putchar(newline ? '\n' : ' '); + else + prev = 1; + printf("%s", namelist[i]->d_name); + } + putchar('\n'); + return 0; +} diff --git a/userland/minibox/utilities/minibox.c b/userland/minibox/utilities/minibox.c new file mode 100644 index 0000000..ec5fdbd --- /dev/null +++ b/userland/minibox/utilities/minibox.c @@ -0,0 +1,15 @@ +#include "include.h" + +void usage(void); +int main(int argc, char **argv); + +// Should a command be called via "minibox " then shift +// argv and argc to become " " and rerun main() +int minibox_main(int argc, char **argv) { + if (argc < 2) + usage(); + + argc--; + argv++; + return main(argc, argv); +} diff --git a/userland/minibox/utilities/pwd.c b/userland/minibox/utilities/pwd.c new file mode 100644 index 0000000..29d8129 --- /dev/null +++ b/userland/minibox/utilities/pwd.c @@ -0,0 +1,12 @@ +#include "include.h" +#include +#include +#include +#include + +int pwd_main(int argc, char **argv) { + char cwd[PATH_MAX]; + COND_PERROR_EXP(NULL == (getcwd(cwd, PATH_MAX)), "getcwd", return 1); + puts(cwd); + return 0; +} diff --git a/userland/minibox/utilities/touch.c b/userland/minibox/utilities/touch.c new file mode 100644 index 0000000..949ad96 --- /dev/null +++ b/userland/minibox/utilities/touch.c @@ -0,0 +1,11 @@ +#include "include.h" +#include + +int touch_main(int argc, char **argv) { + if (argc < 2) + return 1; + int fd; + COND_PERROR_EXP(open(argv[1], 0, O_CREAT), "open", return 1) + close(fd); + return 0; +} diff --git a/userland/minibox/utilities/wc.c b/userland/minibox/utilities/wc.c new file mode 100644 index 0000000..886eb9e --- /dev/null +++ b/userland/minibox/utilities/wc.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include "include.h" + +int cmode, wmode, lmode; + +void output(const char * str, size_t lines, size_t words, size_t chars) +{ + if(lmode) + printf("%d", lines); + + if(wmode) + { + if(lmode) putchar(' '); + + printf("%d", words); + } + + if(cmode) + { + if(lmode) putchar(' '); + + printf("%d", chars); + } + + if(str) printf(" %s", str); + + putchar('\n'); +} + +void wc(int argc, char ** argv) +{ + int fd = fd_stdin; + size_t total_chars, total_words, total_lines; + total_chars = total_words = total_lines = 0; + + if(NULL == *argv) + goto read_stdin; + + + for(;*argv;argv++) + { + int new_word = 1; + size_t chars = 0, + words = chars, + lines = chars; + + fd = open(*argv, O_RDONLY, 0); +read_stdin: + for(char c;read(fd, &c, 1);) + { + if(cmode) + chars++; + + if(wmode) + { + if(isspace(c)) { + new_word = 1; + } else if(new_word) { + words++; + new_word = 0; + } + } + + if(lmode) + if('\n' == c) + lines++; + } + close(fd); + if(lmode) total_lines += lines; + if(wmode) total_words += words; + if(cmode) total_chars += chars; + + output(*argv, lines, words, chars); + if(NULL == *argv) return; // We read from stdin + } + + if(argc > 1) output("total", total_lines, total_words, total_chars); +} + +int wc_main(int argc, char ** argv) +{ + cmode = wmode = lmode = 0; + for(argc--;*++argv && '-' == **argv;argc--) + switch(*(*argv+1)) + { + case 'l': + lmode = 1; + break; + case 'w': + wmode = 1; + break; + case 'c': + cmode = 1; + break; + } + + if(!(lmode || cmode || wmode)) + cmode = wmode = lmode = 1; + + wc(argc, argv); + return 0; +} diff --git a/userland/minibox/utilities/yes.c b/userland/minibox/utilities/yes.c new file mode 100644 index 0000000..ff19004 --- /dev/null +++ b/userland/minibox/utilities/yes.c @@ -0,0 +1,13 @@ +#include "include.h" +#include + +int yes_main(int argc, char **argv) { + if (argc < 2) + for (;;) + puts("y"); + + for (;; putchar('\n')) + for (int i = 1; i < argc; i++) + printf("%s ", argv[i]); + return 0; +} diff --git a/userland/sh/Makefile b/userland/sh/Makefile new file mode 100644 index 0000000..adccfb3 --- /dev/null +++ b/userland/sh/Makefile @@ -0,0 +1,13 @@ +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough -fsanitize=shift,signed-integer-overflow,bounds +BINS=sh +all: $(BINS) + +sh.o: sh.c + $(CC) $(CFLAGS) -L../libc/ -lc -c sh.c -I../libc/ +# $(CC) $(CFLAGS) ../libc/libc.o ../libc/crt0.o sh.c -I../libc/ + +clean: + rm sh sh.o +sh: sh.o + $(CC) -shared -o sh -ffreestanding -nostdlib $(CFLAGS) sh.o -L../libc/ -lc -lgcc #-L../libc/c.a diff --git a/userland/sh/sh b/userland/sh/sh new file mode 100755 index 0000000..7791495 Binary files /dev/null and b/userland/sh/sh differ diff --git a/userland/sh/sh.c b/userland/sh/sh.c new file mode 100644 index 0000000..5fe7f63 --- /dev/null +++ b/userland/sh/sh.c @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MAX_ARGS 20 + +#define IS_SPECIAL(_c) (';' == _c || '\n' == _c || '&' == _c || '|' == _c) + +char *PATH = "/:/bin"; + +int can_open(char *f) { + int rc; + if (-1 == (rc = open(f, O_RDONLY, 0))) + return 0; + close(rc); + return 1; +} + +int find_path(char *file, char *buf) { + if ('/' == *file || '.' == *file) { // Real path + if (!can_open(file)) { + return 0; + } + strcpy(buf, file); + return 1; + } + + char *p = PATH; + for (;;) { + char *b = p; + for (; *p && ':' != *p; p++) + ; + size_t l = p - b; + strlcpy(buf, b, l); + strcat(buf, "/"); + strcat(buf, file); + if (can_open(buf)) { + return 1; + } + if (!*p) + break; + p++; + } + return 0; +} + +int internal_exec(char *file, char **argv) { + char r_path[PATH_MAX]; + if (!find_path(file, r_path)) + return 0; + if (-1 == execv(r_path, argv)) { + perror("exec"); + return 0; + } + return 1; +} + +int execute_program(char *s, size_t l, int ignore_rc, int f_stdout, + int *new_out) { + if (!l) + return -1; + + char c[l + 1]; + memcpy(c, s, l); + c[l] = 0; + + char *argv[MAX_ARGS]; + int args = 0; + char *p = c; + for (size_t i = 0; i <= l; i++) { + if (' ' == c[i]) { + if (p == c + i) { + for (; ' ' == *p; p++, i++) + ; + i--; + continue; + } + c[i] = '\0'; + + if (strlen(p) == 0) + break; + + argv[args] = p; + args++; + p = c + i + 1; + } else if (i == l) { + if (strlen(p) == 0) + break; + argv[args] = p; + args++; + } + } + argv[args] = NULL; + + int fd[2]; + pipe(fd); + + int pid = fork(); + if (0 == pid) { + if (new_out) + dup2(fd[1], 1); + if (-1 != f_stdout) + dup2(f_stdout, 0); + close(fd[0]); + if (!internal_exec(argv[0], argv)) { + printf("exec failed\n"); + exit(1); + } + } + + close(fd[1]); + if (new_out) + *new_out = fd[0]; + + if (ignore_rc) + return 0; + + int rc; + wait(&rc); + return rc; +} + +int compute_expression(char *exp) { + char *n = exp; + int ignore_next = 0; + int rc; + int f_stdout = -1; + int new_out = f_stdout; + for (; *exp; exp++) { + if (!IS_SPECIAL(*exp)) { + continue; + } + if ('\n' == *exp) + break; + if (';' == *exp) { + if (!ignore_next) { + execute_program(n, exp - n, 0, f_stdout, NULL); + } + n = exp + 1; + continue; + } + if ('&' == *exp && '&' == *(exp + 1)) { + if (!ignore_next) { + rc = execute_program(n, exp - n, 0, f_stdout, NULL); + if (0 != rc) + ignore_next = 1; + } + n = exp + 2; + exp++; + continue; + } else if ('&' == *exp) { + if (!ignore_next) { + execute_program(n, exp - n, 1, f_stdout, NULL); + } + n = exp + 1; + continue; + } + if ('|' == *exp && '|' == *(exp + 1)) { + if (!ignore_next) { + rc = execute_program(n, exp - n, 0, f_stdout, NULL); + if (0 == rc) + ignore_next = 1; + } + n = exp + 2; + exp++; + continue; + } else if ('|' == *exp) { + if (!ignore_next) { + execute_program(n, exp - n, 1, f_stdout, &new_out); + f_stdout = new_out; + } + n = exp + 1; + continue; + } + } + if (!ignore_next) + rc = execute_program(n, exp - n, 0, f_stdout, NULL); + return rc; +} + +char *get_line(void) { + char *str = malloc(1024); + char *p = str; + int rc; + for (;;) { + if (0 == (rc = read(0, p, 1))) { + continue; + } + if (0 > rc) { + perror("read"); + continue; + } + if (8 == *p) { + if (p == str) + continue; + putchar(*p); + p--; + continue; + } + putchar(*p); + if ('\n' == *p) { + break; + } + p++; + } + p++; + *p = '\0'; + return str; +} + +int main(void) { + for (;;) { + printf("/ : "); + char *l = get_line(); + compute_expression(l); + free(l); + } + return 0; +} diff --git a/userland/sh/sh_a b/userland/sh/sh_a new file mode 100755 index 0000000..7b435ab Binary files /dev/null and b/userland/sh/sh_a differ diff --git a/userland/sh/sh_bad b/userland/sh/sh_bad new file mode 100755 index 0000000..7f93418 Binary files /dev/null and b/userland/sh/sh_bad differ diff --git a/userland/snake/Makefile b/userland/snake/Makefile new file mode 100644 index 0000000..f29df30 --- /dev/null +++ b/userland/snake/Makefile @@ -0,0 +1,15 @@ +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough -static -fsanitize=shift,signed-integer-overflow,bounds +LIB=-L../libgui -lgui -L../json -ljson -L../libc -lc -lgcc +INC=-I../libc/ -I../json/ -I../libgui/ +BINS=snake +all: $(BINS) + +snake.o: snake.c + $(CC) $(CFLAGS) $(INC) $(LIB) -o $@ -c $< + +snake: snake.o + $(CC) -nostdlib $(CFLAGS) -o $@ $^ $(LIB) + +clean: + rm $(BINS) *.o diff --git a/userland/snake/snake.c b/userland/snake/snake.c new file mode 100644 index 0000000..7bfb312 --- /dev/null +++ b/userland/snake/snake.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GUI_Window *global_w; + +#define SNAKE_WIDTH 10 + +int get_key_event(char *c) { + if (0 >= read(global_w->ws_socket, c, 1)) + return 0; + if (0 == *c) + return 0; + return 1; +} + +void draw_snake(int x, int y) { + int sx = global_w->sx; + uint32_t *b = &global_w->bitmap_ptr[y * sx + x]; + for (int i = 0; i < SNAKE_WIDTH; i++) { + for (int j = 0; j < SNAKE_WIDTH; j++) { + b[j] = 0xFF00FF; + } + b += sx; + } +} + +int clamp(int *x, int *y) { + int clamped = 0; + if (*x + SNAKE_WIDTH > global_w->sx) { + *x = global_w->sx - SNAKE_WIDTH; + clamped = 1; + } + if (*y + SNAKE_WIDTH > global_w->sy) { + *y = global_w->sy - SNAKE_WIDTH; + clamped = 1; + } + return clamped; +} + +void loop() { + int vel = SNAKE_WIDTH; + static int y_dir = SNAKE_WIDTH; + static int x_dir = 0; + static int snake_x = 10; + static int snake_y = 10; + static int ticks = 0; + ticks++; + char c; + if (get_key_event(&c)) { + switch (c) { + case 'w': + y_dir = -1 * vel; + x_dir = 0; + break; + case 's': + y_dir = vel; + x_dir = 0; + break; + case 'a': + x_dir = -1 * vel; + y_dir = 0; + break; + case 'd': + x_dir = vel; + y_dir = 0; + break; + case 'q': + exit(0); + break; + default: + break; + } + } + + if (!(ticks > 5)) + return; + ticks = 0; + + snake_x += x_dir; + snake_y += y_dir; + if (clamp(&snake_x, &snake_y)) + return; + draw_snake(snake_x, snake_y); + if (y_dir || x_dir) + GUI_UpdateWindow(global_w); +} + +int main(void) { + global_w = GUI_CreateWindow(10, 10, 150 * 4, 150 * 4); + assert(global_w); + for (int i = 0; i < 150 * 150 * 4 * 4; i++) + global_w->bitmap_ptr[i] = 0xFFFFFF; + GUI_UpdateWindow(global_w); + for (;;) { + loop(); + msleep(50); + } + return 0; +} diff --git a/userland/terminal/Makefile b/userland/terminal/Makefile new file mode 100644 index 0000000..330f6e0 --- /dev/null +++ b/userland/terminal/Makefile @@ -0,0 +1,15 @@ +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +CFLAGS = -ggdb -ffreestanding -O0 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough -static -fsanitize=shift,signed-integer-overflow,bounds +LIB=-L../libgui -lgui -L../json -ljson -L../libc -lc -lgcc +INC=-I../libc/ -I../json/ -I../libgui/ +BINS=term +all: $(BINS) + +term.o: term.c + $(CC) $(CFLAGS) $(INC) $(LIB) -o $@ -c $< + +term: term.o + $(CC) -nostdlib $(CFLAGS) -o $@ $^ $(LIB) + +clean: + rm $(BINS) *.o diff --git a/userland/terminal/term.c b/userland/terminal/term.c new file mode 100644 index 0000000..8a2ae83 --- /dev/null +++ b/userland/terminal/term.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TERM_BACKGROUND 0x000000 + +int cmdfd; +GUI_Window *global_w; +uint32_t screen_pos_x = 0; +uint32_t screen_pos_y = 0; +int serial_fd; + +void execsh(void) { + char *argv[] = {NULL}; + execv("/sh", argv); +} + +uint32_t cursor_pos_x = 0; +uint32_t cursor_pos_y = 0; + +void screen_remove_old_cursor() { + GUI_OverwriteFont(global_w, cursor_pos_x, cursor_pos_y, TERM_BACKGROUND); +} + +void screen_update_cursor() { + GUI_OverwriteFont(global_w, screen_pos_x, screen_pos_y, 0xFFFFFF); + cursor_pos_x = screen_pos_x; + cursor_pos_y = screen_pos_y; +} + +void screen_putchar(uint32_t c) { + if (c == '\n') { + screen_pos_x = 0; + screen_pos_y += 8; + screen_remove_old_cursor(); + screen_update_cursor(); + return; + } + if (screen_pos_y > global_w->sy - 8) { + uint8_t line[global_w->sx * sizeof(uint32_t)]; + for (int i = 0; i < global_w->sy - 8; i++) { + memcpy(line, global_w->bitmap_ptr + ((i + 8) * global_w->sx), + global_w->sx * sizeof(uint32_t)); + memcpy(global_w->bitmap_ptr + (i * global_w->sx), line, + global_w->sx * sizeof(uint32_t)); + } + for (int i = 0; i < global_w->sx; i += 8) { + GUI_OverwriteFont(global_w, i, screen_pos_y - 8, TERM_BACKGROUND); + } + screen_pos_x = 0; + screen_pos_y -= 8; + } + GUI_DrawFont(global_w, screen_pos_x, screen_pos_y, c); + screen_pos_x += 8; + if (screen_pos_x >= global_w->sx - 8) { + screen_pos_x = 0; + screen_pos_y += 8; + } + screen_update_cursor(); +} + +void screen_delete_char(void) { + GUI_OverwriteFont(global_w, screen_pos_x, screen_pos_y, TERM_BACKGROUND); + screen_pos_x -= 8; + GUI_OverwriteFont(global_w, screen_pos_x, screen_pos_y, TERM_BACKGROUND); + screen_update_cursor(); +} + +void screen_print(const unsigned char *s, int l) { + for (; l; l--, s++) { + if ('\b' == *s) { + screen_delete_char(); + continue; + } + screen_putchar((uint32_t)*s); + } +} + +void newtty(void) { + int m; + int s; + openpty(&m, &s, NULL, NULL, NULL); + int pid = fork(); + if (0 == pid) { + dup2(s, 0); + dup2(s, 1); + dup2(s, 2); + execsh(); + return; + } + close(s); + cmdfd = m; +} + +void writetty(const char *b, size_t len) { + write(serial_fd, b, len); + for (int rc; len; len -= rc) { + rc = write(cmdfd, b, len); + if (-1 == rc) { + perror("write"); + assert(0); + } + } +} + +void run() { + char buffer[4096]; + struct pollfd fds[2]; + fds[0].fd = cmdfd; + fds[0].events = POLLIN; + fds[0].revents = 0; + fds[1].fd = global_w->ws_socket; + fds[1].events = POLLIN; + fds[1].revents = 0; + for (;; fds[0].revents = fds[1].revents = 0) { + poll(fds, 2, 0); + if (fds[0].revents & POLLIN) { + int rc; + if ((rc = read(cmdfd, buffer, 4096))) { + screen_print(buffer, rc); + GUI_UpdateWindow(global_w); + } + } + if (fds[1].revents & POLLIN) { + WS_EVENT e; + int rc; + if (0 >= (rc = read(global_w->ws_socket, &e, sizeof(e)))) + continue; + if (1 == e.ev.release) + continue; + if (0 == e.ev.c) + continue; + write(cmdfd, &e.ev.c, 1); + } + } +} + +int main(void) { + open("/dev/serial", O_RDWR, 0); + open("/dev/serial", O_RDWR, 0); + printf("running the terminal\n"); + int pid = fork(); + if (0 == pid) { + char *argv[] = {NULL}; + execv("/ws", argv); + } + + global_w = GUI_CreateWindow(20, 20, 250 * 4, 150 * 4); + assert(global_w); + for (int i = 0; i < 250 * 150 * 4 * 4; i++) + global_w->bitmap_ptr[i] = TERM_BACKGROUND; + // memset(global_w->bitmap_ptr, 0x0, 50 * 50); + GUI_UpdateWindow(global_w); + newtty(); + run(); + return 0; +} diff --git a/userland/test/Makefile b/userland/test/Makefile new file mode 100644 index 0000000..7287939 --- /dev/null +++ b/userland/test/Makefile @@ -0,0 +1,16 @@ +#CC="/home/anton/opt/cross/bin/i686-elf-gcc" +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +CFLAGS = -O2 -Wall -Wextra -pedantic -Wimplicit-fallthrough -static +LIB=-L../json -L../json/hashmap -ljson -lhashmap +INC=-I../json/ +BINS=test +all: $(BINS) + +test.o: test.c + $(CC) $(CFLAGS) $(INC) $(LIB) -o $@ -c $< + +test: test.o + $(CC) $(CFLAGS) -o $@ $^ $(LIB) + +clean: + rm test.o test diff --git a/userland/test/linux.sh b/userland/test/linux.sh new file mode 100755 index 0000000..d40d6cc --- /dev/null +++ b/userland/test/linux.sh @@ -0,0 +1,4 @@ +#!/bin/bash +gcc -DLINUX test.c -o ./local/a.out +cd local +./a.out diff --git a/userland/test/local/a.out b/userland/test/local/a.out new file mode 100755 index 0000000..1069f1f Binary files /dev/null and b/userland/test/local/a.out differ diff --git a/userland/test/local/testfile b/userland/test/local/testfile new file mode 100644 index 0000000..629ae5e --- /dev/null +++ b/userland/test/local/testfile @@ -0,0 +1 @@ +ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz diff --git a/userland/test/test b/userland/test/test new file mode 100755 index 0000000..63f9d8b Binary files /dev/null and b/userland/test/test differ diff --git a/userland/test/test.c b/userland/test/test.c new file mode 100644 index 0000000..041b08a --- /dev/null +++ b/userland/test/test.c @@ -0,0 +1,722 @@ +#include +#include +//#include +#include +#include +#include +#include +#include +#include + +#if 1 +void dbgln(const char *fmt) { printf("%s\n", fmt); } +#else +void dbgln(const char *fmt, ...) { + printf("| "); + va_list ap; + va_start(ap, fmt); + int rc = vdprintf(1, fmt, ap); + va_end(ap); + printf("\n"); +} +#endif + +void isx_test() { + dbgln("isx TEST"); + { + assert(isspace(' ')); + assert(isspace('\t')); + assert(!isspace('A')); + + assert(isalpha('A')); + assert(!isalpha('9')); + assert(!isalpha(' ')); + assert(!isalpha('z' + 1)); + + assert(isascii('A')); + assert(isascii('9')); + assert(isascii(' ')); + assert(!isascii(0xFF)); + + assert(ispunct('.')); + assert(!ispunct('A')); + + assert(isdigit('9')); + assert(!isdigit('A')); + } + dbgln("isx TEST PASSED"); +} + +void malloc_test(void) { + dbgln("malloc TEST"); + for (int j = 0; j < 100; j++) { + // printf("j : %x\n", j); + uint8_t *t = malloc(400 + j); + memset(t, 0x43 + (j % 10), 400 + j); + uint8_t *p = malloc(900 + j); + memset(p, 0x13 + (j % 10), 900 + j); + assert(p > t && p > (t + 400 + j)); + + for (int i = 0; i < 400 + j; i++) + if (t[i] != 0x43 + (j % 10)) { + printf("t addy: %x, val: %x, should be: %x\n", t + i, t[i], + 0x43 + (j % 10)); + assert(0); + } + + for (int i = 0; i < 900 + j; i++) + if (p[i] != 0x13 + (j % 10)) { + printf("p addy: %x, val: %x, should be: %x\n", p + i, t[i], + 0x13 + (j % 10)); + assert(0); + } + free(t); + } + dbgln("malloc TEST PASSED"); +} + +void memcmp_test(void) { + dbgln("memcmp TEST"); + { + assert(0 == memcmp("\xAA\xBB\xCC", "\xAA\xBB\xCC", 3)); + assert(1 == memcmp("\xAF\xBB\xCC", "\xAA\xBB\xCC", 3)); + } + dbgln("memcmp TEST PASSED"); +} + +void memcpy_test(void) { + dbgln("memcpy TEST"); + { + char buf[100]; + assert(buf == memcpy(buf, "\xAA\xBB\xCC", 3)); + assert(0 == memcmp(buf, "\xAA\xBB\xCC", 3)); + assert(buf == memcpy(buf, "\xCC\xBB\xCC", 3)); + assert(0 == memcmp(buf, "\xCC\xBB\xCC", 3)); + + assert(buf == memcpy(buf, "\xAA\xBB\xCC\xDD", 4)); + assert(0 == memcmp(buf, "\xAA\xBB\xCC\xDD", 4)); + assert(buf == memcpy(buf, "\xAA\xBB\xCC\xEE", 3)); + assert(0 == memcmp(buf, "\xAA\xBB\xCC\xDD", 4)); + } + dbgln("memcpy TEST PASSED"); +} + +void memmove_test(void) { + dbgln("memmove TEST"); + { + char buf[100]; + memcpy(buf, "foobar", 6); + const char *p = buf + 2; // obar + + assert(buf == memmove(buf, p, 4)); + assert(0 == memcmp(buf, "obarar", 6)); + } + dbgln("memmove TEST PASSED"); +} + +void strlen_test(void) { + dbgln("strlen TEST"); + { + assert(0 == strlen("")); + assert(3 == strlen("%is")); + assert(3 == strlen("foo")); + assert(3 == strlen("bar")); + assert(6 == strlen("foobar")); + } + dbgln("strlen TEST PASSED"); +} + +void strnlen_test(void) { + dbgln("strnlen TEST"); + { + assert(0 == strnlen("", 0)); + assert(0 == strnlen("", 3)); + assert(3 == strnlen("foo", 3)); + assert(2 == strnlen("bar", 2)); + assert(3 == strnlen("foobar", 3)); + assert(6 == strnlen("foobar", 6)); + assert(6 == strnlen("foobar", 8)); + } + dbgln("strnlen TEST PASSED"); +} + +/* +void json_test(void) { + dbgln("JSON TEST"); + { + const char *s = "{\"string\": \"hello\", \"object\": {\"string\": \"ff\"}}"; + JSON_CTX ctx; + JSON_Init(&ctx); + JSON_Parse(&ctx, s); + JSON_ENTRY *main_entry = JSON_at(&ctx.global_object, 0); + assert(main_entry != NULL); + JSON_ENTRY *index_entry = JSON_at(main_entry, 0); + JSON_ENTRY *string_entry = JSON_search_name(main_entry, "string"); + assert(index_entry != NULL); + assert(index_entry == string_entry); + char *str = index_entry->value; + assert(0 == strcmp(str, "hello")); + + JSON_ENTRY *object = JSON_search_name(main_entry, "object"); + assert(object != NULL); + JSON_ENTRY *object_string = JSON_search_name(object, "string"); + assert(object_string != NULL); + assert(0 == strcmp(object_string->value, "ff")); + } + dbgln("JSON TEST PASSED"); +}*/ + +void random_test(void) { + dbgln("/dev/random TEST"); + { + int fd = open("/dev/random", O_RDONLY, 0); + uint8_t buffer_1[256]; + assert(256 == read(fd, buffer_1, 256)); + close(fd); + fd = open("/dev/random", O_RDONLY, 0); + uint8_t buffer_2[256]; + assert(256 == read(fd, buffer_2, 256)); + close(fd); + assert(0 != memcmp(buffer_1, buffer_2, 256)); + } + dbgln("/dev/random TEST PASSED"); +} + +void sscanf_test(void) { + dbgln("sscanf TEST"); + { + int d1; + int d2; + sscanf("1337:7331", "%d:%d", &d1, &d2); + assert(1337 == d1); + assert(7331 == d2); + sscanf(" 1234 31415", "%d%d", &d1, &d2); + assert(1234 == d1); + assert(31415 == d2); + sscanf(" 1234 441122", "%*d%d", &d1); + assert(441122 == d1); + + char f; + char b; + sscanf("f:b", "%c:%c", &f, &b); + assert('f' == f); + assert('b' == b); + } + dbgln("sscanf TEST PASSED"); +} + +void strtoul_test(void) { + dbgln("strtoul TEST"); + { + long r; + char *s = "1234"; + char *endptr; + r = strtoul("1234", &endptr, 10); + assert(1234 == r); + assert(endptr == (s + 4)); + } + dbgln("strtoul TEST PASSED"); +} + +void strcspn_test(void) { + dbgln("strcspn TEST"); + { + assert(4 == strcspn("1234", "")); + assert(3 == strcspn("1234", "4")); + assert(2 == strcspn("1234", "43")); + assert(0 == strcspn("1234", "2143")); + } + dbgln("strcspn TEST PASSED"); +} + +void strpbrk_test(void) { + dbgln("strpbrk TEST"); + { + char *s = "01234"; + assert(s + 3 == strpbrk(s, "3")); + assert(s + 4 == strpbrk(s, "4")); + assert(s + 2 == strpbrk(s, "2")); + assert(s + 2 == strpbrk(s, "23")); + assert(NULL == strpbrk(s, "5")); + } + dbgln("strpbrk TEST PASSED"); +} + +void strcpy_test(void) { + dbgln("strcpy TEST"); + { + char buf[10]; + memset(buf, '\xBB', 10); + strcpy(buf, "hello"); + assert(0 == memcmp(buf, "hello\0\xBB\xBB\xBB\xBB", 10)); + } + dbgln("strcpy TEST PASSED"); +} + +void strncpy_test(void) { + dbgln("strncpy TEST"); + { + char buf[10]; + memset(buf, '\xBB', 10); + strncpy(buf, "hello", 3); + assert(0 == memcmp(buf, "hel\xBB\xBB\xBB\xBB\xBB\xBB\xBB", 10)); + strncpy(buf, "hello", 6); + assert(0 == memcmp(buf, "hello\0\xBB\xBB\xBB\xBB", 10)); + } + dbgln("strncpy TEST PASSED"); +} + +void strlcpy_test(void) { + dbgln("strlcpy TEST"); + { + char buf[10]; + memset(buf, '\xBB', 10); + strlcpy(buf, "hello", 3); + assert(0 == memcmp(buf, "hel\x00\xBB\xBB\xBB\xBB\xBB\xBB", 10)); + } + dbgln("strlcpy TEST PASSED"); +} + +void strcat_test(void) { + dbgln("strcat TEST"); + { + char buf[10]; + memset(buf, '\xBB', 10); + strcpy(buf, "hel"); + assert(0 == memcmp(buf, "hel\0\xBB\xBB\xBB\xBB\xBB\xBB", 10)); + strcat(buf, "lo"); + assert(0 == memcmp(buf, "hello\0\xBB\xBB\xBB\xBB", 10)); + } + dbgln("strcat TEST PASSED"); +} + +void strchr_test(void) { + dbgln("strchr TEST"); + { + char *s = "0123412345"; + assert(s + 3 == strchr(s, '3')); + assert(s + 4 + 5 == strchr(s, '5')); + assert(s + 4 == strchr(s, '4')); + assert(NULL == strchr(s, '9')); + } + dbgln("strchr TEST PASSED"); +} + +void strrchr_test(void) { + dbgln("strrchr TEST"); + { + char *s = "0123412345"; + assert(s + 3 + 4 == strrchr(s, '3')); + assert(s == strrchr(s, '0')); + assert(s + 4 + 5 == strrchr(s, '5')); + assert(NULL == strrchr(s, '9')); + } + dbgln("strrchr TEST PASSED"); +} + +void strdup_test(void) { + dbgln("strdup TEST"); + { + char *s; + s = strdup("hello"); + assert(s); + assert(0 == strcmp(s, "hello")); + free(s); + + s = strdup("abc"); + assert(s); + assert(0 == strcmp(s, "abc")); + free(s); + } + dbgln("strdup TEST PASSED"); +} + +void strndup_test(void) { + dbgln("strdup TEST"); + { + char *s; + s = strndup("hello", 5); + assert(s); + assert(0 == strcmp(s, "hello")); + free(s); + + s = strndup("hello", 3); + assert(s); + assert(0 == strcmp(s, "hel")); + free(s); + } + dbgln("strndup TEST PASSED"); +} + +void abs_test(void) { + dbgln("abs TEST"); + { + assert(1 == abs(1)); + assert(1 == abs(-1)); + assert(0 == abs(0)); + } + dbgln("abs TEST PASSED"); +} + +void strspn_test(void) { + dbgln("strspn TEST"); + { + assert(0 == strspn("abc", "")); + assert(0 == strspn("abc", "xyz")); + assert(1 == strspn("abc", "a")); + assert(2 == strspn("abc", "ab")); + assert(3 == strspn("abcd", "abc")); + assert(3 == strspn("abcde", "abce")); + } + dbgln("strspn TEST PASSED"); +} + +void strtol_test(void) { + dbgln("strtol TEST"); + { + char *s = "1234"; + char *e; + long r; + assert(1234 == strtol(s, &e, 10)); + assert(e == (s + 4)); + } + dbgln("strtol TEST PASSED"); +} + +void strcmp_test(void) { +#define EQ(_s1) \ + { assert(0 == strcmp(_s1, _s1)); } + dbgln("strcmp TEST"); + { + EQ("hello, world"); + EQ(""); + EQ("int: 100, hex: 64, octal: 144 a"); + } + dbgln("strcmp TEST PASSED"); +} + +void strncmp_test(void) { + dbgln("strncmp TEST"); + { + assert(0 == strncmp("hello", "hello", 5)); + assert(0 < strncmp("foo", "bar", 3)); + assert(0 == strncmp("foobar", "foofoo", 3)); + } + dbgln("strncmp TEST PASSED"); +} + +void strcasecmp_test(void) { + dbgln("strcasecmp TEST"); + { + assert(0 == strcasecmp("foobar", "FOObar")); + assert(0 == strcasecmp("foobar", "foobar")); + assert(6 == strcasecmp("foobar", "bar")); + } + dbgln("strcasecmp TEST PASSED"); +} + +void strncasecmp_test(void) { + dbgln("strncasecmp TEST"); + { + assert(0 == strncasecmp("foobar", "FOObar", 6)); + assert(0 == strncasecmp("foobar", "foobar", 6)); + assert(0 == strncasecmp("foo", "foobar", 3)); + assert(-1 == strncasecmp("foo", "foobar", 4)); + } + dbgln("strncasecmp TEST PASSED"); +} + +void strstr_test(void) { + dbgln("strstr TEST"); + { + const char *a = "foobar123"; + const char *b = "bar"; + assert(a + 3 == strstr(a, b)); + } + dbgln("strstr TEST PASSED"); +} + +void strtok_test(void) { + dbgln("strtok TEST"); + { + char *s = "hello,world,goodbye"; + assert(0 == strcmp(strtok(s, ","), "hello")); + assert(0 == strcmp(strtok(NULL, ","), "world")); + assert(0 == strcmp(strtok(NULL, ","), "goodbye")); + assert(NULL == strtok(NULL, ",")); + char *s2 = "hello,,world,,goodbye,test"; + assert(0 == strcmp(strtok(s2, ",,"), "hello")); + assert(0 == strcmp(strtok(NULL, ",,"), "world")); + assert(0 == strcmp(strtok(NULL, ","), "goodbye")); + assert(0 == strcmp(strtok(NULL, ","), "test")); + assert(NULL == strtok(NULL, ",")); + } + dbgln("strtok TEST PASSED"); +} + +void fseek_test(void) { + dbgln("fseek TEST"); + { +#ifndef LINUX + FILE *fp = fopen("/testfile", "r"); +#else + FILE *fp = fopen("testfile", "r"); +#endif + assert(NULL != fp); + char c; + assert(0 == ftell(fp)); + assert(1 == fread(&c, 1, 1, fp)); + assert('A' == c); + + assert(1 == ftell(fp)); + assert(1 == fread(&c, 1, 1, fp)); + assert('B' == c); + + assert(2 == ftell(fp)); + fseek(fp, 0, SEEK_SET); + assert(0 == ftell(fp)); + assert(1 == fread(&c, 1, 1, fp)); + assert('A' == c); + fseek(fp, 2, SEEK_SET); + assert(2 == ftell(fp)); + + assert(1 == fread(&c, 1, 1, fp)); + assert('C' == c); + fseek(fp, 2, SEEK_CUR); + assert(5 == ftell(fp)); + assert(1 == fread(&c, 1, 1, fp)); + assert('F' == c); + + char buffer[100]; + assert(6 == ftell(fp)); + fseek(fp, 0, SEEK_SET); + assert(1 == fread(buffer, 10, 1, fp)); + assert(0 == memcmp(buffer, "ABCDEFGHIJK", 10)); + assert(10 == ftell(fp)); + fseek(fp, 1, SEEK_SET); + assert(10 == fread(buffer, 1, 10, fp)); + assert(0 == memcmp(buffer, "BCDEFGHIJKL", 10)); + + fseek(fp, 0, SEEK_END); + assert(0 == fread(&c, 1, 1, fp)); + fseek(fp, -2, SEEK_CUR); + assert(1 == fread(&c, 1, 1, fp)); + assert('z' == c); + fseek(fp, -3, SEEK_END); + assert(1 == fread(&c, 1, 1, fp)); + assert('y' == c); + + assert(0 == fclose(fp)); + } + dbgln("fseek TEST PASSED"); +} + +void printf_test(void) { +#define EXP(exp) \ + { \ + int exp_n = strlen(exp); \ + if (0 != strcmp(buf, exp) || buf_n != exp_n) { \ + printf("buf n : %d\n", buf_n); \ + printf("exp n : %d\n", snprintf(NULL, 0, "%s", exp)); \ + printf("Expected: %s", exp); \ + printf("\n"); \ + printf("Got: %s", buf); \ + printf("\n"); \ + assert(0); \ + } \ + } + dbgln("printf TEST"); + { + char buf[200]; + int buf_n; + buf_n = sprintf(buf, "hello"); + EXP("hello"); + buf_n = sprintf(buf, "hello %s\n", "world"); + EXP("hello world\n"); + buf_n = sprintf(buf, "int: %d", 100); + EXP("int: 100"); + buf_n = sprintf(buf, "int: %d, hex: %x, octal: %o a", 100, 100, 100); + EXP("int: 100, hex: 64, octal: 144 a"); + + buf_n = sprintf(buf, "int: %02d", 1); + EXP("int: 01"); + buf_n = sprintf(buf, "int: %2d", 1); + EXP("int: 1"); + buf_n = sprintf(buf, "int: %00d", 1); + EXP("int: 1"); + + buf_n = sprintf(buf, "hex: %02x", 1); + EXP("hex: 01"); + buf_n = sprintf(buf, "hex: %2x", 1); + EXP("hex: 1"); + buf_n = sprintf(buf, "hex: %00x", 1); + EXP("hex: 1"); + buf_n = sprintf(buf, "hex: %x", 0x622933f2); + EXP("hex: 622933f2"); + + buf_n = sprintf(buf, "oct: %02o", 1); + EXP("oct: 01"); + buf_n = sprintf(buf, "oct: %2o", 1); + EXP("oct: 1"); + buf_n = sprintf(buf, "oct: %00o", 1); + EXP("oct: 1"); + + buf_n = sprintf(buf, "int: %-2dend", 1); + EXP("int: 1 end"); + buf_n = sprintf(buf, "int: %-2dend", 12); + EXP("int: 12end"); + buf_n = sprintf(buf, "int: %-0dend", 1); + EXP("int: 1end"); + + buf_n = sprintf(buf, "int: %-2xend", 1); + EXP("int: 1 end"); + buf_n = sprintf(buf, "int: %-2xend", 12); + EXP("int: c end"); + buf_n = sprintf(buf, "int: %-0xend", 1); + EXP("int: 1end"); + + buf_n = sprintf(buf, "int: %-2oend", 1); + EXP("int: 1 end"); + buf_n = sprintf(buf, "int: %-2oend", 12); + EXP("int: 14end"); + buf_n = sprintf(buf, "int: %-0oend", 1); + EXP("int: 1end"); + + buf_n = sprintf(buf, "string: %.3s", "foobar"); + EXP("string: foo"); + buf_n = sprintf(buf, "string: %.4s", "foobar"); + EXP("string: foob"); + + buf_n = sprintf(buf, "string: %s\n", "ABCDEFGHIJKLMNOPQRSTUVXYZ"); + EXP("string: ABCDEFGHIJKLMNOPQRSTUVXYZ\n"); + + buf_n = sprintf(buf, "string: %6send", "hello"); + EXP("string: helloend"); + buf_n = sprintf(buf, "string: %-6send", "hello"); + EXP("string: hello end"); + const char *data = "hello"; + char *foo = "foo"; + buf_n = sprintf(buf, " %-20s Legacy alias for \"%s\"\n", data, foo); + EXP(" hello Legacy alias for \"foo\"\n"); + buf_n = sprintf(buf, " %-20s %s%s\n", data, foo, "bar"); + EXP(" hello foobar\n"); + // Make sure that parameters have not changed + assert(0 == strcmp(data, "hello")); + assert(0 == strcmp(foo, "foo")); + + /* snprintf test */ + char out_buffer[100]; + memset(out_buffer, 'A', 100); + assert(5 == snprintf(out_buffer, 5, "hello")); + memcmp("helloAAAAA", out_buffer, 10); + assert(10 == snprintf(out_buffer, 5, "hellofoooo")); + memcmp("helloAAAAA", out_buffer, 10); + assert(10 == snprintf(out_buffer, 10, "hellofoooo")); + memcmp("hellofoookAA", out_buffer, 12); + } + dbgln("printf TEST PASSED"); +} + +int cmpfunc(const void *a, const void *b) { return (*(char *)a - *(char *)b); } + +void qsort_test(void) { + dbgln("qsort TEST"); + { + char buf[] = {'B', 'D', 'C', 'A', '\0'}; + qsort(buf, 4, sizeof(char), cmpfunc); + assert(0 == memcmp(buf, "ABCD", 4)); + } + dbgln("qsort TEST PASSED"); +} + +void basename_test(void) { + dbgln("basename TEST"); + { + char path[100]; + const char *s; + strcpy(path, "/foo/bar"); + s = basename(path); + assert(0 == strcmp(s, "bar")); + + strcpy(path, "/foo/bar/"); + s = basename(path); + assert(0 == strcmp(s, "bar")); + + strcpy(path, "/"); + s = basename(path); + assert(0 == strcmp(s, "/")); + + strcpy(path, "//"); + s = basename(path); + assert(0 == strcmp(s, "/")); + + strcpy(path, ""); + s = basename(path); + assert(0 == strcmp(s, ".")); + + s = basename(NULL); + assert(0 == strcmp(s, ".")); + } + dbgln("basename TEST PASSED"); +} + +void dirname_test(void) { + dbgln("dirname TEST"); + { + char path[100]; + const char *s; + strcpy(path, "/foo/bar"); + s = dirname(path); + assert(0 == strcmp(s, "foo")); + + strcpy(path, "/foo/bar/"); + s = dirname(path); + assert(0 == strcmp(s, "foo")); + + strcpy(path, "/foo/bar/zoo"); + s = dirname(path); + assert(0 == strcmp(s, "bar")); + } + dbgln("dirname TEST PASSED"); +} + +int main(void) { + dbgln("START"); + malloc_test(); + // json_test(); + // random_test(); + isx_test(); + memcmp_test(); + memcpy_test(); + memmove_test(); + strlen_test(); + strnlen_test(); + sscanf_test(); + strtoul_test(); + strcspn_test(); + strpbrk_test(); + strcpy_test(); + strncpy_test(); + strlcpy_test(); + strcat_test(); + strchr_test(); + strrchr_test(); + strdup_test(); + strndup_test(); + strspn_test(); + strtol_test(); + strcmp_test(); + strncmp_test(); + strcasecmp_test(); + strncasecmp_test(); + strstr_test(); + strtok_test(); + abs_test(); + // fseek_test(); + printf_test(); + qsort_test(); + basename_test(); + dirname_test(); + // TODO: Add mkstemp + return 0; +} diff --git a/userland/windowserver/Makefile b/userland/windowserver/Makefile new file mode 100644 index 0000000..f67bd66 --- /dev/null +++ b/userland/windowserver/Makefile @@ -0,0 +1,16 @@ +CC="/home/anton/prj/osdev/sysroot/bin/i686-sb-gcc" +CFLAGS = -ggdb -ffreestanding -O2 -Wall -Wextra -pedantic -mgeneral-regs-only -Wimplicit-fallthrough -fsanitize=shift,signed-integer-overflow,bounds +BIN=ws +LIB=-L../json -ljson -L../json/hashmap -lhashmap -L../libc -lc -lgcc +INC=-I../json/ -I../libgui/ +all: $(BIN) +OBJ=ws.o draw.o + +%.o: %.c + $(CC) $(CFLAGS) $(INC) $(LIB) -o $@ -c $< + +clean: + rm $(OBJ) ws + +$(BIN): $(OBJ) + $(CC) -o $(BIN) -ffreestanding -nostdlib $(CFLAGS) $(OBJ) $(LIB) diff --git a/userland/windowserver/draw.c b/userland/windowserver/draw.c new file mode 100644 index 0000000..caa16a2 --- /dev/null +++ b/userland/windowserver/draw.c @@ -0,0 +1,80 @@ +#include "draw.h" +#include + +#define BPP 4 + +#define place_pixel(_p, _w, _h) \ + { *(uint32_t *)(disp->back_buffer + BPP * (_w) + (WIDTH * BPP * (_h))) = _p; } + +#define place_pixel_pos(_p, _pos) \ + { *(uint32_t *)(disp->back_buffer + BPP * (_pos)) = _p; } + +int mx; +int my; + +void update_display(DISPLAY *disp) { + for (int i = 0; i < 20; i++) { + place_pixel(0xFFFFFFFF, mx + i, my + i); + place_pixel(0xFFFFFFFF, mx, my + i / 2); + place_pixel(0xFFFFFFFF, mx + i / 2, my); + } + for (int i = 0; i < disp->size; i++) + disp->true_buffer[i] = disp->back_buffer[i]; + // memcpy(disp->true_buffer, disp->back_buffer, disp->size); +} + +void draw_wallpaper(DISPLAY *disp) { + for (int i = 0; i < disp->size / BPP; i++) { + place_pixel_pos(0xFF00FF, i); + } +} + +void draw_mouse(DISPLAY *disp, int mouse_x, int mouse_y) { + mx = mouse_x; + my = mouse_y; + update_full_display(disp, mouse_x, mouse_y); +} + +void draw_window(DISPLAY *disp, const WINDOW *w) { + int x, y; + uint8_t border_size = disp->border_size; + const int px = w->x + border_size; + const int py = w->y; + const int sx = w->sx; + const int sy = w->sy; + x = px; + y = py; + for (int i = 0; i < sy; i++) { + if((i+py)*WIDTH + px > HEIGHT*WIDTH) + break; + uint32_t *ptr = disp->back_buffer + BPP * ((i + py) * WIDTH) + px * BPP; + if(i*sx > HEIGHT*WIDTH) + break; + uint32_t *bm = &w->bitmap_ptr[i * sx]; + // ((uint8_t *)w->bitmap_ptr) + BPP * ((i + py) * WIDTH) + px * BPP; + for (int j = 0; j < sx; j++) { + ptr[j] = bm[j]; + } + } +} + +void update_active_window(DISPLAY *disp) { + for (int i = 0; i < 100; i++) { + if (!disp->clients[i]) + continue; + if (!disp->clients[i]->w) + continue; + draw_window(disp, disp->clients[i]->w); + } +} + +void update_full_display(DISPLAY *disp, int mouse_x, int mouse_y) { + draw_wallpaper(disp); /* + for (int i = 0; i < 100; i++) { + if (!disp->windows[i]) + continue; + draw_window(disp, disp->windows[i]); + }*/ + update_active_window(disp); + update_display(disp); +} diff --git a/userland/windowserver/draw.h b/userland/windowserver/draw.h new file mode 100644 index 0000000..bf9ff4f --- /dev/null +++ b/userland/windowserver/draw.h @@ -0,0 +1,13 @@ +#ifndef DRAW_H +#define DRAW_H +#include "ws.h" + +#define WIDTH 0x500 +#define HEIGHT 0x320 + +void draw_wallpaper(DISPLAY *disp); +void draw_window(DISPLAY *disp, const WINDOW *w); +void update_full_display(DISPLAY *disp, int mouse_x, int mouse_y); +void update_active_window(DISPLAY *disp); +void draw_mouse(DISPLAY *disp, int mouse_x, int mouse_y); +#endif diff --git a/userland/windowserver/font.h b/userland/windowserver/font.h new file mode 100644 index 0000000..ad63e41 --- /dev/null +++ b/userland/windowserver/font.h @@ -0,0 +1,133 @@ +#ifndef FONT_H +#define FONT_H +char font8x8_basic[128][8] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) + { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) + { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") + { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) + { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) + { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) + { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) + { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') + { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() + { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) + { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) + { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) + { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) + { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) + { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) + { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) + { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) + { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) + { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) + { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) + { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) + { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) + { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) + { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;) + { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) + { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) + { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) + { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) + { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) + { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) + { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) + { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) + { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) + { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) + { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) + { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) + { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) + { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) + { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) + { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) + { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) + { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) + { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) + { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) + { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) + { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) + { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) + { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) + { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) + { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) + { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) + { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) + { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) + { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) + { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) + { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) + { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) + { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) + { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) + { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) + { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) + { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) + { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) + { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) + { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) + { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) + { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) + { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) + { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) + { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) + { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) + { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) + { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) + { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) + { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) + { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) + { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) + { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) + { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) + { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F +}; +#endif diff --git a/userland/windowserver/ws.c b/userland/windowserver/ws.c new file mode 100644 index 0000000..e4f1a9e --- /dev/null +++ b/userland/windowserver/ws.c @@ -0,0 +1,375 @@ +#include +#include +#include +#include +//#include +#include "draw.h" +#include "font.h" +#include "ws.h" +#include +#include +#include +#include +#include +#include + +#define WINDOW_SERVER_SOCKET "/windowserver" + +CLIENT *clients[100]; +CLIENT *active_client; + +int mouse_x = 0; +int mouse_y = 0; + +// void *true_display; +// void *buffer_display; +// uint64_t display_size; +// int border_size; +// uint8_t border_color; +DISPLAY main_display; + +struct pollfd *fds; +uint64_t num_fds; + +uint64_t socket_fd_poll; +uint64_t keyboard_fd_poll; +uint64_t mouse_fd_poll; + +// Taken from drivers/keyboard.c +struct KEY_EVENT { + char c; + uint8_t mode; // (shift (0 bit)) (alt (1 bit)) + uint8_t release; // 0 pressed, 1 released +}; + +int create_socket(void) { + struct sockaddr_un address; + int fd = socket(AF_UNIX, 0, 0); + address.sun_family = AF_UNIX; + size_t str_len = strlen(WINDOW_SERVER_SOCKET); + address.sun_path = malloc(str_len + 1); + memcpy(address.sun_path, WINDOW_SERVER_SOCKET, str_len); + address.sun_path[str_len] = 0; + + bind(fd, (struct sockaddr *)(&address), sizeof(address)); + // for(;;); + /*free(address.sun_path);*/ + return fd; +} + +void setup_display(DISPLAY *disp, const char *path, uint64_t size) { + disp->wallpaper_color = 0x3; + disp->size = size; + disp->vga_fd = open(path, O_RDWR, 0); + if (-1 == disp->vga_fd) { + perror("open"); + for (;;) + ; + } + disp->true_buffer = mmap(NULL, size, 0, 0, disp->vga_fd, 0); + disp->back_buffer = malloc(size + 0x1000); + disp->clients = clients; +} + +void setup(void) { + setup_display(&main_display, "/dev/vbe", 0xBB8000); + draw_wallpaper(&main_display); + update_display(&main_display); + + main_display.border_size = 1; + main_display.border_color = 0xF; + active_client = NULL; + for (int i = 0; i < 100; i++) { + clients[i] = NULL; + } + + num_fds = 100; + fds = malloc(sizeof(struct pollfd[num_fds])); + memset(fds, 0, sizeof(struct pollfd[num_fds])); + for (size_t i = 0; i < num_fds; i++) + fds[i].fd = -1; + // Create socket + int socket_fd = create_socket(); + assert(socket_fd >= 0); + socket_fd_poll = 0; + fds[socket_fd_poll].fd = socket_fd; + fds[socket_fd_poll].events = POLLIN; + fds[socket_fd_poll].revents = 0; + int keyboard_fd = open("/dev/keyboard", O_RDONLY | O_NONBLOCK, 0); + assert(keyboard_fd >= 0); + keyboard_fd_poll = 1; + fds[keyboard_fd_poll].fd = keyboard_fd; + fds[keyboard_fd_poll].events = POLLIN; + fds[keyboard_fd_poll].revents = 0; + int mouse_fd = open("/dev/mouse", O_RDONLY, 0); + assert(mouse_fd >= 0); + mouse_fd_poll = 2; + fds[mouse_fd_poll].fd = mouse_fd; + fds[mouse_fd_poll].events = POLLIN; + fds[mouse_fd_poll].revents = 0; +} + +void reset_revents(struct pollfd *fds, size_t s) { + for (size_t i = 0; i < s - 1; i++) + fds[i].revents = 0; +} + +void add_fd(int fd) { + int i; + for (i = 0; i < num_fds; i++) + if (-1 == fds[i].fd) + break; + + fds[i].fd = fd; + fds[i].events = POLLIN | POLLHUP; + // fds[i].events = POLLIN; + fds[i].revents = 0; +} + +void add_client(int fd) { + int client_socket = accept(fd, NULL, NULL); + add_fd(client_socket); + int i; + for (i = 0; i < 100; i++) + if (!clients[i]) + break; + printf("adding client: %d\n", i); + CLIENT *c = clients[i] = malloc(sizeof(CLIENT)); + c->fd = client_socket; + active_client = c; + printf("clients[0]: %x\n", clients[0]); +} + +#define CLIENT_EVENT_CREATESCREEN 0 +#define CLIENT_EVENT_UPDATESCREEN 1 + +void add_window(CLIENT *c, int fd, int x, int y, int sx, int sy) { + WINDOW *w = malloc(sizeof(WINDOW)); + w->bitmap_fd = fd; + w->bitmap_ptr = mmap(NULL, sx * sy * sizeof(uint32_t), 0, 0, fd, 0); + w->x = x; + w->y = y; + w->sx = sx; + w->sy = sy; + c->w = w; +} + +typedef struct { + uint16_t px; + uint16_t py; + uint16_t sx; + uint16_t sy; + uint8_t name_len; +} WS_EVENT_CREATE; + +void parse_client_event(CLIENT *c) { + uint8_t event_type; + if (0 == read(c->fd, &event_type, sizeof(uint8_t))) { + printf("empty\n"); + return; + } + if (0 == event_type) { + update_full_display(&main_display, mouse_x, mouse_y); + return; + } + if (1 == event_type) { + WS_EVENT_CREATE e; + for (; 0 == read(c->fd, &e, sizeof(e));) + ; + uint8_t bitmap_name[e.name_len + 1]; + read(c->fd, bitmap_name, e.name_len); + bitmap_name[e.name_len] = '\0'; + int bitmap_fd = shm_open(bitmap_name, O_RDWR, O_CREAT); + add_window(c, bitmap_fd, e.px, e.py, e.sx, e.sy); + update_full_display(&main_display, mouse_x, mouse_y); + } +} + +typedef struct { + int type; + struct KEY_EVENT ev; +} WS_EVENT; + +void send_to_client(struct KEY_EVENT ev) { + WS_EVENT e = { + .type = 0, + .ev = ev, + }; + write(active_client->fd, &e, sizeof(e)); +} + +void clamp_screen_position(int *x, int *y) { + if (0 > *x) { + *x = 0; + } + if (0 > *y) { + *y = 0; + } + if (WIDTH < *x) { + *x = WIDTH; + } + if (HEIGHT < *y) { + *y = HEIGHT; + } +} + +int windowserver_key_events(struct KEY_EVENT ev, int *redraw) { + if (!(ev.mode & (1 << 1))) + return 0; + if (!active_client) + return 0; + int x = 0; + int y = 0; + switch (ev.c) { + case 'l': + x++; + break; + case 'h': + x--; + break; + case 'k': + y--; + break; + case 'j': + y++; + break; + } + if (x || y) { + active_client->w->x += x; + active_client->w->y += y; + clamp_screen_position(&active_client->w->x, &active_client->w->y); + *redraw = 1; + return 1; + } + return 0; +} + +struct mouse_event { + uint8_t buttons; + uint8_t x; + uint8_t y; +}; + +void update_mouse(void) { + draw_mouse(&main_display, mouse_x, mouse_y); + return; +} + +void parse_mouse_event(int fd) { + int16_t xc = 0; + int16_t yc = 0; + int middle_button = 0; + for (;;) { + struct mouse_event e[100]; + int rc = read(fd, e, sizeof(e)); + if (rc <= 0) + break; + + int n = rc / sizeof(e[0]); + for (int i = 0; i < n; i++) { + uint8_t xs = e[i].buttons & (1 << 4); + uint8_t ys = e[i].buttons & (1 << 5); + middle_button = e[i].buttons & (1 << 2); + int16_t x = e[i].x; + int16_t y = e[i].y; + if (xs) + x |= 0xFF00; + if (ys) + y |= 0xFF00; + xc += *(int16_t *)&x; + yc += *(int16_t *)&y; + } + } + mouse_x += xc; + mouse_y -= yc; + if (mouse_x < 0) + mouse_x = 0; + if (mouse_y < 0) + mouse_y = 0; + if (middle_button) { + active_client->w->x += xc; + active_client->w->y -= yc; + clamp_screen_position(&active_client->w->x, &active_client->w->y); + } + update_mouse(); +} + +void parse_keyboard_event(int fd) { + if (!active_client) { + return; + } + struct KEY_EVENT ev[250]; + int redraw = 0; + for (;;) { + int rc; + if (0 > (rc = read(fd, &ev[0], sizeof(ev)))) + break; + int n = rc / sizeof(ev[0]); + for (int i = 0; i < n; i++) { + if (windowserver_key_events(ev[i], &redraw)) + continue; + send_to_client(ev[i]); + } + } + if (redraw) + update_full_display(&main_display, mouse_x, mouse_y); +} + +CLIENT *get_client(int fd) { + for (int i = 0; i < 100; i++) { + if (!clients[i]) + continue; + if (clients[i]->fd == fd) + return clients[i]; + } + return NULL; +} + +void kill_client(CLIENT *c) { + c->w = NULL; + update_full_display(&main_display, mouse_x, mouse_y); + active_client = clients[0]; +} + +void parse_revents(struct pollfd *fds, size_t s) { + for (size_t i = 0; i < s - 1; i++) { + if (!fds[i].revents) + continue; + if (-1 == fds[i].fd) + continue; + if (socket_fd_poll == i && fds[i].revents & POLLIN) { + add_client(fds[i].fd); + continue; + } else if (keyboard_fd_poll == i) { + parse_keyboard_event(fds[i].fd); + continue; + } else if (mouse_fd_poll == i) { + parse_mouse_event(fds[i].fd); + continue; + } + CLIENT *c = get_client(fds[i].fd); + assert(c); + if (fds[i].revents & POLLHUP) { + kill_client(c); + fds[i].fd = -1; + } else { + parse_client_event(c); + } + } +} + +void run(void) { + for (;;) { + poll(fds, num_fds, 0); + parse_revents(fds, num_fds); + reset_revents(fds, num_fds); + } +} + +int main(void) { + open("/dev/serial", O_WRITE, 0); + open("/dev/serial", O_WRITE, 0); + setup(); + run(); + return 0; +} diff --git a/userland/windowserver/ws.h b/userland/windowserver/ws.h new file mode 100644 index 0000000..c4daf7b --- /dev/null +++ b/userland/windowserver/ws.h @@ -0,0 +1,30 @@ +#ifndef WS_H +#define WS_H +#include +#include + +typedef struct { + int bitmap_fd; + uint32_t *bitmap_ptr; + int x; + int y; + int sx; + int sy; +} WINDOW; + +typedef struct { + int fd; + WINDOW *w; +} CLIENT; + +typedef struct { + int vga_fd; + uint8_t *back_buffer; + uint8_t *true_buffer; + size_t size; + uint8_t border_size; + uint8_t border_color; + uint8_t wallpaper_color; + CLIENT **clients; +} DISPLAY; +#endif -- cgit v1.2.3