From f47fda7c8061303c0762c6b11b5f916993ead7ca Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Wed, 17 Jun 2026 10:09:34 +0200 Subject: lib: add basic tc attibute RAII type --- CMakeLists.txt | 8 +++ ttwhy/lib.cppm | 10 +--- ttwhy/main.cpp | 9 ++-- ttwhy/scoped_attributes.cppm | 124 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 13 deletions(-) create mode 100644 ttwhy/scoped_attributes.cppm diff --git a/CMakeLists.txt b/CMakeLists.txt index 4eb75c1..3091b9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,7 @@ target_sources("ttwhy-core" PUBLIC FILES "ttwhy/lib.cppm" + "ttwhy/scoped_attributes.cppm" ) target_include_directories("ttwhy-core" PUBLIC @@ -55,6 +56,13 @@ target_link_libraries("ttwhy-core" PUBLIC "ext::asio" ) +target_compile_options("ttwhy-core" PUBLIC + "$<$:-Wall>" + "$<$:-Wextra>" + "$<$:-Werror>" + "$<$:-pedantic-errors>" +) + ### Main Executable add_executable("ttwhy") diff --git a/ttwhy/lib.cppm b/ttwhy/lib.cppm index c7527ee..fe7486f 100644 --- a/ttwhy/lib.cppm +++ b/ttwhy/lib.cppm @@ -1,11 +1,3 @@ export module ttwhy; -namespace ttwhy -{ - - export auto multiply(int lhs, int rhs) -> int - { - return lhs * rhs; - } - -} // namespace ttwhy +export import :scoped_attributes; diff --git a/ttwhy/main.cpp b/ttwhy/main.cpp index fdaba88..32324c0 100644 --- a/ttwhy/main.cpp +++ b/ttwhy/main.cpp @@ -1,14 +1,15 @@ #include -#include +#include import ttwhy; auto main() -> int { - auto context = asio::io_context{}; - - std::println("The answer is {}", ttwhy::multiply(6, 7)); + auto terminal_attributes = ttwhy::scoped_attributes{fileno(stdin)} // + .canonical_mode(false) + .echo(false); + auto context = asio::io_context{}; context.run(); } diff --git a/ttwhy/scoped_attributes.cppm b/ttwhy/scoped_attributes.cppm new file mode 100644 index 0000000..dd66b54 --- /dev/null +++ b/ttwhy/scoped_attributes.cppm @@ -0,0 +1,124 @@ +module; + +#include +#include +#include +#include +#include + +export module ttwhy:scoped_attributes; + +namespace ttwhy +{ + + auto static read_attributes(int file_descriptor) -> termios + { + auto active_attributes = termios{}; + if (tcgetattr(file_descriptor, &active_attributes)) + { + throw std::system_error(errno, std::system_category(), "failed to read termios attributes"); + } + return active_attributes; + } + + auto static get_line_discipline_flag(int file_descriptor, int flag) -> bool + { + auto active_attributes = read_attributes(file_descriptor); + return active_attributes.c_lflag & flag; + } + + auto static set_line_discipline_flag(int file_descriptor, int flag, bool enabled) -> void + { + auto active_attributes = read_attributes(file_descriptor); + + if ((active_attributes.c_lflag & flag) == enabled) + { + return; + } + + if (enabled) + { + active_attributes.c_lflag = active_attributes.c_lflag | flag; + } + else + { + active_attributes.c_lflag = active_attributes.c_lflag & ~flag; + } + + tcsetattr(file_descriptor, TCSANOW, &active_attributes); + } + + //! Store the current TC attributes and restore them on destruction. + export struct scoped_attributes + { + explicit scoped_attributes(int file_descriptor) + : m_file_descriptor{dup(file_descriptor)} + , m_attributes{read_attributes(file_descriptor)} + {} + + scoped_attributes(scoped_attributes const &) = delete; + + scoped_attributes(scoped_attributes && other) + : m_file_descriptor{std::exchange(other.m_file_descriptor, -1)} + , m_attributes{std::move(other.m_attributes)} + {} + + ~scoped_attributes() + { + if (m_file_descriptor > 0) + { + tcsetattr(m_file_descriptor, TCSANOW, &m_attributes); + } + } + + auto operator=(scoped_attributes const &) -> scoped_attributes & = delete; + + auto operator=(scoped_attributes && other) -> scoped_attributes & + { + std::ranges::swap(m_file_descriptor, other.m_file_descriptor); + std::ranges::swap(m_attributes, other.m_attributes); + return *this; + } + + //! Check if canonical mode is currently active + [[nodiscard]] auto canonical_mode() const noexcept -> bool + { + return get_line_discipline_flag(m_file_descriptor, ICANON); + } + + //! Set whether canonical mode is active or not. + auto canonical_mode(bool enabled) & -> scoped_attributes & + { + set_line_discipline_flag(m_file_descriptor, ICANON, enabled); + return *this; + } + + auto canonical_mode(bool enabled) && -> scoped_attributes + { + set_line_discipline_flag(m_file_descriptor, ICANON, enabled); + return std::move(*this); + } + + [[nodiscard]] auto echo() const noexcept -> bool + { + return get_line_discipline_flag(m_file_descriptor, ECHO); + } + + auto echo(bool enabled) & -> scoped_attributes & + { + set_line_discipline_flag(m_file_descriptor, ECHO, enabled); + return *this; + } + + auto echo(bool enabled) && -> scoped_attributes + { + set_line_discipline_flag(m_file_descriptor, ECHO, enabled); + return std::move(*this); + } + + private: + int m_file_descriptor; + termios m_attributes; + }; + +} // namespace ttwhy -- cgit v1.2.3