diff --git a/bastl/include/cstdio b/bastl/include/cstdio index 7cbc106..65cd6fa 100644 --- a/bastl/include/cstdio +++ b/bastl/include/cstdio @@ -4,6 +4,7 @@ #if !defined(BAD_APPLE_OS_CSTDIO_INCLUDED) #define BAD_APPLE_OS_CSTDIO_INCLUDED +#include #include namespace std @@ -21,6 +22,9 @@ using ::fgets; using ::fgetc; using ::getc; using ::getchar; + +bool fgetline(FILE* stream, std::string& outLine) noexcept; +inline bool getline(std::string& outLine) noexcept { return fgetline(stdin, outLine); } } #endif // !defined(BAD_APPLE_OS_CSTDIO_INCLUDED) diff --git a/bastl/include/string b/bastl/include/string index 1f8ed5f..b26a6d6 100644 --- a/bastl/include/string +++ b/bastl/include/string @@ -78,6 +78,15 @@ public: } constexpr basic_string& operator=(std::nullptr_t) = delete; + constexpr basic_string& operator+=(value_type chr) noexcept + { + return append(chr); + } + constexpr basic_string& operator+=(const basic_string& other) noexcept + { + return append(other); + } + [[nodiscard]] constexpr reference operator[](size_type pos) noexcept { return _data[pos]; } [[nodiscard]] constexpr const_reference operator[](size_type pos) const noexcept { return _data[pos]; } @@ -88,8 +97,8 @@ public: [[nodiscard]] constexpr reference front() noexcept { return _data.front(); } [[nodiscard]] constexpr const_reference front() const noexcept { return _data.front(); } - [[nodiscard]] constexpr reference back() noexcept { return _data.back(); } - [[nodiscard]] constexpr const_reference back() const noexcept { return _data.back(); } + [[nodiscard]] constexpr reference back() noexcept { return _data.at(size() - 1); } + [[nodiscard]] constexpr const_reference back() const noexcept { return _data.at(size() - 1); } [[nodiscard]] constexpr pointer data() noexcept { return _data.data(); } [[nodiscard]] constexpr const_pointer data() const noexcept { return _data.data(); } @@ -117,6 +126,29 @@ public: _data.back() = value_type(0); } + constexpr basic_string& append(value_type chr) noexcept + { + _data.back() = chr; + _data.push_back(value_type()); + return *this; + } + constexpr basic_string& append(const basic_string& other) noexcept + { + _data.reserve(_data.size() + other.size()); + _data.resize(_data.size() - 1); + for (char chr : other) + { + _data.push_back(chr); + } + _data.push_back(value_type()); + return *this; + } + constexpr void pop_back() noexcept + { + _data.pop_back(); + _data.back() = value_type(); + } + static inline size_type npos = size_type(-1); }; using string = basic_string; diff --git a/bastl/include/vector b/bastl/include/vector index d1f63af..9e95d55 100644 --- a/bastl/include/vector +++ b/bastl/include/vector @@ -214,6 +214,11 @@ public: ++_size; } + constexpr void pop_back() noexcept + { + resize(size() - 1); + } + template constexpr reference emplace_back(TArgs&&... args) { diff --git a/targets/_any/include/os/tools/ringbuffer.hpp b/targets/_any/include/os/tools/ringbuffer.hpp index 8f4353b..17e62d2 100644 --- a/targets/_any/include/os/tools/ringbuffer.hpp +++ b/targets/_any/include/os/tools/ringbuffer.hpp @@ -19,6 +19,14 @@ private: public: [[nodiscard]] bool full() const noexcept { return mBufferedElements == SIZE; } [[nodiscard]] bool empty() const noexcept { return mBufferedElements == 0; } + [[nodiscard]] std::size_t size() const noexcept { return mBufferedElements; } + + [[nodiscard]] T& operator[](std::size_t index) noexcept { return at(index); } + [[nodiscard]] const T& operator[](std::size_t index) const noexcept { return at(index); } + + [[nodiscard]] T& at(std::size_t index) noexcept { return mElements[(index + mPosition) % SIZE]; } + [[nodiscard]] const T& at(std::size_t index) const noexcept { return mElements[(index + mPosition) % SIZE]; } + bool append(T element) noexcept { if (full()) { @@ -29,6 +37,7 @@ public: mPosition = (mPosition + 1) % SIZE; return true; } + bool next(T& outElement) noexcept { if (empty()) { diff --git a/targets/_any/include/os/tty.hpp b/targets/_any/include/os/tty.hpp index ce539cc..2f0687f 100644 --- a/targets/_any/include/os/tty.hpp +++ b/targets/_any/include/os/tty.hpp @@ -4,6 +4,7 @@ #if !defined(OS_TTY_HPP_INCLUDED) #define OS_TTY_HPP_INCLUDED 1 +#include #include #include @@ -39,9 +40,12 @@ void initialize() noexcept; void setColor(VgaDoubleColor color) noexcept; void putEntryAt(char chr, VgaDoubleColor color, size_t posX, size_t posY) noexcept; void putChar(char chr) noexcept; +void deleteChar() noexcept; void write(const char* data, size_t size) noexcept; void write(const char* data) noexcept; +[[nodiscard]] const std::string& readLine() noexcept; + bool setPSFFont(const void* data, size_t length) noexcept; } // namespace tty diff --git a/targets/_any/src/app/main.cpp b/targets/_any/src/app/main.cpp index bc2a154..d3d49e9 100644 --- a/targets/_any/src/app/main.cpp +++ b/targets/_any/src/app/main.cpp @@ -5,12 +5,12 @@ extern "C" void main() { // __asm__ __volatile__("cli"); + std::string cmd; while(true) { - int chr = std::getchar(); - if (chr != std::EOF) - { - putchar(chr); - } + std::printf("> "); + std::getline(cmd); + cmd.pop_back(); // pop the \n + std::printf("Your command: %s\n", cmd.c_str()); } } diff --git a/targets/_any/src/cstdlib/stdio.cpp b/targets/_any/src/cstdlib/stdio.cpp index 118ed19..8741911 100644 --- a/targets/_any/src/cstdlib/stdio.cpp +++ b/targets/_any/src/cstdlib/stdio.cpp @@ -3,7 +3,6 @@ #include #include -#include "drivers/ps2.hpp" #include "os/serial.hpp" #include "os/tty.hpp" #include "os/tools/printf_helper.hpp" @@ -32,6 +31,41 @@ public: } 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 @@ -64,16 +98,8 @@ class StdinFile : public __file public: bool underflow() noexcept override { - while (mBuffer.empty()) - { - char chr; - while (!mBuffer.full() && baos::ps2::readChar(chr)) - { - mBuffer.append(chr); - if (chr == '\n') { - break; - } - } + for (char chr : tty::readLine()) { + mBuffer.append(chr); } return true; } @@ -186,3 +212,11 @@ char* fgets(char* buffer, int count, FILE* stream) noexcept } } // extern "C" +namespace std +{ +bool fgetline(FILE* stream, std::string& outLine) noexcept +{ + return stream->readLine(outLine); +} +} + diff --git a/targets/_any/src/drivers/ps2.cpp b/targets/_any/src/drivers/ps2.cpp index 57802c8..398d033 100644 --- a/targets/_any/src/drivers/ps2.cpp +++ b/targets/_any/src/drivers/ps2.cpp @@ -51,6 +51,7 @@ const constinit Keymap KEYMAP_EN_US = []() keymap.set(Scancode::Y, 'y', 'Y'); keymap.set(Scancode::Z, 'z', 'Z'); keymap.set(Scancode::ENTER, '\n'); + keymap.set(Scancode::BACKSPACE, '\b'); keymap.set(Scancode::MINUS, '-', '_'); keymap.set(Scancode::EQUALS, '=', '+'); keymap.set(Scancode::TAB, '\t'); @@ -63,6 +64,7 @@ const constinit Keymap KEYMAP_EN_US = []() keymap.set(Scancode::COMMA, ',', '<'); keymap.set(Scancode::DOT, '.', '>'); keymap.set(Scancode::SLASH, '/', '?'); + keymap.set(Scancode::SPACE, ' '); keymap.set(Scancode::KP_ENTER, '\n'); keymap.set(Scancode::KP_0, '0'); @@ -122,9 +124,10 @@ const constinit Keymap KEYMAP_DE_DE = []() keymap.set(Scancode::V, 'v', 'V'); keymap.set(Scancode::W, 'w', 'W'); keymap.set(Scancode::X, 'x', 'X'); - keymap.set(Scancode::Y, 'y', 'Y'); - keymap.set(Scancode::Z, 'z', 'Z'); + keymap.set(Scancode::Y, 'z', 'Z'); + keymap.set(Scancode::Z, 'y', 'Y'); keymap.set(Scancode::ENTER, '\n'); + keymap.set(Scancode::BACKSPACE, '\b'); keymap.set(Scancode::MINUS, '?' /* ß */, '?', '\\'); keymap.set(Scancode::EQUALS, '`' /* ´ */, '`'); keymap.set(Scancode::TAB, '\t'); @@ -137,6 +140,7 @@ const constinit Keymap KEYMAP_DE_DE = []() keymap.set(Scancode::COMMA, ',', ';'); keymap.set(Scancode::DOT, '.', ':'); keymap.set(Scancode::SLASH, '-', '_'); + keymap.set(Scancode::SPACE, ' '); keymap.set(Scancode::KP_ENTER, '\n'); keymap.set(Scancode::KP_0, '0'); diff --git a/targets/_any/src/os/tty.cpp b/targets/_any/src/os/tty.cpp index 8fb56c8..bdb6ef7 100644 --- a/targets/_any/src/os/tty.cpp +++ b/targets/_any/src/os/tty.cpp @@ -3,6 +3,7 @@ #include #include +#include "drivers/ps2.hpp" #include "libs/psf.hpp" #include "os/draw.hpp" #include "os/resources/lat9-08.psf.hpp" @@ -19,6 +20,7 @@ VgaDoubleColor gTerminalColor = VgaDoubleColor(); // uint16_t* gTerminalBuffer = reinterpret_cast(0xB8000); std::vector gTerminalBuffer; psf::Font gTerminalFont; +std::string gReadBuffer; constexpr uint8_t vgaEntryColor(VgaDoubleColor color) { @@ -81,6 +83,17 @@ void putChar(char chr) noexcept } } +void deleteChar() noexcept +{ + if (gTerminalColumn > 0) + { + --gTerminalColumn; + putEntryAt(' ', gTerminalColor, gTerminalColumn, gTerminalRow); + + // TODO: store the length of each line so we can return to the previous one + } +} + void write(const char* data, size_t size) noexcept { for (size_t idx = 0; idx < size; idx++) @@ -94,6 +107,32 @@ void write(const char* data) noexcept write(data, std::strlen(data)); } +const std::string& readLine() noexcept +{ + gReadBuffer.clear(); + while(true) + { + char chr = '\0'; + putChar('_'); + while (!baos::ps2::readChar(chr)); // TODO: arrow key navigation and stuff + deleteChar(); + if (chr == '\b') + { + if (!gReadBuffer.empty()) + { + gReadBuffer.pop_back(); + deleteChar(); + } + continue; + } + gReadBuffer += chr; + putChar(chr); + if (chr == '\n') { + return gReadBuffer; + } + } +} + bool setPSFFont(const void* data, size_t length) noexcept { psf::Font newFont;