1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
-------------------------------------------------------------------------------
--
-- <STRONG>Copyright © 2001, 2002 by Thomas Wolf.</STRONG>
-- <BLOCKQUOTE>
-- This piece of software is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License as published
-- by the Free Software Foundation; either version 2, or (at your option)
-- any later version. This software is distributed in the hope that it will
-- be useful, but <EM>without any warranty</EM>; without even the implied
-- warranty of <EM>merchantability or fitness for a particular purpose.</EM>
-- See the GNU General Public License for more details. You should have
-- received a copy of the GNU General Public License with this distribution,
-- see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-- USA.
-- </BLOCKQUOTE>
-- <BLOCKQUOTE>
-- As a special exception from the GPL, if other files instantiate generics
-- from this unit, or you link this unit with other files to produce an
-- executable, this unit does not by itself cause the resulting executable
-- to be covered by the GPL. This exception does not however invalidate any
-- other reasons why the executable file might be covered by the GPL.
-- </BLOCKQUOTE>
--
-- <AUTHOR>
-- Thomas Wolf (TW) <E_MAIL>
-- </AUTHOR>
--
-- <PURPOSE>
-- This is a thick binding to the @popen@ and @pclose@ routines available
-- on both Unix and Win32. It gives a convenient way to execute an external
-- program and pass it some input, or read its output.
-- </PURPOSE>
--
-- <TASKING>
-- Neither task- not abortion-safe. All operations here should be
-- considered <EM>potentially blocking</EM>.
-- </TASKING>
--
-- <NO_STORAGE>
--
-- <HISTORY>
-- 26-APR-2002 TW Initial version.
-- 29-APR-2002 TW Added auto-close feature.
-- </HISTORY>
-------------------------------------------------------------------------------
pragma License (Modified_GPL);
with Ada.Finalization;
with Ada.IO_Exceptions;
with Ada.Streams;
with Interfaces.C.Strings;
package Util.Pipes is
type Stream_Mode is (In_Stream, Out_Stream);
-- Used in @Open@ to specify the type of the stream.
type Pipe_Stream is new Ada.Streams.Root_Stream_Type with private;
-- I have found no indication whatsoever about the type of the underlying
-- C stream (binary or text mode?). Although you <EM>can</EM> write and
-- read binary data to and from a @Pipe_Stream@, it's probably prudent to
-- consider these streams as <EM>text-only</EM>, because they set up pipes
-- to or from an external processes stdin or stdout handles, which are
-- defined by the ISO C standard as text streams.
Name_Error : exception renames Ada.IO_Exceptions.Name_Error;
-- Raised by @Open@ if the command cannot be executed.
Use_Error : exception renames Ada.IO_Exceptions.Use_Error;
-- Raised by any stream operation if the stream is not open (and by @Open@,
-- if it already is open).
Mode_Error : exception renames Ada.IO_Exceptions.Mode_Error;
-- Stream operations on the returned stream may raise @Mode_Error@ if
-- writing on an @In_Stream@ or reading from an @Out_Stream@ is attempted.
End_Error : exception renames Ada.IO_Exceptions.End_Error;
-- Stream operations on an @In_Stream@ will raise @End_Error@ if EOF is
-- encountered.
Device_Error : exception renames Ada.IO_Exceptions.Device_Error;
-- Raised by the @Put@ or @Get@ operations (and also by @Write@ and
-- @Read@) if the underlying system operations indicate any reading or
-- writing error.
procedure Open
(Stream : in out Pipe_Stream;
Command : in String;
Mode : in Stream_Mode;
Close : in Boolean := True;
Std_In : in String := "");
-- Executes @Command@, which may contain arguments, setting it up such that
-- the executed command's stdin comes from the returned stream if @Mode@
-- is @Out_Stream@, or the command's stdout can be read from that stream
-- if @Mode@ is @In_Stream@. Note that "in" and "out" are from the caller's
-- perspective.
--
-- If <CODE>Close = True</CODE>, the stream is closed automatically when
-- the stream object disappears. Note that this may involve waiting until
-- the external command terminates. @Out_Stream@s always are closed
-- automatically.
--
-- Raises @Name_Error@ if the @Command@ cannot be executed, or @Use_Error@
-- if the stream is already open.
--
-- Note that an <EM>output filter</EM> is created using a stream of mode
-- @Out_Stream@. The external process will share its stdout with the
-- calling application, so you should carefully flush your stdout before
-- opening such a pipe, otherwise, output may become garbled and mixed up.
-- The same applies to an <EM>input filter</EM>: it shares its stdin with
-- the calling application! Unfortunately, one cannot flush an input stream
-- (that would be a meaningless operation anyway), so be careful!
--
-- One way to avoid such problems is using the @Std_In@ parameter. If it
-- is not the empty string, the command's stdin is redirected to come
-- from the given filename (which had better be valid). In other words,
-- the command actually executed is <CODE>Command & " <" & Std_In</CODE>.
-- If this feature is used, the caller is responsible for removing the
-- file, if that is desired.
procedure Close
(Stream : in out Pipe_Stream;
Exit_Code : out Integer);
-- Closes a stream obtained through @Open@. Raises @Use_Error@ if the
-- stream has not been opened.
--
-- An @Out_Stream@ <EM>must</EM> be closed, otherwise your program might
-- not terminate. therefore, @Pipe_Stream@s are controlled, and any
-- @Out_Stream@ is closed automatically when the stream object disappears.
--
-- An @In_Stream@ is only closed automatically if it has been opened with
-- <CODE>Close = True</CODE>, because closing such a stream may involve
-- waiting until the external command has terminated.
--
-- Note: this is a blocking call: it waits until the executed command
-- has terminated, and then returns that commands exit code.
function Is_Open
(Stream : in Pipe_Stream)
return Boolean;
-- Returns @True@ if the @Stream@ is open, and @False@ otherwise.
function End_Of_Stream
(Stream : in Pipe_Stream)
return Boolean;
-- Raises @Mode_Error@ if the @Stream@ is an @Out_Stream@. Otherwise,
-- returns @True@ if the @In_Stream@s end has been reached and @False@
-- otherwise.
procedure Put
(Stream : in Pipe_Stream;
Text : in String);
-- Same semantics as @Ada.Text_IO.Put@.
procedure Put
(Stream : in Pipe_Stream;
Ch : in Character);
-- Same semantics as @Put@ for a string.
procedure Put_Line
(Stream : in Pipe_Stream;
Text : in String);
-- Same semantics as @Ada.Text_IO.Put_Line@.
procedure Get
(Stream : in Pipe_Stream;
Ch : out Character);
-- Same semantics as @Ada.Text_IO.Get@.
procedure Get
(Stream : in Pipe_Stream;
Buffer : out String);
-- Same semantics as @Ada.Text_IO.Get@.
procedure Get_Line
(Stream : in Pipe_Stream;
Buffer : out String;
Last : out Natural);
-- Same semantics as @Ada.Text_IO.Get_Line@.
function Get_Line
(Stream : in Pipe_Stream)
return String;
-- As @Ada.Text_IO.Get_Line@, but always returns a full line.
private
type C_File_Ptr is new Interfaces.C.Strings.chars_ptr;
Null_Ptr : constant C_File_Ptr :=
C_File_Ptr (Interfaces.C.Strings.Null_Ptr);
type Closer (Stream : access Pipe_Stream) is
new Ada.Finalization.Limited_Controlled with null record;
procedure Finalize (C : in out Closer);
type Pipe_Stream is new Ada.Streams.Root_Stream_Type with
record
F : C_File_Ptr := Null_Ptr;
Mode : Stream_Mode;
Close_It : Boolean := True;
Clean_Up : Closer (Pipe_Stream'Access);
end record;
procedure Read
(Stream : in out Pipe_Stream;
Item : out Ada.Streams.Stream_Element_Array;
Last : out Ada.Streams.Stream_Element_Offset);
procedure Write
(Stream : in out Pipe_Stream;
Item : in Ada.Streams.Stream_Element_Array);
end Util.Pipes;
|