Search code examples
c++windowscygwin

How can I flush stdin? (environment: Mingw compiler, running in xterm or mintty of Cygwin)


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.


Solution

  • 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