From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,fabdf3894cea2f63 X-Google-Attributes: gid103376,public From: Matthew Heaney Subject: Re: Weird get_line() Date: 1999/03/30 Message-ID: X-Deja-AN: 460579609 References: NNTP-Posting-Date: Mon, 29 Mar 1999 18:16:04 PDT Newsgroups: comp.lang.ada Date: 1999-03-30T00:00:00+00:00 List-Id: W1bBle 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 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.