diff options
| author | Felix Morgner <felix.morgner@gmail.com> | 2026-09-22 17:54:25 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@gmail.com> | 2026-09-22 17:54:25 +0200 |
| commit | 1212a302b500c37420613086a1b85f0659f09d57 (patch) | |
| tree | 76ef77e7f64c6278f7fd6e6148cc4aae1585eef7 /ttwhy/io/scoped_attributes.cppm | |
| parent | a63e7d65293c07e0567cfdafbce693a543bf2a0d (diff) | |
| download | ttwhy-1212a302b500c37420613086a1b85f0659f09d57.tar.xz ttwhy-1212a302b500c37420613086a1b85f0659f09d57.zip | |
lib/io: refactor I/O module
Diffstat (limited to 'ttwhy/io/scoped_attributes.cppm')
| -rw-r--r-- | ttwhy/io/scoped_attributes.cppm | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/ttwhy/io/scoped_attributes.cppm b/ttwhy/io/scoped_attributes.cppm new file mode 100644 index 0000000..5e42e39 --- /dev/null +++ b/ttwhy/io/scoped_attributes.cppm @@ -0,0 +1,135 @@ +module; + +#include <termios.h> +#include <unistd.h> + +#include <cerrno> +#include <system_error> +#include <utility> + +export module ttwhy.io:scoped_attributes; + +namespace ttwhy::io +{ + + 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; + } + + if (::tcsetattr(file_descriptor, TCSANOW, &active_attributes)) + { + throw std::system_error(errno, std::system_category(), "failed to write termios attributes"); + } + } + + //! Store the current TC attributes and restore them on destruction. + export struct scoped_attributes + { + explicit scoped_attributes(int file_descriptor) + : m_file_descriptor{-1} + , m_attributes{} + { + if (isatty(file_descriptor)) + { + m_file_descriptor = dup(file_descriptor); + m_attributes = read_attributes(m_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); + ::close(m_file_descriptor); + } + } + + 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::io |
