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 }