aboutsummaryrefslogtreecommitdiff
path: root/src/Terminal.c
blob: 6cc24db9f4b2841c67f2d92c31c964cceb879ae5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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");
}