| /**************************************************************************** |
| * * |
| * GNAT COMPILER COMPONENTS * |
| * * |
| * E X P E C T * |
| * * |
| * C Implementation File * |
| * * |
| * Copyright (C) 2001-2005, AdaCore * |
| * * |
| * GNAT is free software; you can redistribute it and/or modify it under * |
| * terms of the GNU General Public License as published by the Free Soft- * |
| * ware Foundation; either version 2, or (at your option) any later ver- * |
| * sion. GNAT is distributed in the hope that it will be useful, but WITH- * |
| * OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * |
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * |
| * for more details. You should have received a copy of the GNU General * |
| * Public License distributed with GNAT; see file COPYING. If not, write * |
| * to the Free Software Foundation, 51 Franklin Street, Fifth Floor, * |
| * Boston, MA 02110-1301, USA. * |
| * * |
| * As a special exception, if you link this file with other files to * |
| * produce an executable, this file does not by itself cause the resulting * |
| * executable to be covered by the GNU General Public License. This except- * |
| * ion does not however invalidate any other reasons why the executable * |
| * file might be covered by the GNU Public License. * |
| * * |
| * GNAT was originally developed by the GNAT team at New York University. * |
| * Extensive contributions were provided by Ada Core Technologies Inc. * |
| * * |
| ****************************************************************************/ |
| |
| #ifdef __alpha_vxworks |
| #include "vxWorks.h" |
| #endif |
| |
| #ifdef IN_RTS |
| #define POSIX |
| #include "tconfig.h" |
| #include "tsystem.h" |
| #else |
| #include "config.h" |
| #include "system.h" |
| #endif |
| |
| #include <sys/types.h> |
| |
| #ifdef __MINGW32__ |
| #if OLD_MINGW |
| #include <sys/wait.h> |
| #endif |
| #elif defined (__vxworks) && defined (__RTP__) |
| #include <wait.h> |
| #else |
| #include <sys/wait.h> |
| #endif |
| |
| /* This file provides the low level functionalities needed to implement Expect |
| capabilities in GNAT.Expect. |
| Implementations for unix and windows systems is provided. |
| Dummy stubs are also provided for other systems. */ |
| |
| #ifdef _AIX |
| /* Work around the fact that gcc/cpp does not define "__unix__" under AiX. */ |
| #define __unix__ |
| #endif |
| |
| #ifdef __APPLE__ |
| /* Work around the fact that gcc/cpp does not define "__unix__" on Darwin. */ |
| #define __unix__ |
| #endif |
| |
| #ifdef _WIN32 |
| |
| #include <windows.h> |
| #include <process.h> |
| |
| void |
| __gnat_kill (int pid, int sig, int close) |
| { |
| if (sig == 9) |
| { |
| if ((HANDLE)pid != NULL) |
| { |
| TerminateProcess ((HANDLE)pid, 0); |
| if (close) |
| CloseHandle ((HANDLE)pid); |
| } |
| } |
| } |
| |
| int |
| __gnat_waitpid (int pid) |
| { |
| DWORD exitcode = 1; |
| DWORD res; |
| |
| if ((HANDLE)pid != NULL) |
| { |
| res = WaitForSingleObject ((HANDLE)pid, INFINITE); |
| GetExitCodeProcess ((HANDLE)pid, &exitcode); |
| CloseHandle ((HANDLE)pid); |
| } |
| |
| return (int) exitcode; |
| } |
| |
| int |
| __gnat_expect_fork (void) |
| { |
| return 0; |
| } |
| |
| void |
| __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[]) |
| { |
| BOOL result; |
| STARTUPINFO SI; |
| PROCESS_INFORMATION PI; |
| SECURITY_ATTRIBUTES SA; |
| int csize = 1; |
| char *full_command; |
| int k; |
| |
| /* compute the total command line length. */ |
| k = 0; |
| while (argv[k]) |
| { |
| csize += strlen (argv[k]) + 1; |
| k++; |
| } |
| |
| full_command = (char *) malloc (csize); |
| full_command[0] = '\0'; |
| |
| /* Startup info. */ |
| SI.cb = sizeof (STARTUPINFO); |
| SI.lpReserved = NULL; |
| SI.lpReserved2 = NULL; |
| SI.lpDesktop = NULL; |
| SI.cbReserved2 = 0; |
| SI.lpTitle = NULL; |
| SI.dwFlags = 0; |
| SI.wShowWindow = SW_HIDE; |
| |
| /* Security attributes. */ |
| SA.nLength = sizeof (SECURITY_ATTRIBUTES); |
| SA.bInheritHandle = TRUE; |
| SA.lpSecurityDescriptor = NULL; |
| |
| k = 0; |
| while (argv[k]) |
| { |
| strcat (full_command, argv[k]); |
| strcat (full_command, " "); |
| k++; |
| } |
| |
| result = CreateProcess |
| (NULL, (char *) full_command, &SA, NULL, TRUE, |
| GetPriorityClass (GetCurrentProcess()), NULL, NULL, &SI, &PI); |
| |
| free (full_command); |
| |
| if (result == TRUE) |
| { |
| CloseHandle (PI.hThread); |
| *pid = (int) PI.hProcess; |
| } |
| else |
| *pid = -1; |
| } |
| |
| int |
| __gnat_pipe (int *fd) |
| { |
| HANDLE read, write; |
| |
| CreatePipe (&read, &write, NULL, 0); |
| fd[0]=_open_osfhandle ((long)read, 0); |
| fd[1]=_open_osfhandle ((long)write, 0); |
| return 0; /* always success */ |
| } |
| |
| int |
| __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set) |
| { |
| #define MAX_DELAY 100 |
| |
| int i, delay, infinite = 0; |
| DWORD avail; |
| HANDLE handles[num_fd]; |
| |
| for (i = 0; i < num_fd; i++) |
| is_set[i] = 0; |
| |
| for (i = 0; i < num_fd; i++) |
| handles[i] = (HANDLE) _get_osfhandle (fd [i]); |
| |
| /* Start with small delays, and then increase them, to avoid polling too |
| much when waiting a long time */ |
| delay = 5; |
| |
| if (timeout < 0) |
| infinite = 1; |
| |
| while (1) |
| { |
| for (i = 0; i < num_fd; i++) |
| { |
| if (!PeekNamedPipe (handles [i], NULL, 0, NULL, &avail, NULL)) |
| return -1; |
| |
| if (avail > 0) |
| { |
| is_set[i] = 1; |
| return 1; |
| } |
| } |
| |
| if (!infinite && timeout <= 0) |
| return 0; |
| |
| Sleep (delay); |
| timeout -= delay; |
| |
| if (delay < MAX_DELAY) |
| delay += 10; |
| } |
| } |
| |
| #elif defined (VMS) |
| #include <unistd.h> |
| #include <stdio.h> |
| #include <unixio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <vms/descrip.h> |
| #include <stdio.h> |
| #include <vms/stsdef.h> |
| #include <vms/iodef.h> |
| |
| int |
| __gnat_waitpid (int pid) |
| { |
| int status = 0; |
| |
| waitpid (pid, &status, 0); |
| status = WEXITSTATUS (status); |
| |
| return status; |
| } |
| |
| int |
| __gnat_pipe (int *fd) |
| { |
| return pipe (fd); |
| } |
| |
| int |
| __gnat_expect_fork (void) |
| { |
| return -1; |
| } |
| |
| void |
| __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[]) |
| { |
| *pid = (int) getpid (); |
| /* Since cmd is fully qualified, it is incorrect to call execvp */ |
| execv (cmd, argv); |
| _exit (1); |
| } |
| |
| int |
| __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set) |
| { |
| int i, num, ready = 0; |
| unsigned int status; |
| int mbxchans [num_fd]; |
| struct dsc$descriptor_s mbxname; |
| struct io_status_block { |
| short int condition; |
| short int count; |
| int dev; |
| } iosb; |
| char buf [256]; |
| |
| for (i = 0; i < num_fd; i++) |
| is_set[i] = 0; |
| |
| for (i = 0; i < num_fd; i++) |
| { |
| |
| /* Get name of the mailbox used in the pipe */ |
| getname (fd [i], buf); |
| |
| /* Assign a channel to the mailbox */ |
| if (strlen (buf) > 0) |
| { |
| mbxname.dsc$w_length = strlen (buf); |
| mbxname.dsc$b_dtype = DSC$K_DTYPE_T; |
| mbxname.dsc$b_class = DSC$K_CLASS_S; |
| mbxname.dsc$a_pointer = buf; |
| |
| status = SYS$ASSIGN (&mbxname, &mbxchans[i], 0, 0, 0); |
| |
| if ((status & 1) != 1) |
| { |
| ready = -1; |
| return ready; |
| } |
| } |
| } |
| |
| num = timeout / 100; |
| |
| while (1) |
| { |
| for (i = 0; i < num_fd; i++) |
| { |
| if (mbxchans[i] > 0) |
| { |
| |
| /* Peek in the mailbox to see if there's data */ |
| status = SYS$QIOW |
| (0, mbxchans[i], IO$_SENSEMODE|IO$M_READERCHECK, |
| &iosb, 0, 0, 0, 0, 0, 0, 0, 0); |
| |
| if ((status & 1) != 1) |
| { |
| ready = -1; |
| goto deassign; |
| } |
| |
| if (iosb.count > 0) |
| { |
| is_set[i] = 1; |
| ready = 1; |
| goto deassign; |
| } |
| } |
| } |
| |
| if (timeout > 0 && num == 0) |
| { |
| ready = 0; |
| goto deassign; |
| } |
| |
| usleep (100000); |
| num--; |
| } |
| |
| deassign: |
| |
| /* Deassign channels assigned above */ |
| for (i = 0; i < num_fd; i++) |
| { |
| if (mbxchans[i] > 0) |
| status = SYS$DASSGN (mbxchans[i]); |
| } |
| |
| return ready; |
| } |
| |
| #elif defined (__unix__) |
| |
| #ifdef __hpux__ |
| #include <sys/ptyio.h> |
| #endif |
| |
| #include <sys/time.h> |
| |
| #ifndef NO_FD_SET |
| #define SELECT_MASK fd_set |
| #else /* !NO_FD_SET */ |
| #ifndef _AIX |
| typedef long fd_mask; |
| #endif /* _AIX */ |
| #ifdef _IBMR2 |
| #define SELECT_MASK void |
| #else /* !_IBMR2 */ |
| #define SELECT_MASK int |
| #endif /* !_IBMR2 */ |
| #endif /* !NO_FD_SET */ |
| |
| void |
| __gnat_kill (int pid, int sig, int close) |
| { |
| kill (pid, sig); |
| } |
| |
| int |
| __gnat_waitpid (int pid) |
| { |
| int status = 0; |
| |
| waitpid (pid, &status, 0); |
| status = WEXITSTATUS (status); |
| |
| return status; |
| } |
| |
| int |
| __gnat_pipe (int *fd) |
| { |
| return pipe (fd); |
| } |
| |
| int |
| __gnat_expect_fork (void) |
| { |
| return fork (); |
| } |
| |
| void |
| __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[]) |
| { |
| *pid = (int) getpid (); |
| /* Since cmd is fully qualified, it is incorrect to call execvp */ |
| execv (cmd, argv); |
| _exit (1); |
| } |
| |
| int |
| __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set) |
| { |
| struct timeval tv; |
| SELECT_MASK rset; |
| SELECT_MASK eset; |
| |
| int max_fd = 0; |
| int ready; |
| int i; |
| int received; |
| |
| tv.tv_sec = timeout / 1000; |
| tv.tv_usec = (timeout % 1000) * 1000; |
| |
| do { |
| FD_ZERO (&rset); |
| FD_ZERO (&eset); |
| |
| for (i = 0; i < num_fd; i++) |
| { |
| FD_SET (fd[i], &rset); |
| FD_SET (fd[i], &eset); |
| |
| if (fd[i] > max_fd) |
| max_fd = fd[i]; |
| } |
| |
| ready = |
| select (max_fd + 1, &rset, NULL, &eset, timeout == -1 ? NULL : &tv); |
| |
| if (ready > 0) |
| { |
| received = 0; |
| |
| for (i = 0; i < num_fd; i++) |
| { |
| if (FD_ISSET (fd[i], &rset)) |
| { |
| is_set[i] = 1; |
| received = 1; |
| } |
| else |
| is_set[i] = 0; |
| } |
| |
| #ifdef __hpux__ |
| for (i = 0; i < num_fd; i++) |
| { |
| if (FD_ISSET (fd[i], &eset)) |
| { |
| struct request_info ei; |
| |
| /* Only query and reset error state if no file descriptor |
| is ready to be read, otherwise we will be signalling a |
| died process too early */ |
| |
| if (!received) |
| { |
| ioctl (fd[i], TIOCREQCHECK, &ei); |
| |
| if (ei.request == TIOCCLOSE) |
| { |
| ioctl (fd[i], TIOCREQSET, &ei); |
| return -1; |
| } |
| |
| ioctl (fd[i], TIOCREQSET, &ei); |
| } |
| ready--; |
| } |
| } |
| #endif |
| } |
| } while (timeout == -1 && ready == 0); |
| |
| return ready; |
| } |
| |
| #else |
| |
| void |
| __gnat_kill (int pid, int sig, int close) |
| { |
| } |
| |
| int |
| __gnat_waitpid (int pid, int sig) |
| { |
| return 0; |
| } |
| |
| int |
| __gnat_pipe (int *fd) |
| { |
| return -1; |
| } |
| |
| int |
| __gnat_expect_fork (void) |
| { |
| return -1; |
| } |
| |
| void |
| __gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[]) |
| { |
| *pid = 0; |
| } |
| |
| int |
| __gnat_expect_poll (int *fd, int num_fd, int timeout, int *is_set) |
| { |
| return -1; |
| } |
| #endif |