1

There are two ways that I know to flush stdin:

(1) bool FlushConsoleInputBuffer(_In_ HANDLE hConsoleInput); (2) fflush (stdin);

However, in my environment:

Compiler: MinGW  g++
Running in: Windows, Cygwin xterm or Cygwin mintty

Neither of them works.

What can I do?

Note: FlushConsoleInputBuffer() works if my program runs under dos prompt window. In addition, FlushConsoleInputBuffer() nicely returns false, when it runs on Cygwin xterm or mintty.

--UPDATE--

I suspect that Cygwin handles stdin separately than Windows native stdin, which make FlushConsoleInputBuffer() fail.

@wallyk: yes. 'flush' means dropping all unread buffered inputs.

--UPDATE-- (final answer accepted and reason)

Tony D is right. The problem is that Cygwin terminal is a unix-like terminal, which allows editing before 'ENTER' key is hit. Thus any partial input must be buffered and will never be passed to stdin before the 'ENTER' key is hit, since it expects editing commands. I guess it should be possible to overcome this by setting terminal to raw mode (not experimented). Yet the editing feature will be lost in the raw mode.

Robin Hsu
  • 4,164
  • 3
  • 20
  • 37
  • 2
    By *flush*, you mean "drop all input sent which has not been read yet by the program", right? – wallyk Aug 24 '15 at 03:59
  • Have you tried doing *both* 1 and 2? If all else fails, you could create an extra thread, which reads all input immediately and buffers it for rest of the program. Then you could easily add "discard all currently read input" function... – hyde Aug 24 '15 at 04:10
  • @hyde neither 1 or 2 works. An extra thread reading input may be able to solve the problem, but the last read, which will be blocked, waiting for the next input, will need a timeout and an abort, in order to simulate the discard function. Not an elegant way, but should be working (and "how to abort a stdin read" may still be a problem.) – Robin Hsu Aug 24 '15 at 06:29
  • What I meant with my comment is, things are buffered in two places. First of all there is buffer in the OS for stuff the application hasn't read yet. And then there is the buffer in the standard library, which may have more data (several keystrokes or lines), than what the application code has actually read yet. And you need to discard everything in both. – hyde Aug 24 '15 at 07:49
  • About threaded approach, it doesn't need timeout in order be able to flush, because the main thread can discard the buffer. The input thread would just block reading, and add to buffer (which needs to be thread safe, obviously). For aborting you still may need some mechanism, indeed, so timeout for that purpose would be useful (but that one linked question seems to have solution for that). – hyde Aug 24 '15 at 07:55
  • Thanks. You are right. – Robin Hsu Aug 24 '15 at 09:44

2 Answers2

2

fflush is meant to be used with an output stream. The behavior of fflush(stdin) is undefined. See http://en.cppreference.com/w/cpp/io/c/fflush.

If you use std::cin to access stdin, you can use std::istream::ignore() to ignore the contents of the stream up to a given number of characters or a given character.

Example:

// Ignore the rest of the line.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Working code: http://ideone.com/Z6zLue

If you are using stdin to access the input stream, you can use the following to ignore the rest of the line.

while ( (c = fgetc(stdin)) != '\n' && c != EOF);

Working code: http://ideone.com/gg0Az2

R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

Discarding exactly and only the data currently buffered/available to stdin isn't supported using only C++ Standard library features.

Most of the time, programmers just ignore (see example at the bottom of that page) the rest of a problematic line then try the next buffered line. If you're concerned there may be a lot of problematic lines - for example, that the user may have cut-and-pasted pages of nonsense that you want to discard, but then you do want to give them a chance to enter further lines, you need to use an OS-specific function to work out when a read on stdin would block. You'd then ignore lines until that would-block condition is true.

select and poll are two such operations that work on most Operating Systems, but from memory they're only defined for socket streams on Windows so of no use to you. Cygwin may or may not support them somehow; if you want to try it - you would ignore lines as long as the stdin file descriptor (which is 0) tests readable. You'll find lots of other Q&A discussing how to see if there's input available: e.g. checking data availability before calling std::getline, Check if stdin is empty, Win32 - read from stdin with timeout

Keep in mind that your terminal program is probably internally buffering what you type until you press ENTER, so at most your program can clear the earlier lines but not a line the user's partially typed (though you could use some heuristic to discard it after it's sent to your program's stdin).

UPDATE

Cruder alternatives that might be good enough in some circumstances:

  • save the now() time, then loop calling getline(std::cin, my_string) until either it fails (e.g. EOF on stdin) or the time between reads is greater than some threshold - say half a second; that way it's likely to consume the already-buffered but unwanted input, and yet ENTER for further hand-typed user input's likely to happen after the discarding loop's terminated: you could prompt ala std::cout >> "bad input discarded - you may press ^U to clear your input buffer if it contains unwanted text...\n"; (Control-U works for many terminals, but check your own)

  • have a particular string like say "--reset--" that the user knows they can type to stop discarding lines and switch back to processing future lines

Community
  • 1
  • 1
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • I know it's not supported by C++, and that's why I mentioned windows API: `bool FlushConsoleInputBuffer(_In_ HANDLE hConsoleInput);` I am asking specifically for Windows Cygwin Xterm/mintty. Yet it does work if it's command prompt window 'cmd'. – Robin Hsu Aug 24 '15 at 06:33
  • @RobinHsu: so - you could try the select/poll option and see if that does work for you in those terminals. Separately, in your comment on R Sahu's answer you say *"It won't work if the unread input are [...] without a line end."* - as above, terminals tend to buffer per line. You may want to use a library that handles character-by-character input, such as ncurses. The `readline` library might give you ways to clear partial lines too, but I'm not sure. – Tony Delroy Aug 24 '15 at 07:09
  • @RobinHsu: FWIW, I added a couple hacky approaches that might be practical for you (or might not), but are at least easy and quick to code.... – Tony Delroy Aug 24 '15 at 09:28