Merge from mainline
[official-gcc.git] / gcc / ada / expect.c
blob6d2cf86e3226594ad5fd44ee1754fdc1b53e0993
1 /****************************************************************************
2 * *
3 * GNAT COMPILER COMPONENTS *
4 * *
5 * E X P E C T *
6 * *
7 * C Implementation File *
8 * *
9 * Copyright (C) 2001-2005, 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 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, 51 Franklin Street, Fifth Floor, *
20 * Boston, MA 02110-1301, 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. *
29 * Extensive contributions were provided by Ada Core Technologies Inc. *
30 * *
31 ****************************************************************************/
33 #ifdef __alpha_vxworks
34 #include "vxWorks.h"
35 #endif
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
46 #include <sys/types.h>
48 #ifdef __MINGW32__
49 #if OLD_MINGW
50 #include <sys/wait.h>
51 #endif
52 #elif defined (__vxworks) && defined (__RTP__)
53 #include <wait.h>
54 #else
55 #include <sys/wait.h>
56 #endif
58 /* This file provides the low level functionalities needed to implement Expect
59 capabilities in GNAT.Expect.
60 Implementations for unix and windows systems is provided.
61 Dummy stubs are also provided for other systems. */
63 #ifdef _AIX
64 /* Work around the fact that gcc/cpp does not define "__unix__" under AiX. */
65 #define __unix__
66 #endif
68 #ifdef __APPLE__
69 /* Work around the fact that gcc/cpp does not define "__unix__" on Darwin. */
70 #define __unix__
71 #endif
73 #ifdef _WIN32
75 #include <windows.h>
76 #include <process.h>
78 void
79 __gnat_kill (int pid, int sig, int close)
81 if (sig == 9)
83 if ((HANDLE)pid != NULL)
85 TerminateProcess ((HANDLE)pid, 0);
86 if (close)
87 CloseHandle ((HANDLE)pid);
92 int
93 __gnat_waitpid (int pid)
95 DWORD exitcode = 1;
96 DWORD res;
98 if ((HANDLE)pid != NULL)
100 res = WaitForSingleObject ((HANDLE)pid, INFINITE);
101 GetExitCodeProcess ((HANDLE)pid, &exitcode);
102 CloseHandle ((HANDLE)pid);
105 return (int) exitcode;
109 __gnat_expect_fork (void)
111 return 0;
114 void
115 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
117 BOOL result;
118 STARTUPINFO SI;
119 PROCESS_INFORMATION PI;
120 SECURITY_ATTRIBUTES SA;
121 int csize = 1;
122 char *full_command;
123 int k;
125 /* compute the total command line length. */
126 k = 0;
127 while (argv[k])
129 csize += strlen (argv[k]) + 1;
130 k++;
133 full_command = (char *) malloc (csize);
134 full_command[0] = '\0';
136 /* Startup info. */
137 SI.cb = sizeof (STARTUPINFO);
138 SI.lpReserved = NULL;
139 SI.lpReserved2 = NULL;
140 SI.lpDesktop = NULL;
141 SI.cbReserved2 = 0;
142 SI.lpTitle = NULL;
143 SI.dwFlags = 0;
144 SI.wShowWindow = SW_HIDE;
146 /* Security attributes. */
147 SA.nLength = sizeof (SECURITY_ATTRIBUTES);
148 SA.bInheritHandle = TRUE;
149 SA.lpSecurityDescriptor = NULL;
151 k = 0;
152 while (argv[k])
154 strcat (full_command, argv[k]);
155 strcat (full_command, " ");
156 k++;
159 result = CreateProcess
160 (NULL, (char *) full_command, &SA, NULL, TRUE,
161 GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI);
163 free (full_command);
165 if (result == TRUE)
167 CloseHandle (PI.hThread);
168 *pid = (int) PI.hProcess;
170 else
171 *pid = -1;
175 __gnat_pipe (int *fd)
177 HANDLE read, write;
179 CreatePipe (&read, &write, NULL, 0);
180 fd[0]=_open_osfhandle ((long)read, 0);
181 fd[1]=_open_osfhandle ((long)write, 0);
182 return 0; /* always success */
186 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
188 #define MAX_DELAY 100
190 int i, delay, infinite = 0;
191 DWORD avail;
192 HANDLE handles[num_fd];
194 for (i = 0; i < num_fd; i++)
195 is_set[i] = 0;
197 for (i = 0; i < num_fd; i++)
198 handles[i] = (HANDLE) _get_osfhandle (fd [i]);
200 /* Start with small delays, and then increase them, to avoid polling too
201 much when waiting a long time */
202 delay = 5;
204 if (timeout < 0)
205 infinite = 1;
207 while (1)
209 for (i = 0; i < num_fd; i++)
211 if (!PeekNamedPipe (handles [i], NULL, 0, NULL, &avail, NULL))
212 return -1;
214 if (avail > 0)
216 is_set[i] = 1;
217 return 1;
221 if (!infinite && timeout <= 0)
222 return 0;
224 Sleep (delay);
225 timeout -= delay;
227 if (delay < MAX_DELAY)
228 delay += 10;
232 #elif defined (VMS)
233 #include <unistd.h>
234 #include <stdio.h>
235 #include <unixio.h>
236 #include <stdlib.h>
237 #include <string.h>
238 #include <vms/descrip.h>
239 #include <stdio.h>
240 #include <vms/stsdef.h>
241 #include <vms/iodef.h>
244 __gnat_waitpid (int pid)
246 int status = 0;
248 waitpid (pid, &status, 0);
249 status = WEXITSTATUS (status);
251 return status;
255 __gnat_pipe (int *fd)
257 return pipe (fd);
261 __gnat_expect_fork (void)
263 return -1;
266 void
267 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
269 *pid = (int) getpid ();
270 /* Since cmd is fully qualified, it is incorrect to call execvp */
271 execv (cmd, argv);
272 _exit (1);
276 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
278 int i, num, ready = 0;
279 unsigned int status;
280 int mbxchans [num_fd];
281 struct dsc$descriptor_s mbxname;
282 struct io_status_block {
283 short int condition;
284 short int count;
285 int dev;
286 } iosb;
287 char buf [256];
289 for (i = 0; i < num_fd; i++)
290 is_set[i] = 0;
292 for (i = 0; i < num_fd; i++)
295 /* Get name of the mailbox used in the pipe */
296 getname (fd [i], buf);
298 /* Assign a channel to the mailbox */
299 if (strlen (buf) > 0)
301 mbxname.dsc$w_length = strlen (buf);
302 mbxname.dsc$b_dtype = DSC$K_DTYPE_T;
303 mbxname.dsc$b_class = DSC$K_CLASS_S;
304 mbxname.dsc$a_pointer = buf;
306 status = SYS$ASSIGN (&mbxname, &mbxchans[i], 0, 0, 0);
308 if ((status & 1) != 1)
310 ready = -1;
311 return ready;
316 num = timeout / 100;
318 while (1)
320 for (i = 0; i < num_fd; i++)
322 if (mbxchans[i] > 0)
325 /* Peek in the mailbox to see if there's data */
326 status = SYS$QIOW
327 (0, mbxchans[i], IO$_SENSEMODE|IO$M_READERCHECK,
328 &iosb, 0, 0, 0, 0, 0, 0, 0, 0);
330 if ((status & 1) != 1)
332 ready = -1;
333 goto deassign;
336 if (iosb.count > 0)
338 is_set[i] = 1;
339 ready = 1;
340 goto deassign;
345 if (timeout > 0 && num == 0)
347 ready = 0;
348 goto deassign;
351 usleep (100000);
352 num--;
355 deassign:
357 /* Deassign channels assigned above */
358 for (i = 0; i < num_fd; i++)
360 if (mbxchans[i] > 0)
361 status = SYS$DASSGN (mbxchans[i]);
364 return ready;
367 #elif defined (__unix__)
369 #ifdef __hpux__
370 #include <sys/ptyio.h>
371 #endif
373 #include <sys/time.h>
375 #ifndef NO_FD_SET
376 #define SELECT_MASK fd_set
377 #else /* !NO_FD_SET */
378 #ifndef _AIX
379 typedef long fd_mask;
380 #endif /* _AIX */
381 #ifdef _IBMR2
382 #define SELECT_MASK void
383 #else /* !_IBMR2 */
384 #define SELECT_MASK int
385 #endif /* !_IBMR2 */
386 #endif /* !NO_FD_SET */
388 void
389 __gnat_kill (int pid, int sig, int close)
391 kill (pid, sig);
395 __gnat_waitpid (int pid)
397 int status = 0;
399 waitpid (pid, &status, 0);
400 status = WEXITSTATUS (status);
402 return status;
406 __gnat_pipe (int *fd)
408 return pipe (fd);
412 __gnat_expect_fork (void)
414 return fork ();
417 void
418 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
420 *pid = (int) getpid ();
421 /* Since cmd is fully qualified, it is incorrect to call execvp */
422 execv (cmd, argv);
423 _exit (1);
427 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
429 struct timeval tv;
430 SELECT_MASK rset;
431 SELECT_MASK eset;
433 int max_fd = 0;
434 int ready;
435 int i;
436 int received;
438 tv.tv_sec = timeout / 1000;
439 tv.tv_usec = (timeout % 1000) * 1000;
441 do {
442 FD_ZERO (&rset);
443 FD_ZERO (&eset);
445 for (i = 0; i < num_fd; i++)
447 FD_SET (fd[i], &rset);
448 FD_SET (fd[i], &eset);
450 if (fd[i] > max_fd)
451 max_fd = fd[i];
454 ready =
455 select (max_fd + 1, &rset, NULL, &eset, timeout == -1 ? NULL : &tv);
457 if (ready > 0)
459 received = 0;
461 for (i = 0; i < num_fd; i++)
463 if (FD_ISSET (fd[i], &rset))
465 is_set[i] = 1;
466 received = 1;
468 else
469 is_set[i] = 0;
472 #ifdef __hpux__
473 for (i = 0; i < num_fd; i++)
475 if (FD_ISSET (fd[i], &eset))
477 struct request_info ei;
479 /* Only query and reset error state if no file descriptor
480 is ready to be read, otherwise we will be signalling a
481 died process too early */
483 if (!received)
485 ioctl (fd[i], TIOCREQCHECK, &ei);
487 if (ei.request == TIOCCLOSE)
489 ioctl (fd[i], TIOCREQSET, &ei);
490 return -1;
493 ioctl (fd[i], TIOCREQSET, &ei);
495 ready--;
498 #endif
500 } while (timeout == -1 && ready == 0);
502 return ready;
505 #else
507 void
508 __gnat_kill (int pid, int sig, int close)
513 __gnat_waitpid (int pid, int sig)
515 return 0;
519 __gnat_pipe (int *fd)
521 return -1;
525 __gnat_expect_fork (void)
527 return -1;
530 void
531 __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
533 *pid = 0;
537 __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set)
539 return -1;
541 #endif