AlanS2000
AlanS2000

Reputation: 47

How to save Doubly_Linked_Lists text to a file for Ada language? Also how to have not fixed size string input?

I am writing a school project to store string to the doubly linked list, but I don't know how to save the final list to a text file. I also what the user to choose the text file name. Can someone show me how to do that? Also for Ada can I have a not fixed-length string as input? Right now I set the string length to 5 but I really wanted to have a flexible length for the string. Below is my code thank you.

with Ada.Containers.Doubly_Linked_Lists;
with Ada.Text_Io; use Ada.Text_Io;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.IO_Exceptions;

procedure main is
   type Command is (A, C, P, E, M);
   package Command_IO is new Ada.Text_IO.Enumeration_IO (Command);
   package String_List is new Ada.Containers.Doubly_Linked_Lists(Unbounded_String);
   use String_List;
   Userinput : String(1 .. 5) := (others => ' '); --This string length is 5
   InsertLocation : String(1 .. 5) := (others => ' '); --This string length is 5
   text : List; -- List is from Doubly_Linked_Lists
   F : File_Type;

begin   
   loop     
      declare
         Cmd : Command;


   procedure Print(Position : Cursor) is -- this subprogram print all string from list 
         begin     
            Put_Line(To_String(Element(Position)));      
            --Put_Line("K");
   end Print;

      begin
         Put_Line("*****************************");
         Put_Line("*Enter A to add a text      *");
         Put_Line("*Enter C to insert a text   *");
         Put_Line("*Enter P the print text list*");
         Put_Line("*Enter E the exit program   *");
         Put_Line("*Enter M to save the list   *");
         Put_Line("*****************************");
         Put_Line(" ");
         Put(">> ");

         Command_IO.Get (Cmd);

         Ada.Text_IO.Skip_Line;

         Put_Line ("read " & Cmd'Image);                -- ' to sort out the not-fully-Ada-aware syntax highlighting
         Put_Line ("  " );
         case Cmd is

         when a =>
            Put_Line("Enter a text " );
            Put(">> " );
            Get(Userinput);  
            text.Append(To_Unbounded_String(Userinput)); -- if letter is a add it to the doubly link list  
            Put_line("  " );

         when c => 
            Put_Line("Enter a text location you want to insert " );
            Put(">> " );
            Get(Userinput);
            Put_Line("Enter a text " );
            Put(">> " );
            Get(InsertLocation);


            text.Insert(Before => text.Find(To_Unbounded_String(Userinput)), New_Item => To_Unbounded_String( InsertLocation ));

         when p =>      
            text.Iterate(Print'access);
            Put_line("  " );


         when m =>
            Put_Line("Save to file"); 
            Create (F, Out_File, "file.txt");
            Put_Line (F, "This string will be written to the file file.txt");
            Close (F);

         when e =>      
            Put_Line("Program Exit");

            exit;   

         end case;   

      exception
         when Ada.IO_Exceptions.Data_Error =>
            Put_Line ("unrecognised command");
            Put_Line (" ");

      end;
   end loop;
end main;

Upvotes: 2

Views: 178

Answers (3)

Jere
Jere

Reputation: 3641

You look like you have all the parts. You can use Text_IO for writing to the file and you can use Unbounded_String to hold strings of any size. For reading in strings of any size, you can use the procedure Get_Line in Text_IO which returns a string of any length or if you really want to use Unbounded_Strings, you can use Ada.Text_IO.Unbounded_IO.Get_Line. I could also optionally suggest looking at Indefinite_Doubly_Linked_List instead of using Unbounded_String, depending on your use case.

For writing to file, just loop over the List and write each element to a file using Text_IO style functions.

Here is some scaffolding showing some of this.

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Indefinite_Doubly_Linked_Lists;
use Ada.Containers;


procedure Hello is

    package Lists is new Indefinite_Doubly_Linked_Lists(String);
    Text : Lists.List;
begin
    Put_Line("Hello, world!");


    Put_Line("Enter a text:" );
    declare
        User_Input : String := Get_Line;
    begin
        Text.Append(New_Item => User_Input);
    end;

    Put_Line("Enter Text to Insert at:");
    declare
        Location : String := Get_Line;
    begin
        Put_Line("Enter New Text:");
        declare
            User_Input : String := Get_Line;
        begin
            Text.Insert(Before => Text.Find(Location), New_Item => User_Input);
        end;
    end;

    -- Loop through list and write each element
    for Line of Text loop
        Put_Line(Line);
        -- Write to file here using Text_IO file operations
    end loop;

end Hello;

Side note, if you spend more time searching your data than you do creating your list, you can also look at Map packages. Ada has both hashed and ordered maps (with indefinite options as well).

Upvotes: 3

user1818839
user1818839

Reputation:

Looks like you are on the right path.

A couple of points :

  • you can ask the user to enter a filename (e.g. in a funciton returning String, used to initialise a variable as in Simon's answer. This function could suggest a default which will be used if the user just presses Return. Then you pass that string to the Create call.
  • Probably the best way to output complex things like lists is to learn Stream I/O. This may be more complex to set up than you need right now, but ultimately it would let you simply "Write" the whole list to file in a single operation. Each data type has 'Read and 'Write attributes, which are procedures you can overload with your own procedures to format the file however you wish. The default 'Write attribute for a list will iterate over the whole List calling each element's own 'Write procedure. (It may also insert information about the List you don't want, that's why it's overloadable...)

Upvotes: 1

Simon Wright
Simon Wright

Reputation: 25491

A couple of observations:

(1) Although a String is a fixed-length object, the length can be determined at initialisation:

declare
   Str : constant String := Get_Line;
begin
   ...

You may have to be a bit creative about using the value in Str outside its scope, the declare block. For example, if it’s the name of a file to be opened, the File_Type object to be opened could be in an outer scope.

(2) If you want to read an integer, use Ada.Integer_Text_IO.Get (followed by Skip_Line, because the Get terminates when the number has been read, leaving the rest of the line, including the terminator, in the input buffer)

Upvotes: 3

Related Questions