Re: variable lenght strings

From: Matthew Heaney (mheaney_at_on2.com)
Date: 10/22/04


Date: Thu, 21 Oct 2004 19:14:19 -0400


"Marius Amado Alves" <amado.alves@netcabo.pt> wrote in message
news:mailman.46.1098398641.10401.comp.lang.ada@ada-france.org...
>> 1) Is it possible to use Get_Line with Unbounded and/or Bounded
>> Strings?
>
> Not in the standard, but subprograms like those are usually around, e.g.
> in the GNAT Library, or end up being written in house.
>
>> 2) If not, how should usei input be managed when lines length isn't
>> known a priori?
>
> There's a way using the standard Get_Line, explained in AdaPower.

Mario is probably referring to an article I posted to CLA a few years' ago,
and which is now archived at the adapower website.

The basic idea is this: algorithms that consume input from a stream need a
way a identify when all of the input has been consumed. Typically this is
done using a special value that you know is outside the range of normal
values, e.g.

declare
   I : Natural;
begin
   loop
     Get (Stream, I);
     exit when I = 0; --the special value
     ... -- do something with I
  end loop;
end;

Text_IO.Get_Line works just like this, except that it's not obvious what the
termination condition is:

declare
   Line : String (1 .. 81);
   Last : Natural;
begin
   loop
     Get_Line (Line, Last);
     .. -- do something with Line (1 .. Last);
    exit when ???
   end loop;
end;

The termination condition is as follows: you know that you've consumed the
entire line when Last < Line'Last. We can now write:

declare
   Line : String (1 .. 81);
   Last : Natural;
begin
   loop
     Get_Line (Line, Last);
     .. -- do something with Line (1 .. Last);
     exit when Last < Line'Last;
   end loop;
end;

Typically you know what a normal line length is, so you declare Line with a
length of Max + 1. (That's why Line'Last is 81 in the examples above.)

Now that you know the termination condition, the next problem is deciding
how to handle a line of input that is longer than your buffer. You can
either handle it as an error, or just copy the buffer into an expandable
string buffer such as Unbounded_String.

If you want, you can use recursion to read the line, and return the string
as a function result:

declare
   function Get_Line (N : Positive := 80) return String is
      Line : String (1 .. N + 1);
      Last : Natural;
   begin
      Get_Line (Line, Last);

      if Last < Line'Last then
        return Line (1 .. Last);
      else
         return Line & Get_Line (2 * N);
      end if;
   end Get_Line;

   Line : constant String := Get_Line;
begin

This avoids the loop, and having to store intermediate results in a buffer.



Relevant Pages

  • Re: why I can not write to the file after initialize the MFC in a service program
    ... you check EVERY return from a call that can fail, ... Why do you need an intermedate buffer to write literal strings anyway? ... For example, if AfxWinInit fails, you copy a 45-character string into a ... So you are going to try to initialize MFC EACH TIME THROUGH THE LOOP? ...
    (microsoft.public.vc.mfc)
  • Re: why I can not write to the file after initialize the MFC in a service program
    ... you check EVERY return from a call that can fail, and any file system call can fail, ... Why do you need an intermedate buffer to write literal strings anyway? ... For example, if AfxWinInit fails, you copy a 45-character string into a 30-character ... So you are going to try to initialize MFC EACH TIME THROUGH THE LOOP? ...
    (microsoft.public.vc.mfc)
  • Re: why I can not write to the file after initialize the MFC in a service program
    ... you don't use char, an obsolete data type ... Why do you need an intermedate buffer to write literal strings anyway? ... For example, if AfxWinInit fails, you copy a 45-character string into a ... So you are going to try to initialize MFC EACH TIME THROUGH THE LOOP? ...
    (microsoft.public.vc.mfc)
  • Re: why I can not write to the file after initialize the MFC in a service program
    ... you don't use char, an obsolete data type ... Why do you need an intermedate buffer to write literal strings anyway? ... For example, if AfxWinInit fails, you copy a 45-character string into a ... So you are going to try to initialize MFC EACH TIME THROUGH THE LOOP? ...
    (microsoft.public.vc.mfc)
  • Re: C string array problems (again)
    ... on the char ** var approach. ... a char string inside a loop and I ... scope and being re-initialized with each loop. ... So why did they declare it ...
    (microsoft.public.vb.general.discussion)