1

Suppose I have a program that accepts input from the keyboard, or alternatively accepts redirected input from a file such that:

#include <iostream>

using namespace std;

int main() {
  string str;
  while (getline(cin, str)) {
    if(str.compare("exit") == 0)
      return 0;
  }
  return 0;
}

In this implementation, I expect that an instance of the program using keyboard input will terminate upon typing "exit", and that an instance of the program using file input will terminate upon EOF.

I would like to implement functionality such that if an instance of the program is running that uses file input, it will allow for keyboard input upon reaching EOF, instead of terminating. I have done some research which suggests that this isn't possible with getline as the condition for the while loop, because it will return false once the file input ends, and I don't know of a way to tell cin that I want to accept keyboard input at that time.

So, is it possible for cin to switch from accepting file input to instead accepting keyboard input while the file is running? If it is not, could you explain why?

Anthony Neace
  • 25,013
  • 7
  • 114
  • 129
  • There's `freopen`, but it's non-standard. – chris Mar 25 '13 at 22:23
  • 2
    Actually, this looks like it might work, and it's definitely better: http://stackoverflow.com/questions/4810516/c-redirecting-stdout – chris Mar 25 '13 at 22:24
  • 2
    When you say it uses file input, I assume you mean through a redirection operator, e.g. `./myProg < foo.txt`. In this case, I believe the only way to switch to keyboard input is to open the tty device and talk to it directly. And that's assuming you're even being run from a terminal. – Lily Ballard Mar 25 '13 at 22:27
  • @KevinBallard Yes, you're correct. I would be using a redirection operator from a terminal. Sorry that I didn't clarify. – Anthony Neace Mar 25 '13 at 22:30
  • This is a curious interface you are designing. There are many that read from stdin, and when the user enters some file command, the programs reads the file and then returns to reading stdin, but then you just open another stream to read the file and close it when done. (Sorry for the run on sentence.) – brian beuning Mar 25 '13 at 22:39

2 Answers2

2

Sure you can. The std::cin.rdbuf() function can reassign another I/O buffer to cin. But you have to obtain the buffer first.

When you use the shell to redirect a file to stdin, the file replaces the keyboard. The shell is otherwise responsible for connecting the keyboard to the program, so now you're left on your own. C++ doesn't define a keyboard interface. Unless you want to use a platform-specific one (probably not worth it) the usage convention of the program needs to change a little.

The most standard solution is to add the input file as a command-line option. This can easily be opened up as a std::filebuf buffer object. Pass that to std::cin.rdbuf(), and save the return value. Now std::cin reads from the file. When finished, pass the saved value to rdbuf to restore it to the original stdin file descriptor, which is still connected to the keyboard.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
1

The problem isn't with std::cin. Using std::cin.rdbuf(newBuf) you can switch input sources. However, what's your new input source? ISO C++ has no idea about keyboards. It does know about standard input, but that's already set to the file contents here.

You can wrap the OS level keyboard interface in a std::streambuf interface, but that's of course not portable.

MSalters
  • 173,980
  • 10
  • 155
  • 350