Just for the record, at the Seventh National Ada Conference, 14-16 March, 1989, I
gave a paper titled "How to Live With TEXT_IO" in which I discussed this
problem. I still think the solution I proposed 10 years ago is the best.
Don't use IO instantiations at all. Always use Get_Line to get whatever
characters the user enters, legal or not. Once you have the string, try to
convert it to the numerical value, enumeration values, or whatever. If the
conversion fails, you can prompt the user to enter the value again. There isn't
any problem with the bad characters being in the buffer because you have already
read and processed them.
Michael Feldman wrote:
> [said Randy]
> > Ada.Text_IO.Get is defined to read only legal characters; if it raises an
> > exception it reads NOTHING. Therefore, the illegal characters remain in the
> > input stream; if you do the same read again, you'll get the same error
> > (because the same characters are still there).
> Just a clarification here. It depends a bit more on the situation
> than Randy focused on. Let's take the case of an enumeration type
> type Colors is (red, green, blue);
> Now instantiate Ada.Text_IO.Enumeration_IO for this type:
> package Color_IO is new Ada.Text_IO.Enumeration_IO (Enum => Colors);
> Now Color_IO.Get will try to read valid Colors tokens. But this is
> a 2-stage process: first read a token _syntactically_, then check
> whether it's within the Colors type. If _either_
> (1) Get cannot read a valid token, _or_
> (2) Get did read a token that was syntactically valid but not in Colors,
> Get raises Ada.Text_IO.Data_Error.
> Suppose the input pointer is looking at
> since an enumeration token can;t begin with a digit, Data_Error is
> raised. The RM _requires_ that the character that causes input to cease
> must remain in the input stream. In this case, it was the 1, so nothing
> was consumed!
> Now suppose the input pointer is looking at
> this token is syntactically valid, but not in Colors. The
> character that causes input to cease is the <enter>. Why? Well,
> to know that the token was bad, Get had to read the token! All
> very logical. Trouble is, here as well, Data_Error is raised!
> So the same exception is raised for "syntactic" as well as "semantic"
> invalidity. So the client program gets no info as to whether the
> token was consumed or not.
> Analogous examples can be given for numeric tokens, but the enum ones
> make it really obvious what's going on.
> I run into this with students all the time. I advise them to use the
> Skip_Line hack for simple cases where ditching the line is OK.
> For real "industrial strength" interactive input, AFAIK there is no
> general alternative to reading a line into a string (using Get_Line),
> then parsing the tokens yourself. Of course, the IO libs help here
> by providing a Get-from-string that behaves like the file one.
> The difference is that now your program "owns" the string, and
> can handle an exception by resorting to a char-by-char parse.
> Even this doesn;t solve it entirely, because a string is, by
> definition, an array of _Character_, and if the *&^%$ thing in
> the input is not in Character, I think you're back to Rick's problem.
> > This behavior was defined in Ada 83, and Ada 95 left it alone for
> > compatibility purposes. This is the number one not-a-bug bug report that we
> > get here at RRS, and I wish it had been defined more intuitively...
> Interesting. The original edition of Booch's "Software Engineering
> with Ada" (1983) contained an example of an input loop with exception
> handler. But he had no reliable compiler to test with, so the example
> did not include the Skip_Line. I can remember reading e-mail
> threads just like this one 15 years ago - everyone thought their
> compilers were junk, but in fact it was Booch's example that was junk.
> Needless to say, he corrected the error in his next reprint!
> A REALLY GOOD discussion of interactive input would be a contribution
> to us all. Maybe we can craft one as a group here, and put it on the
> > Randy.
> Mike Feldman