-- --
-- B o d y --
-- --
--- Copyright (C) 2002-2005 Ada Core Technologies, Inc. --
+-- Copyright (C) 2002-2007, AdaCore --
-- --
-- GNAT is free software; you can redistribute it and/or modify it under --
-- terms of the GNU General Public License as published by the Free Soft- --
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
-- for more details. You should have received a copy of the GNU General --
-- Public License distributed with GNAT; see file COPYING. If not, write --
--- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
--- MA 02111-1307, USA. --
+-- to the Free Software Foundation, 51 Franklin Street, Fifth Floor, --
+-- Boston, MA 02110-1301, USA. --
-- --
-- As a special exception, if other files instantiate generics from this --
-- unit, or you link this unit with other files to produce an executable, --
-- --
------------------------------------------------------------------------------
--- This is the VMS version.
+-- This is the VMS version
-with System; use System;
-with Ada.Calendar; use Ada.Calendar;
+with System; use System;
+with Ada.Calendar; use Ada.Calendar;
with GNAT.IO;
-with GNAT.OS_Lib; use GNAT.OS_Lib;
-with GNAT.Regpat; use GNAT.Regpat;
+with GNAT.OS_Lib; use GNAT.OS_Lib;
+with GNAT.Regpat; use GNAT.Regpat;
-with Unchecked_Deallocation;
+with Ada.Unchecked_Deallocation;
package body GNAT.Expect is
-- Reinitialize the internal buffer.
-- The buffer is deleted up to the end of the last match.
- procedure Free is new Unchecked_Deallocation
+ procedure Free is new Ada.Unchecked_Deallocation
(Pattern_Matcher, Pattern_Matcher_Access);
procedure Call_Filters
procedure Kill (Pid : Process_Id; Sig_Num : Integer);
pragma Import (C, Kill, "decc$kill");
- function Create_Pipe (Pipe : access Pipe_Type) return Integer;
+ function Create_Pipe (Pipe : not null access Pipe_Type) return Integer;
pragma Import (C, Create_Pipe, "__gnat_pipe");
function Poll
function Waitpid (Pid : Process_Id) return Integer;
pragma Import (C, Waitpid, "__gnat_waitpid");
- -- Wait for a specific process id, and return its exit code.
+ -- Wait for a specific process id, and return its exit code
---------
-- "+" --
Close (Descriptor.Output_Fd);
-- ??? Should have timeouts for different signals
- Kill (Descriptor.Pid, 9);
+
+ if Descriptor.Pid > 0 then -- see comment in Send_Signal
+ Kill (Descriptor.Pid, Sig_Num => 9);
+ end if;
GNAT.OS_Lib.Free (Descriptor.Buffer);
Descriptor.Buffer_Size := 0;
- Status := Waitpid (Descriptor.Pid);
+ -- Check process id (see comment in Send_Signal)
+
+ if Descriptor.Pid > 0 then
+ Status := Waitpid (Descriptor.Pid);
+ else
+ raise Invalid_Process;
+ end if;
end Close;
procedure Close (Descriptor : in out Process_Descriptor) is
return;
end if;
- -- Calculate the timeout for the next turn.
+ -- Calculate the timeout for the next turn
+
-- Note that Timeout is, from the caller's perspective, the maximum
-- time until a match, not the maximum time until some output is
- -- read, and thus can not be reused as is for Expect_Internal.
+ -- read, and thus cannot be reused as is for Expect_Internal.
if Timeout /= -1 then
Timeout_Tmp := Integer (Try_Until - Clock) * 1000;
Descriptors (J).Buffer_Size - N;
end if;
- -- Keep what we read in the buffer.
+ -- Keep what we read in the buffer
Descriptors (J).Buffer
(Descriptors (J).Buffer_Index + 1 ..
end if;
end case;
end loop;
-
end Flush;
+ ------------------------
+ -- Get_Command_Output --
+ ------------------------
+
+ function Get_Command_Output
+ (Command : String;
+ Arguments : GNAT.OS_Lib.Argument_List;
+ Input : String;
+ Status : not null access Integer;
+ Err_To_Out : Boolean := False) return String
+ is
+ use GNAT.Expect;
+
+ Process : Process_Descriptor;
+
+ Output : String_Access := new String (1 .. 1024);
+ -- Buffer used to accumulate standard output from the launched
+ -- command, expanded as necessary during execution.
+
+ Last : Integer := 0;
+ -- Index of the last used character within Output
+
+ begin
+ Non_Blocking_Spawn
+ (Process, Command, Arguments, Err_To_Out => Err_To_Out);
+
+ if Input'Length > 0 then
+ Send (Process, Input);
+ end if;
+
+ GNAT.OS_Lib.Close (Get_Input_Fd (Process));
+
+ declare
+ Result : Expect_Match;
+
+ begin
+ -- This loop runs until the call to Expect raises Process_Died
+
+ loop
+ Expect (Process, Result, ".+");
+
+ declare
+ NOutput : String_Access;
+ S : constant String := Expect_Out (Process);
+ pragma Assert (S'Length > 0);
+
+ begin
+ -- Expand buffer if we need more space
+
+ if Last + S'Length > Output'Last then
+ NOutput := new String (1 .. 2 * Output'Last);
+ NOutput (Output'Range) := Output.all;
+ Free (Output);
+
+ -- Here if current buffer size is OK
+
+ else
+ NOutput := Output;
+ end if;
+
+ NOutput (Last + 1 .. Last + S'Length) := S;
+ Last := Last + S'Length;
+ Output := NOutput;
+ end;
+ end loop;
+
+ exception
+ when Process_Died =>
+ Close (Process, Status.all);
+ end;
+
+ if Last = 0 then
+ return "";
+ end if;
+
+ declare
+ S : constant String := Output (1 .. Last);
+ begin
+ Free (Output);
+ return S;
+ end;
+ end Get_Command_Output;
+
------------------
-- Get_Error_Fd --
------------------
procedure Interrupt (Descriptor : in out Process_Descriptor) is
SIGINT : constant := 2;
-
begin
Send_Signal (Descriptor, SIGINT);
end Interrupt;
Call_Filters (Descriptor, Full_Str (Full_Str'First .. Last), Input);
- Discard := Write (Descriptor.Input_Fd,
- Full_Str'Address,
- Last - Full_Str'First + 1);
+ Discard :=
+ Write (Descriptor.Input_Fd,
+ Full_Str'Address,
+ Last - Full_Str'First + 1);
-- Shouldn't we at least have a pragma Assert on the result ???
end Send;
Signal : Integer)
is
begin
- Kill (Descriptor.Pid, Signal);
- -- ??? Need to check process status here.
+ -- A nonpositive process id passed to kill has special meanings. For
+ -- example, -1 means kill all processes in sight, including self, in
+ -- POSIX and Windows (and something slightly different in Linux). See
+ -- man pages for details. In any case, we don't want to do that. Note
+ -- that Descriptor.Pid will be -1 if the process was not successfully
+ -- started; we don't want to kill ourself in that case.
+
+ if Descriptor.Pid > 0 then
+ Kill (Descriptor.Pid, Signal);
+ -- ??? Need to check process status here
+ else
+ raise Invalid_Process;
+ end if;
end Send_Signal;
---------------------------------
Pipe1 : in out Pipe_Type;
Pipe2 : in out Pipe_Type;
Pipe3 : in out Pipe_Type;
- Cmd : in String;
- Args : in System.Address)
+ Cmd : String;
+ Args : System.Address)
is
pragma Warnings (Off, Pid);
procedure Set_Up_Communications
(Pid : in out Process_Descriptor;
Err_To_Out : Boolean;
- Pipe1 : access Pipe_Type;
- Pipe2 : access Pipe_Type;
- Pipe3 : access Pipe_Type)
+ Pipe1 : not null access Pipe_Type;
+ Pipe2 : not null access Pipe_Type;
+ Pipe3 : not null access Pipe_Type)
is
begin
-- Create the pipes
is
pragma Warnings (Off, Descriptor);
pragma Warnings (Off, User_Data);
-
begin
GNAT.IO.Put (Str);
end Trace_Filter;