Search code examples
adagnat

Start executable from Ada program and read result


I found this question and the first answer contains some example code demonstrating how to start an executable with Ada code. The output of the executable is written to the standard output.

What options do I have to read the output of the executable for further parsing/processing in Ada (for example line by line)?


Solution

  • If you use GNAT, then you might want to take a look at Get_Command_Output in the GNAT.Expect package. Here's an example:

    with Ada.Text_IO, GNAT.Expect;
    
    procedure Main is
    
       Command    : constant String := "gnat";   
       Argument_1 : aliased String  := "--version";
       Input      : constant String := ""; 
       Status     : aliased Integer := 0;      
    
       --  Execute the command and retrieve the output.
    
       Output : String :=
                  GNAT.Expect.Get_Command_Output
                    (Command    => Command,
                     Arguments  => (1 => Argument_1'Unchecked_Access),
                     Input      => Input,
                     Status     => Status'Access,
                     Err_To_Out => False);
    
       --  NOTE: Cheating with Unchecked_Access, OK for demo. You may want
       --        to properly new and Free these strings (see Argument_List 
       --        type in package GNAT.OS_Lib).
    
    begin  
       Ada.Text_IO.Put_Line (Output);
    end Main;
    

    The program returns after execution:

    $ ./main
    GNAT Community 2019 (20190517-83)
    Copyright (C) 1996-2019, Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    

    As can be seen, the result is returned as a single string. You will have do the line splitting yourself.


    Update

    An update in response to some comments below.

    You might also consider using the system function if you're targeting the Windows platform (see also this post on SO). Quoting from the function reference:

    The system function passes command to the command interpreter, which executes the string as an operating-system command.

    This is similar to what the program cmd.exe does. You can obtain the output of the command by redirecting its output to a file (i.e. using >) and then subsequently read it back. Here's an example:

    with Ada.Text_IO;              
    with Ada.Text_IO.Unbounded_IO;
    with Ada.Strings.Unbounded;
    
    with Interfaces.C;
    with Interfaces.C.Strings;         
    
    procedure Main is
    
       use Ada.Strings.Unbounded;
       Content : Unbounded_String := Null_Unbounded_String;   
    
    begin
    
       --  Execute.
       declare   
    
          use Interfaces.C;
          use Interfaces.C.Strings; 
    
          function system (command : chars_ptr) return int
            with Import, Convention => C, External_Name => "system";      
    
          command : chars_ptr := New_String("gnat --version > gnat_version.out");
          result  : int       := system (command); 
    
       begin
          --  Check value of result (omitted in this example).
          Free(Command);
       end;
    
       --  Read.
       declare
    
          use Ada.Text_IO;
          use Ada.Text_IO.Unbounded_IO;  
    
          Fd : File_Type;
    
       begin  
          Open (Fd, In_File, "./gnat_version.out");
          while not End_Of_File (Fd) loop
             Content := Content 
               & Unbounded_String'(Get_Line (Fd))
               & ASCII.CR & ASCII.LF;   --  Restore the line break removed by Get_Line.
          end loop;
          Close (fd);
       end;
    
       --  Show.
       Ada.Text_IO.Unbounded_IO.Put (Content);   
    
    end Main;