/**************************************************************************** * * * 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 #ifdef __MINGW32__ #if OLD_MINGW #include #endif #elif defined (__vxworks) && defined (__RTP__) #include #else #include #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 #include 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 #include #include #include #include #include #include #include #include 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 #endif #include #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