Ada: I/O

Ada: I/O

Working with input/output in Ada

Programs in most languages, including Ada programs, have to deal with input and output in some form. This is because:

  • Programs need to accept input from the user or other systems in order to process data and perform tasks.

  • Programs need to provide output to the user or other systems to communicate results.

Ada deals with input/output in the following ways:

  1. It has built-in types for representing input and output, like Standard_Input and Standard_Output.

  2. It defines a set of standard Input/Output packages that provide routines for reading from and writing to files, streams, terminals, etc. These include:

  • TEXT_IO - for formatted text input/output

  • INTEGER_IO - for reading/writing integers

  • FLOAT_IO - for reading/writing floats

  • CHARACTER_IO - for reading/writing characters

  1. It allows the user to define their own input/output packages for specific needs.

  2. It supports exceptions to handle I/O errors gracefully.

  3. Ada programs accept input through mechanisms like:

  • Get procedures - to read from Standard_Input

  • Put procedures - to write to Standard_Output

  • Read procedures - to read from files

  1. Ada programs provide output through mechanisms like:
  • Put procedures

  • Write procedures - to write to files

  • Put_Line procedures - to write a line of text

  1. Ada supports streams - a logical sequence of elements - as an abstraction for input/output. This allows programs to read/write data without knowing the specific source or destination.

So in summary, Ada - like most programming languages - provides a variety of built-in types, packages and mechanisms to help programs deal with accepting input from the user/system and providing output to communicate results. The exact methods may differ from language to language, but the general concepts are similar.


Printing out

In Ada, you can print messages to the console and standard output in a few ways:

  1. Using the Put procedure from the TEXT_IO package:
WITH TEXT_IO;
 USE TEXT_IO;

PROCEDURE Hello is
BEGIN
   Put ("Hello, world!");   -- Prints to standard output
END Hello;
  1. Using the Put_Line procedure from the TEXT_IO package:
WITH TEXT_IO;
 USE TEXT_IO;

PROCEDURE Hello is
BEGIN
   Put_Line ("Hello, world!");  -- Prints to standard output and adds a new line
END Hello;
  1. Writing to Standard_Output:
WITH Ada.Text_IO;
 USE Ada.Text_IO;

PROCEDURE Hello is
BEGIN
   Ada.Text_IO.Put (Standard_Output, "Hello, world!");
END Hello;
  1. Using Put for user-defined types:
WITH Ada.Text_IO;  
 USE Ada.Text_IO;

TYPE Name is NEW String (1..30);

PROCEDURE Hello (N : IN Name) is
BEGIN
   Put (N);
END Hello;

PROCEDURE Main is
   Name1 : Name := "John";
BEGIN
   Hello (Name1);  
END Main;
  1. Writing to a file instead of standard output using Put_Line and Write from the TEXT_IO or STREAM_IO packages.

So in summary, Ada provides various procedures in the standard TEXT_IO package to print messages to the console and standard output. The Put and Put_Line procedures are the most common, but you can also write directly to Standard_Output or files for more flexibility.


Reading values

In Ada, you can accept input from the console and capture it into a variable in a few ways:

  1. Using the Get procedure from the TEXT_IO package:
WITH TEXT_IO;
USE TEXT_IO;

PROCEDURE Input is
    Input_String : String(1..100);
BEGIN
    Get(Input_String); -- Accepts input from the console and stores in Input_String
END Input;
  1. Using the Get_Line procedure from the TEXT_IO package:
WITH TEXT_IO;   
USE TEXT_IO;

PROCEDURE Input is
    Input_String : String(1..100);   
BEGIN
    Get_Line(Input_String); -- Accepts input including spaces and stores in Input_String
END Input;
  1. Reading from Standard_Input:
WITH Ada.Text_IO;
USE Ada.Text_IO;

PROCEDURE Input is
    Input_String : String(1..100);
BEGIN
    Ada.Text_IO.Get(Standard_Input, Input_String);
END Input;
  1. Using Get for user-defined types:
WITH Ada.Text_IO;
USE Ada.Text_IO;

TYPE Name is NEW String(1..30);

PROCEDURE Input (N : OUT Name) is
BEGIN
    Get(N);
END Input;

PROCEDURE Main is
    Name1 : Name;  
BEGIN
    Input(Name1);
    Put(Name1);     
END Main;
  1. Reading from a file instead of standard input using Get_Line and Read from the TEXT_IO or STREAM_IO packages.

So in summary, Ada provides various procedures in the standard TEXT_IO package to accept input from the console and store it in variables. The Get and Get_Line procedures are the most common, but you can also read from Standard_Input or files for more flexibility.


Clear Console

You can clear the console in Ada using the Clear_Line and Clear_Screen procedures from the TEXT_IO package.

To clear the current line on the console, use Clear_Line:

WITH TEXT_IO;  
USE TEXT_IO;

PROCEDURE Clear is  
BEGIN
    Clear_Line; -- Clears current line  
END Clear;

To clear the entire console screen, use Clear_Screen:

WITH TEXT_IO;  
USE TEXT_IO;

PROCEDURE Clear is
BEGIN
    Clear_Screen; -- Clears entire screen  
END Clear;

You can call these procedures anywhere in your Ada program to clear the console as needed.

For example:

WITH TEXT_IO;  
USE TEXT_IO;

PROCEDURE Clear_Example is
BEGIN
    Put_Line ("First line");
    Put_Line ("Second line");

    Clear_Screen;

    Put_Line ("Third line");  
END Clear_Example;

This will print the first two lines, then clear the screen and print the third line, starting with a clean console.

So in summary, the Clear_Line and Clear_Screen procedures from the TEXT_IO package allow you to clear the current line or entire console screen respectively from within your Ada programs.


Standard Input

To accept standard input into an Ada program for CLI (command line interface) applications, you can use the Get and Get_Line procedures from the Ada.Text_IO package.

For example:

WITH Ada.Text_IO;    
USE Ada.Text_IO;

PROCEDURE CLI is
    Input_String : String(1..100);
BEGIN
    Get(Standard_Input, Input_String);
    Put_Line ("You entered: " & Input_String);
END CLI;

Here we are using Get to read from Standard_Input, which represents the standard input stream (typically the user's keyboard input). This will accept input until a newline is entered.

We can also use Get_Line to accept an entire line of input:

WITH Ada.Text_IO;  
USE Ada.Text_IO;

PROCEDURE CLI is
    Input_String : String(1..100);
BEGIN
    Get_Line(Standard_Input, Input_String);   
    Put_Line ("You entered: " & Input_String);
END CLI;

Get_Line will accept input up until the end of line, including spaces.

You can then process the input however you need within your program.

To run this Ada CLI program, you can compile it and then run it from the command line:

adaclang CLI.ada -o CLI
./CLI

The program will then wait for you to enter input, which it will read from Standard_Input and display back.

So in summary, to accept standard input (keyboard input) for Ada CLI applications, use the Get and Get_Line procedures from the Ada.Text_IO package and read from the Standard_Input stream.


Line by Line

To read standard input as a stream and iterate over input line by line in Ada, you can do the following:

  1. Use the Ada.Text_IO.Stream_IO package to read from Standard_Input as a stream:
WITH Ada.Text_IO.Stream_IO;
USE Ada.Text_IO.Stream_IO;

PROCEDURE Read_Stream is
   File : Stream_Access := Standard_Input;
BEGIN
   -- Read from stream
END Read_Stream;
  1. Use the Read_Line procedure to read each line of input:
LOOP
   declare
      Line : String(1..200);   
   BEGIN
      Stream(File).Read_Line(Line, Last);  
      -- Process line of input      
   EXCEPTION
      when End_Error =>
         EXIT;
   END;
END LOOP;

We use a loop and read each line using Read_Line. We catch the End_Error exception which is raised when the end of the input stream is reached.

  1. You can then process each line of input within the loop:
LOOP
   -- Read line  
   Stream(File).Read_Line(Line, Last);

   Put_Line("You entered: " & Line);
END LOOP;

Here we are simply displaying each line of input.

  1. Don't forget to close the stream when done:
Stream(File).Close;

So in summary, to read standard input line by line in Ada:

  • Use the Stream_IO package and Standard_Input stream

  • Use the Read_Line procedure to read each line

  • Process each line within a loop

  • Catch the End_Error exception to exit the loop

  • Close the stream when finished


Stream

A stream in Ada is an abstraction that represents a source or destination of data. Streams provide a uniform interface for performing input and output operations.

There are two main kinds of streams in Ada:

  1. File streams - Represent files on the disk. You can read from and write to file streams to perform file I/O.

  2. Internal streams - Represent in-memory input and output sources. This includes things like:

  • Standard_Input - Represents the standard input stream, typically the user's keyboard.

  • Standard_Output - Represents the standard output stream, typically the user's console.

  • Standard_Error - Represents the standard error stream.

So in summary, streams in Ada provide an abstraction for performing input and output operations, whether that be from files, the keyboard, console or other internal sources.

The key types of streams are:

  • File streams - For file I/O

  • Internal streams - For in-memory I/O, including standard input/output/error

The Ada.Text_IO package provides procedures for performing text-based I/O using streams. The Ada.Stream_IO package provides a lower-level interface for binary I/O using streams.

So streams provide a uniform, high-level interface for performing input and output in Ada, hiding the underlying implementation details. They can represent various sources and destinations of data.


Files and Folders

Ada has excellent support for working with files and folders:

  • For opening and reading from files, Ada has the Ada.Text_IO and Ada.Stream_IO packages. These provide procedures and functions for opening files, reading from them, writing to them, and closing them.

  • You can open a file using the Open procedure:

FILE : File_Type;

OPEN (FILE, Mode => In_File, Name => "filename.txt");

Here we are opening an existing text file in input mode.

  • You can then read from the file using Text_IO functions like Get_Line():
Get_Line(FILE, Variable);
  • For writing to files, you use procedures like Put() and Put_Line():
OPEN (FILE, Mode => Out_File, Name => "filename.txt");

Put_Line(FILE, "Some text");
  • Once done, you close the file using Close():
Close(FILE);
  • Ada also has functions for checking if a file exists, getting its size, renaming files, deleting files, etc.

  • For working with folders, Ada has the Ada.Directories package. It provides functions for:

  • Creating new folders using Create_Directory()

  • Deleting folders using Delete_Directory()

  • Listing the contents of a folder using Directory_Entries()

  • Checking if a folder exists using Exists()

  • Getting the current working directory using Current_Directory()

So in summary, Ada provides robust and standardized ways of working with files and folders using the Text_IO, Stream_IO and Directories packages. You can perform most common file and folder operations in a straightforward manner.


Best Practice

Here are some best practices for working with files in Ada:

  1. Use Stream_IO instead of Text_IO whenever possible. Stream_IO provides a lower-level interface that is more efficient and portable. Text_IO is convenient but not as robust.

  2. Always check for errors when opening files. Use exceptions to catch errors:

BEGIN
   OPEN (FILE, ...);
EXCEPTION
   WHEN others =>
      -- Handle error
END;
  1. Close files as soon as you are done with them. This frees up resources and avoids leaving files open unintentionally.

  2. Use try..finally blocks to ensure files are closed even if an exception occurs:

BEGIN
   OPEN (FILE, ...);
   ...  
   -- Read/Write file   
FINALLY
   Close (FILE);  
END;
  1. Use meaningful names for file variables. This makes the code self-documenting.

  2. Use absolute paths instead of relative paths whenever possible. This avoids issues if the current working directory changes.

  3. Avoid hardcoding file names. Use constants or variables to store file names. This makes the code more flexible and maintainable.

  4. Consider using a file pool to manage open files. This avoids exceeding the operating system limit on open files.

  5. Use buffering to improve performance. Ada provides buffering for both Text_IO and Stream_IO.

  6. Comment your file I/O code clearly. Explain what the file represents and how it is used.

So in summary, check for errors, close files as soon as possible, use meaningful names, avoid hardcoding, consider buffering and comment your code. Following these best practices will result in robust, maintainable and efficient file I/O in your Ada programs.


Disclaim: This article was created with Rix AI. I have created several prompts to get this result. I hope I have cover most of this topic. If you need more feel free to ask more questions in the comments below.