]> granicus.if.org Git - neomutt/commitdiff
fix: mutt_any_key_to_continue()
authorRichard Russon <rich@flatcap.org>
Fri, 13 Sep 2019 23:15:52 +0000 (00:15 +0100)
committerRichard Russon <rich@flatcap.org>
Sun, 15 Sep 2019 15:35:02 +0000 (16:35 +0100)
Originally, this function relied on `fflush(stdin)` to clear the input
buffer, but that isn't portable.  This version changes the terminal
settings, temporarily, so that it can read single characters without
blocking, or line-buffering.

curs_lib.c

index 8212d56e919e628d8365816e44d7ee74649522a0..5bad79026306918a1cbe04908adfa6746080d579 100644 (file)
@@ -523,18 +523,6 @@ void mutt_perror_debug(const char *s)
   mutt_error("%s: %s (errno = %d)", s, p ? p : _("unknown error"), errno);
 }
 
-/**
- * mutt_flush_stdin - remove characters from stdin until '\n' or EOF is encountered
- */
-void mutt_flush_stdin(void)
-{
-  int c;
-  do
-  {
-    c = fgetc(stdin);
-  } while ((c != '\n') && (c != EOF));
-}
-
 /**
  * mutt_any_key_to_continue - Prompt the user to 'press any key' and wait
  * @param s Message prompt
@@ -543,28 +531,44 @@ void mutt_flush_stdin(void)
  */
 int mutt_any_key_to_continue(const char *s)
 {
-  struct termios t;
+  struct termios term;
   struct termios old;
 
   int fd = open("/dev/tty", O_RDONLY);
   if (fd < 0)
     return EOF;
-  tcgetattr(fd, &t);
-  memcpy((void *) &old, (void *) &t, sizeof(struct termios)); /* save original state */
-  t.c_lflag &= ~(ICANON | ECHO);
-  t.c_cc[VMIN] = 1;
-  t.c_cc[VTIME] = 0;
-  tcsetattr(fd, TCSADRAIN, &t);
-  fflush(stdout);
+
+  tcgetattr(fd, &old); // Save the current tty settings
+
+  term = old;
+  term.c_lflag &= ~(ICANON | ECHO); // Canonical (not line-buffered), don't echo the characters
+  term.c_cc[VMIN] = 1;    // Wait for at least one character
+  term.c_cc[VTIME] = 255; // Wait for 25.5s
+  tcsetattr(fd, TCSANOW, &term);
+
   if (s)
     fputs(s, stdout);
   else
     fputs(_("Press any key to continue..."), stdout);
   fflush(stdout);
-  int ch = fgetc(stdin);
-  mutt_flush_stdin();
-  tcsetattr(fd, TCSADRAIN, &old);
+
+  char ch = '\0';
+  // Wait for a character.  This might timeout, so loop.
+  while (read(fd, &ch, 1) == 0)
+    ;
+
+  // Change the tty settings to be non-blocking
+  term.c_cc[VMIN] = 0;  // Returning with zero characters is acceptable
+  term.c_cc[VTIME] = 0; // Don't wait
+  tcsetattr(fd, TCSANOW, &term);
+
+  char buf[64];
+  while (read(fd, buf, sizeof(buf)) > 0) // Mop up any remaining chars
+    ;
+
+  tcsetattr(fd, TCSANOW, &old); // Restore the previous tty settings
   close(fd);
+
   fputs("\r\n", stdout);
   mutt_clear_error();
   return (ch >= 0) ? ch : EOF;