tags:

views:

845

answers:

5

I have an application that implements an interactive shell, similar to how the Python console / irb works. The problem now is that if the user accidentally hits ^D EOF is issued and my getline() call returns an empty string which i treat as "no input" and display the prompt again.

This then results in an endless loop that prints the prompt.

Now in Python I would solve that problem by catching EOFError, but in C++ no exception is raised I could catch and there doesn't seem to be a setting on cin to ignore EOF.

Any hints?

+1  A: 

The getline() function signals errors by using the following bits:

  • eofbit
  • failbit
  • badbit

Try checking these before you proceed.

dirkgently
I can check them, but I can't ignore EOF that way. So I can't continue to use the input stream. I could only quit the application which is not what I want.
Armin Ronacher
darnit, you beat me by 1min :) +1
Johannes Schaub - litb
Have you tried cin.clear(); ?
dirkgently
dirkgently, the link links to istream::getline though. chances are high he uses std::getline ( http://www.cplusplus.com/reference/string/getline.html ).
Johannes Schaub - litb
mitsuhiko, just do if(!getline(std::cin, myline)) { std::cin.clear(); std::cout << "behave, please!" << std::endl; }
Johannes Schaub - litb
that did the trick. thanks
Armin Ronacher
@litb: Possible. I get the benefit of the doubt ;-)
dirkgently
restored answer below containing an example.
Johannes Schaub - litb
+2  A: 

If it could not read anything, it sets the failbit. Just test the stream in an if condition, and clear the bit:

if(!getline(std::cin, myline)) {
    std::cin.clear();
    std::cout << "you should enter something" << std::endl;
}

Internally, the sequence is this way in your case:

  • Wait on the terminal for a string. Terminal will block until the user emits a newline. Two probable error cases possible
    1. User presses immediately EOF. This will make getline read nothing at all, and it will set the failbit and the eofbit.
    2. User inputs something and then presses EOF. This will make getline consume something and then it hits EOF while trying to get the next character. This cause eofbit to be set.
  • You will try to read something again. The extraction function will create an object of type istream::sentry which checks in what state the stream is. If any of the errorbits are set, it will cause the extraction function to immediately return. That caused the endless loop before.

A call to clear() clears all error bits, and you can go on reading your stuff again.

Johannes Schaub - litb
A: 

See http://www.horstmann.com/cpp/pitfalls.html

You can use code like:

while (cin)
{  int x;
   cin >> x;
   if (cin) a.push_back(x);
}
Amit Kumar
I don't see how that would solve the problem described.
ypnos
@ypnos the code was meant to be an example, not a solution. Anyway, we now have a solution, thanks to Litb
Amit Kumar
A: 

Ok, in other answers using cin.clear() was described as a possible solution.

Another trick is that you use other means to process the input from the console than the typical standard in by setting the terminal to another mode so you can process Ctrl+D directly. In RAW mode or others, you gain more direct access to the input and control sequences from the user side (like Ctrl+D or Ctrl+C) are not handled elswhere anymore.

Some libraries you may try to gather more information (or even save coding time):

½ You can find some information about your problem in the docs here.

ypnos
+1  A: 

Correct solution thanks to litb:

if (!getline(std::cin, str)) {
    std::cin.clear();
    std::cout << std::endl;
}
Armin Ronacher
Please accept his answer as the right one by clicking on the green arrow thing left to it.
ypnos
Can't do that yet. For reasons unknown to my I just got a new account although I logged in with my existing one :-/
Armin Ronacher
@mitsuhiko Probably you logged in using a different openid account.
Amit Kumar
Got back my account. Seems like stackoverflows OpenID delegate support is a bit buggy
Armin Ronacher