aboutsummaryrefslogtreecommitdiff
path: root/src/Terminal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Terminal.c')
-rw-r--r--src/Terminal.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/Terminal.c b/src/Terminal.c
new file mode 100644
index 0000000..6cc24db
--- /dev/null
+++ b/src/Terminal.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "Globals.h"
+#include "Terminal.h"
+
+static struct termios orig_term;
+
+int tty_fd = -1;
+int tty_out_fd = -1;
+int orig_stdout = -1;
+int stdin_is_tty = 0;
+
+void restore_terminal(void) {
+ if (tty_fd >= 0) {
+ tcsetattr(tty_fd, TCSAFLUSH, &orig_term);
+ }
+
+ int restore_fd = tty_out_fd >= 0 ? tty_out_fd : STDOUT_FILENO;
+ dprintf(restore_fd, "\033[?1049l\033[2J\033[?25h\033[0m");
+
+ if (tty_fd >= 0) {
+ close(tty_fd);
+ }
+ if (tty_out_fd >= 0 && tty_out_fd != STDOUT_FILENO) {
+ close(tty_out_fd);
+ }
+ if (orig_stdout >= 0 && orig_stdout != STDOUT_FILENO) {
+ close(orig_stdout);
+ }
+}
+
+static void handle_signal(int sig) {
+ restore_terminal();
+ _exit(128 + sig);
+}
+
+void setup_terminal(void) {
+ signal(SIGINT, handle_signal);
+ signal(SIGTERM, handle_signal);
+
+ if (isatty(STDOUT_FILENO)) {
+ tty_out_fd = STDOUT_FILENO;
+ } else {
+ tty_out_fd = open("/dev/tty", O_WRONLY);
+ if (tty_out_fd < 0) {
+ fprintf(stderr, "Error: cannot open terminal for output\n");
+ exit(1);
+ }
+ }
+
+ tty_fd = open("/dev/tty", O_RDWR);
+ if (tty_fd < 0) {
+ tty_fd = dup(STDIN_FILENO);
+ }
+
+ if (tty_fd < 0) {
+ dprintf(tty_out_fd, "\033[?1049l\033[2J\033[?25h");
+ close(tty_out_fd);
+ fprintf(stderr, "Error: cannot open terminal for keyboard input\n");
+ exit(1);
+ }
+
+ struct termios t;
+ tcgetattr(tty_fd, &orig_term);
+ atexit(restore_terminal);
+ tcgetattr(tty_fd, &t);
+ t.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(tty_fd, TCSAFLUSH, &t);
+ dprintf(tty_out_fd, "\033[?1049l\033[2J\033[?25l");
+}