diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2025-12-18 14:00:03 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2025-12-18 14:00:03 +0100 |
| commit | 8042003647b50e9fddfe500677a132130449d69e (patch) | |
| tree | 82e89f225b8324c91a84d61008c790136d681b5a /kernel | |
| parent | 0c8e77b367ca617beb2c30cd7e032cd9b24aeea4 (diff) | |
| download | teachos-8042003647b50e9fddfe500677a132130449d69e.tar.xz teachos-8042003647b50e9fddfe500677a132130449d69e.zip | |
kapi/cio: implement formatted printing
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/src/kapi/cio.cpp | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/kernel/src/kapi/cio.cpp b/kernel/src/kapi/cio.cpp index 66493b6..500d61e 100644 --- a/kernel/src/kapi/cio.cpp +++ b/kernel/src/kapi/cio.cpp @@ -1,5 +1,10 @@ #include "kapi/cio.hpp" +#include <kstd/format> + +#include <array> +#include <cstddef> +#include <iterator> #include <optional> #include <string_view> #include <utility> @@ -20,6 +25,63 @@ namespace teachos::cio }; constinit null_device null_device::instance; + + struct write_buffer + { + constexpr auto static size = 128uz; + + write_buffer(write_buffer const &) = delete; + write_buffer(write_buffer &&) = delete; + auto operator=(write_buffer const &) -> write_buffer & = delete; + auto operator=(write_buffer &&) -> write_buffer & = delete; + + explicit write_buffer(output_device * device, bool write_to_error) + : m_device{device} + , m_write_to_error{write_to_error} + {} + + ~write_buffer() noexcept + { + flush(); + } + + auto flush() noexcept -> void + { + if (m_position > 0) + { + std::string_view chunk{m_buffer.data(), m_position}; + if (m_write_to_error) + { + m_device->write_error(chunk); + } + else + { + m_device->write(chunk); + } + m_position = 0; + } + } + + auto static callback(void * object, std::string_view text) -> void + { + auto * self = static_cast<write_buffer *>(object); + for (char const character : text) + { + if (self->m_position >= size) + { + self->flush(); + } + self->m_buffer.at(self->m_position++) = character; + } + } + + private: + output_device * m_device; + bool m_write_to_error; + std::array<char, size> m_buffer{}; + std::size_t m_position{}; + }; + } // namespace // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) @@ -54,4 +116,97 @@ namespace teachos::cio active_device->writeln_error(text); } + namespace + { + auto static vprint_impl(std::string_view fmt, kstd::format_args args, bool write_to_error) -> void + { + if (!active_device) + return; + + auto writer = write_buffer{active_device, write_to_error}; + auto context = kstd::format_context{.writer = write_buffer::callback, .user_data = &writer}; + + auto current = fmt.begin(); + auto end = fmt.end(); + auto next_automatic_index = 0uz; + + while (current != end) + { + if (*current != '{') + { + auto start = current; + while (current != end && *current != '{') + { + std::advance(current, 1); + } + context.push(std::string_view(start, current - start)); + continue; + } + + if (std::next(current) != end && *(std::next(current)) == '{') + { + context.push('{'); + std::advance(current, 2); + continue; + } + + std::advance(current, 1); + + auto index = 0uz; + if (current != end && *current >= '0' && *current <= '9') + { + while (current != end && *current >= '0' && *current <= '9') + { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers) + index = index * 10 + static_cast<std::size_t>(*current - '0'); + std::advance(current, 1); + } + } + else + { + index = next_automatic_index++; + } + + auto remaining_fmt = std::string_view{current, static_cast<std::size_t>(std::distance(current, end))}; + + auto const arg = args.get(index); + if (arg.format) + { + auto const after_specs = arg.format(arg.value, remaining_fmt, context); + auto const consumed = remaining_fmt.size() - after_specs.size(); + std::advance(current, consumed); + } + else + { + context.push("{?}"); + while (current != end && *current != '}') + std::advance(current, 1); + } + + if (current != end && *current == '}') + { + std::advance(current, 1); + } + else + { + context.push("{fmt-err}"); + while (current != end && *current != '}') + std::advance(current, 1); + if (current != end) + std::advance(current, 1); + } + } + } + } // namespace + + auto vprint(std::string_view fmt, kstd::format_args args) -> void + { + vprint_impl(fmt, args, false); + } + + auto vprint_error(std::string_view fmt, kstd::format_args args) -> void + { + vprint_impl(fmt, args, true); + } + } // namespace teachos::cio
\ No newline at end of file |
