I need some help with this GET_LINE function. Is there any easy
way to read in a string, of indeterminite length? For example,
asking the user to input their first name.
This is what I tried:
NAME : STRING (1 .. 40);
TEMP : INTEGER := 40;
GET_LINE(NAME, TEMP);
But that doesn't accomplish what I want. That reads in exactly 40
characters no matter what. Can anyone please help? It
would be very much appreciated!
Thanks,
Mike
: GET_LINE(NAME, TEMP);
Max_Line_Length : constant := 255; -- or whatever
subtype Line_Range_Type is Integer range 1..Max_Line_Length;
subtype Line_Type is String (Line_Range_Type);
Name : Line_Type := (others => ' ');
Last_In : Natural := 0;
Line : Line_Type := (others => ' ');
begin
Text_Io.Get_Line (Item => Name, Last => Last_In);
-- So now you have Name (1..Last_In) entered for the Name !!!
--
Not necessarily the opinion of the company...
--
---------------------------------------------------------------------------
James A. Krzyzanowski - Senior Software Engineer - AFATDS
Magnavox Electronic Systems Company * Fort Wayne, IN 46808 * (219) 429-6446
Internet: jak...@most.magec.com * AOL: jim...@aol.com * MOST: jakrzy@most
"I'd rather be right than politically correct !!!"
---------------------------------------------------------------------------
: I need some help with this GET_LINE function. Is there any easy
: way to read in a string, of indeterminite length? For example,
: asking the user to input their first name.
: This is what I tried:
: NAME : STRING (1 .. 40);
: TEMP : INTEGER := 40;
: GET_LINE(NAME, TEMP);
: But that doesn't accomplish what I want. That reads in exactly 40
: characters no matter what. Can anyone please help? It
: would be very much appreciated!
: Thanks,
: Mike
-- ====================== reply separator =========================
Mike,
Text_IO.Get_Line reads up to the number of characters you enter before
the carriage-return/line-feed. Your variable, Temp, need not be initialized
since it is an out parameter from Get_Line. As an out parameter, it will
contain the actual length of the string entered.
When doing keyboard entry, I usually prefer to define the maximum size of the
string as (1..80) in obeisance to the continual tyranny of the 80-column
card. Other than that, you can freely manipulate string slices using the
actual number of characters entered.
If you had used, instead, Text_IO.Get, you would be required to enter the
exact number of characters.
Richard Riehle
adaw...@netcom.com
>Text_IO.Get_Line reads up to the number of characters you enter before
>the carriage-return/line-feed. Your variable, Temp, need not be initialized
>since it is an out parameter from Get_Line. As an out parameter, it will
>contain the actual length of the string entered.
>When doing keyboard entry, I usually prefer to define the maximum size of the
>string as (1..80) in obeisance to the continual tyranny of the 80-column
>card. Other than that, you can freely manipulate string slices using the
>actual number of characters entered.
One ought to be making this string (1 .. 81) to account for the rare line
that is the full 80 characters. If the string is (1..80) and you're
reading a series of lines, and one of them happens to be 80 characters
before the end-of-line, Text_IO.Get_Line will return from a call with the
first 80 from the line, and then the next call to Text_IO.Get_Line will
hit the end-of-line and come back with a null string as its output, which
is a misleading result.
By making the string (1 .. 81), this condition can't ever occur.
--
Dave Marshall
dmar...@netcom.com
: One ought to be making this string (1 .. 81) to account for the rare line
: that is the full 80 characters. If the string is (1..80) and you're
: reading a series of lines, and one of them happens to be 80 characters
: before the end-of-line, Text_IO.Get_Line will return from a call with the
: first 80 from the line, and then the next call to Text_IO.Get_Line will
: hit the end-of-line and come back with a null string as its output, which
: is a misleading result.
: By making the string (1 .. 81), this condition can't ever occur.
Dave,
Appreciate your note on the potential for exceeding the number 80. As a
person of great antiquity, long constrained by the mental image of a
piece of cardboard riddled with little rectangular holes, I admit that
my solution might fail under the circumstances you suggest.
In reality, if such exists, even 81 might be two small. On an MS-DOS
keyboard I can enter as many as 128 characters at the command prompt
before the operating system begins beeping as a continuous scream.
In revisiting the issue raised by the original post, it occurs to me that
there are other, even more intriguing solutions to this problem which
involve dynamically constrained declarations and access types. The
solution is left as an exercise for the student.
I recommend a function that hides the third param (Last) internally and
returns (unconstrained type) only the number of characters the user typed.
But there's still the question, "What are you assigning the result to?"
(since a string object must be constrained.)
Internally, the function can work the way others have already posted.
---------------------------------------------------------------------------
W. Wesley Groleau INTERNET: wgro...@lear.mitre.org
The MITRE Corporation VOICE: 908-389-6596 (-6732)
145 Wyckoff Road FAX: 908-542-3679
Eatontown, NJ 07724-1842 TEMP. HOME: 908-389-4800 ext. 311
( or P.O. Box 90, Eatontown, NJ -- wa...@freenet.Victoria.BC.CA )
---------------------------------------------------------------------------
function input_line (file : file_type := standard_input) return string;
: But there's still the question, "What are you assigning the result to?"
: (since a string object must be constrained.)
declare
the_line : constant string := input_line;
begin
-- process the line
end;
I did not compile this but is this what you mean?
--
Peter Hermann Tel:+49-711-685-3611 Fax:3758 p...@csv.ica.uni-stuttgart.de
Pfaffenwaldring 27, 70569 Stuttgart Uni Computeranwendungen
Team Ada: "C'mon people let the world begin" (Paul McCartney)
"No, Get_Line always reads an entire line. If the line is more than 80
characters long, only the first 80 characters will be returned, but the
entire line will be read."
This is plain wrong. Ada 83 and Ada 95 are the same, and the description
of Get_Line can be found in RM A.10.7(19)
... reading stops if the end of the string is met ...
Incidentally, annex A is quite easy reading compared to much of the rest
of the RM, and is a workable primary source for an accurate description
of how the standard library routines work.
--
-- The following function is from "Ada Letters, May/June 1989"
-- Volume IX, Number 4
-- in article "Variable-Length String Input in Ada'
-- by Jeffrey R. Carter
--
function get_line(file : text_io.file_type := text_io.current_input)
return string is
char : character;
begin
if text_io.end_of_line(file) then
-- skip line terminator - ready to 'get' next 'line'
text_io.skip_line(file);
return ""; -- null string terminates recursion
else
text_io.get( file, char);
return char & get_line(file);--(FILE => file);
end if;
end get_line;
No, Get_Line always reads an entire line. If the line is more than 80
characters long, only the first 80 characters will be returned, but the
entire line will be read.
Kenneth Almquist
The trick is that if the length of the line you read is exactly
the length of your string, there's no skipline. Of course the RM
describes the mechanism but it's surprising when you first encounter
this feature. A way to proceed :
Line : String (1 .. Max_Line_Length);
Last : Natural;
begin
Get_Line (Line, Last);
if Last = Max_Line_Length and then
End_Of_Line and then
not End_Of_File -- if you use non-Ada generated files
then
Skip_line;
else
-- line too long !
end if;
end;
Hope this help,
Laurent
As my compiler provides an enhanced IO-package, with
function Get_Line (File : File_Type) return String;
I use the construction
declare
The_Line : constant String := Get_Line (myfile);
begin
-- process the line
end;
a lot. It works fine!
--
Leif Euren CelsiusTech Systems AB
Methods & Tools S-175 88 JARFALLA
tel: +46-8-58084072 Sweden
Ouch! This is really slow and the only way to properly handle the
return from this function in Ada 83 is
declare
str : constant String := get_list(file);
begin
-- do something with str
end;
Something I have used many times but do not like. The other alternative,
of course is to use dynamic memory allocation.
Now, some may say "so it's slow", but in every program I have worked on it
has been an issue. Especially after the product is at a demonstration
point and people are shocked at the incredibly poor performance and
immediately blame it on Ada.
Although, it makes my job somewhat easier at times when I have to make
a program perform better :-). In fact, one program received a 200%
increase in performance by removing most of the function calls that
returned unconstrained arrays. It's amazing how much has to be done
to support this.
I'm not saying these kinds of functions are bad, but users need to
weight the penalties vs. convenience/maintainability/etc. for using
this kind of function. Not many people are aware.
--
-- Sean McNeil se...@mcneil.com
No limits? Most implementations have a limit on bounded strings.
Fortunately, that limit is usually high enough to not matter.
The get_lineI suggested does not have the overhead of recursion--which
would be rather extreme if deeper than a "reasonable" string length,
nor (at the source level) of iteration. I now offer an abbreviated
version of it's internals which IMHO are better style (i.e., simple)
AND better performance:
Temp : STRING ( 1 .. Ridiculous );
...
GET_LINE ( File, Temp, Last );
return Temp ( 1 .. Last );
---------------------------------------------------------------------------
W. Wesley Groleau (Wes) INTERNET: wgro...@lear.mitre.org
Sorry, Kenneth. Check RM83, 14.3.6 (13). "... reading also stops if the
end of the string is met."
Phil Brashear
CTA INCORPORATED
Everyone seems to be missing the point that our solutions should
not have artificial constraints! If we are ever to achieve true
software reuse, we need to limit these constraints. What if I want
to feed some 'non human typed' input to the program? Sure the MAX LINE LENGTH
could work provided it is MUCH bigger than 80.
The recursive solution I posted has no limits (other than stack depth :-).
-scott
The point is that Get_Line reads 80 characters but will not
do a Skip_Line. So it depends what you call "entire line" :-)
Laurent
"Everyone seems to be missing the point that our solutions should
not have artificial constraints! If we are ever to achieve true
software reuse, we need to limit these constraints. What if I want
to feed some 'non human typed' input to the program? Sure the MAX LINE LENGTH
could work provided it is MUCH bigger than 80.
The recursive solution I posted has no limits (other than stack depth :-)."
Yes, but it is not a solution that anyone would actually use in a real
program (at least I hope not), because it is so obviously unacceptably
inefficient.
If you want to program something that will indeed read lines of arbitrary
length, then you want to use a nice big line buffer, with some special
code (similar to what Laurent Guerby posted, except that his worry about
"non-Ada generated files" is unnecessary] to deal with the case where the
buffer is full.
" Temp : STRING ( 1 .. Ridiculous );
...
GET_LINE ( File, Temp, Last );
return Temp ( 1 .. Last );"
but the trouble here is choosing ridiculous. If you make ridiculous be
integer'last, then you will surely blow the stack without needing
recursion. If you make it less, then there is the (very small) chance
that the input file will be more ridiculous than your implementation.
That's why a completely accurate solution should check last for being
equal to ridiculous and add (not quite trivial) code to deal with this
case.
This may however be safely left a moot point, in practice you can
choose a perfectly workable value of ridiculous, and this is indeed
the aboslutely standard approach that is typically used in Ada programs.
|> I need some help with this GET_LINE function. Is there any easy
|> way to read in a string, of indeterminite length?
In Ada 95, it makes sense to define your own Get_Line procedure with an
Unbounded_String parameter:
with Ada.Strings.Unbounded, Ada.Text_IO;
use Ada.Strings.Unbounded, Ada.Text_IO;
procedure Get_Line (File: in File_Type; Item: out Unbounded_String);
In Ada 83, you can achieve similar effects with pointers to strings
(remembering to free your dynamically allocated strings when you are done
with them!).
This Get_Line is easily implemented in terms of the standard Get_Line.
The trick is in detecting when the standard Get_Line has read a full line
and moved on to the next one. This can be accomplished by comparing the
current line number (as reported by the function Text_IO.Line) before and
after the call on Get_Line. Here is the Ada-95 code:
procedure Get_Line (File: in File_Type; Item: out Unbounded_String) is
Buffer_Size : constant := 1024;
Buffer : String (1 .. Buffer_Size);
Last : Integer range 0 .. Buffer_Size;
Starting_Line_Number : Positive_Count := Line (File);
begin
Ada.Text_IO.Get_Line (File, Buffer, Last);
Item := To_Unbounded_String ( Buffer(1 .. Last) );
while Line (File) = Starting_Line_Number loop
Ada.Text_IO.Get_Line (File, Buffer, Last);
Append ( Item, Buffer (1 .. Last) );
end loop;
end Get_Line;
(The value chosen for Buffer_Size is arbitrary. Unless you're especially
short on memory, I would choose a size expected to be larger than most
input lines, so that the loop almost never gets executed and is just
there to handle pathological cases.)
--
Norman H. Cohen nco...@watson.ibm.com
|> In article <dewar.805082732@gnat> de...@cs.nyu.edu (Robert Dewar) writes:
|> The trick is that if the length of the line you read is exactly
|> the length of your string, there's no skipline. Of course the RM
|> describes the mechanism but it's surprising when you first encounter
|> this feature.
Well, RM95 describes the mechanism, but RM83 14.3.6(13) is hopelessly
ambiguous about this case. It took a binding interpretation by the ARG,
AI-00050, to resolve the issue for Ada 83. (The ARG produced the Ada
Commentary Integration Document (ACID), a version of RM83 with revised
wording reflecting approved interpretations of the standard, and RM95
uses the ACID description of Get_Line.)
--
Norman H. Cohen nco...@watson.ibm.com
P.S.--My earlier posting giving an Unbounded_String version of Get_Line
assumes that the input file is not divided into multiple pages.
If there is a page consisting of a single line, it will concatenate
this line (line number 1) onto the first line of the next page
(also line number 1). This can be avoided by examining both the
current page number and the current line number rather than just
the current line number.
I have always wished that 'get_line' was a function for just this reason.
Actually not for this reason, but to structure programs that didn't have
to have 'intermediate' results. Instead they can be passed around as parameters
through recursion, etc.
As far as the stack solution being 'obviously unacceptably inefficient'
and never used in a real program.. I beg to differ. I use it all the time.
Placing big 'buffers' somewhere on the stack in not 'obviously' faster.
I'm sure it is slower, but as mentioned before, LIMITS are what seem to
hurt the reuse of programs. Now, again if ADA provided the solution ....
.enough.
-scott
The real limiting factor on line length is imposed by the OS and
if the OS has a limit, make that the size of the buffer.
>This may however be safely left a moot point, in practice you can
>choose a perfectly workable value of ridiculous, and this is indeed
>the aboslutely standard approach that is typically used in Ada programs.
>
Many moons ago, safe limits would have been 80 or 132 characters
since that was the common line limitation of punch cards,
terminals or line printers. Today, that doesn't necessarily apply.
For most user input files, we've found that a line length of 256
characters is never overrun in practice and wouldn't likely impose
any extreme overhead.
What you do with computer generated ASCII files such as Postscript
output from a word processor or other similar situations, I'm not
sure. These sorts of files might get really extreme. I guess
that's where your solution of checking LAST and doing something
with the overflow comes in.
Does Ada95 provide a means of dealing with this in an efficient
manner? I've found most Ada83 implementations bog-slow in using
individual GETs of characters - there ought to be a better way.
Pax,
Marin
Marin David Condic, Senior Computer Engineer ATT: 407.796.8997
M/S 731-93 Technet: 796.8997
Pratt & Whitney, GESP Fax: 407.796.4669
P.O. Box 109600 Internet: COND...@PWFL.COM
West Palm Beach, FL 33410-9600 Internet: MDCO...@AOL.COM
===============================================================================
"A verbal contract isn't worth the paper it's written on."
-- Samuel Goldwyn
===============================================================================
Of course the trouble is that in many (most these days) OS's (DOS, NT,
Unix, OS/2, ...) there is no such limit.
However, you don't have to read individual characters, you can
perfectly well do get_line calls of big chunks, no need to retreat
to reading character by character.
Note that when I say there is no limit, that's not quite right, obviously
the line length is limited by the file size, which has a practical limit
corresponding to c long (because otherwise you can't do lseek's).
Of course, I'm not quite sure if you don't simply end up avoiding
all the overhead of doing individual GETs of characters only to
end up imposing it on yourself all over again as you de-block the
input. (The sort of thing that's needed in lexical analyzers - GET
& UNGET of individual characters, that is...) It might make an
interesting Sience Fair Experiment.
Pax,
Marin
Marin David Condic, Senior Computer Engineer ATT: 407.796.8997
M/S 731-93 Technet: 796.8997
Pratt & Whitney, GESP Fax: 407.796.4669
P.O. Box 109600 Internet: COND...@PWFL.COM
West Palm Beach, FL 33410-9600 Internet: MDCO...@AOL.COM
===============================================================================
"Languages don't kill people. *Programmers* kill people!"
-- Anon.
===============================================================================
ucaa...@iris2.csv.ica.uni-stuttgart.de (Peter Hermann) wrote:
> the_line : constant string := input_line;
>I did not compile this but is this what you mean?
Yes and no. I've done that often, but the person that started the thread
didn`t say why he (she?) wanted an unconstrained Get_Line.
---------------------------------------------------------------------------
W. Wesley Groleau INTERNET: wgro...@lear.mitre.org
In article <3t923s$7...@cronkite.ocis.temple.edu>,
mpu...@astro.ocis.temple.edu (Pu Wei Long) writes:
|> I need some help with this GET_LINE function. Is there any easy
|> way to read in a string, of indeterminite length?
In Ada 95, it makes sense to define your own Get_Line procedure with an
Unbounded_String parameter:
with Ada.Strings.Unbounded, Ada.Text_IO;
use Ada.Strings.Unbounded, Ada.Text_IO;
procedure Get_Line (File: in File_Type; Item: out Unbounded_String);
In Ada 83, you can achieve similar effects with pointers to strings
(remembering to free your dynamically allocated strings when you are done
with them!).
This Get_Line is easily implemented in terms of the standard Get_Line.
The trick is in detecting when the standard Get_Line has read a full line
and moved on to the next one. This can be accomplished by comparing the
current page and line numbers (as reported by the Text_IO functions
Page and Line) before and after the call on Get_Line. Here is the Ada-95
code:
procedure Get_Line (File: in File_Type; Item: out Unbounded_String) is
Buffer_Size : constant := 1024;
Buffer : String (1 .. Buffer_Size);
Last : Integer range 0 .. Buffer_Size;
Starting_Line_Number : Positive_Count := Line (File);
Starting_Page_Number : Positive_Count := Page (File);
begin
Ada.Text_IO.Get_Line (File, Buffer, Last);
Item := To_Unbounded_String ( Buffer(1 .. Last) );
while Line (File) = Starting_Line_Number and then
Page (File) = Starting_Page_Number loop
Ada.Text_IO.Get_Line (File, Buffer, Last);
Append ( Item, Buffer (1 .. Last) );
end loop;
end Get_Line;
(The value chosen for Buffer_Size is arbitrary. Unless you're especially
short on memory, I would choose a size expected to be larger than most
input lines, so that the loop almost never gets executed and is just
there to handle pathological cases. If you never deal with multipage
files, you can eliminate the comparison of page numbers, which is only
needed to detect when you've advanced from line one of a one-line page to
line one of the next page.)
"As far as the stack solution being 'obviously unacceptably inefficient'
and never used in a real program.. I beg to differ. I use it all the time.
Placing big 'buffers' somewhere on the stack in not 'obviously' faster.
I'm sure it is slower, but as mentioned before, LIMITS are what seem to
hurt the reuse of programs. Now, again if ADA provided the solution ...."
Yes it *is* obvious that placing a big buffer somewhere on the stack is
faster. The only difference between allocating 2 bytes and 2000 bytes
on the stack is the difference in time between subtracting 2 and 2000
from the stack pointer (which on most machines takes pretty much the
same time :-)
Maybe I remember Scott's solution wrongly, but I thought he read in
one character at a time, that's really gruesome, never mind the recursion
overhead. Of course it is handy to have a function that has no limits,
but this can be programmed efficiently. I will in a moment post a complete
implementation, setup for incorporation into GNAT (but easily adapted for
use with other compilers).
OK, here it is, remember that you need -gnatg to compile predefined
language units. Or perhaps I should not say "remember" here, since I
am not sure this is properly documented (we do not generally expect
people to be making new language defined units :-)
The spec goes in a-teioau.ads and the body in a-teioau.adb. I will add
this package to the next GNAT release, with the intention that additional
useful subprograms can be added later.
<<I must say, I like the subject line of this thread :-) >>
------------------------------------------------------------------------------
-- --
-- GNAT RUNTIME COMPONENTS --
-- --
-- A D A . T E X T _ I O . A U X --
-- --
-- S p e c --
-- --
-- $Revision: 1.1 $ --
-- --
-- Copyright (c) 1995 ACT, All Rights Reserved --
-- --
-- The GNAT library is free software; you can redistribute it and/or modify --
-- it under terms of the GNU Library General Public License as published by --
-- the Free Software Foundation; either version 2, or (at your option) any --
-- later version. The GNAT library is distributed in the hope that it will --
-- be useful, but WITHOUT ANY WARRANTY; without even the implied warranty --
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
-- Library General Public License for more details. You should have --
-- received a copy of the GNU Library General Public License along with --
-- the GNAT library; see the file COPYING.LIB. If not, write to the Free --
-- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
-- --
------------------------------------------------------------------------------
-- This package provides some auxiliary functions for use with Text_IO
package Ada.Text_IO.Aux is
function Get_Line return String;
-- Read Current_Input and return string that includes all characters
-- from the current character up to the end of the line, with no limit
-- on its length. Raises End_Error if at end of file.
function Get_Line (File : in File_Type) return String;
-- Same, but reads from specified file
end Ada.Text_IO.Aux;
------------------------------------------------------------------------------
-- --
-- GNAT RUNTIME COMPONENTS --
-- --
-- A D A . T E X T _ I O . A U X --
-- --
-- B o d y --
-- --
-- $Revision: 1.1 $ --
-- --
-- Copyright (c) 1995 ACT, All Rights Reserved --
-- --
-- The GNAT library is free software; you can redistribute it and/or modify --
-- it under terms of the GNU Library General Public License as published by --
-- the Free Software Foundation; either version 2, or (at your option) any --
-- later version. The GNAT library is distributed in the hope that it will --
-- be useful, but WITHOUT ANY WARRANTY; without even the implied warranty --
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
-- Library General Public License for more details. You should have --
-- received a copy of the GNU Library General Public License along with --
-- the GNAT library; see the file COPYING.LIB. If not, write to the Free --
-- Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
-- --
------------------------------------------------------------------------------
package body Ada.Text_IO.Aux is
--------------
-- Get_Line --
--------------
-- Current_Input case
function Get_Line return String is
Buffer : String (1 .. 2000);
-- Buffer to read in chunks of remaining line. Will work with any
-- size buffer. We choose a length so that most of the time no
-- recursion will be required.
Last : Natural;
begin
Get_Line (Buffer, Last);
-- If the buffer is not full, then we are all done
if Last < Buffer'Last then
return Buffer (1 .. Last);
-- Otherwise, we still have characters left on the line. Note that
-- as specified by (RM A.10.7(19)) the end of line is not skipped
-- in this case, even if we are right at it now.
else
return Buffer & Get_Line;
end if;
end Get_Line;
-- Case of reading from a specified file. Note that we could certainly
-- share code between these two versions, but these are very short
-- routines, and we may as well aim for maximum speed, cutting out an
-- intermediate call (calls returning string may be somewhat slow)
function Get_Line (File : in File_Type) return String is
Buffer : String (1 .. 2000);
Last : Natural;
begin
Get_Line (File, Buffer, Last);
if Last < Buffer'Last then
return Buffer (1 .. Last);
else
return Buffer & Get_Line (File);
end if;
end Get_Line;
end Ada.Text_IO.Aux;
no, that's wrong, the secondary stack is only used temporarily to return
the result, so it does not grow at all, in this case, even if there is
recursion.
As for the constant, sure .. this is such a trivial piece of code that
one hardly needs to get fanatic about it. I wouldn't even have bothered
to put it in the library, except that it seems a nice starting point
for what may turn out to be a bunch of useful auxiliary routines for
Text_IO. And yes of course you can make the constant smaller if you
want. I suppose if you really want to get fanatical, then you could
make the size be a defaulted argument,
but enough, this is a pretty trivial problem, I am not sure it warrants
much more discussion at this stage :-)
How about some suggestions for other useful functions -- things you
always wanted to see in Text_IO and never found???
> Yes it *is* obvious that placing a big buffer somewhere on the stack is
> faster. The only difference between allocating 2 bytes and 2000 bytes
> on the stack is the difference in time between subtracting 2 and 2000
> from the stack pointer (which on most machines takes pretty much the
> same time :-)
Yes, but I think 2000 byte buffers are overkill for this problem. There
may be other constraints as well (like stack size). I don't know if
pthread stacks grow automatically like the main stack of a UNIX program,
but the Linux pthread package has a default of 64K so there is plenty
of room unless you have something like an embedded system (then you
probably wouldn't be doing get_line calls anyway).
> Maybe I remember Scott's solution wrongly, but I thought he read in
> one character at a time, that's really gruesome, never mind the recursion
> overhead. Of course it is handy to have a function that has no limits,
> but this can be programmed efficiently.
You remember correctly.
> function Get_Line return String is
> Buffer : String (1 .. 2000);
> -- Buffer to read in chunks of remaining line. Will work with any
> -- size buffer. We choose a length so that most of the time no
> -- recursion will be required.
>
IMO, 256 would have been plenty. Also, I haven't looked at the GNAT
code much, but I'd think a constant at the top of the package would
have been better than a hard coded number. I hope this is atypical ;-)
I recall that quite some time ago the GNAT implementation of unconstrained
function return values were discussed. If I remember right, GNAT uses a
secondary stack for this. Is there a limitation on the size of this
secondary stack? Was 2000 chosen to help reduce the secondary stack
requirements? From the solution presented, it appears that if recursion
occurs, the secondary stack requirements will grow alot faster than the
program stack.
> As for the constant, sure .. this is such a trivial piece of code that
> one hardly needs to get fanatic about it. I wouldn't even have bothered
> to put it in the library, except that it seems a nice starting point
> for what may turn out to be a bunch of useful auxiliary routines for
> Text_IO. And yes of course you can make the constant smaller if you
> want. I suppose if you really want to get fanatical, then you could
> make the size be a defaulted argument,
I don't really care, but it's always fun to tease, isn't it?
> How about some suggestions for other useful functions -- things you
> always wanted to see in Text_IO and never found???
How about the one that has been discussed at length recently: File_Exists?
Or has that already made your list? I stopped reading that thread a
while back.
By the way, I think it's great that the GNAT team is willing to extend
the basic libraries with useful items like an Ada.Text_IO.Aux package.
KUTGW
Incidentally, we plan eventually to recognize the existing -pedantic
switch in GCC, to suppress all use of GNAT dependent pragmas and
attributes, and it should probably also suppress non-standard
grand-children of Ada.
I think there shoud be (at least) two categories for code to be detected
by -pedantic. If you have a program that uses GNAT's Ada.Text_IO.Aux and
you port that program, it is easy to compile Ada.Text_IO.Aux with the
other compiler. On the other hand, if you use the 'Img (or 'Mage)
attribute, then you can't get the other compiler to understand it and must
modify your code.
Mats
"I think there shoud be (at least) two categories for code to be detected
by -pedantic. If you have a program that uses GNAT's Ada.Text_IO.Aux and
you port that program, it is easy to compile Ada.Text_IO.Aux with the
other compiler. On the other hand, if you use the 'Img (or 'Mage)
attribute, then you can't get the other compiler to understand it and must
modify your code."
"It is easy to compile Ada.Text_IO.Aux"
not so fast, compilers are allowd to arbitrarily restrict the compilation
of new children of Ada's children, and even if the compiler allows it,
you cannot count on the environment being sufficiently similar. For
instance there might be a name clash.
That is why the use of non-standard grand-children of Ada definitely
SHOULD come under the -pedantic switch. Children of GNAT are another
matter, and indeed in this case it is really more appropriate to make
the new Get_Line function a child of GNAT precisely so that it does not
run into this portability problem.
Didn't you say earlier that this function (or one like it) is already
in a Posix package?
Well, if it isn't anywhere else, I guess I'd like to see some of the
other file management functions, like:
procedure Change_Directory (New_Directory : in String);
function Catalog return Some_Kind_Of_List_Of_Strings_Listing_All_Files;
procedure Rename (Old_Name, New_Name : in String);
procedure Delete (File_Name : in String);
I'm not sure this stuff really counts as "text" I/O, though (The same goes
for File_Exists).
--
T.E.D.
| Work - mailto:denn...@escmail.orl.mmc.com |
| Home - mailto:denn...@iag.net |
| URL - http://www.iag.net/~dennison |
> How about some suggestions for other useful functions -- things you
> always wanted to see in Text_IO and never found???
One that I always end up writing when I need to read and write
enumeration types is one which allows "arbitrary" strings to be
written for each enumeration value, with a default of the enumeration
literal name. This allows for niceties such as mixed case, replacing
underscores, and using reserved words. Of course, the Get function
recognizes the same names, and you need a Set function to change the
name.
Of course if you really want to be ambitious, how about a
(generic) scanner and (generic) parser? For building compilers, you
wouldn't want to rebuild the parser tables every time, but the more I
think about it, this is a very nice and very doable project. For
casual use an LL1 tool would be fine, and assuming that the tool built
a tree, you could use tagged types to associate actions with
productions...
I'll have to think a lot more about that, and probably build the
scanner (lexer) as a prototype...
--
Robert I. Eachus
with Standard_Disclaimer;
use Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...
> I hadn't thought of that! That's pretty darned clever! Any notion
> as to what might make an efficient blocking factor?
Any "reasonable" blocking factor works. The usual values I have
seen have been in the 120-250 range, but nothing wrong with Robert
Dewar's proposed 2K in most Ada implementations.
It takes a long while to get used to the fact that in Ada (and in
APL ;-) arrays and strings should be treated as basic types and
processed as such. Usually, the compiler can generate much better
special case code for things like string processing than the user can
write.
In the case of I/O the speedup is extreme. Even if I need to
parse an input stream myself, I'll usually read it in a line at a time
to avoid all the overhead associated with file system calls.
>That is why the use of non-standard grand-children of Ada definitely
>SHOULD come under the -pedantic switch. Children of GNAT are another
>matter, and indeed in this case it is really more appropriate to make
>the new Get_Line function a child of GNAT precisely so that it does not
>run into this portability problem.
I'm not sure whether this statement came from Robert or Mats, but I
agree with it. Technically and esthetically, I think it's preferable to
keep implementation-dependent packages plainly marked as such. Making
it a grandchild of Ada is misleading, IMHO.
Mike Feldman
I'm not sure whether this statement came from Robert or Mats, but I
agree with it. Technically and esthetically, I think it's preferable to
keep implementation-dependent packages plainly marked as such. Making
it a grandchild of Ada is misleading, IMHO.
Mike, I trust you realize that in some cases, it is essential that the
implementation defined packages be grandchildren of Ada because they
require vsibility to the private part of their parents. That is why
an implementation is allowd to add grand-children to Ada.
True, that is not required for the Get_Line function I did, and I have
indeed moved that to GNAT.IO_Aux, but for example
Ada.Text_IO.C_Streams obviously has to be a grandchild of Ada, since it
needs visibility to the private declaration of Text_IO.File_Type
P.S. for those who have not browsed around GNAT's implementatoin
depednent packages, this one allows extraction of the C stream from an
Ada file, and building an Ada file from a C stream identifier.
> I'm not sure whether this statement came from Robert or Mats, but I
> agree with it. Technically and esthetically, I think it's preferable to
> keep implementation-dependent packages plainly marked as such. Making
> it a grandchild of Ada is misleading, IMHO.
I think Mike's philosophical point of view here misses the fact
that, as written, the package needs to be a child of Ada.Text_IO. It
would be possible, but I think unfriendly, to write the interface as a
generic needing several types from Text_IO as parameters. It would
definitely be more unfriendly to have a hidden means of twiddling
Text_IO state.
>Mike, I trust you realize that in some cases, it is essential that the
>implementation defined packages be grandchildren of Ada because they
>require vsibility to the private part of their parents. That is why
>an implementation is allowd to add grand-children to Ada.
Ah, good point.
>True, that is not required for the Get_Line function I did, and I have
>indeed moved that to GNAT.IO_Aux, but for example
>Ada.Text_IO.C_Streams obviously has to be a grandchild of Ada, since it
>needs visibility to the private declaration of Text_IO.File_Type
Right.
Thanks for the clarification.
Mike Feldman