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