do not keep getting a key if reading from stdin fail - iomenu - interactive terminal-based selection menu
 (HTM) git clone git://bitreich.org/iomenu git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/iomenu
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit ab7bc829f2023b41b1edcf1926aa6a973169de41
 (DIR) parent 3d11052f21bd037d4ba92b875e8315016976dfc9
 (HTM) Author: Josuah Demangeon <mail@josuah.net>
       Date:   Wed, 11 Apr 2018 22:03:43 +0200
       
       do not keep getting a key if reading from stdin fail
       
       Diffstat:
         M iomenu.c                            |      60 +++++++++++++++++++-------------
       
       1 file changed, 36 insertions(+), 24 deletions(-)
       ---
 (DIR) diff --git a/iomenu.c b/iomenu.c
       @@ -21,7 +21,6 @@
        
        static struct termios        termios;
        struct winsize                ws;
       -static int                ttyfd;
        static int                linec = 0, matchc = 0, cur = 0;
        static char                **linev = NULL, **matchv = NULL;
        static char                input[LINE_MAX];
       @@ -29,8 +28,8 @@ static int                hsflag = 0;
        char                        *argv0;
        
        /*
       -** Keep the line if it match every token (in no particular order, and allowed to
       -** be overlapping).
       +** Keep the line if it match every token (in no particular order,
       +** and allowed to be overlapping).
        */
        static int
        match_line(char *line, char **tokv)
       @@ -44,18 +43,35 @@ match_line(char *line, char **tokv)
        }
        
        /*
       -** Free the structures, reset the terminal state and exit with an error message.
       +** Free the structures, reset the terminal state and exit with an
       +** error message.
        */
        static void
        die(const char *s)
        {
       -        tcsetattr(ttyfd, TCSANOW, &termios);
       -        close(ttyfd);
       +        if (tcsetattr(STDERR_FILENO, TCSANOW, &termios) == -1)
       +                perror("tcsetattr while dying");
       +        close(STDERR_FILENO);
                perror(s);
                exit(EXIT_FAILURE);
        }
        
        /*
       +** Read one key from stdin and die if it failed to prevent to read
       +** in an endless loop.  This caused the load average to go over 10
       +** at work.  :S
       +*/
       +int
       +getkey(void)
       +{
       +        int c;
       +
       +        if ((c = fgetc(stdin)) == EOF)
       +                die("getting a key");
       +        return c;
       +}
       +
       +/*
        ** Split a buffer into an array of lines, without allocating memory for every
        ** line, but using the input buffer and replacing '\n' by '\0'.
        */
       @@ -266,14 +282,14 @@ top:
                        move(+1);
                        break;
                case CSI('5'):        /* page up */
       -                if (fgetc(stdin) != '~')
       +                if (getkey() != '~')
                                break;
                        /* FALLTHROUGH */
                case ALT('v'):
                        move_page(-1);
                        break;
                case CSI('6'):        /* page down */
       -                if (fgetc(stdin) != '~')
       +                if (getkey() != '~')
                                break;
                        /* FALLTHROUGH */
                case CTL('V'):
       @@ -291,10 +307,10 @@ top:
                        print_selection();
                        return 0;
                case ALT('['):
       -                k = CSI(fgetc(stdin));
       +                k = CSI(getkey());
                        goto top;
                case ESC:
       -                k = ALT(fgetc(stdin));
       +                k = ALT(getkey());
                        goto top;
                default:
                        add_char((char) k);
       @@ -353,12 +369,12 @@ set_terminal(void)
                struct termios        new;
        
                fputs("\x1b[s\x1b[?1049h\x1b[H", stderr);
       -        if (tcgetattr(ttyfd, &termios) < 0 || tcgetattr(ttyfd, &new) < 0) {
       -                perror("tcgetattr");
       -                exit(EXIT_FAILURE);
       -        }
       +        if (tcgetattr(STDERR_FILENO, &termios) == -1 ||
       +            tcgetattr(STDERR_FILENO, &new) == -1)
       +                die("setting terminal");
                new.c_lflag &= ~(ICANON | ECHO | IEXTEN | IGNBRK | ISIG);
       -        tcsetattr(ttyfd, TCSANOW, &new);
       +        if (tcsetattr(STDERR_FILENO, TCSANOW, &new) == -1)
       +                die("tcsetattr");
        }
        
        /*
       @@ -368,7 +384,8 @@ static void
        reset_terminal(void)
        {
                fputs("\x1b[2J\x1b[u\033[?1049l", stderr);
       -        tcsetattr(ttyfd, TCSANOW, &termios);
       +        if (tcsetattr(STDERR_FILENO, TCSANOW, &termios))
       +                die("resetting terminal");
        }
        
        static void
       @@ -378,7 +395,7 @@ sighandle(int sig)
        
                switch (sig) {
                case SIGWINCH:
       -                if (ioctl(ttyfd, TIOCGWINSZ, &ws) < 0)
       +                if (ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1)
                                die("ioctl");
                        print_screen();
                        break;
       @@ -403,11 +420,7 @@ init(void)
                filter(linec, linev);
        
                if (freopen("/dev/tty", "r", stdin) == NULL)
       -                die("freopen /dev/tty");
       -        if (freopen("/dev/tty", "w", stderr) == NULL)
       -                die("freopen /dev/tty");
       -        if ((ttyfd = open("/dev/tty", O_RDWR)) < 0)
       -                die("open /dev/tty");
       +                die("reopening /dev/tty as stdin");
        
                set_terminal();
                sighandle(SIGWINCH);
       @@ -436,12 +449,11 @@ main(int argc, char *argv[])
                pledge("stdio tty", NULL);
        #endif
        
       -        while ((exit_code = key(fgetc(stdin))) > 0)
       +        while ((exit_code = key(getkey())) > 0)
                        print_screen();
        
                print_screen();
                reset_terminal();
       -        close(ttyfd);
        
                return exit_code;
        }