fe
terminal file explorer and picker
git clone https://9o.is/git/fe.git
tty.c
(4101B)
1 #include <unistd.h>
2 #include <fcntl.h>
3 #include <stdlib.h>
4 #include <stdarg.h>
5 #include <termios.h>
6 #include <sys/ioctl.h>
7 #include <sys/select.h>
8 #include <signal.h>
9 #include <errno.h>
10 #include "tty.h"
11
12 static void tty_reset(const tty_t *tty) {
13 tcsetattr(tty->fdin, TCSANOW, &tty->original_termios);
14 }
15
16 static void handle_sigwinch(int sig){
17 (void)sig;
18 }
19
20 static void tty_getwinsz(tty_t *tty) {
21 struct winsize ws;
22 if (ioctl(fileno(tty->fout), TIOCGWINSZ, &ws) == -1) {
23 tty->maxwidth = 80;
24 tty->maxheight = 25;
25 } else {
26 tty->maxwidth = ws.ws_col;
27 tty->maxheight = ws.ws_row;
28 }
29 }
30
31 void tty_close(tty_t *tty) {
32 tty_reset(tty);
33 fclose(tty->fout);
34 close(tty->fdin);
35 }
36
37 void tty_init(tty_t *tty, const char *tty_filename) {
38 tty->fdin = open(tty_filename, O_RDONLY);
39 if (tty->fdin < 0) {
40 perror("Failed to open tty");
41 exit(EXIT_FAILURE);
42 }
43
44 tty->fout = fopen(tty_filename, "w");
45 if (!tty->fout) {
46 perror("Failed to open tty");
47 exit(EXIT_FAILURE);
48 }
49
50 if (setvbuf(tty->fout, NULL, _IOFBF, 16384)) {
51 perror("setvbuf");
52 exit(EXIT_FAILURE);
53 }
54
55 if (tcgetattr(tty->fdin, &tty->original_termios)) {
56 perror("tcgetattr");
57 exit(EXIT_FAILURE);
58 }
59
60 struct termios new_termios = tty->original_termios;
61
62 /*
63 * Disable all of
64 * ICANON Canonical input (erase and kill processing).
65 * ECHO Echo.
66 * ISIG Signals from control characters
67 * ICRNL Conversion of CR characters into NL
68 */
69 new_termios.c_iflag &= ~(ICRNL);
70 new_termios.c_lflag &= ~(ICANON | ECHO | ISIG);
71
72 if (tcsetattr(tty->fdin, TCSANOW, &new_termios))
73 perror("tcsetattr");
74
75 tty_getwinsz(tty);
76
77 tty_setnormal(tty);
78
79 signal(SIGWINCH, handle_sigwinch);
80 }
81
82 char tty_getchar(const tty_t *tty) {
83 char ch;
84 int size = read(tty->fdin, &ch, 1);
85 if (size < 0) {
86 perror("error reading from tty");
87 exit(EXIT_FAILURE);
88 } else if (size == 0) {
89 /* EOF */
90 exit(EXIT_FAILURE);
91 } else {
92 return ch;
93 }
94 }
95
96 int tty_input_ready(const tty_t *tty, long int timeout, int return_on_signal) {
97 fd_set readfs;
98 FD_ZERO(&readfs);
99 FD_SET(tty->fdin, &readfs);
100
101 struct timespec ts = {timeout / 1000, (timeout % 1000) * 1000000};
102
103 sigset_t mask;
104 sigemptyset(&mask);
105 if (!return_on_signal)
106 sigaddset(&mask, SIGWINCH);
107
108 int err = pselect(
109 tty->fdin + 1,
110 &readfs,
111 NULL,
112 NULL,
113 timeout < 0 ? NULL : &ts,
114 return_on_signal ? NULL : &mask);
115
116 if (err < 0) {
117 if (errno == EINTR) {
118 return 0;
119 } else {
120 perror("select");
121 exit(EXIT_FAILURE);
122 }
123 } else {
124 return FD_ISSET(tty->fdin, &readfs);
125 }
126 }
127
128 static void tty_sgr(tty_t *tty, int code) {
129 tty_printf(tty, "%c%c%im", 0x1b, '[', code);
130 }
131
132 void tty_setfg(tty_t *tty, int fg) {
133 if (tty->fgcolor != fg) {
134 tty_sgr(tty, 30 + fg);
135 tty->fgcolor = fg;
136 }
137 }
138
139 void tty_setinvert(tty_t *tty) {
140 tty_sgr(tty, 7);
141 }
142
143 void tty_setnormal(tty_t *tty) {
144 tty_sgr(tty, 0);
145 tty->fgcolor = 9;
146 }
147
148 void tty_newline(tty_t *tty) {
149 tty_printf(tty, "%c%cK\n", 0x1b, '[');
150 }
151
152 void tty_clearline(tty_t *tty) {
153 tty_printf(tty, "%c%cK\r", 0x1b, '[');
154 }
155
156 void tty_setcol(tty_t *tty, int col) {
157 tty_printf(tty, "%c%c%iG", 0x1b, '[', col + 1);
158 }
159
160 void tty_moveup(tty_t *tty, int i) {
161 tty_printf(tty, "%c%c%iA", 0x1b, '[', i);
162 }
163
164 void tty_title(tty_t *tty, char *title) {
165 tty_printf(tty, "\033]0;%s\007", title);
166 }
167
168 void tty_printf(tty_t *tty, const char *fmt, ...) {
169 va_list args;
170 va_start(args, fmt);
171 vfprintf(tty->fout, fmt, args);
172 va_end(args);
173 }
174
175 void tty_flush(tty_t *tty) {
176 fflush(tty->fout);
177 }
178
179 size_t tty_getheight(const tty_t *tty) {
180 return tty->maxheight;
181 }
182
183 void tty_hide_cursor(tty_t *tty) {
184 fputs("\x1b[?25l", tty->fout);
185 }
186
187 void tty_unhide_cursor(tty_t *tty) {
188 fputs("\x1b[?25h", tty->fout);
189 }