472574384b
2009-11-30 Pascal Obry <obry@adacore.com> * expect.c: Fix cast to avoid warnings in x86-64 Windows. 2009-11-30 Thomas Quinot <quinot@adacore.com> * gnat_rm.texi, s-sechas.adb, s-sechas.ads, s-shshco.adb, s-shshco.ads, g-md5.adb, g-md5.ads, g-sha256.ads, s-shsh64.adb, s-shsh64.ads, s-sehamd.adb, s-sehamd.ads, g-sha512.ads, g-sha1.adb, g-sha1.ads, Makefile.rtl, g-sha224.ads, g-sha384.ads, s-shsh32.adb, s-shsh32.ads, s-sehash.adb, s-sehash.ads: Reimplementation of GNAT.MD5 and GNAT.SHA1 to factor shared code and avoid unnecessary stack copies. Also introduce new functions SHA-{224,256,384,512} From-SVN: r154812
514 lines
11 KiB
C
514 lines
11 KiB
C
/****************************************************************************
|
|
* *
|
|
* GNAT COMPILER COMPONENTS *
|
|
* *
|
|
* E X P E C T *
|
|
* *
|
|
* C Implementation File *
|
|
* *
|
|
* Copyright (C) 2001-2009, 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>
|
|
#elif defined (__Lynx__)
|
|
/* ??? See comment in adaint.c. */
|
|
#define GCC_RESOURCE_H
|
|
#include <sys/wait.h>
|
|
#elif defined (__nucleus__)
|
|
/* No wait.h available on Nucleus */
|
|
#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>
|
|
#include <signal.h>
|
|
#include <io.h>
|
|
#include "mingw32.h"
|
|
|
|
void
|
|
__gnat_kill (int pid, int sig, int close)
|
|
{
|
|
HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
|
|
if (h == NULL)
|
|
return;
|
|
if (sig == 9)
|
|
{
|
|
TerminateProcess (h, 0);
|
|
__gnat_win32_remove_handle (NULL, pid);
|
|
}
|
|
else if (sig == SIGINT)
|
|
GenerateConsoleCtrlEvent (CTRL_C_EVENT, pid);
|
|
else if (sig == SIGBREAK)
|
|
GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid);
|
|
/* ??? The last two alternatives don't really work. SIGBREAK requires setting
|
|
up process groups at start time which we don't do; treating SIGINT is just
|
|
not possible apparently. So we really only support signal 9. Fortunately
|
|
that's all we use in GNAT.Expect */
|
|
|
|
CloseHandle (h);
|
|
}
|
|
|
|
int
|
|
__gnat_waitpid (int pid)
|
|
{
|
|
HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
|
|
DWORD exitcode = 1;
|
|
DWORD res;
|
|
|
|
if (h != NULL)
|
|
{
|
|
res = WaitForSingleObject (h, INFINITE);
|
|
GetExitCodeProcess (h, &exitcode);
|
|
CloseHandle (h);
|
|
}
|
|
|
|
__gnat_win32_remove_handle (NULL, pid);
|
|
return (int) exitcode;
|
|
}
|
|
|
|
int
|
|
__gnat_expect_fork (void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
__gnat_expect_portable_execvp (int *pid, char *cmd, char *argv[])
|
|
{
|
|
*pid = __gnat_portable_no_block_spawn (argv);
|
|
}
|
|
|
|
int
|
|
__gnat_pipe (int *fd)
|
|
{
|
|
HANDLE read, write;
|
|
|
|
CreatePipe (&read, &write, NULL, 0);
|
|
fd[0]=_open_osfhandle ((intptr_t)read, 0);
|
|
fd[1]=_open_osfhandle ((intptr_t)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>
|
|
#include <signal.h>
|
|
|
|
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 -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__) && !defined (__nucleus__)
|
|
|
|
#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
|