comp.lang.ada
 help / color / mirror / Atom feed
* 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

* 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