820 lines
17 KiB
PkgConfig
820 lines
17 KiB
PkgConfig
|
/* gawkmisc.c --- miscellaneous gawk routines that are OS specific. -*-C-*- */
|
||
|
|
||
|
/*
|
||
|
* Copyright (C) 1986, 1988, 1989, 1991 - 2003, 2012, 2016-2019, 2021, 2022,
|
||
|
* the Free Software Foundation, Inc.
|
||
|
*
|
||
|
* This file is part of GAWK, the GNU implementation of the
|
||
|
* AWK Progamming Language.
|
||
|
*
|
||
|
* GAWK is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* GAWK is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT 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
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||
|
*/
|
||
|
|
||
|
const char quote = '\'';
|
||
|
const char envsep = ';';
|
||
|
|
||
|
# ifdef DEFPATH
|
||
|
const char *defpath = DEFPATH;
|
||
|
# else
|
||
|
const char *defpath = ".;c:\\lib\\awk;c:\\gnu\\lib\\awk";
|
||
|
# endif
|
||
|
/* the Makefile should define DEFLIBPATH */
|
||
|
const char *deflibpath = DEFLIBPATH;
|
||
|
|
||
|
#ifdef __MINGW32__
|
||
|
|
||
|
#ifdef HAVE_SOCKETS
|
||
|
#include <socket.h>
|
||
|
|
||
|
#undef socket
|
||
|
#undef setsockopt
|
||
|
#undef bind
|
||
|
#undef connect
|
||
|
#undef listen
|
||
|
#undef accept
|
||
|
#undef recvfrom
|
||
|
#undef shutdown
|
||
|
#endif
|
||
|
|
||
|
#define WIN32_LEAN_AND_MEAN
|
||
|
#include <windows.h>
|
||
|
|
||
|
/* gawk_name --- pull out the "gawk" part from how the OS called us */
|
||
|
|
||
|
const char *
|
||
|
gawk_name(filespec)
|
||
|
const char *filespec;
|
||
|
{
|
||
|
char *p, *q;
|
||
|
|
||
|
p = (char *) filespec; /* Sloppy... */
|
||
|
|
||
|
/* OS/2 allows / for directory separator too */
|
||
|
if ((q = strrchr(p, '\\')) != NULL)
|
||
|
p = q + 1;
|
||
|
if ((q = strrchr(p, '/')) != NULL
|
||
|
&& (p == NULL || q > p)) /* support mixed d:\foo/bar\gawk.exe */
|
||
|
p = q + 1;
|
||
|
if ((q = strchr(p, '.')) != NULL)
|
||
|
*q = '\0';
|
||
|
return strlwr(p);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* os_arg_fixup --- fixup the command line */
|
||
|
|
||
|
void
|
||
|
os_arg_fixup(argcp, argvp)
|
||
|
int *argcp;
|
||
|
char ***argvp;
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* os_devopen --- open special per-OS devices */
|
||
|
|
||
|
int
|
||
|
os_devopen(name, flag)
|
||
|
const char *name;
|
||
|
int flag;
|
||
|
{
|
||
|
if (strcmp(name, "/dev/null") == 0)
|
||
|
return open("NUL", flag);
|
||
|
/* FIXME: */
|
||
|
/* else if (strcmp(name, "/dev/tty") == 0)
|
||
|
* return open("???", flag);
|
||
|
*/
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
/* optimal_bufsize --- determine optimal buffer size */
|
||
|
|
||
|
size_t
|
||
|
optimal_bufsize(fd, stb)
|
||
|
int fd;
|
||
|
struct stat *stb;
|
||
|
{
|
||
|
/* force all members to zero in case OS doesn't use all of them. */
|
||
|
memset(stb, '\0', sizeof(struct stat));
|
||
|
|
||
|
/*
|
||
|
* DOS doesn't have the file system block size in the
|
||
|
* stat structure. So we have to make some sort of reasonable
|
||
|
* guess. We use stdio's BUFSIZ, since that is what it was
|
||
|
* meant for in the first place.
|
||
|
*/
|
||
|
#define DEFBLKSIZE BUFSIZ
|
||
|
|
||
|
if (fstat(fd, stb) == -1)
|
||
|
fatal("can't stat fd %d (%s)", fd, strerror(errno));
|
||
|
if (S_ISREG(stb->st_mode)
|
||
|
&& 0 < stb->st_size && stb->st_size < DEFBLKSIZE) /* small file */
|
||
|
return stb->st_size;
|
||
|
return DEFBLKSIZE;
|
||
|
}
|
||
|
|
||
|
/* ispath --- return true if path has directory components */
|
||
|
|
||
|
int
|
||
|
ispath(file)
|
||
|
const char *file;
|
||
|
{
|
||
|
for (; *file; file++) {
|
||
|
switch (*file) {
|
||
|
case '/':
|
||
|
case '\\':
|
||
|
case ':':
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* isdirpunct --- return true if char is a directory separator */
|
||
|
|
||
|
int
|
||
|
isdirpunct(c)
|
||
|
int c;
|
||
|
{
|
||
|
return (strchr(":\\/", c) != NULL);
|
||
|
}
|
||
|
|
||
|
/* os_close_on_exec --- set close on exec flag, print warning if fails */
|
||
|
|
||
|
void
|
||
|
os_close_on_exec(fd, name, what, dir)
|
||
|
int fd;
|
||
|
const char *name, *what, *dir;
|
||
|
{
|
||
|
HANDLE fh = (HANDLE)_get_osfhandle(fd);
|
||
|
|
||
|
if (fh && fh != INVALID_HANDLE_VALUE)
|
||
|
SetHandleInformation(fh, HANDLE_FLAG_INHERIT, 0);
|
||
|
}
|
||
|
|
||
|
/* os_isdir --- is this an fd on a directory? */
|
||
|
|
||
|
#if ! defined(S_ISDIR) && defined(S_IFDIR)
|
||
|
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||
|
#endif
|
||
|
|
||
|
int
|
||
|
os_isdir(fd)
|
||
|
int fd;
|
||
|
{
|
||
|
struct stat sbuf;
|
||
|
|
||
|
return (fstat(fd, &sbuf) == 0 && S_ISDIR(sbuf.st_mode));
|
||
|
}
|
||
|
|
||
|
/* os_isreadable --- fd can be read from */
|
||
|
|
||
|
int
|
||
|
os_isreadable(const awk_input_buf_t *iobuf, bool *isdir)
|
||
|
{
|
||
|
*isdir = false;
|
||
|
|
||
|
switch (iobuf->sbuf.st_mode & S_IFMT) {
|
||
|
case S_IFREG:
|
||
|
case S_IFCHR: /* ttys, /dev/null, .. */
|
||
|
#ifdef S_IFSOCK
|
||
|
case S_IFSOCK:
|
||
|
#endif
|
||
|
#ifdef S_IFIFO
|
||
|
case S_IFIFO:
|
||
|
#endif
|
||
|
return true;
|
||
|
case S_IFDIR:
|
||
|
*isdir = true;
|
||
|
/* fall through */
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* os_is_setuid --- true if running setuid root */
|
||
|
|
||
|
int
|
||
|
os_is_setuid()
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* os_setbinmode --- set binary mode on file */
|
||
|
|
||
|
static int orig_tty_mode = -1;
|
||
|
|
||
|
int
|
||
|
os_setbinmode(fd, mode)
|
||
|
int fd, mode;
|
||
|
{
|
||
|
int prev_mode = setmode(fd, mode);
|
||
|
|
||
|
/* Save the original tty mode as we found it. */
|
||
|
if (orig_tty_mode == -1 && fd >= 0 && fd <= 2)
|
||
|
orig_tty_mode = prev_mode;
|
||
|
return prev_mode;
|
||
|
}
|
||
|
|
||
|
/* os_restore_mode --- restore the original mode of the console device */
|
||
|
|
||
|
void
|
||
|
os_restore_mode (fd)
|
||
|
int fd;
|
||
|
{
|
||
|
if (orig_tty_mode != -1) {
|
||
|
setmode(fd, orig_tty_mode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* os_isatty --- return true if fd is a tty */
|
||
|
|
||
|
int
|
||
|
os_isatty(int fd)
|
||
|
{
|
||
|
return (isatty(fd) && lseek(fd, SEEK_CUR, 0) == -1);
|
||
|
}
|
||
|
|
||
|
/* files_are_same --- return true if files are identical */
|
||
|
|
||
|
int
|
||
|
files_are_same(char *path, SRCFILE *src)
|
||
|
{
|
||
|
struct stat st;
|
||
|
size_t pathlen;
|
||
|
char *p, *s;
|
||
|
|
||
|
if (stat (path, & st) == 0) {
|
||
|
/* If they have a working `stat', honor that. */
|
||
|
if (!(st.st_dev == src->sbuf.st_dev
|
||
|
&& st.st_ino == src->sbuf.st_ino))
|
||
|
return 0;
|
||
|
|
||
|
/* Compare modification times. */
|
||
|
if (st.st_mtime != src->mtime)
|
||
|
return 0;
|
||
|
|
||
|
/* Compare absolute file names case-insensitively, and
|
||
|
treat forward- and back-slashes as equal. */
|
||
|
pathlen = strlen(path);
|
||
|
for (p = path, s = src->fullpath;
|
||
|
p <= path + pathlen;
|
||
|
p++, s++) {
|
||
|
if (tolower(*p) != tolower(*s)
|
||
|
&& !((*p == '/' || *p == '\\')
|
||
|
&& (*s == '/' || *s == '\\')))
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
extern void *xmalloc (size_t);
|
||
|
|
||
|
/* Emulate setenv and unsetenv.
|
||
|
|
||
|
Note: this is only actually used in MinGW64 builds, since
|
||
|
mingw.org's MinGW has these functions as inlines in stdlib.h since
|
||
|
mingwrt-5.0. */
|
||
|
int
|
||
|
setenv (const char *name, const char *value, int rewrite)
|
||
|
{
|
||
|
char *entry;
|
||
|
|
||
|
if (*value == '=')
|
||
|
++value;
|
||
|
|
||
|
if (getenv (name) && !rewrite)
|
||
|
return 0;
|
||
|
|
||
|
entry = xmalloc (strlen (name) + 1 + strlen (value) + 1);
|
||
|
strcat (strcat (strcpy (entry, name), "="), value);
|
||
|
if (putenv (entry) != 0)
|
||
|
{
|
||
|
free (entry);
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
unsetenv (const char *name)
|
||
|
{
|
||
|
if (!name || !*name || strchr (name, '=') != NULL)
|
||
|
return -1;
|
||
|
|
||
|
return setenv (name, "", 1);
|
||
|
}
|
||
|
|
||
|
/* MinGW 3.21 and later defines usleep as an inline function in
|
||
|
unistd.h, which conflicts with the version below. */
|
||
|
#if __MINGW32_MAJOR_VERSION + (__MINGW32_MINOR_VERSION > 20) < 4
|
||
|
int
|
||
|
usleep(unsigned int usec)
|
||
|
{
|
||
|
double msecf = usec / 1000.0;
|
||
|
|
||
|
Sleep ((DWORD)msecf);
|
||
|
|
||
|
return usec - msecf * 1000 < 0 ? 0 : (int)(usec - msecf * 1000);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* The implementation of wctob in the MS runtime is problematic
|
||
|
because it doesn't allow to distinguish between WEOF and 0xff, due
|
||
|
to integer sign extension. It also causes failures in dfa.c when
|
||
|
characters with the 8th bit set are involved. This replacement
|
||
|
version fixes that. */
|
||
|
|
||
|
#include <wchar.h>
|
||
|
|
||
|
int
|
||
|
wctob (wint_t wc)
|
||
|
{
|
||
|
char buf[64];
|
||
|
|
||
|
if (!(MB_CUR_MAX <= sizeof (buf)))
|
||
|
abort ();
|
||
|
/* Handle the case where WEOF is a value that does not fit in a wchar_t. */
|
||
|
if (wc == (wchar_t)wc)
|
||
|
if (wctomb (buf, (wchar_t)wc) == 1)
|
||
|
return (unsigned char) buf[0];
|
||
|
return EOF;
|
||
|
}
|
||
|
|
||
|
|
||
|
#undef setlocale
|
||
|
#include <locale.h>
|
||
|
|
||
|
/* On Posix systems, 'setlocale' looks at LC_* variables in the
|
||
|
environment, and Gawk users might expect that on Windows as well.
|
||
|
The replacement implementation below does that, and also fixes a
|
||
|
few additional quirks with locales on Windows. */
|
||
|
static const char *
|
||
|
lc_var (int category)
|
||
|
{
|
||
|
static const char *loc_name[LC_MAX - LC_MIN + 1] = {
|
||
|
"LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC", "LC_TIME"
|
||
|
};
|
||
|
|
||
|
/* This function assumes LC_* categories are small numbers between 0
|
||
|
and 5, as shown above, so if that changes at some point, complain
|
||
|
vociferously. */
|
||
|
if (LC_ALL != 0 || LC_CTYPE != 2 || LC_TIME != 5)
|
||
|
abort ();
|
||
|
/* Ensured by the caller, so should never happen. */
|
||
|
if (category < LC_MIN || category > LC_MAX)
|
||
|
return "????";
|
||
|
return loc_name[category];
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
w32_setlocale (int category, const char *value)
|
||
|
{
|
||
|
const char *new_locale = value;
|
||
|
|
||
|
if (LC_MIN <= category && category <= LC_MAX
|
||
|
&& value && *value == '\0')
|
||
|
{
|
||
|
const char *lc_val = getenv ("LC_ALL");
|
||
|
|
||
|
if (!lc_val)
|
||
|
lc_val = getenv (lc_var (category));
|
||
|
if (!lc_val)
|
||
|
lc_val = getenv ("LANG");
|
||
|
if (lc_val)
|
||
|
new_locale = lc_val;
|
||
|
}
|
||
|
|
||
|
/* If VALUE includes a codeset, i.e. a Windows codepage number, we
|
||
|
must also set the LC_CTYPE locale to the same value, because
|
||
|
LC_CTYPE is the only category which is documented to be able to
|
||
|
change the codepage. */
|
||
|
if (category != LC_ALL && category != LC_CTYPE)
|
||
|
{
|
||
|
const char *p = strchr (new_locale, '.');
|
||
|
|
||
|
if (p && isdigit (p[1]))
|
||
|
setlocale (LC_CTYPE, new_locale);
|
||
|
}
|
||
|
return setlocale (category, new_locale);
|
||
|
}
|
||
|
|
||
|
/* Replacement for the missing nl_langinfo. Only CODESET is currently
|
||
|
supported. */
|
||
|
#include <langinfo.h>
|
||
|
|
||
|
char *
|
||
|
nl_langinfo (int item)
|
||
|
{
|
||
|
switch (item)
|
||
|
{
|
||
|
case CODESET:
|
||
|
{
|
||
|
/* Shamelessly stolen from Gnulib's nl_langinfo.c. */
|
||
|
static char buf[2 + 10 + 1];
|
||
|
char const *locale = setlocale (LC_CTYPE, NULL);
|
||
|
char *codeset = buf;
|
||
|
size_t codesetlen;
|
||
|
codeset[0] = '\0';
|
||
|
|
||
|
if (locale && locale[0])
|
||
|
{
|
||
|
/* If the locale name contains an encoding after the
|
||
|
dot, return it. */
|
||
|
char *dot = strchr (locale, '.');
|
||
|
|
||
|
if (dot)
|
||
|
{
|
||
|
/* Look for the possible @... trailer and remove it,
|
||
|
if any. */
|
||
|
char *codeset_start = dot + 1;
|
||
|
char const *modifier = strchr (codeset_start, '@');
|
||
|
|
||
|
if (! modifier)
|
||
|
codeset = codeset_start;
|
||
|
else
|
||
|
{
|
||
|
codesetlen = modifier - codeset_start;
|
||
|
if (codesetlen < sizeof buf)
|
||
|
{
|
||
|
codeset = memcpy (buf, codeset_start, codesetlen);
|
||
|
codeset[codesetlen] = '\0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/* If setlocale is successful, it returns the number of the
|
||
|
codepage, as a string. Otherwise, fall back on Windows
|
||
|
API GetACP, which returns the locale's codepage as a
|
||
|
number (although this doesn't change according to what
|
||
|
the 'setlocale' call specified). Either way, prepend
|
||
|
"CP" to make it a valid codeset name. */
|
||
|
codesetlen = strlen (codeset);
|
||
|
if (0 < codesetlen && codesetlen < sizeof buf - 2)
|
||
|
memmove (buf + 2, codeset, codesetlen + 1);
|
||
|
else
|
||
|
sprintf (buf + 2, "%u", GetACP ());
|
||
|
codeset = memcpy (buf, "CP", 2);
|
||
|
|
||
|
return codeset;
|
||
|
}
|
||
|
default:
|
||
|
return (char *) "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* On MS-Windows with MinGW, execvp causes the shell and the re-exec'ed
|
||
|
* dgawk to compete for the keyboard input.
|
||
|
*
|
||
|
* This will need work if we ever need a real version of execvp.
|
||
|
*/
|
||
|
int w32_execvp(const char *file, char **argv)
|
||
|
{
|
||
|
if (_spawnvp(_P_WAIT, file, (const char * const *)argv) != -1)
|
||
|
exit(EXIT_SUCCESS);
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
#ifdef DYNAMIC
|
||
|
|
||
|
#include <winerror.h>
|
||
|
#include <dlfcn.h>
|
||
|
|
||
|
static DWORD last_err;
|
||
|
|
||
|
void *
|
||
|
dlopen (const char *file, int mode)
|
||
|
{
|
||
|
char dllfn[MAX_PATH], *p;
|
||
|
HANDLE dllhandle;
|
||
|
|
||
|
if (mode != RTLD_LAZY)
|
||
|
{
|
||
|
errno = EINVAL;
|
||
|
last_err = ERROR_INVALID_PARAMETER;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* MSDN says to be sure to use backslashes in the DLL file name. */
|
||
|
strcpy (dllfn, file);
|
||
|
for (p = dllfn; *p; p++)
|
||
|
if (*p == '/')
|
||
|
*p = '\\';
|
||
|
|
||
|
dllhandle = LoadLibrary (dllfn);
|
||
|
if (!dllhandle)
|
||
|
last_err = GetLastError ();
|
||
|
|
||
|
return dllhandle;
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
dlerror (void)
|
||
|
{
|
||
|
static char errbuf[1024];
|
||
|
DWORD ret;
|
||
|
|
||
|
if (!last_err)
|
||
|
return NULL;
|
||
|
|
||
|
ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
|
||
|
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
||
|
NULL, last_err, 0, errbuf, sizeof (errbuf), NULL);
|
||
|
while (ret > 0 && (errbuf[ret - 1] == '\n' || errbuf[ret - 1] == '\r'))
|
||
|
--ret;
|
||
|
|
||
|
errbuf[ret] = '\0';
|
||
|
if (!ret)
|
||
|
sprintf (errbuf, "Error code %lu", last_err);
|
||
|
|
||
|
last_err = 0;
|
||
|
return errbuf;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
dlclose (void *handle)
|
||
|
{
|
||
|
if (!handle || handle == INVALID_HANDLE_VALUE)
|
||
|
return -1;
|
||
|
if (!FreeLibrary (handle))
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void *
|
||
|
dlsym (void *handle, const char *name)
|
||
|
{
|
||
|
FARPROC addr = NULL;
|
||
|
|
||
|
if (!handle || handle == INVALID_HANDLE_VALUE)
|
||
|
{
|
||
|
last_err = ERROR_INVALID_PARAMETER;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
addr = GetProcAddress (handle, name);
|
||
|
if (!addr)
|
||
|
last_err = GetLastError ();
|
||
|
|
||
|
return (void *)addr;
|
||
|
}
|
||
|
#endif /* DYNAMIC */
|
||
|
|
||
|
#ifdef HAVE_SOCKETS
|
||
|
int
|
||
|
socket_to_fd(SOCKET s)
|
||
|
{
|
||
|
return (s == INVALID_SOCKET
|
||
|
? INVALID_HANDLE
|
||
|
: _open_osfhandle (s, O_BINARY | O_NOINHERIT));
|
||
|
}
|
||
|
|
||
|
int
|
||
|
w32_socket(int family, int type, int protocol)
|
||
|
{
|
||
|
/* We need to use WSASocket rather than socket, since the latter
|
||
|
creates overlapped sockets that cannot be used in file I/O
|
||
|
APIs. */
|
||
|
SOCKET s = WSASocket (family, type, protocol, NULL, 0, 0);
|
||
|
|
||
|
if (s == INVALID_SOCKET)
|
||
|
{
|
||
|
switch (WSAGetLastError ())
|
||
|
{
|
||
|
case WSAEMFILE:
|
||
|
errno = EMFILE;
|
||
|
break;
|
||
|
case WSANOTINITIALISED:
|
||
|
case WSAENETDOWN:
|
||
|
errno = EACCES;
|
||
|
break;
|
||
|
case WSAENOBUFS:
|
||
|
errno = ENOMEM;
|
||
|
break;
|
||
|
case WSAEFAULT:
|
||
|
errno = EFAULT;
|
||
|
break;
|
||
|
default:
|
||
|
errno = EINVAL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return socket_to_fd (s);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
w32_setsockopt (int fd, int level, int optname, const char *optval, int optlen)
|
||
|
{
|
||
|
SOCKET s = FD_TO_SOCKET (fd);
|
||
|
|
||
|
return setsockopt (s, level, optname, optval, optlen);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
w32_bind (int fd, const struct sockaddr *name, int namelen)
|
||
|
{
|
||
|
SOCKET s = FD_TO_SOCKET (fd);
|
||
|
|
||
|
return bind (s, name, namelen);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
w32_connect (int fd, const struct sockaddr *name, int namelen)
|
||
|
{
|
||
|
SOCKET s = FD_TO_SOCKET (fd);
|
||
|
|
||
|
return connect (s, name, namelen);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
w32_listen (int fd, int backlog)
|
||
|
{
|
||
|
SOCKET s = FD_TO_SOCKET (fd);
|
||
|
|
||
|
return listen (s, backlog);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
w32_accept (int fd, struct sockaddr *addr, int *addrlen)
|
||
|
{
|
||
|
SOCKET s = FD_TO_SOCKET (fd);
|
||
|
|
||
|
return socket_to_fd (accept (s, addr, addrlen));
|
||
|
}
|
||
|
|
||
|
SOCKET
|
||
|
valid_socket (int fd)
|
||
|
{
|
||
|
SOCKET s = FD_TO_SOCKET (fd);
|
||
|
int ov, ol = 4;
|
||
|
|
||
|
if (s == INVALID_SOCKET
|
||
|
|| (getsockopt (s, SOL_SOCKET, SO_TYPE, (char *)&ov, &ol) == SOCKET_ERROR
|
||
|
&& WSAGetLastError() == WSAENOTSOCK))
|
||
|
return (SOCKET)0;
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
w32_closesocket (int fd)
|
||
|
{
|
||
|
SOCKET s = valid_socket (fd);
|
||
|
int res1, res2 = 0;
|
||
|
|
||
|
if (!s && fd == FAKE_FD_VALUE)
|
||
|
return 0;
|
||
|
|
||
|
res1 = close (fd);
|
||
|
if (s)
|
||
|
res2 = closesocket (s);
|
||
|
|
||
|
if (res1 == -1 || res2 == SOCKET_ERROR)
|
||
|
return -1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
w32_recvfrom (int fd, char *buf, int len, int flags,
|
||
|
struct sockaddr *from, int *fromlen)
|
||
|
{
|
||
|
SOCKET s = FD_TO_SOCKET (fd);
|
||
|
|
||
|
return recvfrom (s, buf, len, flags, from, fromlen);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
w32_shutdown (int fd, int how)
|
||
|
{
|
||
|
SOCKET s = FD_TO_SOCKET (fd);
|
||
|
|
||
|
return shutdown (s, how);
|
||
|
}
|
||
|
|
||
|
#endif /* HAVE_SOCKETS */
|
||
|
|
||
|
/* Translate abnormal exit status of Windows programs into the signal
|
||
|
that terminated the program. This is required to support scm_kill
|
||
|
and WTERMSIG. */
|
||
|
|
||
|
#include <signal.h>
|
||
|
|
||
|
struct signal_and_status {
|
||
|
int sig;
|
||
|
unsigned status;
|
||
|
};
|
||
|
|
||
|
static const struct signal_and_status sigtbl[] = {
|
||
|
{SIGSEGV, 0xC0000005}, /* access to invalid address */
|
||
|
{SIGSEGV, 0xC0000008}, /* invalid handle */
|
||
|
{SIGILL, 0xC000001D}, /* illegal instruction */
|
||
|
{SIGILL, 0xC0000025}, /* non-continuable instruction */
|
||
|
{SIGSEGV, 0xC000008C}, /* array bounds exceeded */
|
||
|
{SIGFPE, 0xC000008D}, /* float denormal */
|
||
|
{SIGFPE, 0xC000008E}, /* float divide by zero */
|
||
|
{SIGFPE, 0xC000008F}, /* float inexact */
|
||
|
{SIGFPE, 0xC0000090}, /* float invalid operation */
|
||
|
{SIGFPE, 0xC0000091}, /* float overflow */
|
||
|
{SIGFPE, 0xC0000092}, /* float stack check */
|
||
|
{SIGFPE, 0xC0000093}, /* float underflow */
|
||
|
{SIGFPE, 0xC0000094}, /* integer divide by zero */
|
||
|
{SIGFPE, 0xC0000095}, /* integer overflow */
|
||
|
{SIGILL, 0xC0000096}, /* privileged instruction */
|
||
|
{SIGSEGV, 0xC00000FD}, /* stack overflow */
|
||
|
{SIGTERM, 0xC000013A}, /* Ctrl-C exit */
|
||
|
{SIGINT, 0xC000013A}
|
||
|
};
|
||
|
|
||
|
int
|
||
|
w32_status_to_termsig (unsigned status)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < sizeof (sigtbl) / sizeof (sigtbl[0]); i++)
|
||
|
if (status == sigtbl[i].status)
|
||
|
return sigtbl[i].sig;
|
||
|
|
||
|
return SIGTERM;
|
||
|
}
|
||
|
|
||
|
/* Emulate the missing strsignal. */
|
||
|
char *
|
||
|
strsignal (int signo)
|
||
|
{
|
||
|
switch (signo)
|
||
|
{
|
||
|
case SIGINT:
|
||
|
return "SIGINT";
|
||
|
case SIGILL:
|
||
|
return "SIGILL";
|
||
|
case SIGFPE:
|
||
|
return "SIGFPE";
|
||
|
case SIGSEGV:
|
||
|
return "SIGSEGV";
|
||
|
case SIGTERM:
|
||
|
return "SIGTERM";
|
||
|
case SIGBREAK:
|
||
|
return "SIGBREAK";
|
||
|
case SIGABRT:
|
||
|
return "SIGABRT";
|
||
|
default:
|
||
|
return "Unknown signal";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
os_maybe_set_errno (void)
|
||
|
{
|
||
|
if (errno == 0 || errno == EINVAL) {
|
||
|
DWORD w32err = GetLastError ();
|
||
|
|
||
|
switch (w32err)
|
||
|
{
|
||
|
/* When stdout is redirected to a pipe, and the program that
|
||
|
reads the pipe (e.g., a pager) exits, Windows doesn't set
|
||
|
errno to a useful value. Help it DTRT. */
|
||
|
case ERROR_BAD_PIPE:
|
||
|
case ERROR_PIPE_BUSY:
|
||
|
case ERROR_NO_DATA:
|
||
|
case ERROR_PIPE_NOT_CONNECTED:
|
||
|
errno = EPIPE;
|
||
|
break;
|
||
|
default:
|
||
|
errno = EINVAL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
init_sockets(void)
|
||
|
{
|
||
|
#if defined(HAVE_SOCKETS)
|
||
|
WSADATA winsockData;
|
||
|
int errcode;
|
||
|
|
||
|
if ((errcode = WSAStartup (0x101, &winsockData)) != 0
|
||
|
|| winsockData.wVersion != 0x101)
|
||
|
fatal(_("cannot start Winsock (%d)"), errcode);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#endif /* __MINGW32__ */
|