]>
Commit | Line | Data |
---|---|---|
70482933 RK |
1 | /**************************************************************************** |
2 | * * | |
3 | * GNAT COMPILER COMPONENTS * | |
4 | * * | |
5 | * E X P E C T * | |
6 | * * | |
7 | * C Implementation File * | |
8 | * * | |
fbf5a39b | 9 | * Copyright (C) 2001-2003 Ada Core Technologies, Inc. * |
70482933 RK |
10 | * * |
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 2, 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. See the GNU General Public License * | |
17 | * for more details. You should have received a copy of the GNU General * | |
18 | * Public License distributed with GNAT; see file COPYING. If not, write * | |
19 | * to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, * | |
20 | * MA 02111-1307, USA. * | |
21 | * * | |
22 | * As a special exception, if you link this file with other files to * | |
23 | * produce an executable, this file does not by itself cause the resulting * | |
24 | * executable to be covered by the GNU General Public License. This except- * | |
25 | * ion does not however invalidate any other reasons why the executable * | |
26 | * file might be covered by the GNU Public License. * | |
27 | * * | |
28 | * GNAT was originally developed by the GNAT team at New York University. * | |
fbf5a39b | 29 | * Extensive contributions were provided by Ada Core Technologies Inc. * |
70482933 RK |
30 | * * |
31 | ****************************************************************************/ | |
32 | ||
33 | #ifdef __alpha_vxworks | |
34 | #include "vxWorks.h" | |
35 | #endif | |
36 | ||
37 | #ifdef IN_RTS | |
38 | #define POSIX | |
39 | #include "tconfig.h" | |
40 | #include "tsystem.h" | |
41 | #else | |
42 | #include "config.h" | |
43 | #include "system.h" | |
44 | #endif | |
45 | ||
46 | /* This file provides the low level functionalities needed to implement Expect | |
47 | capabilities in GNAT.Expect. | |
48 | Implementations for unix and windows systems is provided. | |
49 | Dummy stubs are also provided for other systems. */ | |
50 | ||
51 | #ifdef _AIX | |
52 | /* Work around the fact that gcc/cpp does not define "unix" under AiX. */ | |
53 | #define unix | |
54 | #endif | |
55 | ||
56 | #ifdef _WIN32 | |
57 | ||
58 | #include <windows.h> | |
59 | #include <process.h> | |
60 | ||
70482933 | 61 | void |
fbf5a39b | 62 | __gnat_kill (int pid, int sig) |
70482933 | 63 | { |
fbf5a39b AC |
64 | HANDLE process_handle; |
65 | ||
66 | if (sig == 9) | |
67 | { | |
68 | process_handle = OpenProcess (PROCESS_TERMINATE, FALSE, pid); | |
69 | if (process_handle != NULL) | |
70 | TerminateProcess (process_handle, 0); | |
71 | } | |
70482933 RK |
72 | } |
73 | ||
74 | int | |
75 | __gnat_expect_fork () | |
76 | { | |
77 | return 0; | |
78 | } | |
79 | ||
80 | void | |
fbf5a39b | 81 | __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[]) |
70482933 | 82 | { |
07fc65c4 | 83 | *pid = (int) spawnve (_P_NOWAIT, cmd, argv, NULL); |
70482933 RK |
84 | } |
85 | ||
86 | int | |
fbf5a39b | 87 | __gnat_pipe (int *fd) |
70482933 RK |
88 | { |
89 | HANDLE read, write; | |
90 | ||
91 | CreatePipe (&read, &write, NULL, 0); | |
fbf5a39b AC |
92 | fd[0]=_open_osfhandle ((long)read, 0); |
93 | fd[1]=_open_osfhandle ((long)write, 0); | |
70482933 RK |
94 | return 0; /* always success */ |
95 | } | |
96 | ||
97 | int | |
fbf5a39b | 98 | __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set) |
70482933 | 99 | { |
fbf5a39b AC |
100 | #define MAX_DELAY 100 |
101 | ||
102 | int i, delay, infinite = 0; | |
70482933 RK |
103 | DWORD avail; |
104 | HANDLE handles[num_fd]; | |
105 | ||
106 | for (i = 0; i < num_fd; i++) | |
107 | is_set[i] = 0; | |
108 | ||
109 | for (i = 0; i < num_fd; i++) | |
fbf5a39b AC |
110 | handles[i] = (HANDLE) _get_osfhandle (fd [i]); |
111 | ||
112 | /* Start with small delays, and then increase them, to avoid polling too | |
113 | much when waiting a long time */ | |
114 | delay = 5; | |
70482933 | 115 | |
fbf5a39b AC |
116 | if (timeout < 0) |
117 | infinite = 1; | |
70482933 RK |
118 | |
119 | while (1) | |
120 | { | |
121 | for (i = 0; i < num_fd; i++) | |
fbf5a39b AC |
122 | { |
123 | if (!PeekNamedPipe (handles [i], NULL, 0, NULL, &avail, NULL)) | |
124 | return -1; | |
70482933 | 125 | |
fbf5a39b AC |
126 | if (avail > 0) |
127 | { | |
128 | is_set[i] = 1; | |
129 | return 1; | |
130 | } | |
131 | } | |
70482933 | 132 | |
fbf5a39b AC |
133 | if (!infinite && timeout <= 0) |
134 | return 0; | |
70482933 | 135 | |
fbf5a39b AC |
136 | Sleep (delay); |
137 | timeout -= delay; | |
138 | ||
139 | if (delay < MAX_DELAY) | |
140 | delay += 10; | |
70482933 RK |
141 | } |
142 | } | |
143 | ||
07fc65c4 GB |
144 | #elif defined (VMS) |
145 | #include <unistd.h> | |
146 | #include <stdio.h> | |
147 | #include <unixio.h> | |
148 | #include <stdlib.h> | |
149 | #include <string.h> | |
150 | #include <descrip.h> | |
151 | #include <stdio.h> | |
152 | #include <stsdef.h> | |
153 | #include <iodef.h> | |
154 | ||
155 | int | |
fbf5a39b | 156 | __gnat_pipe (int *fd) |
07fc65c4 GB |
157 | { |
158 | return pipe (fd); | |
159 | } | |
160 | ||
161 | int | |
162 | __gnat_expect_fork () | |
163 | { | |
164 | return -1; | |
165 | } | |
166 | ||
167 | void | |
fbf5a39b | 168 | __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[]) |
07fc65c4 | 169 | { |
fbf5a39b AC |
170 | *pid = (int) getpid (); |
171 | /* Since cmd is fully qualified, it is incorrect to call execvp */ | |
07fc65c4 | 172 | execv (cmd, argv); |
fbf5a39b | 173 | _exit (1); |
07fc65c4 GB |
174 | } |
175 | ||
176 | int | |
fbf5a39b | 177 | __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set) |
07fc65c4 GB |
178 | { |
179 | int i, num, ready = 0; | |
180 | unsigned int status; | |
181 | int mbxchans [num_fd]; | |
182 | struct dsc$descriptor_s mbxname; | |
183 | struct io_status_block { | |
184 | short int condition; | |
185 | short int count; | |
186 | int dev; | |
187 | } iosb; | |
188 | char buf [256]; | |
189 | ||
190 | for (i = 0; i < num_fd; i++) | |
191 | is_set[i] = 0; | |
192 | ||
193 | for (i = 0; i < num_fd; i++) | |
194 | { | |
195 | ||
196 | /* Get name of the mailbox used in the pipe */ | |
197 | getname (fd [i], buf); | |
198 | ||
199 | /* Assign a channel to the mailbox */ | |
200 | if (strlen (buf) > 0) | |
201 | { | |
202 | mbxname.dsc$w_length = strlen (buf); | |
203 | mbxname.dsc$b_dtype = DSC$K_DTYPE_T; | |
204 | mbxname.dsc$b_class = DSC$K_CLASS_S; | |
205 | mbxname.dsc$a_pointer = buf; | |
206 | ||
207 | status = SYS$ASSIGN (&mbxname, &mbxchans[i], 0, 0, 0); | |
fbf5a39b AC |
208 | |
209 | if ((status & 1) != 1) | |
210 | { | |
211 | ready = -1; | |
212 | return ready; | |
213 | } | |
07fc65c4 GB |
214 | } |
215 | } | |
216 | ||
217 | num = timeout / 100; | |
218 | ||
219 | while (1) | |
220 | { | |
221 | for (i = 0; i < num_fd; i++) | |
222 | { | |
223 | if (mbxchans[i] > 0) | |
224 | { | |
225 | ||
226 | /* Peek in the mailbox to see if there's data */ | |
227 | status = SYS$QIOW | |
228 | (0, mbxchans[i], IO$_SENSEMODE|IO$M_READERCHECK, | |
229 | &iosb, 0, 0, 0, 0, 0, 0, 0, 0); | |
230 | ||
fbf5a39b AC |
231 | if ((status & 1) != 1) |
232 | { | |
233 | ready = -1; | |
234 | goto deassign; | |
235 | } | |
236 | ||
07fc65c4 GB |
237 | if (iosb.count > 0) |
238 | { | |
239 | is_set[i] = 1; | |
240 | ready = 1; | |
241 | goto deassign; | |
242 | } | |
243 | } | |
244 | } | |
245 | ||
fbf5a39b | 246 | if (timeout > 0 && num == 0) |
07fc65c4 GB |
247 | { |
248 | ready = 0; | |
249 | goto deassign; | |
250 | } | |
251 | ||
252 | usleep (100000); | |
253 | num--; | |
254 | } | |
255 | ||
256 | deassign: | |
257 | ||
258 | /* Deassign channels assigned above */ | |
259 | for (i = 0; i < num_fd; i++) | |
260 | { | |
261 | if (mbxchans[i] > 0) | |
262 | status = SYS$DASSGN (mbxchans[i]); | |
263 | } | |
264 | ||
265 | return ready; | |
266 | } | |
267 | ||
70482933 RK |
268 | #elif defined (unix) |
269 | ||
fbf5a39b AC |
270 | #ifdef hpux |
271 | #include <sys/ptyio.h> | |
272 | #endif | |
273 | ||
70482933 RK |
274 | #include <sys/time.h> |
275 | ||
276 | #ifndef NO_FD_SET | |
277 | #define SELECT_MASK fd_set | |
278 | #else /* !NO_FD_SET */ | |
279 | #ifndef _AIX | |
280 | typedef long fd_mask; | |
281 | #endif /* _AIX */ | |
282 | #ifdef _IBMR2 | |
283 | #define SELECT_MASK void | |
284 | #else /* !_IBMR2 */ | |
285 | #define SELECT_MASK int | |
286 | #endif /* !_IBMR2 */ | |
287 | #endif /* !NO_FD_SET */ | |
288 | ||
fbf5a39b AC |
289 | void |
290 | __gnat_kill (int pid, int sig) | |
291 | { | |
292 | kill (pid, sig); | |
293 | } | |
294 | ||
70482933 | 295 | int |
fbf5a39b | 296 | __gnat_pipe (int *fd) |
70482933 RK |
297 | { |
298 | return pipe (fd); | |
299 | } | |
300 | ||
301 | int | |
302 | __gnat_expect_fork () | |
303 | { | |
304 | return fork (); | |
305 | } | |
306 | ||
307 | void | |
fbf5a39b | 308 | __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[]) |
70482933 | 309 | { |
fbf5a39b AC |
310 | *pid = (int) getpid (); |
311 | /* Since cmd is fully qualified, it is incorrect to call execvp */ | |
312 | execv (cmd, argv); | |
313 | _exit (1); | |
70482933 RK |
314 | } |
315 | ||
316 | int | |
fbf5a39b | 317 | __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set) |
70482933 RK |
318 | { |
319 | struct timeval tv; | |
320 | SELECT_MASK rset; | |
fbf5a39b AC |
321 | SELECT_MASK eset; |
322 | ||
70482933 RK |
323 | int max_fd = 0; |
324 | int ready; | |
325 | int i; | |
fbf5a39b | 326 | int received; |
70482933 RK |
327 | |
328 | tv.tv_sec = timeout / 1000; | |
329 | tv.tv_usec = (timeout % 1000) * 1000; | |
330 | ||
fbf5a39b AC |
331 | do { |
332 | FD_ZERO (&rset); | |
333 | FD_ZERO (&eset); | |
70482933 | 334 | |
70482933 | 335 | for (i = 0; i < num_fd; i++) |
fbf5a39b AC |
336 | { |
337 | FD_SET (fd[i], &rset); | |
338 | FD_SET (fd[i], &eset); | |
339 | ||
340 | if (fd[i] > max_fd) | |
341 | max_fd = fd[i]; | |
342 | } | |
343 | ||
344 | ready = | |
345 | select (max_fd + 1, &rset, NULL, &eset, timeout == -1 ? NULL : &tv); | |
346 | ||
347 | if (ready > 0) | |
348 | { | |
349 | received = 0; | |
350 | ||
351 | for (i = 0; i < num_fd; i++) | |
352 | { | |
353 | if (FD_ISSET (fd[i], &rset)) | |
354 | { | |
355 | is_set[i] = 1; | |
356 | received = 1; | |
357 | } | |
358 | else | |
359 | is_set[i] = 0; | |
360 | } | |
361 | ||
362 | #ifdef hpux | |
363 | for (i = 0; i < num_fd; i++) | |
364 | { | |
365 | if (FD_ISSET (fd[i], &eset)) | |
366 | { | |
367 | struct request_info ei; | |
368 | ||
369 | /* Only query and reset error state if no file descriptor | |
370 | is ready to be read, otherwise we will be signalling a | |
371 | died process too early */ | |
372 | ||
373 | if (!received) | |
374 | { | |
375 | ioctl (fd[i], TIOCREQCHECK, &ei); | |
376 | ||
377 | if (ei.request == TIOCCLOSE) | |
378 | { | |
379 | ioctl (fd[i], TIOCREQSET, &ei); | |
380 | return -1; | |
381 | } | |
382 | ||
383 | ioctl (fd[i], TIOCREQSET, &ei); | |
384 | } | |
385 | ready--; | |
386 | } | |
387 | } | |
388 | #endif | |
389 | } | |
390 | } while (timeout == -1 && ready == 0); | |
70482933 RK |
391 | |
392 | return ready; | |
393 | } | |
394 | ||
395 | #else | |
396 | ||
fbf5a39b AC |
397 | void |
398 | __gnat_kill (int pid, int sig) | |
399 | { | |
400 | } | |
401 | ||
70482933 | 402 | int |
fbf5a39b | 403 | __gnat_pipe (int *fd) |
70482933 RK |
404 | { |
405 | return -1; | |
406 | } | |
407 | ||
408 | int | |
409 | __gnat_expect_fork () | |
410 | { | |
411 | return -1; | |
412 | } | |
413 | ||
414 | void | |
fbf5a39b | 415 | __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[]) |
70482933 | 416 | { |
07fc65c4 | 417 | *pid = 0; |
70482933 RK |
418 | } |
419 | ||
420 | int | |
fbf5a39b | 421 | __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set) |
70482933 RK |
422 | { |
423 | return -1; | |
424 | } | |
425 | #endif |