ubuntu-buildroot/output/build/host-gawk-5.2.0/pc/gawkmisc.pc

820 lines
17 KiB
PkgConfig
Raw Normal View History

2024-04-01 15:19:46 +00:00
/* 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__ */