aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--ttwhy/lib.cppm10
-rw-r--r--ttwhy/main.cpp9
-rw-r--r--ttwhy/scoped_attributes.cppm124
4 files changed, 138 insertions, 13 deletions
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
+ "$<$<CXX_COMPILER_ID:Clang,GNU>:-Wall>"
+ "$<$<CXX_COMPILER_ID:Clang,GNU>:-Wextra>"
+ "$<$<CXX_COMPILER_ID:Clang,GNU>:-Werror>"
+ "$<$<CXX_COMPILER_ID:Clang,GNU>:-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 <asio/io_context.hpp>
-#include <print>
+#include <stdio.h>
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 <cerrno>
+#include <system_error>
+#include <termios.h>
+#include <unistd.h>
+#include <utility>
+
+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