More implementation of the C standard library.

This commit is contained in:
Patrick 2024-02-04 02:01:08 +01:00
parent 2a612d2d83
commit b965486de3
21 changed files with 658 additions and 68 deletions

View File

@ -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')

View File

@ -0,0 +1,27 @@
#pragma once
#if !defined(BAD_APPLE_OS_CCTYPE_INCLUDED)
#define BAD_APPLE_OS_CCTYPE_INCLUDED
#include <ctype.h>
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)

View File

@ -0,0 +1,9 @@
#pragma once
#if !defined(BAD_APPLE_OS_CERRNO_INCLUDED)
#define BAD_APPLE_OS_CERRNO_INCLUDED
#include <errno.h>
#endif // !defined(BAD_APPLE_OS_CERRNO_INCLUDED)

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,82 @@
#pragma once
#if !defined(BAD_APPLE_OS_STRING_VIEW_INCLUDED)
#define BAD_APPLE_OS_STRING_VIEW_INCLUDED
#include <limits>
#include <stdexcept>
#include <string>
namespace std
{
template<typename CharT, typename Traits = char_traits<CharT>>
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<typename It, typename End>
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<size_type>::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<char>;
using wstring_view = basic_string_view<wchar_t>;
}
#endif // !defined(BAD_APPLE_OS_STRING_VIEW_INCLUDED)

View File

@ -4,7 +4,7 @@
#if !defined(BAD_APPLE_OS_UTILITY_INCLUDED)
#define BAD_APPLE_OS_UTILITY_INCLUDED
#include "type_traits"
#include <type_traits>
namespace std
{

View File

@ -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(

View File

@ -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)

View File

@ -6,6 +6,7 @@
#include <array>
#include <cstddef>
#include <span>
namespace baos
{
@ -47,6 +48,33 @@ public:
--mBufferedElements;
return true;
}
[[nodiscard]] bool isDataContinuous() const noexcept
{
return mBufferedElements <= mPosition;
}
void normalize() noexcept
{
std::array<T, SIZE> tempElements;
auto it = tempElements.begin();
while (next(*it)) { ++it; }
mBufferedElements = it - tempElements.begin();
mElements = std::move(tempElements);
mPosition = mBufferedElements;
}
std::span<T> getAll(bool reset = true) noexcept
{
if (!isDataContinuous()) {
normalize();
}
std::span<T> result = {mElements.data() + mPosition - mBufferedElements, mBufferedElements};
if (reset) {
mBufferedElements = 0;
}
return result;
}
};
}

View File

@ -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]);
}

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -0,0 +1,79 @@
#include <ctype.h>
#include <cstring>
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;
}
}

View File

@ -0,0 +1,15 @@
#include <errno.h>
namespace
{
constinit int gErrno = 0; // TODO: make this thread-local once there are threads
}
extern "C"
{
int* __errno() noexcept
{
return &gErrno;
}
}

View File

@ -2,7 +2,10 @@
#include <stdio.h>
#include <algorithm>
#include <bit>
#include <limits>
#include <string>
#include <string_view>
#include <stdarg.h>
#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<char, BUFFER_SIZE> 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
{
if (pos != end)
{
*pos = static_cast<char>(chr);
++pos;
}
}
};
class InFile : public __file
{
protected:
static constexpr unsigned BUFFER_SIZE = 4096;
baos::RingBuffer<char, BUFFER_SIZE> mBuffer;
protected:
virtual bool underflow() noexcept = 0;
public:
bool readChar(char& outChar) noexcept override
{
while (!mBuffer.next(outChar))
{
if (!underflow())
{
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
protected:
static constexpr unsigned BUFFER_SIZE = 4096;
baos::RingBuffer<char, BUFFER_SIZE> mWriteBuffer;
protected:
virtual void overflow() noexcept = 0;
public:
void putChar(char chr) noexcept
{
::putchar(chr);
while (mWriteBuffer.full()) {
overflow();
}
mWriteBuffer.append(chr);
if (chr == '\n')
{
overflow();
}
}
void putString(std::string_view str) noexcept
{
for (char chr : str)
{
putChar(chr);
}
}
void flush() noexcept
{
overflow();
}
};
struct BufferPrinter
{
char* pos = nullptr;
char* end = nullptr;
void putchar(int chr) noexcept // NOLINT
{
if (pos != end)
{
*pos = static_cast<char>(chr);
++pos;
}
}
};
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<char> 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<char>(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<char>(chr));
if (chr == '\n')
{
serialWrite(PORT_COM1, '\r');
serialWrite(PORT_COM1, '\n');
}
else
{
serialWrite(PORT_COM1, static_cast<std::uint8_t>(chr));
}
return 0;
#else
char asChar = static_cast<char>(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<RegularPrinter>().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<char*>(std::numeric_limits<std::uintptr_t>::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<OutFile*>(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<OutFile*>(stream)->putChar(static_cast<char>(ch));
return stream->isError() ? EOF : 0;
}
int fputs(const char* str, FILE* stream) noexcept
{
static_cast<OutFile*>(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<OutFile*>(stream))).vprintf(format, vlist);
}
} // extern "C"
namespace std

View File

@ -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<char*>(chr);
}
++chr;
if (!*chr) {
return nullptr;
}
}
}
size_t strlen(const char* str) noexcept
{
size_t len = 0;