do not keep getting a key if reading from stdin fail - iomenu - interactive terminal-based selection menu
HTML 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
HTML 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;
}