diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-07-13 12:00:39 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-07-13 12:00:39 +0200 |
| commit | 48b95e0b46e32f35ea6f16f41ab99286856292bf (patch) | |
| tree | 63360b4044913ad2ffd75834e6cd4aec0b8dc0bc | |
| parent | 9f6b1af8b27d73db12025645aa54f78e352cd77c (diff) | |
| download | kernel-48b95e0b46e32f35ea6f16f41ab99286856292bf.tar.xz kernel-48b95e0b46e32f35ea6f16f41ab99286856292bf.zip | |
kapi: extend panic formatting
| -rw-r--r-- | kapi/kapi/system.hpp | 44 | ||||
| -rw-r--r-- | kernel/kapi/system.cpp | 9 | ||||
| -rw-r--r-- | libs/kstd/kstd/bits/format/formatter/cstring.hpp | 6 | ||||
| -rw-r--r-- | libs/kstd/kstd/bits/format/vformat.cpp | 20 | ||||
| -rw-r--r-- | libs/kstd/kstd/bits/format/vformat.hpp | 44 | ||||
| -rw-r--r-- | libs/kstd/kstd/format.tests.cpp | 90 |
6 files changed, 209 insertions, 4 deletions
diff --git a/kapi/kapi/system.hpp b/kapi/kapi/system.hpp index 8a20af94..f7dd4d7c 100644 --- a/kapi/kapi/system.hpp +++ b/kapi/kapi/system.hpp @@ -1,8 +1,15 @@ #ifndef TEACHOS_KAPI_SYSTEM_HPP #define TEACHOS_KAPI_SYSTEM_HPP +#include <kstd/format.hpp> +#include <kstd/system_error.hpp> + +#include <array> +#include <cstddef> #include <source_location> +#include <span> #include <string_view> +#include <type_traits> namespace kapi::system { @@ -10,6 +17,26 @@ namespace kapi::system //! @addtogroup kapi-system-kernel-defined //! @{ + template<typename... FormatArguments> + struct panic_format_string + { + kstd::format_string<FormatArguments...> format; + std::source_location location; + + template<std::size_t Size> + consteval panic_format_string(char const (&format)[Size], // NOLINT + std::source_location location = std::source_location::current()) + : format{format} + , location{location} + {} + + consteval panic_format_string(std::string_view const & format, + std::source_location location = std::source_location::current()) + : format{format} + , location{location} + {} + }; + //! Terminate kernel execution with the given error message. //! //! This function terminates the execution of the kernel and attempts to issue the given error message to the user. @@ -17,6 +44,14 @@ namespace kapi::system //! @param message The message associated with the panic [[noreturn]] auto panic(std::string_view message, std::source_location = std::source_location::current()) -> void; + //! Termite kernel execution with the given error message and error code. + //! + //! This function terminates the execution of the kernel and attempts to issue the given error message to the user. + //! @param message The message associated with the panic. + //! @param error The erro code associated with the panic. + [[noreturn]] auto panic(std::string_view message, kstd::error_code error, + std::source_location = std::source_location::current()) -> void; + //! @} // end group kernel-defined //! @addtogroup kapi-system-platform-defined @@ -26,6 +61,15 @@ namespace kapi::system auto memory_initialized() -> void; //! @} // end group platform-defined + // + template<typename... FormatArguments> + [[noreturn]] auto panic(panic_format_string<std::type_identity_t<FormatArguments>...> format, + FormatArguments &&... arguments) + { + auto buffer = std::array<char, 512uz>{}; + auto [_, length] = kstd::format_to(std::span{buffer}, format.format, std::forward<FormatArguments>(arguments)...); + panic(std::string_view{buffer.data(), length}, format.location); + } } // namespace kapi::system diff --git a/kernel/kapi/system.cpp b/kernel/kapi/system.cpp index 86c99515..23dadd3a 100644 --- a/kernel/kapi/system.cpp +++ b/kernel/kapi/system.cpp @@ -3,6 +3,7 @@ #include <kapi/cpu.hpp> #include <kstd/print.hpp> +#include <kstd/system_error.hpp> #include <source_location> #include <string_view> @@ -18,4 +19,12 @@ namespace kapi::system cpu::halt(); } + [[gnu::weak]] + auto panic(std::string_view message, kstd::error_code error, std::source_location location) -> void + { + kstd::println(kstd::print_sink::stderr, "[PANIC] in {} : {} ({}:{}) @ {}:{}", location.function_name(), message, + error.category().name(), error.message(), location.file_name(), location.line()); + cpu::halt(); + } + } // namespace kapi::system diff --git a/libs/kstd/kstd/bits/format/formatter/cstring.hpp b/libs/kstd/kstd/bits/format/formatter/cstring.hpp index 553c8caf..12cb9c6f 100644 --- a/libs/kstd/kstd/bits/format/formatter/cstring.hpp +++ b/libs/kstd/kstd/bits/format/formatter/cstring.hpp @@ -5,6 +5,7 @@ #include <kstd/bits/format/formatter.hpp> #include <kstd/bits/format/formatter/string_view.hpp> +#include <cstddef> #include <string_view> namespace kstd @@ -24,6 +25,11 @@ namespace kstd { }; + template<std::size_t Size> + struct formatter<char[Size]> : formatter<char const *> // NOLINT + { + }; + } // namespace kstd #endif
\ No newline at end of file diff --git a/libs/kstd/kstd/bits/format/vformat.cpp b/libs/kstd/kstd/bits/format/vformat.cpp index 495f0a10..7210a0b6 100644 --- a/libs/kstd/kstd/bits/format/vformat.cpp +++ b/libs/kstd/kstd/bits/format/vformat.cpp @@ -1,6 +1,7 @@ #include <kstd/format.hpp> #include <kstd/string.hpp> +#include <algorithm> #include <cstddef> #include <iterator> #include <string_view> @@ -221,4 +222,23 @@ namespace kstd::bits::format return m_size; } + auto span_writer::push(std::string_view text) -> void + { + if (m_position < m_span.size() - 1) + { + auto space_left = m_span.size() - m_position; + auto to_copy = std::min(space_left, text.size()); + std::ranges::copy_n(text.begin(), to_copy, m_span.subspan(m_position).begin()); + m_position += to_copy; + } + } + + auto span_writer::push(char character) -> void + { + if (m_position < m_span.size() - 1) + { + m_span[m_position++] = character; + } + } + } // namespace kstd::bits::format
\ No newline at end of file diff --git a/libs/kstd/kstd/bits/format/vformat.hpp b/libs/kstd/kstd/bits/format/vformat.hpp index 829e0ea4..63b41ab6 100644 --- a/libs/kstd/kstd/bits/format/vformat.hpp +++ b/libs/kstd/kstd/bits/format/vformat.hpp @@ -11,8 +11,10 @@ #include <algorithm> #include <cstddef> #include <iterator> +#include <span> #include <string_view> #include <type_traits> +#include <utility> namespace kstd { @@ -28,7 +30,7 @@ namespace kstd //! @param args The arguments for the format string. auto vformat_to(output_buffer & buffer, std::string_view format, format_args args) -> void; - struct string_writer : output_buffer + struct string_writer final : output_buffer { auto push(std::string_view text) -> void final; auto push(char character) -> void final; @@ -40,7 +42,7 @@ namespace kstd }; //! A buffer that merely records the size of the output written to it. - struct size_recorder : output_buffer + struct size_recorder final : output_buffer { auto push(std::string_view text) -> void final; auto push(char character) -> void final; @@ -52,9 +54,9 @@ namespace kstd }; template<std::output_iterator<char> Output> - struct iterator_writer : output_buffer + struct iterator_writer final : output_buffer { - explicit iterator_writer(Output iterator) + constexpr explicit iterator_writer(Output iterator) : m_output{iterator} {} @@ -77,6 +79,25 @@ namespace kstd Output m_output{}; }; + struct span_writer final : output_buffer + { + constexpr explicit span_writer(std::span<char> span) + : m_span{span} + {} + + auto push(std::string_view text) -> void override; + auto push(char character) -> void override; + + [[nodiscard]] constexpr auto position() const noexcept -> std::size_t + { + return m_position; + } + + private: + std::size_t m_position{}; + std::span<char> m_span{}; + }; + } // namespace bits::format //! Format a given string with the provided arguments. @@ -108,6 +129,21 @@ namespace kstd return buffer.iterator(); } + //! Format a given string with the provided arguments. + //! + //! @param span The span to write to. + //! @param format The format string. + //! @param args The arguments for the format string. + //! @return A pair of the span written to and the next position to write to. + template<typename... ArgumentTypes> + auto format_to(std::span<char> span, format_string<std::type_identity_t<ArgumentTypes>...> format, + ArgumentTypes &&... args) -> std::pair<std::span<char>, std::size_t> + { + auto buffer = bits::format::span_writer{span}; + bits::format::vformat_to(buffer, format.str_view, make_format_args(std::forward<ArgumentTypes>(args)...).args); + return {span, buffer.position()}; + } + //! Determine the number of characters required to format the format string with the given arguments. //! //! @param format The format string. diff --git a/libs/kstd/kstd/format.tests.cpp b/libs/kstd/kstd/format.tests.cpp index d38a8107..a34cf063 100644 --- a/libs/kstd/kstd/format.tests.cpp +++ b/libs/kstd/kstd/format.tests.cpp @@ -2,6 +2,7 @@ #include <catch2/catch_test_macros.hpp> +#include <array> #include <iterator> #include <sstream> #include <string_view> @@ -116,6 +117,95 @@ SCENARIO("Formatting to an output iterator", "[format]") } } +SCENARIO("Formatting to a span", "[format]") +{ + GIVEN("a format string without any placeholders") + { + constexpr auto fmt = "This is a test"sv; + + WHEN("calling format without any arguments.") + { + auto buffer = std::array<char, 100>{}; + auto [span, length] = kstd::format_to(buffer, fmt); + + THEN("the unmodified string is written to the span") + { + REQUIRE(std::string_view{span.data(), length} == "This is a test"); + } + } + + WHEN("calling format with additional arguments") + { + auto buffer = std::array<char, 100>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 1, 2, 3); + + THEN("the unmodified string is written to the span") + { + REQUIRE(std::string_view(span.data(), length) == "This is a test"); + } + } + + WHEN("the span is too small") + { + auto buffer = std::array<char, 4>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 1, 2, 3); + + THEN("the written length is equal to the span size") + { + REQUIRE(length == span.size()); + } + + THEN("only part of the unmodified string is written to the span") + { + REQUIRE(std::string_view(span.data(), length) == "This"); + } + } + } + + GIVEN("a format string with placeholders") + { + constexpr auto fmt = "Here are some placeholders: {} {} {}"sv; + + WHEN("calling format with the same number of arguments as there are placeholders") + { + auto buffer = std::array<char, 100>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 1, true, -100); + + THEN("the formatted string is written to the span") + { + REQUIRE(std::string_view{span.data(), length} == "Here are some placeholders: 1 true -100"); + } + } + + WHEN("calling format with too many arguments") + { + auto buffer = std::array<char, 100>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 2, false, -200, 4, 5, 6); + + THEN("the formatted string is written to the span") + { + REQUIRE(std::string_view{span.data(), length} == "Here are some placeholders: 2 false -200"); + } + } + + WHEN("the span is too small") + { + auto buffer = std::array<char, 4>{}; + auto [span, length] = kstd::format_to(buffer, fmt, 2, false, -200, 4, 5, 6); + + THEN("the written length is equal to the span size") + { + REQUIRE(length == span.size()); + } + + THEN("only part of the unmodified string is written to the span") + { + REQUIRE(std::string_view(span.data(), length) == "Here"); + } + } + } +} + SCENARIO("Determining formatted size") { GIVEN("a format string without any placeholders") |
