1 ------------------------------------------------------------------------------
3 -- GNAT LIBRARY COMPONENTS --
5 -- G N A T . E X P E C T . T T Y --
9 -- Copyright (C) 2000-2011, AdaCore --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with GNAT
.OS_Lib
; use GNAT
.OS_Lib
;
34 with System
; use System
;
36 package body GNAT
.Expect
.TTY
is
38 On_Windows
: constant Boolean := Directory_Separator
= '\';
39 -- True when on Windows
45 overriding
procedure Close
46 (Descriptor
: in out TTY_Process_Descriptor
;
49 procedure Terminate_Process
(Process
: System
.Address
);
50 pragma Import
(C
, Terminate_Process
, "__gnat_terminate_process");
52 function Waitpid
(Process
: System
.Address
) return Integer;
53 pragma Import
(C
, Waitpid
, "__gnat_waitpid");
54 -- Wait for a specific process id, and return its exit code
56 procedure Free_Process
(Process
: System
.Address
);
57 pragma Import
(C
, Free_Process
, "__gnat_free_process");
59 procedure Close_TTY
(Process
: System
.Address
);
60 pragma Import
(C
, Close_TTY
, "__gnat_close_tty");
63 -- If we haven't already closed the process
65 if Descriptor
.Process
= System
.Null_Address
then
69 if Descriptor
.Input_Fd
/= Invalid_FD
then
70 Close
(Descriptor
.Input_Fd
);
73 if Descriptor
.Error_Fd
/= Descriptor
.Output_Fd
74 and then Descriptor
.Error_Fd
/= Invalid_FD
76 Close
(Descriptor
.Error_Fd
);
79 if Descriptor
.Output_Fd
/= Invalid_FD
then
80 Close
(Descriptor
.Output_Fd
);
83 -- Send a Ctrl-C to the process first. This way, if the
84 -- launched process is a "sh" or "cmd", the child processes
85 -- will get terminated as well. Otherwise, terminating the
86 -- main process brutally will leave the children running.
88 Interrupt
(Descriptor
);
91 Terminate_Process
(Descriptor
.Process
);
92 Status
:= Waitpid
(Descriptor
.Process
);
94 if not On_Windows
then
95 Close_TTY
(Descriptor
.Process
);
98 Free_Process
(Descriptor
.Process
'Address);
99 Descriptor
.Process
:= System
.Null_Address
;
101 GNAT
.OS_Lib
.Free
(Descriptor
.Buffer
);
102 Descriptor
.Buffer_Size
:= 0;
106 overriding
procedure Close
(Descriptor
: in out TTY_Process_Descriptor
) is
109 Close
(Descriptor
, Status
);
112 -----------------------------
113 -- Close_Pseudo_Descriptor --
114 -----------------------------
116 procedure Close_Pseudo_Descriptor
117 (Descriptor
: in out TTY_Process_Descriptor
)
120 Descriptor
.Buffer_Size
:= 0;
121 GNAT
.OS_Lib
.Free
(Descriptor
.Buffer
);
122 end Close_Pseudo_Descriptor
;
128 overriding
procedure Interrupt
129 (Descriptor
: in out TTY_Process_Descriptor
)
131 procedure Internal
(Process
: System
.Address
);
132 pragma Import
(C
, Internal
, "__gnat_interrupt_process");
134 if Descriptor
.Process
/= System
.Null_Address
then
135 Internal
(Descriptor
.Process
);
139 procedure Interrupt
(Pid
: Integer) is
140 procedure Internal
(Pid
: Integer);
141 pragma Import
(C
, Internal
, "__gnat_interrupt_pid");
146 -----------------------
147 -- Pseudo_Descriptor --
148 -----------------------
150 procedure Pseudo_Descriptor
151 (Descriptor
: out TTY_Process_Descriptor
'Class;
152 TTY
: GNAT
.TTY
.TTY_Handle
;
153 Buffer_Size
: Natural := 4096) is
155 Descriptor
.Input_Fd
:= GNAT
.TTY
.TTY_Descriptor
(TTY
);
156 Descriptor
.Output_Fd
:= Descriptor
.Input_Fd
;
160 Descriptor
.Buffer_Size
:= Buffer_Size
;
162 if Buffer_Size
/= 0 then
163 Descriptor
.Buffer
:= new String (1 .. Positive (Buffer_Size
));
165 end Pseudo_Descriptor
;
171 overriding
procedure Send
172 (Descriptor
: in out TTY_Process_Descriptor
;
174 Add_LF
: Boolean := True;
175 Empty_Buffer
: Boolean := False)
177 Header
: String (1 .. 5);
182 (Process
: System
.Address
;
186 pragma Import
(C
, Internal
, "__gnat_send_header");
189 Length
:= Str
'Length;
192 Length
:= Length
+ 1;
195 Internal
(Descriptor
.Process
, Header
, Length
, Ret
);
199 -- Need to use the header
202 (Process_Descriptor
(Descriptor
),
203 Header
& Str
, Add_LF
, Empty_Buffer
);
207 (Process_Descriptor
(Descriptor
),
208 Str
, Add_LF
, Empty_Buffer
);
217 (Descriptor
: in out TTY_Process_Descriptor
'Class;
221 procedure Internal
(Process
: System
.Address
; R
, C
: Integer);
222 pragma Import
(C
, Internal
, "__gnat_setup_winsize");
224 if Descriptor
.Process
/= System
.Null_Address
then
225 Internal
(Descriptor
.Process
, Rows
, Columns
);
229 ---------------------------
230 -- Set_Up_Communications --
231 ---------------------------
233 overriding
procedure Set_Up_Communications
234 (Pid
: in out TTY_Process_Descriptor
;
235 Err_To_Out
: Boolean;
236 Pipe1
: access Pipe_Type
;
237 Pipe2
: access Pipe_Type
;
238 Pipe3
: access Pipe_Type
)
240 pragma Unreferenced
(Err_To_Out
, Pipe1
, Pipe2
, Pipe3
);
242 function Internal
(Process
: System
.Address
) return Integer;
243 pragma Import
(C
, Internal
, "__gnat_setup_communication");
246 if Internal
(Pid
.Process
'Address) /= 0 then
247 raise Invalid_Process
with "cannot setup communication.";
249 end Set_Up_Communications
;
251 ---------------------------------
252 -- Set_Up_Child_Communications --
253 ---------------------------------
255 overriding
procedure Set_Up_Child_Communications
256 (Pid
: in out TTY_Process_Descriptor
;
257 Pipe1
: in out Pipe_Type
;
258 Pipe2
: in out Pipe_Type
;
259 Pipe3
: in out Pipe_Type
;
261 Args
: System
.Address
)
263 pragma Unreferenced
(Pipe1
, Pipe2
, Pipe3
, Cmd
);
265 (Process
: System
.Address
; Argv
: System
.Address
; Use_Pipes
: Integer)
267 pragma Import
(C
, Internal
, "__gnat_setup_child_communication");
270 Pid
.Pid
:= Internal
(Pid
.Process
, Args
, Boolean'Pos (Pid
.Use_Pipes
));
271 end Set_Up_Child_Communications
;
273 ----------------------------------
274 -- Set_Up_Parent_Communications --
275 ----------------------------------
277 overriding
procedure Set_Up_Parent_Communications
278 (Pid
: in out TTY_Process_Descriptor
;
279 Pipe1
: in out Pipe_Type
;
280 Pipe2
: in out Pipe_Type
;
281 Pipe3
: in out Pipe_Type
)
283 pragma Unreferenced
(Pipe1
, Pipe2
, Pipe3
);
286 (Process
: System
.Address
;
287 Inputfp
: out File_Descriptor
;
288 Outputfp
: out File_Descriptor
;
289 Errorfp
: out File_Descriptor
;
290 Pid
: out Process_Id
);
291 pragma Import
(C
, Internal
, "__gnat_setup_parent_communication");
295 (Pid
.Process
, Pid
.Input_Fd
, Pid
.Output_Fd
, Pid
.Error_Fd
, Pid
.Pid
);
296 end Set_Up_Parent_Communications
;
302 procedure Set_Use_Pipes
303 (Descriptor
: in out TTY_Process_Descriptor
;
304 Use_Pipes
: Boolean) is
306 Descriptor
.Use_Pipes
:= Use_Pipes
;