2015-05-22 Eric Botcazou <ebotcazou@adacore.com>
[official-gcc.git] / gcc / ada / expect.c
bloba6c1c8fee03ab48c6267ae9e0d82717c6a6e9d85
1 /****************************************************************************
2 * *
3 * GNAT RUN-TIME COMPONENTS *
4 * *
5 * E X P E C T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 2001-2015, AdaCore *
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 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. *
17 * *
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. *
21 * *
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/>. *
26 * *
27 * GNAT was originally developed by the GNAT team at New York University. *
28 * Extensive contributions were provided by Ada Core Technologies Inc. *
29 * *
30 ****************************************************************************/
32 #ifdef __alpha_vxworks
33 #include "vxWorks.h"
34 #endif
36 #ifdef IN_RTS
37 #define POSIX
38 #include "tconfig.h"
39 #include "tsystem.h"
40 #else
41 #include "config.h"
42 #include "system.h"
43 #endif
45 #include <sys/types.h>
47 #ifdef __MINGW32__
48 # if OLD_MINGW
49 # include <sys/wait.h>
50 # endif
51 #elif defined (__vxworks) && defined (__RTP__)
52 # include <wait.h>
53 #elif defined (__Lynx__)
54 /* ??? See comment in adaint.c. */
55 # define GCC_RESOURCE_H
56 # include <sys/wait.h>
57 #elif defined (__PikeOS__)
58 /* No wait.h available */
59 #else
60 #include <sys/wait.h>
61 #endif
63 /* This file provides the low level functionalities needed to implement Expect
64 capabilities in GNAT.Expect.
65 Implementations for unix and windows systems is provided.
66 Dummy stubs are also provided for other systems. */
68 #ifdef _AIX
69 /* Work around the fact that gcc/cpp does not define "__unix__" under AiX. */
70 #define __unix__
71 #endif
73 #ifdef __APPLE__
74 /* Work around the fact that gcc/cpp does not define "__unix__" on Darwin. */
75 #define __unix__
76 #endif
78 #ifdef _WIN32
80 #include <windows.h>
81 #include <process.h>
82 #include <signal.h>
83 #include <io.h>
84 #include "mingw32.h"
86 void
87 __gnat_kill (int pid, int sig, int close)
89 HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
90 if (h == NULL)
91 return;
92 if (sig == 9)
94 TerminateProcess (h, 0);
95 __gnat_win32_remove_handle (NULL, pid);
97 else if (sig == SIGINT)
98 GenerateConsoleCtrlEvent (CTRL_C_EVENT, pid);
99 else if (sig == SIGBREAK)
100 GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid);
101 /* ??? The last two alternatives don't really work. SIGBREAK requires setting
102 up process groups at start time which we don't do; treating SIGINT is just
103 not possible apparently. So we really only support signal 9. Fortunately
104 that's all we use in GNAT.Expect */
106 CloseHandle (h);
110 __gnat_waitpid (int pid)
112 HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
113 DWORD exitcode = 1;
114 DWORD res;
116 if (h != NULL)
118 res = WaitForSingleObject (h, INFINITE);
119 GetExitCodeProcess (h, &exitcode);
120 CloseHandle (h);
123 __gnat_win32_remove_handle (NULL, pid);
124 return (int) exitcode;
128 __gnat_expect_fork (void)
130 return 0;
133 void
134 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
136 *pid = __gnat_portable_no_block_spawn (argv);
140 __gnat_pipe (int *fd)
142 HANDLE read, write;
144 CreatePipe (&read, &write, NULL, 0);
145 fd[0]=_open_osfhandle ((intptr_t)read, 0);
146 fd[1]=_open_osfhandle ((intptr_t)write, 0);
147 return 0; /* always success */
151 __gnat_expect_poll (int *fd,
152 int num_fd,
153 int timeout,
154 int *dead_process,
155 int *is_set)
157 #define MAX_DELAY 100
159 int i, delay, infinite = 0;
160 DWORD avail;
161 HANDLE handles[num_fd];
163 *dead_process = 0;
165 for (i = 0; i < num_fd; i++)
166 is_set[i] = 0;
168 for (i = 0; i < num_fd; i++)
169 handles[i] = (HANDLE) _get_osfhandle (fd [i]);
171 /* Start with small delays, and then increase them, to avoid polling too
172 much when waiting a long time */
173 delay = 5;
175 if (timeout < 0)
176 infinite = 1;
178 while (1)
180 for (i = 0; i < num_fd; i++)
182 if (!PeekNamedPipe (handles [i], NULL, 0, NULL, &avail, NULL))
184 *dead_process = i + 1;
185 return -1;
187 if (avail > 0)
189 is_set[i] = 1;
190 return 1;
194 if (!infinite && timeout <= 0)
195 return 0;
197 Sleep (delay);
198 timeout -= delay;
200 if (delay < MAX_DELAY)
201 delay += 10;
205 #elif defined (VMS)
206 #include <unistd.h>
207 #include <stdio.h>
208 #include <unixio.h>
209 #include <stdlib.h>
210 #include <string.h>
211 #include <vms/descrip.h>
212 #include <stdio.h>
213 #include <vms/stsdef.h>
214 #include <vms/iodef.h>
215 #include <signal.h>
217 void
218 __gnat_kill (int pid, int sig, int close)
220 kill (pid, sig);
224 __gnat_waitpid (int pid)
226 int status = 0;
228 waitpid (pid, &status, 0);
229 status = WEXITSTATUS (status);
231 return status;
235 __gnat_pipe (int *fd)
237 return pipe (fd);
241 __gnat_expect_fork (void)
243 return -1;
246 void
247 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
249 *pid = (int) getpid ();
250 /* Since cmd is fully qualified, it is incorrect to call execvp */
251 execv (cmd, argv);
252 _exit (1);
256 __gnat_expect_poll (int *fd,
257 int num_fd,
258 int timeout,
259 int *dead_process,
260 int *is_set)
262 int i, num, ready = 0;
263 unsigned int status;
264 int mbxchans [num_fd];
265 struct dsc$descriptor_s mbxname;
266 struct io_status_block {
267 short int condition;
268 short int count;
269 int dev;
270 } iosb;
271 char buf [256];
273 *dead_process = 0;
275 for (i = 0; i < num_fd; i++)
276 is_set[i] = 0;
278 for (i = 0; i < num_fd; i++)
281 /* Get name of the mailbox used in the pipe */
282 getname (fd [i], buf);
284 /* Assign a channel to the mailbox */
285 if (strlen (buf) > 0)
287 mbxname.dsc$w_length = strlen (buf);
288 mbxname.dsc$b_dtype = DSC$K_DTYPE_T;
289 mbxname.dsc$b_class = DSC$K_CLASS_S;
290 mbxname.dsc$a_pointer = buf;
292 status = SYS$ASSIGN (&mbxname, &mbxchans[i], 0, 0, 0);
294 if ((status & 1) != 1)
296 ready = -1;
297 dead_process = i + 1;
298 return ready;
303 num = timeout / 100;
305 while (1)
307 for (i = 0; i < num_fd; i++)
309 if (mbxchans[i] > 0)
312 /* Peek in the mailbox to see if there's data */
313 status = SYS$QIOW
314 (0, mbxchans[i], IO$_SENSEMODE|IO$M_READERCHECK,
315 &iosb, 0, 0, 0, 0, 0, 0, 0, 0);
317 if ((status & 1) != 1)
319 ready = -1;
320 goto deassign;
323 if (iosb.count > 0)
325 is_set[i] = 1;
326 ready = 1;
327 goto deassign;
332 if (timeout > 0 && num == 0)
334 ready = 0;
335 goto deassign;
338 usleep (100000);
339 num--;
342 deassign:
344 /* Deassign channels assigned above */
345 for (i = 0; i < num_fd; i++)
347 if (mbxchans[i] > 0)
348 status = SYS$DASSGN (mbxchans[i]);
351 return ready;
353 #elif defined (__unix__)
355 #ifdef __hpux__
356 #include <sys/ptyio.h>
357 #endif
359 #include <sys/time.h>
361 #ifndef NO_FD_SET
362 #define SELECT_MASK fd_set
363 #else /* !NO_FD_SET */
364 #ifndef _AIX
365 typedef long fd_mask;
366 #endif /* _AIX */
367 #ifdef _IBMR2
368 #define SELECT_MASK void
369 #else /* !_IBMR2 */
370 #define SELECT_MASK int
371 #endif /* !_IBMR2 */
372 #endif /* !NO_FD_SET */
374 void
375 __gnat_kill (int pid, int sig, int close)
377 kill (pid, sig);
381 __gnat_waitpid (int pid)
383 int status = 0;
385 waitpid (pid, &status, 0);
386 status = WEXITSTATUS (status);
388 return status;
392 __gnat_pipe (int *fd)
394 return pipe (fd);
398 __gnat_expect_fork (void)
400 return fork ();
403 void
404 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
406 *pid = (int) getpid ();
407 /* Since cmd is fully qualified, it is incorrect to call execvp */
408 execv (cmd, argv);
409 _exit (1);
413 __gnat_expect_poll (int *fd,
414 int num_fd,
415 int timeout,
416 int *dead_process,
417 int *is_set)
419 struct timeval tv;
420 SELECT_MASK rset;
421 SELECT_MASK eset;
423 int max_fd = 0;
424 int ready;
425 int i;
426 int received;
428 *dead_process = 0;
430 tv.tv_sec = timeout / 1000;
431 tv.tv_usec = (timeout % 1000) * 1000;
433 do {
434 FD_ZERO (&rset);
435 FD_ZERO (&eset);
437 for (i = 0; i < num_fd; i++)
439 FD_SET (fd[i], &rset);
440 FD_SET (fd[i], &eset);
442 if (fd[i] > max_fd)
443 max_fd = fd[i];
446 ready =
447 select (max_fd + 1, &rset, NULL, &eset, timeout == -1 ? NULL : &tv);
449 if (ready > 0)
451 received = 0;
453 for (i = 0; i < num_fd; i++)
455 if (FD_ISSET (fd[i], &rset))
457 is_set[i] = 1;
458 received = 1;
460 else
461 is_set[i] = 0;
464 #ifdef __hpux__
465 for (i = 0; i < num_fd; i++)
467 if (FD_ISSET (fd[i], &eset))
469 struct request_info ei;
471 /* Only query and reset error state if no file descriptor
472 is ready to be read, otherwise we will be signalling a
473 died process too early */
475 if (!received)
477 ioctl (fd[i], TIOCREQCHECK, &ei);
479 if (ei.request == TIOCCLOSE)
481 ioctl (fd[i], TIOCREQSET, &ei);
482 dead_process = i + 1;
483 return -1;
486 ioctl (fd[i], TIOCREQSET, &ei);
488 ready--;
491 #endif
493 } while (timeout == -1 && ready == 0);
495 return ready;
498 #else
500 void
501 __gnat_kill (int pid ATTRIBUTE_UNUSED,
502 int sig ATTRIBUTE_UNUSED,
503 int close ATTRIBUTE_UNUSED)
508 __gnat_waitpid (int pid ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED)
510 return 0;
514 __gnat_pipe (int *fd ATTRIBUTE_UNUSED)
516 return -1;
520 __gnat_expect_fork (void)
522 return -1;
525 void
526 __gnat_expect_portable_execvp (int *pid ATTRIBUTE_UNUSED,
527 char *cmd ATTRIBUTE_UNUSED,
528 char *argv[] ATTRIBUTE_UNUSED)
530 *pid = 0;
534 __gnat_expect_poll (int *fd ATTRIBUTE_UNUSED,
535 int num_fd ATTRIBUTE_UNUSED,
536 int timeout ATTRIBUTE_UNUSED,
537 int *dead_process ATTRIBUTE_UNUSED,
538 int *is_set ATTRIBUTE_UNUSED)
540 *dead_process = 0;
541 return -1;
543 #endif