aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2025-12-18 14:00:03 +0100
committerFelix Morgner <felix.morgner@ost.ch>2025-12-18 14:00:03 +0100
commit8042003647b50e9fddfe500677a132130449d69e (patch)
tree82e89f225b8324c91a84d61008c790136d681b5a /kernel
parent0c8e77b367ca617beb2c30cd7e032cd9b24aeea4 (diff)
downloadteachos-8042003647b50e9fddfe500677a132130449d69e.tar.xz
teachos-8042003647b50e9fddfe500677a132130449d69e.zip
kapi/cio: implement formatted printing
Diffstat (limited to 'kernel')
-rw-r--r--kernel/src/kapi/cio.cpp155
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