* Weird get_line() @ 1999-03-28 0:00 W1bBle 1999-03-28 0:00 ` Matthew Heaney 0 siblings, 1 reply; 5+ messages in thread From: W1bBle @ 1999-03-28 0:00 UTC (permalink / raw) I have an extremely strange problem with get_line() In the main part of the program, it functions as normal. However, when it is used inside a loop (like you would need to implement a basic text menu on your terminal) the program appears to "skip" over the get_line() statement, removing the possibility of user input, which kind of defeats the purpose of having a menu. get() suffers no such problems. Any ideas? I'm using the gnat system. Thank you W1bBle -----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Weird get_line() 1999-03-28 0:00 Weird get_line() W1bBle @ 1999-03-28 0:00 ` Matthew Heaney 1999-03-28 0:00 ` W1bBle 0 siblings, 1 reply; 5+ messages in thread From: Matthew Heaney @ 1999-03-28 0:00 UTC (permalink / raw) W1bBle <layabouts@the-giant-sofa.demon.co.uk> writes: > I have an extremely strange problem with get_line() > > In the main part of the program, it functions as normal. However, when it is > used inside a loop (like you would need to implement a basic text menu on > your terminal) the program appears to "skip" over the get_line() statement, > removing the possibility of user input, which kind of defeats the purpose of > having a menu. get() suffers no such problems. Any ideas? I'm using the > gnat system. Make sure your line buffer is larger than (and not just equal) the user's input. Remember that the buffer holds both the actual data entered by the user, and an indication of whether the entire line has been consumed. See my response to the post "Sequential???" on 23 Jan 99 for an explanation of how Get_Line works. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Weird get_line() 1999-03-28 0:00 ` Matthew Heaney @ 1999-03-28 0:00 ` W1bBle 1999-03-29 0:00 ` Matthew Heaney 0 siblings, 1 reply; 5+ messages in thread From: W1bBle @ 1999-03-28 0:00 UTC (permalink / raw) In article <m3soaptpo9.fsf@mheaney.ni.net>, Matthew Heaney <matthew_heaney@acm.org> wrote: > W1bBle <layabouts@the-giant-sofa.demon.co.uk> writes: > > > I have an extremely strange problem with get_line() > > > > In the main part of the program, it functions as normal. However, when it is > > used inside a loop (like you would need to implement a basic text menu on > > your terminal) the program appears to "skip" over the get_line() statement, > > removing the possibility of user input, which kind of defeats the purpose of > > having a menu. get() suffers no such problems. Any ideas? I'm using the > > gnat system. > > Make sure your line buffer is larger than (and not just equal) the > user's input. > > Remember that the buffer holds both the actual data entered by the user, > and an indication of whether the entire line has been consumed. > > See my response to the post "Sequential???" on 23 Jan 99 for an > explanation of how Get_Line works. > > OK, thanks but I already knew that (like in C where you need an array one bigger than the string you have to hold, to handle the /0 chracter). Anyway... I've discovered that after issuing a get() and waiting for the user to input a number (from a menu choice) what was happening was a /0 was left in the input stream. This made the get_line() immediately following it think that you had pressed return. It just processed whatever was left in stdin. So putting a get_line() command immediately after the get() swallows the remaining /0 character and then another get_line() reads the, now meaningful, input from stdin. It appears that both the version of gnat I'm using on Geek Gadgets (on an Amiga but also on BeOS AFAIK) and the version running on an SGI server at my university share this "feature." Is this behaviour part of the specification for get()? Surely it would be designed to swallow that last /0 to prevent erroneous input? Has anyone come across this before??? I only ask because it appears to me to be a bit of an oversight on someone's part... ;) C ya W1bBle -----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Weird get_line() 1999-03-28 0:00 ` W1bBle @ 1999-03-29 0:00 ` Matthew Heaney 0 siblings, 0 replies; 5+ messages in thread From: Matthew Heaney @ 1999-03-29 0:00 UTC (permalink / raw) W1bBle <layabouts@the-giant-sofa.demon.co.uk> writes: > I've discovered that after issuing a get() and waiting for the user to > input a number (from a menu choice) what was happening was a /0 was left > in the input stream. That's because the user put 2 characters in the stream, one for the menu item, and another for the <return>. It's up to you to consume both characters. Don't use Get to fetch the menu item. Use Get_Line: declare Line : String (1 .. 20); Last : Natural; begin <display list of menu items> <<Getting_Selection>> null; Put ("Ready: "); Get_Line (Line, Last); if Last = 0 then goto Terminate_Processing; elsif Last > 1 then Put_Line ("entry too long; try again"); goto Getting_Selection; elsif Line (1) = 'h' then <display list of menu items> goto Getting_Selection; elsif Line (1) = 'x' then goto Terminate_Processing; elsif Line (1) = 'o' then goto Open_File; elsif Line (1) = ... end; Using Get_Line will ensure that all characters are consumed, including the line terminator. > This made the get_line() immediately following it think that you had > pressed return. It just processed whatever was left in stdin. Yes, that is correct, because the <return> is still in the stream. So just always use Get_Line, and don't bother with Get. > So putting a get_line() command immediately after the get() swallows the > remaining /0 character and then another get_line() reads the, now > meaningful, input from stdin. Yes, that is correct. The line terminator was not consumed by the Get, because it only consumed the first character. Get didn't see the line terminator, because it came _after_ the character. > It appears that both the version of gnat I'm using on Geek Gadgets (on > an Amiga but also on BeOS AFAIK) and the version running on an SGI > server at my university share this "feature." Yes, it is a feature. And yes, it does make sense. Get only consumes a line terminator if it sees one _before_ the next non-control character. > Is this behaviour part of the specification for get()? You can read all about Text_IO in section A.10 of your handy-dandy reference manual. > Surely it would be designed to swallow that last /0 to prevent erroneous > input? Surely ... not. It only consumes line terminators that come before non-control characters, not after. What you're suggesting doesn't make any sense. If you want an operation to fetch a char and the line terminator that _follows_ it, then use Get_Line. > Has anyone come across this before??? Yup. When I started learning Ada 12 years ago. > I only ask because it appears to me to be a bit of an oversight on > someone's part... ;) C ya W1bBle Oh I agree with you, there is an oversight on someone's part... My advice to you and everyone else is to always first use Get_Line to transfer characters from standard input, and then internally vet and parse the character string. Don't bother with Get, Skip_Line, Integer_IO.Get, Float_IO.Get, etc. Just use Get_Line. ^ permalink raw reply [flat|nested] 5+ messages in thread
[parent not found: <yam7758.1500.1147822784@post.demon.co.uk>]
* Re: Weird get_line() [not found] <yam7758.1500.1147822784@post.demon.co.uk> @ 1999-03-30 0:00 ` Matthew Heaney 0 siblings, 0 replies; 5+ messages in thread From: Matthew Heaney @ 1999-03-30 0:00 UTC (permalink / raw) W1bBle <layabouts@the-giant-sofa.demon.co.uk> writes: > >Using Get_Line will ensure that all characters are consumed, including > >the line terminator. > > > > Yeah, that's exactly what I suspected was happening. Forgive me for > saying this, but don't you think that because of this the above code > being necessary makes the whole solution less elegant? No, because you're doing something inherently low-level (I/O). If you want something else, you could try playing around with Get_Immediate. > >So just always use Get_Line, and don't bother with Get. > > > > So what was get() designed for? If get_line() was for handling strings > in a competent manner, why even /have/ get() in the first place? Because sometimes you'll want to consume a character at a time. Realize that Text_IO is for reading characters from a file and for reading characters from a human. If you're reading from a file, you may need to read one character at a time, and Get is fine for that. But for reading characters entered by a human user on standard input, it has been my experience that using Get_Line is simpler. Idioms for interaction with a human user are different from the idioms for reading characters out of a file. > >Get didn't see the line terminator, because it came _after_ the > >character. > > Ahem. How does get know when you have finished giving it input if you > don't put in a line terminator? That's an implementation issue. The terminal driver delivers the buffer when you press return, and you're using Get to read characters out of the buffer one at a time. The alternative is to read the characters all at once, by using Get_Line. Another possibility is to use Get_Immediate. It has been my experience that for reading text input from a user, the simplest thing is just use Get_Line for the I/O part (to move the input buffer from standard input to the application), and then interrogate the buffer myself, as a separate step. > >Yes, it is a feature. And yes, it does make sense. Get only consumes a > >line terminator if it sees one _before_ the next non-control character. > > Pardon???!!! Assuming the input stream hasn't been loaded (under a > true unix system) with data from a pipe, and stdin is looking at the > keyboard device (or any other, slow, serial input device, if you see > what I mean...) then how will it know the character that it is > checking at a moment in time, which in this case could be line > terminator, say, is followed by another non control character? I'm not sure I understand your question. The invocation Get (C); won't complete until the user enters a non-control character. You can hit the <return> key all you want, but until you enter a non-control character, Get won't complete. Try it: with Text_IO; use Text_IO; procedure Test_Get is C : Character; begin Get (C); end; > >You can read all about Text_IO in section A.10 of your handy-dandy > >reference manual. > > > > Do you mean that impenetrable, indecipherable heap of ascii that Ada > home has a link to? A.10 isn't all that bad. At some point you're going to have to familiarize yourself with the RM. > >If you want an operation to fetch a char and the line terminator that > >_follows_ it, then use Get_Line. > > But what if it is a number to be loaded into a variable? Do you really > want to write a whole chunk of code to parse a string, figure out (bad > pun) that you have a number, and then shove it in the variable? Did m$ > have a hand in developing this...? ;) No. All I'm saying is to use Get_Line as a means of doing the I/O, to move the input line from the terminal to the application. When you get the line, then you use other mechanisms to convert the string buffer to a number. To convert a string to a value, you can use T'Value: declare Value : constant Integer := Integer'Value (Line (1 .. Last); begin or use: Get (From : in String; Item : out Num; Last : out Positive); as in declare Value : Integer; Last : Positive; begin Get (From => Line (1 .. Last), Item => Value, Last => Last); end; The first method will raise Constraint_Error if the text isn't a number, the second method will raise Data_Error. No, you don't have to write string parsing algorithms yourself. That wasn't what I was advocating. There are other Get operations: Get (Item : out Num; Width : in Field := 0); that combine the two steps, consuming some of the characters from the terminal, checking that the lexeme forms a valid number, and then doing the conversion. I prefer a two-step approach: 1) use Get_Line to move the data to the app 2) use T'Value or Get (From : in String; ...) to convert the string to a number The problem with the other approach is that you have to do a Skip_Line anyway, because Get (Item : out Num; ...) doesn't consume the end-of-line. So you might as well just use Get_Line, which does the Skip_Line automatically. > >My advice to you and everyone else is to always first use Get_Line to > >transfer characters from standard input, and then internally vet and > >parse the character string. > > > >Don't bother with Get, Skip_Line, Integer_IO.Get, Float_IO.Get, etc. > >Just use Get_Line. > > Phwar! Like I said, a lot of work for such a simple task. Or so it > seems to me at least. I think there is a misunderstanding, because the task is not that hard. I meant, Don't use the Get (Item : out Num; ...) operations. I also meant, Do use Get_Line (Line, Last); Get (Line (1 .. Last), Item, Last); or do use Get_Line (Line, Last); Item := I'Value (Line (1 .. Last)); >I've seen C code use OS calls to open up a completely functional > window and type "Hello World" on my Amiga in less lines of code than it would > take to implement this heavyweight string parser. No, you don't have to write a string parser. That has already been done: the operation Get (From : in String; ...), and the attribute T'Value. > And when I think some source I copied out of an assembly book could > reset my machine in 380 bytes of code once compiled I just want to > cry! I think I'm beginning to hate this part of my uni course... :-/ It's not that bad; I may have confused you with my earlier post. > Anyway, thanks for the advice. I think I'll keep in mind the vague operation > of the wonderful get() in the future and compensate accordingly. Remember, there are two Get operations. 1) One to fetch the data and convert it to a number: Get (Item : out Num; ...) 2) Another to just convert a string to a number. Get (From : in String; Item : out Num; ...); I recommend that for processing text entered by a human user, you use the second Get, and not the first. > Its actually cheaper purely in terms of clock cycles just to insert a > get_line() to compensate for get()'s inadequacies. It's not an efficiency issue. You're doing the same work using either techniques: first move data, then convert data. I'm arguing that you keep the work as two explicit steps. > Oh well. I'm sure there's something nice about Ada somewhere. Maybe > she was a pretty girl or something ;) There are many nice things about Ada. You just have to give the language a chance to work for you. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~1999-03-30 0:00 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 1999-03-28 0:00 Weird get_line() W1bBle 1999-03-28 0:00 ` Matthew Heaney 1999-03-28 0:00 ` W1bBle 1999-03-29 0:00 ` Matthew Heaney [not found] <yam7758.1500.1147822784@post.demon.co.uk> 1999-03-30 0:00 ` Matthew Heaney
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox