comp.lang.ada
 help / color / mirror / Atom feed
* Text_IO.End_Of_File Problem
@ 2001-11-25 22:42 Hambut
  2001-11-26  1:53 ` Jeffrey Carter
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Hambut @ 2001-11-25 22:42 UTC (permalink / raw)


Hi,

I'm getting an exception with the attached code, and I can't see what
I'm doing wrong, or why it's falling over.

The code basically:

1.  Opens a file (sequential IO)
2.  Fills it with a sequence of Ascii.LF's and ASCII.CR's
3.  Closes it and reopens it as text_io
4.  reads each character in and outputs it's Ascii value to screen.

What *seems* to be happening is that text_io.end_of_file is not
detecting the end of file properly in this case [or I've made some
elementary error (having spent lots of time correcting my errors up to
now I know which option my money's on :-)].  

I'd appreciate it if someone on here could have a peer at this and
give me a pointer as to where I'm going wrong.

The output I get from executing the code is:

"
 13
 13

raised ADA.IO_EXCEPTIONS.END_ERROR : a-textio.adb:394
"

Thanks in advance for any help.

Cheers,

Hambut.

=====Code Follows======

with Text_Io;
with Ada.Sequential_Io;
procedure Eof_Fails is

   package Io is new Ada.Sequential_Io( Character );

   Test_File_Name : constant String := "Test_fails";
   Sequential_File : Io.File_Type;
   Text_File : Text_Io.File_Type;

   Failure_Characters : constant String := ( 1 => Ascii.CR,
					     2 => Ascii.CR,
					     3 => Ascii.LF,
					     4 => Ascii.CR,
					     5 => Ascii.CR,
					     6 => Ascii.LF,
					     7 => Ascii.CR,
					     8 => Ascii.LF );
    
-- These seem to work OK.
--       Failure_Characters : constant String := ( 1 => Ascii.CR,
--                                                 2 => Ascii.CR,
--                                                 3 => Ascii.LF,
--                                                 4 => Ascii.CR );

   C : Character;
begin
   -- First set up the test file
   --
   Io.Create( File => Sequential_File,
              Name => Test_File_Name );

   for I in Failure_Characters'First..Failure_Characters'Last loop
      Io.Write( File => Sequential_File,
                Item => Failure_Characters(I) );
   end loop;

   Io.Close( File => Sequential_File );

   -- Now try and read in as a text file
   --
   Text_Io.Open( File => Text_File,
                 Mode => Text_Io.In_File,
                 Name => Test_File_Name );

   while not Text_Io.End_Of_File( File => Text_File ) loop
      Text_Io.Get( File => Text_File,
                   Item => C );
      Text_Io.Put_Line( Integer'Image( Character'Pos(C)));
    end loop;

   Text_Io.Close( File => Text_File );
exception
   when others =>
      Text_Io.Close( File => Text_File );
      raise;
end Eof_fails;



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-25 22:42 Text_IO.End_Of_File Problem Hambut
@ 2001-11-26  1:53 ` Jeffrey Carter
  2001-11-26 12:30   ` Hambut
  2001-11-26 13:25   ` Hambut
  2001-11-26  2:15 ` Patrick Hohmeyer
  2001-11-26  2:35 ` Nick Roberts
  2 siblings, 2 replies; 11+ messages in thread
From: Jeffrey Carter @ 2001-11-26  1:53 UTC (permalink / raw)


Hambut wrote:
> 
> Hi,
> 
> I'm getting an exception with the attached code, and I can't see what
> I'm doing wrong, or why it's falling over.

It's not falling over, it's terminating with an unhandled exception.

> The output I get from executing the code is:
> 
> "
>  13
>  13
> 
> raised ADA.IO_EXCEPTIONS.END_ERROR : a-textio.adb:394
> "
> 
> =====Code Follows======
> 
> with Text_Io;
> with Ada.Sequential_Io;
> procedure Eof_Fails is
> 
>    package Io is new Ada.Sequential_Io( Character );
> 
>    Test_File_Name : constant String := "Test_fails";
>    Sequential_File : Io.File_Type;
>    Text_File : Text_Io.File_Type;
> 
>    Failure_Characters : constant String := ( 1 => Ascii.CR,
>                                              2 => Ascii.CR,
>                                              3 => Ascii.LF,
>                                              4 => Ascii.CR,
>                                              5 => Ascii.CR,
>                                              6 => Ascii.LF,
>                                              7 => Ascii.CR,
>                                              8 => Ascii.LF );

What you are doing is writing characters that contain embedded within
them what your specific system considers line terminators. Based on your
sample output, I would guess you're running under Win32. On such
systems, a line terminator is a CR followed by an LF. So you have (in
Text_IO terms) 3 lines. The first 2 lines contain a single character,
which is a CR; the 3rd line is null.

Next, note how Ada.Text_IO.Get (Character) works. It skips any line
terminators looking for a character. So your first call to Get reads
item 1 above. The second skips a line terminator (items 2 & 3) and reads
item 4. You are not now at the end of the file, so End_Of_File returns
False. Your 3rd call to get skips 2 line terminators (items 5-8), which
brings you to the end of the file, raising End_Error.

Note that on a different system, with (a) different character(s)
representing a line terminator, you would get different results, but you
could still define a value for Failure_Characters that would cause the
program to raise End_Error even though End_Of_File is False.

> 
> -- These seem to work OK.
> --       Failure_Characters : constant String := ( 1 => Ascii.CR,
> --                                                 2 => Ascii.CR,
> --                                                 3 => Ascii.LF,
> --                                                 4 => Ascii.CR );

This would work on Win32 because after the 2nd call to Get (which reads
item 4), you are at the end of the file, so End_Of_File returns True.

> 
>    C : Character;
> begin
>    -- First set up the test file
>    --
>    Io.Create( File => Sequential_File,
>               Name => Test_File_Name );
> 
>    for I in Failure_Characters'First..Failure_Characters'Last loop

Note that X'First .. X'Last is equivalent to X'range, which is clearer.

>       Io.Write( File => Sequential_File,
>                 Item => Failure_Characters(I) );
>    end loop;
> 
>    Io.Close( File => Sequential_File );
> 
>    -- Now try and read in as a text file
>    --
>    Text_Io.Open( File => Text_File,
>                  Mode => Text_Io.In_File,
>                  Name => Test_File_Name );
> 
>    while not Text_Io.End_Of_File( File => Text_File ) loop
>       Text_Io.Get( File => Text_File,
>                    Item => C );
>       Text_Io.Put_Line( Integer'Image( Character'Pos(C)));
>     end loop;
> 
>    Text_Io.Close( File => Text_File );
> exception
>    when others =>
>       Text_Io.Close( File => Text_File );
>       raise;
> end Eof_fails;

The basic lesson is that Text_IO interprets the characters in your file,
and in the process does not return every character to you. This can
result in some operations reading past the end of the file, although
End_Of_File has just returned False.

-- 
Jeff Carter
"We call your door-opening request a silly thing."
Monty Python & the Holy Grail



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-25 22:42 Text_IO.End_Of_File Problem Hambut
  2001-11-26  1:53 ` Jeffrey Carter
@ 2001-11-26  2:15 ` Patrick Hohmeyer
  2001-11-26 12:36   ` Hambut
  2001-11-26  2:35 ` Nick Roberts
  2 siblings, 1 reply; 11+ messages in thread
From: Patrick Hohmeyer @ 2001-11-26  2:15 UTC (permalink / raw)


Hambut wrote :

> Hi,
> 
> I'm getting an exception with the attached code, and I can't see what
> I'm doing wrong, or why it's falling over.
> 
> The code basically:
> 
> 1.  Opens a file (sequential IO)
> 2.  Fills it with a sequence of Ascii.LF's and ASCII.CR's
> 3.  Closes it and reopens it as text_io
> 4.  reads each character in and outputs it's Ascii value to screen.
> 

<re-arangement>

>    Failure_Characters : constant String := ( 1 => Ascii.CR,
> 2 => Ascii.CR,
> 3 => Ascii.LF,
> 4 => Ascii.CR,
> 5 => Ascii.CR,
> 6 => Ascii.LF,
> 7 => Ascii.CR,
> 8 => Ascii.LF );

In Ada.Text_IO an end_of_line equals CR LF (as in windows)
So your file reads : CR, end_of_line, CR, end_of_line, end_of_line

> What *seems* to be happening is that text_io.end_of_file is not
> detecting the end of file properly in this case [or I've made some
> elementary error (having spent lots of time correcting my errors up to
> now I know which option my money's on :-)].

Get (Item : Character) skips all end_of_line's (and all end_of_page)
and reads the first "normal" character.

But end_of_file just tests the next character, so when the last character
of your file is an end_of_line, an EOF test doesn't prevent
Get (Item : Character) to skip the last end_of_line and depass the EOF.

To get rid of this you must test for an end_of_line and
when you encounter one, skip it with Skip_Line.

Does this pointer helps, or do you want a corrected code?

-- 
Patrick Hohmeyer



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-25 22:42 Text_IO.End_Of_File Problem Hambut
  2001-11-26  1:53 ` Jeffrey Carter
  2001-11-26  2:15 ` Patrick Hohmeyer
@ 2001-11-26  2:35 ` Nick Roberts
  2001-11-26 12:13   ` Hambut
  2 siblings, 1 reply; 11+ messages in thread
From: Nick Roberts @ 2001-11-26  2:35 UTC (permalink / raw)


Hambut, the basic answer is: you cannot mix Ada.Sequential_IO and
Ada.Text_IO! The format in which Sequential_IO writes data is
implementation-dependent, and may not even vaguely correspond to anything
that Text_IO can read back.

I have two questions for you:

(1) WHY were you trying to write with Sequential_IO and then read with
Text_IO?

(2) WHAT do you really want to do?

I will help you with (2) if I can (and if you require).

--
Best wishes,
Nick Roberts






^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-26  2:35 ` Nick Roberts
@ 2001-11-26 12:13   ` Hambut
  2001-11-26 18:00     ` Nick Roberts
  0 siblings, 1 reply; 11+ messages in thread
From: Hambut @ 2001-11-26 12:13 UTC (permalink / raw)


"Nick Roberts" <nickroberts@adaos.worldonline.co.uk> wrote in message news:<9tsbca$4g95n$1@ID-25716.news.dfncis.de>...
> Hambut, the basic answer is: you cannot mix Ada.Sequential_IO and
> Ada.Text_IO! The format in which Sequential_IO writes data is
> implementation-dependent, and may not even vaguely correspond to anything
> that Text_IO can read back.

I appreciate this.  the reason I mixed the two was to get a small
self-contained program to demonstrate my problem.  The actual app uses
text_io to set the file up, and text_io to read the file.  However
doing this I managed to get an exception to occur where I didn't
expect one.  Hence the query.

> 
> I have two questions for you:
> 
> (1) WHY were you trying to write with Sequential_IO and then read with
> Text_IO?

See above.

> 
> (2) WHAT do you really want to do?
> 

What I really want to do is fairly trivial really (or at least should
be), and involves downloading an email, writing it into a file, and
then parsing the email to extract attachments etc.  Currently I'm
downloading the email and saving it into a temporary file, and then
later opening it to pull out the attachment.  Perhaps my real problem
is using text_io to write POP3-type output straight to a file (it adds
a load of superfluous line ends I guess), in which case Sequential_IO
looks more hopeful.

> I will help you with (2) if I can (and if you require).

I'm hoping I won't need help with this, but you're offer is much
appreciated.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-26  1:53 ` Jeffrey Carter
@ 2001-11-26 12:30   ` Hambut
  2001-11-26 16:50     ` Mark Biggar
  2001-11-26 13:25   ` Hambut
  1 sibling, 1 reply; 11+ messages in thread
From: Hambut @ 2001-11-26 12:30 UTC (permalink / raw)


First apologies - I should have specified that I was working on
Wondows with Gnat 3.13p.

Jeffrey Carter <jrcarter@acm.org> wrote in message news:<3C01A0AA.AF2F54BF@acm.org>...
> Hambut wrote:
> > 
> > Hi,
> > 
> > I'm getting an exception with the attached code, and I can't see what
> > I'm doing wrong, or why it's falling over.
> 
> It's not falling over, it's terminating with an unhandled exception.

Well - I do handle it, I just purposely raise it again so I can see
the exception :-).

> > 
> >    Failure_Characters : constant String := ( 1 => Ascii.CR,
> >                                              2 => Ascii.CR,
> >                                              3 => Ascii.LF,
> >                                              4 => Ascii.CR,
> >                                              5 => Ascii.CR,
> >                                              6 => Ascii.LF,
> >                                              7 => Ascii.CR,
> >                                              8 => Ascii.LF );
> 
> What you are doing is writing characters that contain embedded within
> them what your specific system considers line terminators. Based on your
> sample output, I would guess you're running under Win32. On such
> systems, a line terminator is a CR followed by an LF. So you have (in
> Text_IO terms) 3 lines. The first 2 lines contain a single character,
> which is a CR; the 3rd line is null.

Perhaps this is a part of my problem - Reading the secret documents,
and looking at a-textio.ads I noted that LM (Line marker?) was set to
Ascii.LF.

I should have spent more time looking for windows specific docs
perhaps?

> 
> Next, note how Ada.Text_IO.Get (Character) works. It skips any line
> terminators looking for a character. So your first call to Get reads
> item 1 above. The second skips a line terminator (items 2 & 3) and reads
> item 4. You are not now at the end of the file, so End_Of_File returns
> False. Your 3rd call to get skips 2 line terminators (items 5-8), which
> brings you to the end of the file, raising End_Error.
> 
> Note that on a different system, with (a) different character(s)
> representing a line terminator, you would get different results, but you
> could still define a value for Failure_Characters that would cause the
> program to raise End_Error even though End_Of_File is False.
> 

Hmm - OK I understand what you're saying.  I think my naive(?) view
was that End_of_File would return true when there were no more
characters for Get to return.  To me this seems like an intuitive
assumption.

> 
> The basic lesson is that Text_IO interprets the characters in your file,
> and in the process does not return every character to you. This can
> result in some operations reading past the end of the file, although
> End_Of_File has just returned False.

This seems counter-intuitive.  However assuming that it is in line
with the LRM I guess it must be OK.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-26  2:15 ` Patrick Hohmeyer
@ 2001-11-26 12:36   ` Hambut
  0 siblings, 0 replies; 11+ messages in thread
From: Hambut @ 2001-11-26 12:36 UTC (permalink / raw)


Patrick Hohmeyer <pi3_1415926536@yahoo.ca> wrote in message news:<uahM7.2663$3i2.402543@news20.bellglobal.com>...
<snip>

> To get rid of this you must test for an end_of_line and
> when you encounter one, skip it with Skip_Line.
> 

Does this mean I need to do something like:

1.  Test for end_of_line
2.  If true then repeatedly skip_line and test for end_of_line until
it's false
3.  Test for end_of_file??

Hmm doesn't seem to work too well.. Perhaps it needs a repeated test
for end_of_file in 2 when end_of_line is true.

> Does this pointer helps, or do you want a corrected code?


It might help.  Cheers for the reply.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-26  1:53 ` Jeffrey Carter
  2001-11-26 12:30   ` Hambut
@ 2001-11-26 13:25   ` Hambut
  1 sibling, 0 replies; 11+ messages in thread
From: Hambut @ 2001-11-26 13:25 UTC (permalink / raw)


Jeffrey Carter <jrcarter@acm.org> wrote in message news:<3C01A0AA.AF2F54BF@acm.org>...

<snip>

In an earlier reply I said that I thought the way that end_of_file
works seemed non-intuitive.  Well after a little thought it doesn't
seem so non-intuitive now.  So please disregard those comments.

I was mixing end_of_file with an imaginary
'end_of_characters_for_get_to_return' function.  I think there was a
cognitive error in my thoughts at the time.....



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-26 12:30   ` Hambut
@ 2001-11-26 16:50     ` Mark Biggar
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Biggar @ 2001-11-26 16:50 UTC (permalink / raw)


Hambut wrote:
> 
> Hmm - OK I understand what you're saying.  I think my naive(?) view
> was that End_of_File would return true when there were no more
> characters for Get to return.  To me this seems like an intuitive
> assumption.


It may be intuitive, but that assumption requires arbitrarily
far look ahead.  Consider a large file containing a single character
followed by 1,000,000+ line terminators.  Your assumption requires
reading the whole file on encountering the first line terminator.

--
Mark Biggar
mark.a.biggar@home.com



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-26 12:13   ` Hambut
@ 2001-11-26 18:00     ` Nick Roberts
  2001-11-27  9:51       ` Hambut
  0 siblings, 1 reply; 11+ messages in thread
From: Nick Roberts @ 2001-11-26 18:00 UTC (permalink / raw)


Sequential_IO is definitely not what you require. What I need to know now is
how you are getting text from your POP3 server.

If you are able to read text lines from the server, like this:

   Text: String(1..1024); -- arbitrary length
   Last: Natural;
...
   Get_Line(Server,Text,Last);

with the line ends (almost certainly CRLFs) dealt with correctly, you should
have no trouble transferring to a text file, e.g.:

   loop
      if End_of_File(Server) then
         -- deal with premature termination
      end if; -- or catch End_Error
      Get_Line(Server,Text,Last);
      exit when Last=1 and Text(1)='.';
      Put_Line(Temp,Text(1..Last));
   end loop;

regardless of how many blank lines there may be. Of course this must be
preceded and followed by code that sends the right commands to the server (I
forget the commands now, I'm stretching my memory back 10 years as it is ;-)
and interprets its response codes.

Don't forget to close or reset the Temp file. E.g.:

   Close(Temp); -- after writing to it
...
   Open(Temp,In_File,Temp_Name);
   -- now process it for attachments

If your code is just getting TCP segments (rather than whole lines), I
suggest you need a buffer task to deliver actual lines to your main code.

When you come to writing out the attachments, for those which produce binary
data you will need to use Ada.Streams.Stream_IO to write out the binary
data.

Happy to give more detail on any point, if you require.

Does any of this help you?

--
Best wishes,
Nick Roberts


> > (2) WHAT do you really want to do?
> >
>
> What I really want to do is fairly trivial really (or at least should
> be), and involves downloading an email, writing it into a file, and
> then parsing the email to extract attachments etc.  Currently I'm
> downloading the email and saving it into a temporary file, and then
> later opening it to pull out the attachment.  Perhaps my real problem
> is using text_io to write POP3-type output straight to a file (it adds
> a load of superfluous line ends I guess), in which case Sequential_IO
> looks more hopeful.






^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Text_IO.End_Of_File Problem
  2001-11-26 18:00     ` Nick Roberts
@ 2001-11-27  9:51       ` Hambut
  0 siblings, 0 replies; 11+ messages in thread
From: Hambut @ 2001-11-27  9:51 UTC (permalink / raw)


"Nick Roberts" <nickroberts@adaos.worldonline.co.uk> wrote in message news:<9tu05r$4ua5t$1@ID-25716.news.dfncis.de>...
> Sequential_IO is definitely not what you require. 

Perhaps not. It seemed attractive because it doesn't add line ends in,
which would mean that I wouldn't have to strip off the 'CRLF's
returned from the server.  Basically laziness on my part.

I assume you're definitely against the use of sequential_io in this
case is because there's no guarantee (within the standard?) that
text_io would be able to sensibly read it back.  Which seems sensible
in general.

Cheers for the help. I'll no doubt be back with other daft questions.

<snip>

> 
> When you come to writing out the attachments, for those which produce binary
> data you will need to use Ada.Streams.Stream_IO to write out the binary
> data.
> 

A good point.

cheers,

Hambut



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2001-11-27  9:51 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-11-25 22:42 Text_IO.End_Of_File Problem Hambut
2001-11-26  1:53 ` Jeffrey Carter
2001-11-26 12:30   ` Hambut
2001-11-26 16:50     ` Mark Biggar
2001-11-26 13:25   ` Hambut
2001-11-26  2:15 ` Patrick Hohmeyer
2001-11-26 12:36   ` Hambut
2001-11-26  2:35 ` Nick Roberts
2001-11-26 12:13   ` Hambut
2001-11-26 18:00     ` Nick Roberts
2001-11-27  9:51       ` Hambut

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox