-- Source code for an article published at the Ada Home -- -- A Thick Ada 95 Binding for Unix Child Processes and Pipes -- by Jim Rogers -- February 1998 -- -- See -------------------------------------------------------------------------------- -- This package defines a thick Ada binding to the UNIX popen and pclose -- commands -------------------------------------------------------------------------------- with Interfaces.C_Streams; use Interfaces.C_Streams; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package Ada_Home.Unix.Pipe_Commands is type stream is private; type IO_MODE is (read_file, write_file); function execute (Command : in string; IO_type : in IO_Mode) return stream; function read_next (FromFile : in stream) return unbounded_string; procedure write_next (ToFile : in stream; Message : in string); procedure close (OpenFile : in stream); Access_Error : exception; -- Raised when attempt is made to violate IO_MODE End_Of_File : exception; -- Raised on detection of End_of_file during read private type stream is record FileStream : Files; Mode : IO_Mode; end record; end Ada_Home.Unix.Pipe_Commands; -- Source code for an article published at the Ada Home -- -- A Thick Ada 95 Binding for Unix Child Processes and Pipes -- by Jim Rogers -- February 1998 -- -- See -------------------------------------------------------------------------------- -- Implementation of a thick Ada binding to the UNIX popen and pclose -- commands -------------------------------------------------------------------------------- with Interfaces.C; use Interfaces.C; with Ada.Characters.Latin_1; package body Ada_Home.Unix.Pipe_Commands is LF : constant Interfaces.C_Streams.int := Character'Pos (Ada.Characters.Latin_1.LF); -- Unix end of line function popen (Command : char_array; Mode : char_array) return Files; pragma import (C, popen); function pclose (FileStream : FILEs) return Interfaces.C_Streams.int; pragma import (C, pclose); function execute (Command : in string; IO_type : in IO_Mode) return stream is Result : stream; begin case IO_Type is when read_file => Result.FileStream := popen(to_C(Command), to_C("r")); when write_file => Result.FileStream := popen(to_C(Command), to_C("w")); end case; Result.Mode := IO_Type; return Result; end execute; function read_next (FromFile : in stream) return unbounded_string is Result : Unbounded_String := Null_Unbounded_String; char_buf : Interfaces.C_Streams.int; temp : character; begin if Fromfile.Mode = write_file then raise Access_Error; end if; loop char_buf := fgetc (FromFile.FileStream); if char_buf = EOF then raise End_Of_File; end if; exit when char_buf = LF; -- end of line? temp := character'val (char_buf); Result := Result & temp; end loop; return Result; end read_next; procedure write_next (ToFile : in stream; Message : in string) is rc : Interfaces.C_Streams.int; begin if ToFile.Mode = read_file then raise Access_Error; end if; for I in Message'Range loop rc := fputc (character'pos(Message(I)), ToFile.FileStream); end loop; rc := fputc (LF, ToFile.FileStream); -- add end of line end write_next; procedure close (OpenFile : in stream) is rc : Interfaces.C_Streams.int; begin rc := pclose (OpenFile.FileStream); end close; end Ada_Home.Unix.Pipe_Commands; -- Source code for an article published at the Ada Home -- -- A Thick Ada 95 Binding for Unix Child Processes and Pipes -- by Jim Rogers -- February 1998 -- -- See ---------------------------------------------------------------------------- -- Test commands package ---------------------------------------------------------------------------- with Ada_Home.Unix.Pipe_Commands; use Ada_Home.Unix.Pipe_Commands; with Ada.Text_IO; use Ada.Text_IO; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; procedure Pipe_Commands_Test is command : constant string := "ps -u"; FileStream : stream; command2 : constant string := "cat ada_home-unix-pipe_commands.ads"; command3 : constant string := "tee foo.test"; command4 : constant string := "tee foo2.test"; Message : constant string := "This is the string I am writing."; procedure print_buf(FileStream : in stream) is Buffer : unbounded_String; begin loop begin Buffer := read_next(FileStream); put_line(to_string(Buffer)); exception when Ada_Home.Unix.Pipe_Commands.End_of_file => exit; end; end loop; end print_buf; begin put_line("Status of user processes:"); FileStream := execute(command, read_file); print_buf(FileStream); close(FileStream); new_line(2); put_line("Listing a file with command '" & command2 & "':"); FileStream := execute(command2, read_file); print_buf(FileStream); close(FileStream); new_line(2); put("Today's date is: "); FileStream := execute("date", read_file); print_buf(FileStream); close(FileStream); new_line(2); put_line("Output through a pipe to the tee command:"); put_line("(look in foo.test for the same string.)"); FileStream := execute(command3, write_file); write_next(FileStream, Message); close(FileStream); new_line(2); put_line("Attempt illegal input from a pipe to the tee command:"); FileStream := execute(command4, write_file); begin print_buf(FileStream); exception when Access_Error => put_line ("Detected improper attempt to read from a pipe opened for write only."); end; close(FileStream); end Pipe_Commands_Test; package Ada_Home is end Ada_Home; package Ada_Home.Unix is end Ada_Home.Unix;