How do i prevent this loop from reading if the input ends on a space?

Viewed 371

I just picked up Ada a few minutes ago, so forgive me if this seems like a trivial question.

There is a loop in my program that causes an end error if the input ends with a " " character. My program works for correct input but I'm trying to catch some edge cases.

> echo "1 2 3 " | ./eofloop3a

raised ADA.IO_EXCEPTIONS.END_ERROR : a-textio.adb:506

The loop in question

procedure fun1 is
   F : Integer;
begin
  while (not End_Of_File) loop
    Get(F);
  end loop;
end fun1;

Why is this happening and is there a way to prevent reading out of bounds? I was thinking the while condition should've prevented this from happening.

2 Answers

This is the expected result. It happens because "The exception End_Error is propagated by a Get procedure if an attempt is made to skip a file terminator." In the context of your example input, after Get has read 3, End_Of_File remains False. Get then "skips any leading blanks" and encounters the end of file while attempting to read "the longest possible sequence of characters matching the syntax of a numeric literal."

One solution is to catch the exception and handle it as warranted by your use case. For example,

procedure Fun1 is
   F : Integer;
begin
   while (not End_Of_File) loop
      Get (F);
   end loop;
exception
   when End_Error =>
      Put_Line ("Warning: Ignoring trailing non-numeric data.");
end Fun1;

Also consider catching Data_Error if your program is intended to reject malformed integer literals.

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Main is
   Name : String := "data.txt";
   The_File : File_Type;

begin
   Open(File => The_File,
        Mode => In_File,
        Name => Name);
   
   while not End_Of_File(The_File) loop
      declare
         Str : String := Get_Line(The_File);
         Idx : Positive;
         F   : Integer;
      begin
         Idx := Str'First;
         while Idx <= Str'Last loop
            Get(From => Str(Idx..Str'Last),
                Item => F,
                Last => Idx);
            Put(F'Image);
            Idx := Idx + 1;
         end loop;
         New_Line;
      end;
   end loop;
   Close(The_File);
end Main;

No exceptions generated. Read the input file one line at a time then read from the string generated by the above line read to process each integer. This works without exception even when an input line contains trailing characters.

Related