1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- G N A T . E X P E C T --
11 -- Copyright (C) 2000-2001 Ada Core Technologies, Inc. --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- As a special exception, if other files instantiate generics from this --
25 -- unit, or you link this unit with other files to produce an executable, --
26 -- this unit does not by itself cause the resulting executable to be --
27 -- covered by the GNU General Public License. This exception does not --
28 -- however invalidate any other reasons why the executable file might be --
29 -- covered by the GNU Public License. --
31 -- GNAT is maintained by Ada Core Technologies Inc (http://www.gnat.com). --
33 ------------------------------------------------------------------------------
36 with GNAT
.OS_Lib
; use GNAT
.OS_Lib
;
37 with GNAT
.Regpat
; use GNAT
.Regpat
;
38 with System
; use System
;
39 with Unchecked_Conversion
;
40 with Unchecked_Deallocation
;
41 with Ada
.Calendar
; use Ada
.Calendar
;
43 package body GNAT
.Expect
is
45 function To_Pid
is new
46 Unchecked_Conversion
(OS_Lib
.Process_Id
, Process_Id
);
48 type Array_Of_Pd
is array (Positive range <>) of Process_Descriptor_Access
;
50 procedure Expect_Internal
51 (Descriptors
: in out Array_Of_Pd
;
52 Result
: out Expect_Match
;
54 Full_Buffer
: Boolean);
55 -- Internal function used to read from the process Descriptor.
57 -- Three outputs are possible:
58 -- Result=Expect_Timeout, if no output was available before the timeout
60 -- Result=Expect_Full_Buffer, if Full_Buffer is True and some characters
61 -- had to be discarded from the internal buffer of Descriptor.
62 -- Result=<integer>, indicates how many characters were added to the
63 -- internal buffer. These characters are from indexes
64 -- Descriptor.Buffer_Index - Result + 1 .. Descriptor.Buffer_Index
65 -- Process_Died is raised if the process is no longer valid.
67 procedure Reinitialize_Buffer
68 (Descriptor
: in out Process_Descriptor
'Class);
69 -- Reinitialize the internal buffer.
70 -- The buffer is deleted up to the end of the last match.
72 procedure Free
is new Unchecked_Deallocation
73 (Pattern_Matcher
, Pattern_Matcher_Access
);
75 procedure Call_Filters
76 (Pid
: Process_Descriptor
'Class;
78 Filter_On
: Filter_Type
);
79 -- Call all the filters that have the appropriate type.
80 -- This function does nothing if the filters are locked
82 ------------------------------
83 -- Target dependent section --
84 ------------------------------
86 function Dup
(Fd
: File_Descriptor
) return File_Descriptor
;
87 pragma Import
(C
, Dup
);
89 procedure Dup2
(Old_Fd
, New_Fd
: File_Descriptor
);
90 pragma Import
(C
, Dup2
);
92 procedure Kill
(Pid
: Process_Id
; Sig_Num
: Integer);
93 pragma Import
(C
, Kill
);
95 function Create_Pipe
(Pipe
: access Pipe_Type
) return Integer;
96 pragma Import
(C
, Create_Pipe
, "__gnat_pipe");
99 (Fd
: File_Descriptor
;
101 N
: Integer) return Integer;
102 pragma Import
(C
, Read
, "read");
103 -- Read N bytes to address A from file referenced by FD. Returned value
104 -- is count of bytes actually read, which can be less than N at EOF.
106 procedure Close
(Fd
: File_Descriptor
);
107 pragma Import
(C
, Close
);
108 -- Close a file given its file descriptor.
111 (Fd
: File_Descriptor
;
113 N
: Integer) return Integer;
114 pragma Import
(C
, Write
, "write");
115 -- Read N bytes to address A from file referenced by FD. Returned value
116 -- is count of bytes actually read, which can be less than N at EOF.
119 (Fds
: System
.Address
;
122 Is_Set
: System
.Address
) return Integer;
123 pragma Import
(C
, Poll
, "__gnat_expect_poll");
124 -- Check whether there is any data waiting on the file descriptor
125 -- Out_fd, and wait if there is none, at most Timeout milliseconds
126 -- Returns -1 in case of error, 0 if the timeout expired before
127 -- data became available.
129 -- Out_Is_Set is set to 1 if data was available, 0 otherwise.
135 function "+" (S
: String) return GNAT
.OS_Lib
.String_Access
is
137 return new String'(S);
145 (P : GNAT.Regpat.Pattern_Matcher)
146 return Pattern_Matcher_Access
149 return new GNAT.Regpat.Pattern_Matcher'(P
);
157 (Descriptor
: in out Process_Descriptor
;
158 Filter
: Filter_Function
;
159 Filter_On
: Filter_Type
:= Output
;
160 User_Data
: System
.Address
:= System
.Null_Address
;
161 After
: Boolean := False)
163 Current
: Filter_List
:= Descriptor
.Filters
;
167 while Current
/= null and then Current
.Next
/= null loop
168 Current
:= Current
.Next
;
171 if Current
= null then
172 Descriptor
.Filters
:=
173 new Filter_List_Elem
'
174 (Filter => Filter, Filter_On => Filter_On,
175 User_Data => User_Data, Next => null);
178 new Filter_List_Elem'
179 (Filter
=> Filter
, Filter_On
=> Filter_On
,
180 User_Data
=> User_Data
, Next
=> null);
184 Descriptor
.Filters
:=
185 new Filter_List_Elem
'
186 (Filter => Filter, Filter_On => Filter_On,
187 User_Data => User_Data, Next => Descriptor.Filters);
195 procedure Call_Filters
196 (Pid : Process_Descriptor'Class;
198 Filter_On : Filter_Type)
200 Current_Filter : Filter_List;
203 if Pid.Filters_Lock = 0 then
204 Current_Filter := Pid.Filters;
206 while Current_Filter /= null loop
207 if Current_Filter.Filter_On = Filter_On then
208 Current_Filter.Filter
209 (Pid, Str, Current_Filter.User_Data);
212 Current_Filter := Current_Filter.Next;
221 procedure Close (Descriptor : in out Process_Descriptor) is
223 Pid : OS_Lib.Process_Id;
226 Close (Descriptor.Input_Fd);
228 if Descriptor.Error_Fd /= Descriptor.Output_Fd then
229 Close (Descriptor.Error_Fd);
232 Close (Descriptor.Output_Fd);
234 -- ??? Should have timeouts for different signals, see ddd
235 Kill (Descriptor.Pid, 9);
237 GNAT.OS_Lib.Free (Descriptor.Buffer);
238 Descriptor.Buffer_Size := 0;
240 Wait_Process (Pid, Success);
241 Descriptor.Pid := To_Pid (Pid);
249 (Descriptor : in out Process_Descriptor;
250 Result : out Expect_Match;
252 Timeout : Integer := 10000;
253 Full_Buffer : Boolean := False)
257 Expect (Descriptor, Result, Never_Match, Timeout, Full_Buffer);
259 Expect (Descriptor, Result, Compile (Regexp), Timeout, Full_Buffer);
264 (Descriptor : in out Process_Descriptor;
265 Result : out Expect_Match;
267 Matched : out GNAT.Regpat.Match_Array;
268 Timeout : Integer := 10000;
269 Full_Buffer : Boolean := False)
272 pragma Assert (Matched'First = 0);
275 (Descriptor, Result, Never_Match, Matched, Timeout, Full_Buffer);
278 (Descriptor, Result, Compile (Regexp), Matched, Timeout,
284 (Descriptor : in out Process_Descriptor;
285 Result : out Expect_Match;
286 Regexp : GNAT.Regpat.Pattern_Matcher;
287 Timeout : Integer := 10000;
288 Full_Buffer : Boolean := False)
290 Matched : GNAT.Regpat.Match_Array (0 .. 0);
293 Expect (Descriptor, Result, Regexp, Matched, Timeout, Full_Buffer);
297 (Descriptor : in out Process_Descriptor;
298 Result : out Expect_Match;
299 Regexp : GNAT.Regpat.Pattern_Matcher;
300 Matched : out GNAT.Regpat.Match_Array;
301 Timeout : Integer := 10000;
302 Full_Buffer : Boolean := False)
305 Descriptors : Array_Of_Pd := (1 => Descriptor'Unrestricted_Access);
306 Try_Until : Time := Clock + Duration (Timeout) / 1000.0;
307 Timeout_Tmp : Integer := Timeout;
310 pragma Assert (Matched'First = 0);
311 Reinitialize_Buffer (Descriptor);
314 -- First, test if what is already in the buffer matches (This is
315 -- required if this package is used in multi-task mode, since one of
316 -- the tasks might have added something in the buffer, and we don't
317 -- want other tasks to wait for new input to be available before
318 -- checking the regexps).
321 (Regexp, Descriptor.Buffer (1 .. Descriptor.Buffer_Index), Matched);
323 if Descriptor.Buffer_Index >= 1 and then Matched (0).First /= 0 then
325 Descriptor.Last_Match_Start := Matched (0).First;
326 Descriptor.Last_Match_End := Matched (0).Last;
330 -- Else try to read new input
332 Expect_Internal (Descriptors, N, Timeout_Tmp, Full_Buffer);
334 if N = Expect_Timeout or else N = Expect_Full_Buffer then
339 -- Calculate the timeout for the next turn.
340 -- Note that Timeout is, from the caller's perspective, the maximum
341 -- time until a match, not the maximum time until some output is
342 -- read, and thus can not be reused as is for Expect_Internal.
344 if Timeout /= -1 then
345 Timeout_Tmp := Integer (Try_Until - Clock) * 1000;
347 if Timeout_Tmp < 0 then
348 Result := Expect_Timeout;
354 -- Even if we had the general timeout above, we have to test that the
355 -- last test we read from the external process didn't match.
358 (Regexp, Descriptor.Buffer (1 .. Descriptor.Buffer_Index), Matched);
360 if Matched (0).First /= 0 then
362 Descriptor.Last_Match_Start := Matched (0).First;
363 Descriptor.Last_Match_End := Matched (0).Last;
369 (Descriptor : in out Process_Descriptor;
370 Result : out Expect_Match;
371 Regexps : Regexp_Array;
372 Timeout : Integer := 10000;
373 Full_Buffer : Boolean := False)
375 Patterns : Compiled_Regexp_Array (Regexps'Range);
376 Matched : GNAT.Regpat.Match_Array (0 .. 0);
379 for J in Regexps'Range loop
380 Patterns (J) := new Pattern_Matcher'(Compile
(Regexps
(J
).all));
383 Expect
(Descriptor
, Result
, Patterns
, Matched
, Timeout
, Full_Buffer
);
385 for J
in Regexps
'Range loop
391 (Descriptor
: in out Process_Descriptor
;
392 Result
: out Expect_Match
;
393 Regexps
: Compiled_Regexp_Array
;
394 Timeout
: Integer := 10000;
395 Full_Buffer
: Boolean := False)
397 Matched
: GNAT
.Regpat
.Match_Array
(0 .. 0);
400 Expect
(Descriptor
, Result
, Regexps
, Matched
, Timeout
, Full_Buffer
);
404 (Result
: out Expect_Match
;
405 Regexps
: Multiprocess_Regexp_Array
;
406 Timeout
: Integer := 10000;
407 Full_Buffer
: Boolean := False)
409 Matched
: GNAT
.Regpat
.Match_Array
(0 .. 0);
412 Expect
(Result
, Regexps
, Matched
, Timeout
, Full_Buffer
);
416 (Descriptor
: in out Process_Descriptor
;
417 Result
: out Expect_Match
;
418 Regexps
: Regexp_Array
;
419 Matched
: out GNAT
.Regpat
.Match_Array
;
420 Timeout
: Integer := 10000;
421 Full_Buffer
: Boolean := False)
423 Patterns
: Compiled_Regexp_Array
(Regexps
'Range);
426 pragma Assert
(Matched
'First = 0);
428 for J
in Regexps
'Range loop
429 Patterns
(J
) := new Pattern_Matcher
'(Compile (Regexps (J).all));
432 Expect (Descriptor, Result, Patterns, Matched, Timeout, Full_Buffer);
434 for J in Regexps'Range loop
440 (Descriptor : in out Process_Descriptor;
441 Result : out Expect_Match;
442 Regexps : Compiled_Regexp_Array;
443 Matched : out GNAT.Regpat.Match_Array;
444 Timeout : Integer := 10000;
445 Full_Buffer : Boolean := False)
448 Descriptors : Array_Of_Pd := (1 => Descriptor'Unrestricted_Access);
451 pragma Assert (Matched'First = 0);
453 Reinitialize_Buffer (Descriptor);
456 -- First, test if what is already in the buffer matches (This is
457 -- required if this package is used in multi-task mode, since one of
458 -- the tasks might have added something in the buffer, and we don't
459 -- want other tasks to wait for new input to be available before
460 -- checking the regexps).
462 if Descriptor.Buffer /= null then
463 for J in Regexps'Range loop
466 Descriptor.Buffer (1 .. Descriptor.Buffer_Index),
469 if Matched (0) /= No_Match then
470 Result := Expect_Match (J);
471 Descriptor.Last_Match_Start := Matched (0).First;
472 Descriptor.Last_Match_End := Matched (0).Last;
478 Expect_Internal (Descriptors, N, Timeout, Full_Buffer);
480 if N = Expect_Timeout or else N = Expect_Full_Buffer then
488 (Result : out Expect_Match;
489 Regexps : Multiprocess_Regexp_Array;
490 Matched : out GNAT.Regpat.Match_Array;
491 Timeout : Integer := 10000;
492 Full_Buffer : Boolean := False)
495 Descriptors : Array_Of_Pd (Regexps'Range);
498 pragma Assert (Matched'First = 0);
500 for J in Descriptors'Range loop
501 Descriptors (J) := Regexps (J).Descriptor;
502 Reinitialize_Buffer (Regexps (J).Descriptor.all);
506 -- First, test if what is already in the buffer matches (This is
507 -- required if this package is used in multi-task mode, since one of
508 -- the tasks might have added something in the buffer, and we don't
509 -- want other tasks to wait for new input to be available before
510 -- checking the regexps).
512 for J in Regexps'Range loop
513 Match (Regexps (J).Regexp.all,
514 Regexps (J).Descriptor.Buffer
515 (1 .. Regexps (J).Descriptor.Buffer_Index),
518 if Matched (0) /= No_Match then
519 Result := Expect_Match (J);
520 Regexps (J).Descriptor.Last_Match_Start := Matched (0).First;
521 Regexps (J).Descriptor.Last_Match_End := Matched (0).Last;
526 Expect_Internal (Descriptors, N, Timeout, Full_Buffer);
528 if N = Expect_Timeout or else N = Expect_Full_Buffer then
535 ---------------------
536 -- Expect_Internal --
537 ---------------------
539 procedure Expect_Internal
540 (Descriptors : in out Array_Of_Pd;
541 Result : out Expect_Match;
543 Full_Buffer : Boolean)
545 Num_Descriptors : Integer;
546 Buffer_Size : Integer := 0;
550 type File_Descriptor_Array is
551 array (Descriptors'Range) of File_Descriptor;
552 Fds : aliased File_Descriptor_Array;
554 type Integer_Array is array (Descriptors'Range) of Integer;
555 Is_Set : aliased Integer_Array;
558 for J in Descriptors'Range loop
559 Fds (J) := Descriptors (J).Output_Fd;
561 if Descriptors (J).Buffer_Size = 0 then
562 Buffer_Size := Integer'Max (Buffer_Size, 4096);
565 Integer'Max (Buffer_Size, Descriptors (J).Buffer_Size);
570 Buffer : aliased String (1 .. Buffer_Size);
571 -- Buffer used for input. This is allocated only once, not for
572 -- every iteration of the loop
575 -- Loop until we match or we have a timeout
579 Poll (Fds'Address, Fds'Length, Timeout, Is_Set'Address);
581 case Num_Descriptors is
591 Result := Expect_Timeout;
597 for J in Descriptors'Range loop
598 if Is_Set (J) = 1 then
599 Buffer_Size := Descriptors (J).Buffer_Size;
601 if Buffer_Size = 0 then
605 N := Read (Descriptors (J).Output_Fd, Buffer'Address,
608 -- Error or End of file
611 -- ??? Note that ddd tries again up to three times
612 -- in that case. See LiterateA.C:174
616 -- If there is no limit to the buffer size
618 if Descriptors (J).Buffer_Size = 0 then
621 Tmp : String_Access := Descriptors (J).Buffer;
625 Descriptors (J).Buffer :=
626 new String (1 .. Tmp'Length + N);
627 Descriptors (J).Buffer (1 .. Tmp'Length) :=
629 Descriptors (J).Buffer
630 (Tmp'Length + 1 .. Tmp'Length + N) :=
633 Descriptors (J).Buffer_Index :=
634 Descriptors (J).Buffer'Last;
637 Descriptors (J).Buffer :=
639 Descriptors (J).Buffer.all :=
641 Descriptors (J).Buffer_Index := N;
646 -- Add what we read to the buffer
648 if Descriptors (J).Buffer_Index + N - 1 >
649 Descriptors (J).Buffer_Size
651 -- If the user wants to know when we have
652 -- read more than the buffer can contain.
655 Result := Expect_Full_Buffer;
659 -- Keep as much as possible from the buffer,
660 -- and forget old characters.
662 Descriptors (J).Buffer
663 (1 .. Descriptors (J).Buffer_Size - N) :=
664 Descriptors (J).Buffer
665 (N - Descriptors (J).Buffer_Size +
666 Descriptors (J).Buffer_Index + 1 ..
667 Descriptors (J).Buffer_Index);
668 Descriptors (J).Buffer_Index :=
669 Descriptors (J).Buffer_Size - N;
672 -- Keep what we read in the buffer.
674 Descriptors (J).Buffer
675 (Descriptors (J).Buffer_Index + 1 ..
676 Descriptors (J).Buffer_Index + N) :=
678 Descriptors (J).Buffer_Index :=
679 Descriptors (J).Buffer_Index + N;
682 -- Call each of the output filter with what we
686 (Descriptors (J).all, Buffer (1 .. N), Output);
688 Result := Expect_Match (N);
702 function Expect_Out (Descriptor : Process_Descriptor) return String is
704 return Descriptor.Buffer (1 .. Descriptor.Last_Match_End);
707 ----------------------
708 -- Expect_Out_Match --
709 ----------------------
711 function Expect_Out_Match (Descriptor : Process_Descriptor) return String is
713 return Descriptor.Buffer
714 (Descriptor.Last_Match_Start .. Descriptor.Last_Match_End);
715 end Expect_Out_Match;
722 (Descriptor : in out Process_Descriptor;
723 Timeout : Integer := 0)
725 Num_Descriptors : Integer;
727 Is_Set : aliased Integer;
728 Buffer_Size : Integer := 8192;
729 Buffer : aliased String (1 .. Buffer_Size);
732 -- Empty the current buffer
734 Descriptor.Last_Match_End := Descriptor.Buffer_Index;
735 Reinitialize_Buffer (Descriptor);
737 -- Read everything from the process to flush its output
741 Poll (Descriptor.Output_Fd'Address, 1, Timeout, Is_Set'Address);
743 case Num_Descriptors is
750 -- Timeout => End of flush
759 N := Read (Descriptor.Output_Fd, Buffer'Address,
777 function Get_Error_Fd
778 (Descriptor : Process_Descriptor)
779 return GNAT.OS_Lib.File_Descriptor
782 return Descriptor.Error_Fd;
789 function Get_Input_Fd
790 (Descriptor : Process_Descriptor)
791 return GNAT.OS_Lib.File_Descriptor
794 return Descriptor.Input_Fd;
801 function Get_Output_Fd
802 (Descriptor : Process_Descriptor)
803 return GNAT.OS_Lib.File_Descriptor
806 return Descriptor.Output_Fd;
814 (Descriptor : Process_Descriptor)
818 return Descriptor.Pid;
825 procedure Interrupt (Descriptor : in out Process_Descriptor) is
826 SIGINT : constant := 2;
829 Send_Signal (Descriptor, SIGINT);
836 procedure Lock_Filters (Descriptor : in out Process_Descriptor) is
838 Descriptor.Filters_Lock := Descriptor.Filters_Lock + 1;
841 ------------------------
842 -- Non_Blocking_Spawn --
843 ------------------------
845 procedure Non_Blocking_Spawn
846 (Descriptor : out Process_Descriptor'Class;
848 Args : GNAT.OS_Lib.Argument_List;
849 Buffer_Size : Natural := 4096;
850 Err_To_Out : Boolean := False)
852 function Fork return Process_Id;
853 pragma Import (C, Fork, "__gnat_expect_fork");
854 -- Starts a new process if possible.
855 -- See the Unix command fork for more information. On systems that
856 -- don't support this capability (Windows...), this command does
857 -- nothing, and Fork will return Null_Pid.
859 Pipe1, Pipe2, Pipe3 : aliased Pipe_Type;
862 Arg_List : aliased array (1 .. Args'Length + 2) of System.Address;
864 Command_With_Path : String_Access;
867 -- Create the rest of the pipes
869 Set_Up_Communications
870 (Descriptor, Err_To_Out, Pipe1'Access, Pipe2'Access, Pipe3'Access);
872 -- Fork a new process
874 Descriptor.Pid := Fork;
876 -- Are we now in the child (or, for Windows, still in the common
879 if Descriptor.Pid = Null_Pid then
881 Command_With_Path := Locate_Exec_On_Path (Command);
883 -- Prepare an array of arguments to pass to C
884 Arg := new String (1 .. Command_With_Path'Length + 1);
885 Arg (1 .. Command_With_Path'Length) := Command_With_Path.all;
886 Arg (Arg'Last) := ASCII.Nul;
887 Arg_List (1) := Arg.all'Address;
889 for J in Args'Range loop
890 Arg := new String (1 .. Args (J)'Length + 1);
891 Arg (1 .. Args (J)'Length) := Args (J).all;
892 Arg (Arg'Last) := ASCII.Nul;
893 Arg_List (J + 2 - Args'First) := Arg.all'Address;
896 Arg_List (Arg_List'Last) := System.Null_Address;
898 -- This does not return on Unix systems
900 Set_Up_Child_Communications
901 (Descriptor, Pipe1, Pipe2, Pipe3, Command_With_Path.all,
904 Free (Command_With_Path);
907 -- Did we have an error when spawning the child ?
909 if Descriptor.Pid < Null_Pid then
912 -- We are now in the parent process
914 Set_Up_Parent_Communications (Descriptor, Pipe1, Pipe2, Pipe3);
919 Descriptor.Buffer_Size := Buffer_Size;
921 if Buffer_Size /= 0 then
922 Descriptor.Buffer := new String (1 .. Positive (Buffer_Size));
924 end Non_Blocking_Spawn;
926 -------------------------
927 -- Reinitialize_Buffer --
928 -------------------------
930 procedure Reinitialize_Buffer
931 (Descriptor : in out Process_Descriptor'Class)
934 if Descriptor.Buffer_Size = 0 then
936 Tmp : String_Access := Descriptor.Buffer;
941 (1 .. Descriptor.Buffer_Index - Descriptor.Last_Match_End);
944 Descriptor.Buffer.all := Tmp
945 (Descriptor.Last_Match_End + 1 .. Descriptor.Buffer_Index);
950 Descriptor.Buffer_Index := Descriptor.Buffer'Last;
954 (1 .. Descriptor.Buffer_Index - Descriptor.Last_Match_End) :=
956 (Descriptor.Last_Match_End + 1 .. Descriptor.Buffer_Index);
958 if Descriptor.Buffer_Index > Descriptor.Last_Match_End then
959 Descriptor.Buffer_Index :=
960 Descriptor.Buffer_Index - Descriptor.Last_Match_End;
962 Descriptor.Buffer_Index := 0;
966 Descriptor.Last_Match_Start := 0;
967 Descriptor.Last_Match_End := 0;
968 end Reinitialize_Buffer;
974 procedure Remove_Filter
975 (Descriptor : in out Process_Descriptor;
976 Filter : Filter_Function)
978 Previous : Filter_List := null;
979 Current : Filter_List := Descriptor.Filters;
982 while Current /= null loop
983 if Current.Filter = Filter then
984 if Previous = null then
985 Descriptor.Filters := Current.Next;
987 Previous.Next := Current.Next;
992 Current := Current.Next;
1001 (Descriptor : in out Process_Descriptor;
1003 Add_LF : Boolean := True;
1004 Empty_Buffer : Boolean := False)
1007 Full_Str : constant String := Str & ASCII.LF;
1009 Result : Expect_Match;
1010 Descriptors : Array_Of_Pd := (1 => Descriptor'Unrestricted_Access);
1013 if Empty_Buffer then
1015 -- Force a read on the process if there is anything waiting.
1017 Expect_Internal (Descriptors, Result,
1018 Timeout => 0, Full_Buffer => False);
1019 Descriptor.Last_Match_End := Descriptor.Buffer_Index;
1023 Reinitialize_Buffer (Descriptor);
1027 Last := Full_Str'Last;
1029 Last := Full_Str'Last - 1;
1032 Call_Filters (Descriptor, Full_Str (Full_Str'First .. Last), Input);
1034 N := Write (Descriptor.Input_Fd,
1036 Last - Full_Str'First + 1);
1043 procedure Send_Signal
1044 (Descriptor : Process_Descriptor;
1048 Kill (Descriptor.Pid, Signal);
1049 -- ??? Need to check process status here.
1052 ---------------------------------
1053 -- Set_Up_Child_Communications --
1054 ---------------------------------
1056 procedure Set_Up_Child_Communications
1057 (Pid : in out Process_Descriptor;
1058 Pipe1 : in out Pipe_Type;
1059 Pipe2 : in out Pipe_Type;
1060 Pipe3 : in out Pipe_Type;
1062 Args : in System.Address)
1064 Input, Output, Error : File_Descriptor;
1067 -- Since Windows does not have a separate fork/exec, we need to
1068 -- perform the following actions:
1069 -- - save stdin, stdout, stderr
1070 -- - replace them by our pipes
1071 -- - create the child with process handle inheritance
1072 -- - revert to the previous stdin, stdout and stderr.
1074 Input := Dup (GNAT.OS_Lib.Standin);
1075 Output := Dup (GNAT.OS_Lib.Standout);
1076 Error := Dup (GNAT.OS_Lib.Standerr);
1078 -- Since we are still called from the parent process, there is no way
1079 -- currently we can cleanly close the unneeded ends of the pipes, but
1080 -- this doesn't really matter.
1081 -- We could close Pipe1.Output, Pipe2.Input, Pipe3.Input.
1083 Dup2 (Pipe1.Input, GNAT.OS_Lib.Standin);
1084 Dup2 (Pipe2.Output, GNAT.OS_Lib.Standout);
1085 Dup2 (Pipe3.Output, GNAT.OS_Lib.Standerr);
1087 Portable_Execvp (Cmd & ASCII.Nul, Args);
1089 -- The following commands are not executed on Unix systems, and are
1090 -- only required for Windows systems. We are now in the parent process.
1092 -- Restore the old descriptors
1094 Dup2 (Input, GNAT.OS_Lib.Standin);
1095 Dup2 (Output, GNAT.OS_Lib.Standout);
1096 Dup2 (Error, GNAT.OS_Lib.Standerr);
1100 end Set_Up_Child_Communications;
1102 ---------------------------
1103 -- Set_Up_Communications --
1104 ---------------------------
1106 procedure Set_Up_Communications
1107 (Pid : in out Process_Descriptor;
1108 Err_To_Out : Boolean;
1109 Pipe1 : access Pipe_Type;
1110 Pipe2 : access Pipe_Type;
1111 Pipe3 : access Pipe_Type) is
1115 if Create_Pipe (Pipe1) /= 0 then
1119 if Create_Pipe (Pipe2) /= 0 then
1123 Pid.Input_Fd := Pipe1.Output;
1124 Pid.Output_Fd := Pipe2.Input;
1127 Pipe3.all := Pipe2.all;
1129 if Create_Pipe (Pipe3) /= 0 then
1134 Pid.Error_Fd := Pipe3.Input;
1135 end Set_Up_Communications;
1137 ----------------------------------
1138 -- Set_Up_Parent_Communications --
1139 ----------------------------------
1141 procedure Set_Up_Parent_Communications
1142 (Pid : in out Process_Descriptor;
1143 Pipe1 : in out Pipe_Type;
1144 Pipe2 : in out Pipe_Type;
1145 Pipe3 : in out Pipe_Type)
1148 Close (Pipe1.Input);
1149 Close (Pipe2.Output);
1150 Close (Pipe3.Output);
1151 end Set_Up_Parent_Communications;
1157 procedure Trace_Filter
1158 (Descriptor : Process_Descriptor'Class;
1160 User_Data : System.Address := System.Null_Address)
1166 --------------------
1167 -- Unlock_Filters --
1168 --------------------
1170 procedure Unlock_Filters (Descriptor : in out Process_Descriptor) is
1172 if Descriptor.Filters_Lock > 0 then
1173 Descriptor.Filters_Lock := Descriptor.Filters_Lock - 1;