From b965486de3860ec387eed88263a4d4452ce04b5b Mon Sep 17 00:00:00 2001 From: Patrick Wuttke Date: Sun, 4 Feb 2024 02:01:08 +0100 Subject: [PATCH] More implementation of the C standard library. --- targets/_any/bastl/SConscript | 2 +- targets/_any/bastl/include/cctype | 27 ++ targets/_any/bastl/include/cerrno | 9 + targets/_any/bastl/include/cstdint | 15 ++ targets/_any/bastl/include/cstring | 8 +- targets/_any/bastl/include/string_view | 82 +++++++ targets/_any/bastl/include/utility | 2 +- targets/_any/init/SConscript | 3 +- targets/_any/init/src/{main.c => main.cpp} | 0 targets/_any/kernel/include/os/serial.hpp | 11 + .../kernel/include/os/tools/ringbuffer.hpp | 28 +++ targets/_any/kernel/src/syscall.cpp | 1 + targets/_any/stdlib/SConscript | 2 + targets/_any/stdlib/include/ctype.h | 28 +++ targets/_any/stdlib/include/errno.h | 165 ++++++++++++- targets/_any/stdlib/include/stdio.h | 4 + targets/_any/stdlib/include/stdlib.h | 1 + targets/_any/stdlib/src/ctype.cpp | 79 ++++++ targets/_any/stdlib/src/errno.cpp | 15 ++ targets/_any/stdlib/src/stdio.cpp | 230 +++++++++++++----- targets/_any/stdlib/src/string.cpp | 14 ++ 21 files changed, 658 insertions(+), 68 deletions(-) create mode 100644 targets/_any/bastl/include/cctype create mode 100644 targets/_any/bastl/include/cerrno create mode 100644 targets/_any/bastl/include/string_view rename targets/_any/init/src/{main.c => main.cpp} (100%) create mode 100644 targets/_any/stdlib/include/ctype.h create mode 100644 targets/_any/stdlib/src/ctype.cpp create mode 100644 targets/_any/stdlib/src/errno.cpp diff --git a/targets/_any/bastl/SConscript b/targets/_any/bastl/SConscript index 590b854..30b3ee5 100644 --- a/targets/_any/bastl/SConscript +++ b/targets/_any/bastl/SConscript @@ -5,6 +5,6 @@ bastl_sources = Split(''' src/new.cpp ''') -env.Append(KERNEL_SOURCES = [env.File(f) for f in bastl_sources]) +# env.Append(KERNEL_SOURCES = [env.File(f) for f in bastl_sources]) Return('env') \ No newline at end of file diff --git a/targets/_any/bastl/include/cctype b/targets/_any/bastl/include/cctype new file mode 100644 index 0000000..0a3fda5 --- /dev/null +++ b/targets/_any/bastl/include/cctype @@ -0,0 +1,27 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_CCTYPE_INCLUDED) +#define BAD_APPLE_OS_CCTYPE_INCLUDED + +#include + +namespace std +{ +using ::isalnum; +using ::isalpha; +using ::islower; +using ::isupper; +using ::isdigit; +using ::isxdigit; +using ::iscntrl; +using ::isgraph; +using ::isspace; +using ::isblank; +using ::isprint; +using ::ispunct; +using ::tolower; +using ::toupper; +} + +#endif // !defined(BAD_APPLE_OS_CCTYPE_INCLUDED) diff --git a/targets/_any/bastl/include/cerrno b/targets/_any/bastl/include/cerrno new file mode 100644 index 0000000..dd456c2 --- /dev/null +++ b/targets/_any/bastl/include/cerrno @@ -0,0 +1,9 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_CERRNO_INCLUDED) +#define BAD_APPLE_OS_CERRNO_INCLUDED + +#include + +#endif // !defined(BAD_APPLE_OS_CERRNO_INCLUDED) diff --git a/targets/_any/bastl/include/cstdint b/targets/_any/bastl/include/cstdint index 3484804..67d260a 100644 --- a/targets/_any/bastl/include/cstdint +++ b/targets/_any/bastl/include/cstdint @@ -16,6 +16,21 @@ using ::uint8_t; using ::uint16_t; using ::uint32_t; using ::uint64_t; + +using ::intptr_t; +using ::uintptr_t; + +using ::int_fast8_t; +using ::int_fast16_t; +using ::int_fast32_t; +using ::int_fast64_t; +using ::uint_fast8_t; +using ::uint_fast16_t; +using ::uint_fast32_t; +using ::uint_fast64_t; + +using ::intmax_t; +using ::uintmax_t; } #endif // !defined(BAD_APPLE_OS_CSTDINT_INCLUDED) diff --git a/targets/_any/bastl/include/cstring b/targets/_any/bastl/include/cstring index 25b0e3b..69cc73b 100644 --- a/targets/_any/bastl/include/cstring +++ b/targets/_any/bastl/include/cstring @@ -8,12 +8,16 @@ namespace std { -using ::strlen; - using ::memcmp; using ::memcpy; using ::memmove; using ::memset; + + +using ::strcat; +using ::strchr; +using ::strcpy; +using ::strlen; } #endif // !defined(BAD_APPLE_OS_CSTRING_INCLUDED) diff --git a/targets/_any/bastl/include/string_view b/targets/_any/bastl/include/string_view new file mode 100644 index 0000000..57b8e4d --- /dev/null +++ b/targets/_any/bastl/include/string_view @@ -0,0 +1,82 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_STRING_VIEW_INCLUDED) +#define BAD_APPLE_OS_STRING_VIEW_INCLUDED + +#include +#include +#include + +namespace std +{ +template> +class basic_string_view +{ +public: + using traits_type = Traits; + using value_type = CharT; + using pointer = CharT*; + using const_pointer = const CharT*; + using reference = CharT&; + using const_reference = const CharT&; + using iterator = const CharT*; + using const_iterator = const CharT*; + // TODO: reverse iterators + using size_type = size_t; + using difference_type = ptrdiff_t; +private: + const_pointer _begin = nullptr; + const_pointer _end = nullptr; +public: + constexpr basic_string_view() noexcept = default; + constexpr basic_string_view(const basic_string_view&) noexcept = default; + constexpr basic_string_view(const_pointer s, size_type count) noexcept : _begin(s), _end(s + count) {} + constexpr basic_string_view(const_pointer s) noexcept : _begin(s), _end(s) + { + while (*_end) { ++_end; } + } + template + constexpr basic_string_view(It first, End last) noexcept : _begin(first), _end(last) {} + constexpr basic_string_view(nullptr_t) = delete; + + constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default; + + [[nodiscard]] constexpr iterator begin() const noexcept { return _begin; } + [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return _begin; } + [[nodiscard]] constexpr iterator end() const noexcept { return _end; } + [[nodiscard]] constexpr const_iterator cend() const noexcept { return _end; } + // TODO: reverse iterators + + [[nodiscard]] constexpr const_reference operator[](size_type pos) const noexcept { return _begin[pos]; } + [[nodiscard]] constexpr const_reference at(size_type pos) const + { + if (pos >= size()) { + __ba_throw out_of_range(); + } + return _begin[pos]; + } + [[nodiscard]] constexpr const_reference front() const noexcept { return *_begin; } + [[nodiscard]] constexpr const_reference back() const noexcept { return _end[-1]; } + [[nodiscard]] constexpr const_pointer data() const noexcept { return _begin; } + + [[nodiscard]] constexpr size_type size() const noexcept { return _end - _begin; } + [[nodiscard]] constexpr size_type length() const noexcept { return _end - _begin; } + [[nodiscard]] constexpr size_type max_size() const noexcept { return numeric_limits::max(); } + [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } + + constexpr void remove_prefix(size_type n) noexcept { _begin += n; } + constexpr void remove_suffix(size_type n) noexcept { _end -= n; } + + constexpr void swap(basic_string_view& v) noexcept + { + swap(_begin, v._begin); + swap(_end, v._end); + } +}; + +using string_view = basic_string_view; +using wstring_view = basic_string_view; +} + +#endif // !defined(BAD_APPLE_OS_STRING_VIEW_INCLUDED) diff --git a/targets/_any/bastl/include/utility b/targets/_any/bastl/include/utility index 4e241ca..c7e6db0 100644 --- a/targets/_any/bastl/include/utility +++ b/targets/_any/bastl/include/utility @@ -4,7 +4,7 @@ #if !defined(BAD_APPLE_OS_UTILITY_INCLUDED) #define BAD_APPLE_OS_UTILITY_INCLUDED -#include "type_traits" +#include namespace std { diff --git a/targets/_any/init/SConscript b/targets/_any/init/SConscript index ffeff26..97e0cb6 100644 --- a/targets/_any/init/SConscript +++ b/targets/_any/init/SConscript @@ -2,7 +2,7 @@ Import('env') init_sources = Split(''' - src/main.c + src/main.cpp ''') init_env = env.Clone() @@ -11,6 +11,7 @@ init_env['CC'] = 'x86_64-elf-baos-gcc' init_env['CXX'] = 'x86_64-elf-baos-g++' init_env['LD'] = 'x86_64-elf-baos-g++' init_env.Append(CXXFLAGS = ['-fno-exceptions', '-fno-rtti', '-std=c++20']) +init_env.Append(LINKFLAGS = ['-nostdlib++']) # TODO: this should be changed in GCC, but I can't find a way to do it init_env.Append(CPPPATH = ['#targets/_any/bastl/include', '#targets/_any/stdlib/include', '#targets/_any/kernel/include']) prog_init = init_env.Program( diff --git a/targets/_any/init/src/main.c b/targets/_any/init/src/main.cpp similarity index 100% rename from targets/_any/init/src/main.c rename to targets/_any/init/src/main.cpp diff --git a/targets/_any/kernel/include/os/serial.hpp b/targets/_any/kernel/include/os/serial.hpp index 39608df..a829742 100644 --- a/targets/_any/kernel/include/os/serial.hpp +++ b/targets/_any/kernel/include/os/serial.hpp @@ -55,4 +55,15 @@ inline void serialWriteString(std::uint16_t port, const char* str) noexcept } } +inline void serialWriteString(std::uint16_t port, const char* str, size_t count) noexcept +{ + for (size_t pos = 0; pos < count; ++pos) + { + if (str[pos] == '\n') { + serialWrite(port, '\r'); + } + serialWrite(port, str[pos]); + } +} + #endif // !defined(BAD_APPLE_OS_SERIAL_HPP_INCLUDED) diff --git a/targets/_any/kernel/include/os/tools/ringbuffer.hpp b/targets/_any/kernel/include/os/tools/ringbuffer.hpp index 17e62d2..fe7f344 100644 --- a/targets/_any/kernel/include/os/tools/ringbuffer.hpp +++ b/targets/_any/kernel/include/os/tools/ringbuffer.hpp @@ -6,6 +6,7 @@ #include #include +#include namespace baos { @@ -47,6 +48,33 @@ public: --mBufferedElements; return true; } + + [[nodiscard]] bool isDataContinuous() const noexcept + { + return mBufferedElements <= mPosition; + } + + void normalize() noexcept + { + std::array tempElements; + auto it = tempElements.begin(); + while (next(*it)) { ++it; } + mBufferedElements = it - tempElements.begin(); + mElements = std::move(tempElements); + mPosition = mBufferedElements; + } + + std::span getAll(bool reset = true) noexcept + { + if (!isDataContinuous()) { + normalize(); + } + std::span result = {mElements.data() + mPosition - mBufferedElements, mBufferedElements}; + if (reset) { + mBufferedElements = 0; + } + return result; + } }; } diff --git a/targets/_any/kernel/src/syscall.cpp b/targets/_any/kernel/src/syscall.cpp index 2088265..6de0c8d 100644 --- a/targets/_any/kernel/src/syscall.cpp +++ b/targets/_any/kernel/src/syscall.cpp @@ -27,6 +27,7 @@ void sysFileRead(unsigned fileDescriptor, char* buffer, std::size_t count) noexc void sysFileWrite(unsigned fileDescriptor, const char* buffer, std::size_t count) noexcept { + serialWriteString(PORT_COM1, buffer, count); for (std::size_t index = 0; index < count; ++index) { serialWrite(PORT_COM1, buffer[index]); } diff --git a/targets/_any/stdlib/SConscript b/targets/_any/stdlib/SConscript index e1a615d..45f952a 100644 --- a/targets/_any/stdlib/SConscript +++ b/targets/_any/stdlib/SConscript @@ -7,6 +7,8 @@ env['CRT0_PATH'] = env.File(f'src/crt0.{env["TARGET_ARCH"]}.s').abspath stdlib_sources = Split(f''' src/assert.cpp + src/ctype.cpp + src/errno.cpp src/stdio.cpp src/stdlib.cpp src/string.cpp diff --git a/targets/_any/stdlib/include/ctype.h b/targets/_any/stdlib/include/ctype.h new file mode 100644 index 0000000..d8f3e5a --- /dev/null +++ b/targets/_any/stdlib/include/ctype.h @@ -0,0 +1,28 @@ + +#pragma once + +#if !defined(BAD_APPLE_OS_CTYPE_H_INCLUDED) +#define BAD_APPLE_OS_CTYPE_H_INCLUDED + +#include "./detail/common.h" + +BA_EXTERN_C_BEGIN + +BA_CXX_NODISCARD int isalnum(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int isalpha(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int islower(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int isupper(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int isdigit(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int isxdigit(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int iscntrl(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int isgraph(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int isspace(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int isblank(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int isprint(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int ispunct(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int tolower(int ch) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD int toupper(int ch) BA_CXX_NOEXCEPT; + +BA_EXTERN_C_END + +#endif // !defined(BAD_APPLE_OS_CTYPE_H_INCLUDED) diff --git a/targets/_any/stdlib/include/errno.h b/targets/_any/stdlib/include/errno.h index b101cca..7885d94 100644 --- a/targets/_any/stdlib/include/errno.h +++ b/targets/_any/stdlib/include/errno.h @@ -1,7 +1,170 @@ - +// shamelessly stolen from my Linux distro (which means this is GPL code!) #pragma once #if !defined(BAD_APPLE_OS_ERRNO_H_INCLUDED) #define BAD_APPLE_OS_ERRNO_H_INCLUDED +#include "./detail/common.h" + +#define errno (*__errno()) + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ + +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ + +/* + * This error code is special: arch syscall entry code will return + * -ENOSYS if users try to call a syscall that doesn't exist. To keep + * failures of syscalls that really do exist distinguishable from + * failures due to attempts to use a nonexistent syscall, syscall + * implementations should refrain from returning -ENOSYS. + */ +#define ENOSYS 38 /* Invalid system call number */ + +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ +#define ECANCELED 125 /* Operation Canceled */ +#define ENOKEY 126 /* Required key not available */ +#define EKEYEXPIRED 127 /* Key has expired */ +#define EKEYREVOKED 128 /* Key has been revoked */ +#define EKEYREJECTED 129 /* Key was rejected by service */ + +/* for robust mutexes */ +#define EOWNERDEAD 130 /* Owner died */ +#define ENOTRECOVERABLE 131 /* State not recoverable */ + +#define ERFKILL 132 /* Operation not possible due to RF-kill */ + +#define EHWPOISON 133 /* Memory page has hardware error */ + +BA_EXTERN_C_BEGIN + +BA_CXX_NODISCARD int* __errno() BA_CXX_NOEXCEPT; + + + +BA_EXTERN_C_END + #endif // !defined(BAD_APPLE_OS_ERRNO_H_INCLUDED) diff --git a/targets/_any/stdlib/include/stdio.h b/targets/_any/stdlib/include/stdio.h index 529524b..ac5f043 100644 --- a/targets/_any/stdlib/include/stdio.h +++ b/targets/_any/stdlib/include/stdio.h @@ -33,6 +33,7 @@ int vprintf(const char* BA_C_RESTRICT format, va_list vlist) BA_CXX_NOEXCEPT; int sprintf(char* BA_C_RESTRICT buffer, const char* BA_C_RESTRICT format, ...) BA_CXX_NOEXCEPT; int snprintf(char* BA_C_RESTRICT buffer, size_t bufferSize, const char* BA_C_RESTRICT format, ...) BA_CXX_NOEXCEPT __attribute__((format(printf, 3, 4))); int vsnprintf(char* BA_C_RESTRICT buffer, size_t bufferSize, const char* BA_C_RESTRICT format, va_list vlist) BA_CXX_NOEXCEPT; +int vsprintf(char* BA_C_RESTRICT buffer, const char* BA_C_RESTRICT format, va_list vlist) BA_CXX_NOEXCEPT; int fclose(FILE* stream) BA_CXX_NOEXCEPT; int fflush(FILE* stream) BA_CXX_NOEXCEPT; @@ -40,6 +41,8 @@ int fgetc(FILE* stream) BA_CXX_NOEXCEPT; FILE* fopen(const char* BA_C_RESTRICT filename, const char* BA_C_RESTRICT mode) BA_CXX_NOEXCEPT; char* fgets(char* buffer, int count, FILE* stream) BA_CXX_NOEXCEPT; int fprintf(FILE* BA_C_RESTRICT stream, const char* BA_C_RESTRICT format, ...) BA_CXX_NOEXCEPT __attribute__((format(printf, 2, 3))); +int fputc(int ch, FILE* stream) BA_CXX_NOEXCEPT; +int fputs(const char* BA_C_RESTRICT str, FILE* BA_C_RESTRICT stream) BA_CXX_NOEXCEPT; size_t fread(void* BA_C_RESTRICT buffer, size_t size, size_t count, FILE* BA_C_RESTRICT stream) BA_CXX_NOEXCEPT; int fseek(FILE* stream, long offset, int origin) BA_CXX_NOEXCEPT; long ftell(FILE* stream) BA_CXX_NOEXCEPT; @@ -49,6 +52,7 @@ int vfprintf(FILE* BA_C_RESTRICT stream, const char* BA_C_RESTRICT format, va_li inline int getc(FILE* stream) BA_CXX_NOEXCEPT { return fgetc(stream); } inline int getchar() BA_CXX_NOEXCEPT { return fgetc(stdin); } +inline int putc(int ch, FILE* stream) BA_CXX_NOEXCEPT { return fputc(ch, stream); } BA_EXTERN_C_END diff --git a/targets/_any/stdlib/include/stdlib.h b/targets/_any/stdlib/include/stdlib.h index da521e8..807d884 100644 --- a/targets/_any/stdlib/include/stdlib.h +++ b/targets/_any/stdlib/include/stdlib.h @@ -15,6 +15,7 @@ BA_CXX_NORETURN void exit(int exitCode) BA_CXX_NOEXCEPT; BA_CXX_NODISCARD char* getenv(const char* name) BA_CXX_NOEXCEPT; BA_CXX_NODISCARD int abs(int n) BA_CXX_NOEXCEPT; +BA_CXX_NODISCARD double atof(const char* str) BA_CXX_NOEXCEPT; BA_CXX_NODISCARD int atoi(const char* str) BA_CXX_NOEXCEPT; BA_CXX_NODISCARD void* calloc(size_t num, size_t size) BA_CXX_NOEXCEPT; diff --git a/targets/_any/stdlib/src/ctype.cpp b/targets/_any/stdlib/src/ctype.cpp new file mode 100644 index 0000000..b3c27b7 --- /dev/null +++ b/targets/_any/stdlib/src/ctype.cpp @@ -0,0 +1,79 @@ + +#include + +#include + +extern "C" +{ +int isalnum(int ch) noexcept +{ + return isdigit(ch) || isalpha(ch); +} + +int isalpha(int ch) noexcept +{ + return islower(ch) || isupper(ch); +} + +int islower(int ch) noexcept +{ + return ch >= 'a' && ch <= 'z'; +} + +int isupper(int ch) noexcept +{ + return ch >= 'A' && ch <= 'Z'; +} + +int isdigit(int ch) noexcept +{ + return ch >= '0' && ch <= '9'; +} + +int isxdigit(int ch) noexcept +{ + return isdigit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); +} + +int iscntrl(int ch) noexcept +{ + return (ch >= 0x00 && ch <= 0x1F) || ch == 0x7F; +} + +int isgraph(int ch) noexcept +{ + return isalnum(ch) || ispunct(ch); +} + +int isspace(int ch) noexcept +{ + static const char SPACE_CHARS[] = " \f\n\r\t\v"; + return strchr(SPACE_CHARS, ch) != nullptr; +} + +int isblank(int ch) noexcept +{ + return ch == ' ' || ch == '\t'; +} + +int isprint(int ch) noexcept +{ + return isgraph(ch) || isspace(ch); +} + +int ispunct(int ch) noexcept +{ + static const char PUNCTUATION_CHARS[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; + return strchr(PUNCTUATION_CHARS, ch) != nullptr; +} + +int tolower(int ch) noexcept +{ + return isupper(ch) ? (ch - 'A' + 'a') : ch; +} + +int toupper(int ch) noexcept +{ + return islower(ch) ? (ch - 'a' + 'A') : ch; +} +} diff --git a/targets/_any/stdlib/src/errno.cpp b/targets/_any/stdlib/src/errno.cpp new file mode 100644 index 0000000..be6fc91 --- /dev/null +++ b/targets/_any/stdlib/src/errno.cpp @@ -0,0 +1,15 @@ + +#include + +namespace +{ +constinit int gErrno = 0; // TODO: make this thread-local once there are threads +} + +extern "C" +{ +int* __errno() noexcept +{ + return &gErrno; +} +} diff --git a/targets/_any/stdlib/src/stdio.cpp b/targets/_any/stdlib/src/stdio.cpp index d60e1b6..785bb20 100644 --- a/targets/_any/stdlib/src/stdio.cpp +++ b/targets/_any/stdlib/src/stdio.cpp @@ -2,7 +2,10 @@ #include #include +#include +#include #include +#include #include #include "os/tools/printf_helper.hpp" #include "os/tools/ringbuffer.hpp" @@ -17,34 +20,64 @@ struct __file { protected: - static constexpr unsigned BUFFER_SIZE = 4096; - - baos::RingBuffer mBuffer; bool mEof = false; bool mError = false; -protected: - virtual bool underflow() noexcept = 0; public: [[nodiscard]] bool isEof() const noexcept { return mEof; } [[nodiscard]] bool isError() const noexcept { return mError; } - bool readChar(char& outChar) noexcept + virtual bool readChar(char& outChar) noexcept { return false; } + virtual bool readLine(std::string& outLine) noexcept { return false; } +}; + +namespace +{ +struct BufferPrinter +{ + char* pos = nullptr; + char* end = nullptr; + + void putchar(int chr) noexcept // NOLINT { - while (!mBuffer.next(outChar)) { - if (!underflow()) { + if (pos != end) + { + *pos = static_cast(chr); + ++pos; + } + } +}; + +class InFile : public __file +{ +protected: + static constexpr unsigned BUFFER_SIZE = 4096; + + baos::RingBuffer mBuffer; +protected: + virtual bool underflow() noexcept = 0; + +public: + bool readChar(char& outChar) noexcept override + { + while (!mBuffer.next(outChar)) + { + if (!underflow()) + { return false; } } return true; } - bool readLine(std::string& outLine) noexcept + bool readLine(std::string& outLine) noexcept override { outLine.clear(); - while(true) + while (true) { - while (mBuffer.empty()) { - if (!underflow()) { + while (mBuffer.empty()) + { + if (!underflow()) + { return false; } } @@ -71,35 +104,46 @@ public: return true; } } + } }; -namespace +class OutFile : public __file { -struct RegularPrinter -{ - void putchar(int chr) noexcept // NOLINT - { - ::putchar(chr); - } -}; +protected: + static constexpr unsigned BUFFER_SIZE = 4096; -struct BufferPrinter -{ - char* pos = nullptr; - char* end = nullptr; - - void putchar(int chr) noexcept // NOLINT + baos::RingBuffer mWriteBuffer; +protected: + virtual void overflow() noexcept = 0; +public: + void putChar(char chr) noexcept { - if (pos != end) + while (mWriteBuffer.full()) { + overflow(); + } + mWriteBuffer.append(chr); + if (chr == '\n') { - *pos = static_cast(chr); - ++pos; + overflow(); } } + + void putString(std::string_view str) noexcept + { + for (char chr : str) + { + putChar(chr); + } + } + + void flush() noexcept + { + overflow(); + } }; -class StdinFile : public __file +class StdinFile : public InFile { public: bool underflow() noexcept override @@ -114,49 +158,52 @@ public: #endif } }; + +class StdoutFile : public OutFile +{ +public: + void overflow() noexcept override + { + std::span chars = mWriteBuffer.getAll(); + if (!chars.empty()) + { +#if defined(__baos_kernel_source__) + serialWriteString(PORT_COM1, chars.data(), chars.size()); + tty::write(chars.data(), chars.size()); +#else + baos::doSyscall(baos::Syscall::FILE_WRITE, 0, chars.data(), chars.size()); +#endif + } + } +}; + +struct FilePrinter +{ + OutFile& file; + + void putchar(int chr) noexcept + { + file.putChar(static_cast(chr)); + } +}; + StdinFile gStdin; +StdoutFile gStdout; } extern "C" { FILE* __stdin = &gStdin; +FILE* __stdout = &gStdout; -// TODO: line-buffering int putchar(int chr) noexcept { -#if defined(__baos_kernel_source__) - tty::putChar(static_cast(chr)); - if (chr == '\n') - { - serialWrite(PORT_COM1, '\r'); - serialWrite(PORT_COM1, '\n'); - } - else - { - serialWrite(PORT_COM1, static_cast(chr)); - } - return 0; -#else - char asChar = static_cast(chr); - baos::doSyscall(baos::Syscall::FILE_WRITE, 0, &asChar, 1); - return 0; -#endif + return fputc(chr, stdout); } int puts(const char* str) noexcept { -#if defined(__baos_kernel_source__) - while (*str) - { - putchar(*str); - ++str; - } - putchar('\n'); - return 0; -#else - baos::doSyscall(baos::Syscall::FILE_WRITE, 0, str, std::strlen(str)); - return 0; -#endif + return fputs(str, stdout); } int printf(const char* format, ...) noexcept @@ -168,9 +215,18 @@ int printf(const char* format, ...) noexcept return result; } -int vprintf(const char* format, va_list vlist) BA_CXX_NOEXCEPT +int vprintf(const char* format, va_list vlist) noexcept { - return baos::PrintFHelper().vprintf(format, vlist); + return vfprintf(stdout, format, vlist); +} + +int sprintf(char* buffer, const char* format, ...) noexcept +{ + va_list parameters; + va_start(parameters, format); + const int result = vsprintf(buffer, format, parameters); + va_end(parameters); + return result; } int snprintf(char* buffer, size_t bufferSize, const char* format, ...) noexcept @@ -196,6 +252,30 @@ int vsnprintf(char* buffer, size_t bufferSize, const char* format, va_list vlist return length; } +int vsprintf(char* buffer, const char* format, va_list vlist) noexcept +{ + BufferPrinter printer{ + .pos = buffer, + .end = std::bit_cast(std::numeric_limits::max()) + }; + const int length = baos::PrintFHelper(printer).vprintf(format, vlist); + buffer[length] = '\0'; + return length; +} + +int fclose(FILE* stream) noexcept +{ + (void) stream; + // TODO: implement + return EOF; +} + +int fflush(FILE* stream) noexcept +{ + static_cast(stream)->flush(); + return stream->isError() ? EOF : 0; +} + int fgetc(FILE* stream) noexcept { char chr; @@ -232,6 +312,32 @@ char* fgets(char* buffer, int count, FILE* stream) noexcept buffer[pos] = '\0'; return buffer; } + +int fprintf(FILE* stream, const char* format, ...) noexcept +{ + va_list parameters; + va_start(parameters, format); + const int result = vfprintf(stream, format, parameters); + va_end(parameters); + return result; +} + +int fputc(int ch, FILE* stream) noexcept +{ + static_cast(stream)->putChar(static_cast(ch)); + return stream->isError() ? EOF : 0; +} + +int fputs(const char* str, FILE* stream) noexcept +{ + static_cast(stream)->putString(str); + return stream->isError() ? EOF : 0; +} + +int vfprintf(FILE* stream, const char* format, va_list vlist) noexcept +{ + return baos::PrintFHelper(FilePrinter(*static_cast(stream))).vprintf(format, vlist); +} } // extern "C" namespace std diff --git a/targets/_any/stdlib/src/string.cpp b/targets/_any/stdlib/src/string.cpp index e6abf25..4eb774d 100644 --- a/targets/_any/stdlib/src/string.cpp +++ b/targets/_any/stdlib/src/string.cpp @@ -58,6 +58,20 @@ void* memset(void* dest, int value, size_t count) noexcept return dest; } +char* strchr(const char* str, int ch) noexcept +{ + for (const char* chr = str;; ++chr) + { + if (*chr == ch) { + return const_cast(chr); + } + ++chr; + if (!*chr) { + return nullptr; + } + } +} + size_t strlen(const char* str) noexcept { size_t len = 0;