9

I have defined

subtype String10 is String(1..10);

and I am attempting to get keyboard input to it without having to manually enter whitespace before hitting enter. I tried get_line() but from some reason it wouldn't actually wait for input before outputting the get put() command, and I also think it will just leave whatever was in the string before there and not fill it with white space.

I know about and have used Bounded_String and Unbounded_String, but I am wondering if there is a way to make this work.

I've tried making a function for it:

--getString10--
procedure getString10(s : string10) is
   c : character;
   k : integer;
begin
   for i in integer range 1..10 loop
      get(c);
      if Ada.Text_IO.End_Of_Line = false then
         s(i) := c;
      else
         k := i;
         exit;
      end if;
   end loop;

   for i in integer range k..10 loop
      s(i) := ' ';
   end loop;
end getString10;

but, here, I know the s(i) doesn't work, and I don't think the

"if Ada.Text_IO.End_Of_Line = false then" 

does what I'm hoping it will do either. It's kinda just a placeholder while I look for the actual way to do it.

I been searching for a couple hours now, but Ada documentation isn't as available or clear as other languages. I've found a lot about getting strings, but not what I'm looking for.

Keith M
  • 853
  • 10
  • 28
user1279914
  • 185
  • 1
  • 5
  • 19
  • 1
    Equality comparisons to `true` and `false` are not particularly clear. Rather than `if Ada.Text_IO.End_Of_Line = false then`, just write `if not Ada.Text_IO.End_Of_Line then`. (Though I don't think you need to use `End_Of_Line` anyway.) – Keith Thompson Dec 01 '12 at 03:08

2 Answers2

7

Just pre-initialize the string with spaces before calling Get_Line.

Here's a little program I just threw together:

with Ada.Text_IO; use Ada.Text_IO;
procedure Foo is
    S: String(1 .. 10) := (others => ' ');
    Last: Integer;
begin
    Put("Enter S: ");
    Get_Line(S, Last);
    Put_Line("S = """ & S & """");
    Put_Line("Last = " & Integer'Image(Last));
end Foo;

and the output I get when I run it:

Enter S: hello
S = "hello     "
Last =  5

Another possibility, rather than pre-initializing the string, is to set the remainder to spaces after the Get_Line call:

with Ada.Text_IO; use Ada.Text_IO;
procedure Foo is
    S: String(1 .. 10);
    Last: Integer;
begin
    Put("Enter S: ");
    Get_Line(S, Last);
    S(Last+1 .. S'Last) := (others => ' ');
    Put_Line("S = """ & S & """");
    Put_Line("Last = " & Integer'Image(Last));
end Foo;

For very large arrays, the latter approach might be more efficient because it doesn't assign the initial portion of the string twice, but in practice the difference is unlikely to be significant.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Thanks. I'm not sure why I didn't think of just pre-initializing it. Does the "(others => ' ')" just fill S with spaces? I've only used it in case structures so far, so I'm not sure what else it does. – user1279914 Dec 01 '12 at 03:34
  • 2
    +1 for actually addressing the question. :-) @user1279914: See also [*4.3.3 Array Aggregates*](http://www.adaic.org/resources/add_content/standards/05rm/html/RM-4-3-3.html). – trashgod Dec 01 '12 at 03:38
  • 1
    Yes, an `others` clause in an array aggregate refers to all elements not otherwise specified. If there's *only* an `others` clause, it refers to all elements of the array. – Keith Thompson Dec 01 '12 at 03:44
3

As an alternative, use either function Get_Line, which returns a fixed-length String that "has a lower bound of 1 and an upper bound of the number of characters read." The example Line_By_Line uses the variation that reads from a file. If need be, you can then use procedure Move to copy the Source string to the Target string; the procedure automatically pads with space by default.

Addendum: For example, this Line_Test pads with * and silently truncates long lines on the right.

with Ada.Integer_Text_IO;
with Ada.Strings.Fixed;
with Ada.Text_IO;

procedure Line_Test is
   Line_Count : Natural := 0;
   Buffer: String(1 .. 10);
begin
   while not Ada.Text_IO.End_Of_File loop
      declare
         Line : String := Ada.Text_IO.Get_Line;
      begin
         Line_Count := Line_Count + 1;
         Ada.Integer_Text_IO.Put(Line_Count, 0);
         Ada.Text_IO.Put_Line(": " & Line);
         Ada.Strings.Fixed.Move(
            Source  => Line,
            Target  => Buffer,
            Drop    => Ada.Strings.Right,
            Justify => Ada.Strings.Left,
            Pad     => '*');
         Ada.Integer_Text_IO.Put(Line_Count, 0);
         Ada.Text_IO.Put_Line(": " & Buffer);
      end;
   end loop;
end Line_Test;
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • I tried get_line(), but it kept printing the following put() before waiting for input for some reason. I am actually getting input from the keyboard, but sometimes using an input file also. I'll see if I can make it work with Move(). Thanks. – user1279914 Dec 01 '12 at 02:42
  • 1
    You may be seeing the effect described [here](http://stackoverflow.com/a/10472352/230513). Ping me here if you update your question with new code. – trashgod Dec 01 '12 at 02:52