#include #include #include #include #include "os/tools/printf_helper.hpp" #include "os/tools/ringbuffer.hpp" #if defined(__baos_kernel_source__) #include "os/serial.hpp" #include "os/tty.hpp" #else #include "os/syscall.hpp" #endif 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 { while (!mBuffer.next(outChar)) { if (!underflow()) { return false; } } return true; } bool readLine(std::string& outLine) noexcept { outLine.clear(); while(true) { while (mBuffer.empty()) { if (!underflow()) { return false; } } // first check if there is a \n in the stream std::size_t count = mBuffer.size(); for (std::size_t idx = 0; idx < mBuffer.size(); ++idx) { if (mBuffer[idx] == '\n') { count = idx + 1; break; } } outLine.reserve(outLine.size() + count); for (std::size_t idx = 0; idx < count; ++idx) { char chr = '\0'; mBuffer.next(chr); outLine.append(chr); } if (outLine.back() == '\n') { return true; } } } }; namespace { struct RegularPrinter { void putchar(int chr) noexcept // NOLINT { ::putchar(chr); } }; struct BufferPrinter { char* pos = nullptr; char* end = nullptr; void putchar(int chr) noexcept // NOLINT { if (pos != end) { *pos = static_cast(chr); ++pos; } } }; class StdinFile : public __file { public: bool underflow() noexcept override { #if defined(__baos_kernel_source__) for (char chr : tty::readLine()) { mBuffer.append(chr); } return true; #else return false; // TODO!!! #endif } }; StdinFile gStdin; } extern "C" { FILE* __stdin = &gStdin; // 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 } 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 } int printf(const char* format, ...) noexcept { va_list parameters; va_start(parameters, format); const int result = vprintf(format, parameters); va_end(parameters); return result; } int vprintf(const char* format, va_list vlist) BA_CXX_NOEXCEPT { return baos::PrintFHelper().vprintf(format, vlist); } int snprintf(char* buffer, size_t bufferSize, const char* format, ...) noexcept { va_list parameters; va_start(parameters, format); const int result = vsnprintf(buffer, bufferSize, format, parameters); va_end(parameters); return result; } int vsnprintf(char* buffer, size_t bufferSize, const char* format, va_list vlist) noexcept { BufferPrinter printer{ .pos = buffer, .end = bufferSize > 0 ? buffer + bufferSize - 1 : buffer }; const int length = baos::PrintFHelper(printer).vprintf(format, vlist); if (bufferSize > 0) { buffer[std::min(static_cast(bufferSize - 1), length)] = '\0'; } return length; } int fgetc(FILE* stream) noexcept { char chr; if (!stream->readChar(chr)) { return EOF; } return chr; } char* fgets(char* buffer, int count, FILE* stream) noexcept { if (count < 1) { return nullptr; } if (count == 1) { *buffer = '\0'; return buffer; } int pos = 0; for (; pos < count - 1; ++pos) { if (!stream->readChar(buffer[pos])) { if (stream->isError() || pos == 0) { return nullptr; } break; } } buffer[pos] = '\0'; return buffer; } } // extern "C" namespace std { bool fgetline(FILE* stream, std::string& outLine) noexcept { return stream->readLine(outLine); } }