aboutsummaryrefslogtreecommitdiffstats
path: root/io.c
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2013-06-01 13:03:29 +0300
committerEli Zaretskii <eliz@gnu.org>2013-06-01 13:03:29 +0300
commit5482bf19246965d6839fe9df1aec0785f0b1a329 (patch)
tree818777446f62f531462f2b64b70d9868bcdcaa95 /io.c
parenta25b9b39ac2c49b822328414240061f6d22ddef2 (diff)
downloadegawk-5482bf19246965d6839fe9df1aec0785f0b1a329.tar.gz
egawk-5482bf19246965d6839fe9df1aec0785f0b1a329.tar.bz2
egawk-5482bf19246965d6839fe9df1aec0785f0b1a329.zip
Support |& on MS-Windows, both for sockets and for pipes.
io.c (SHUT_RD) [SD_RECEIVE]: Define to SD_RECEIVE. (SHUT_WR) [SD_SEND]: Define to SD_SEND. (SHUT_RDWR) [SD_BOTH]: Define to SD_BOTH. (FD_TO_SOCKET, closemaybesocket) [!FD_TO_SOCKET]: New macros. (SOCKET_TO_FD, SOCKET) [!SOCKET_TO_FD]: New macros. (PIPES_SIMULATED): Define only for DJGPP. (pipe) [__MINGW32__]: Define to call _pipe, unless PIPES_SIMULATED is defined. (init_io) [HAVE_SOCKETS]: Call init_sockets. (iop_close, socketopen): Call closemaybesocket instead of close. (redirect) [__MINGW32__]: Call wait_any with a non-zero argument. (devopen) [__EMX__ || __MINGW32__]: Don't call stat on network pseudo-filenames. (two_way_open) [HAVE_SOCKETS]: Switch input and output to binary mode if appropriate. (two_way_open) [!PIPES_SIMULATED]: Use the __EMX__ code for MinGW as well. [__MINGW32__] Call spawnl to invoke $ComSpec and pass it a suitably quoted command line. (two_way_open) [__MINGW32__]: Wait only for a specified process ID. If successful, update the exit status of the exited process. Don't use signals that are undefined on MinGW. (two_way_open) [!PIPES_SIMULATED]: Use the __EMX__ code for MinGW as well. (min): Define only if not already defined. (read_with_timeout) [__MINGW32__]: Allow reading from sockets with timeout. (gawk_fclose) [__MINGW32__]: Close the underlying socket as well. getopt.c: Include stdlib.h for MinGW as well. pc/popen.h (SIGKILL) [__MINGW32__]: Define. (kill, quote_cmd): New prototypes. pc/popen.c: Include popen.h and errno.h. (popen, pclose, system): Undefine macros. (WIN32_LEAN_AND_MEAN) [__MINGW32__]: Define and include windows.h. (kill, quote_cmd) [!PIPES_SIMULATED]: New functions. (os_popen): Make the function definition match its prototype exactly. pc/gawkmisc.pc [HAVE_SOCKETS]: Include socket.h and windows.h. (socket, setsockopt, bind, connect, listen, accept, recvfrom) (shutdown): Undefine macros. (os_close_on_exec) [__MINGW32__]: Non-trivial implementation. (init_sockets, socket_to_fd, w32_socket, w32_setsockopt) (w32_bind, w32_connect, w32_listen, w32_accept, valid_socket) (w32_closesocket, w32_recvfrom, w32_shutdown) [HAVE_SOCKETS]: New functions for MinGW, emulate Posix sockets specified by file descriptors. pc/config.h (HAVE_GETADDRINFO, HAVE_SOCKADDR_STORAGE) (HAVE_SOCKETS) [__MINGW32__]: Define. pc/config.sed (HAVE_GETADDRINFO, HAVE_SOCKADDR_STORAGE) (HAVE_SOCKETS) [__MINGW32__]: Define. pc/Makefile.tst (fmtspcl): Announce expected failure only if not built with MPFR. (inetecht, inetdayt): For MinGW, warn about time-outs. (beginfile1, clos1way, getlndir): Announce expected failure only with DJGPP. (exit): Describe the failure on MinGW. (readdir): Explain why test might fail with bad ls.exe. pc/Makefile (mingw32, mingw32-readline, mingw32-mpfr) (mingw32-readline-mpfr): Add -lws2_32 to the link flags. (gawkmisc$O): Depend on socket.h. (io$O): Depend on socket.h and in.h. (popen$O): New dependency. posix/gawkmisc.c (init_sockets): New dummy function. extension/filefuncs.c [_WIN32]: Define WIN32_LEAN_AND_MEAN before including windows.h. extension/readdir.c [__MINGW32__]: Define WIN32_LEAN_AND_MEAN before including windows.h. extension/filefuncs.c [HAVE_GETSYSTEMTIMEASFILETIME]: Define WIN32_LEAN_AND_MEAN before including windows.h. test/clos1way.awk: Don't use features of Posix shells, to allow this test to work on Windows. test/beginfile2.sh: Leave one blank between the left quote and the following slash. Use non-absolute name for a non-existent file. This is to avoid breakage on Windows due to MSYS transformation of Posix style /foo/bar absolute file names. test/beginfile2.ok: Adapt to changes in beginfile2.sh.
Diffstat (limited to 'io.c')
-rw-r--r--io.c177
1 files changed, 145 insertions, 32 deletions
diff --git a/io.c b/io.c
index 4f682622..c8b1f9a1 100644
--- a/io.c
+++ b/io.c
@@ -119,15 +119,38 @@
#ifdef HAVE_SOCKETS
#ifndef SHUT_RD
-#define SHUT_RD 0
+# ifdef SD_RECEIVE
+# define SHUT_RD SD_RECEIVE
+# else
+# define SHUT_RD 0
+# endif
#endif
#ifndef SHUT_WR
-#define SHUT_WR 1
+# ifdef SD_SEND
+# define SHUT_WR SD_SEND
+# else
+# define SHUT_WR 1
+# endif
#endif
#ifndef SHUT_RDWR
-#define SHUT_RDWR 2
+# ifdef SD_BOTH
+# define SHUT_RDWR SD_BOTH
+# else
+# define SHUT_RDWR 2
+# endif
+#endif
+
+/* MinGW defines non-trivial macros on pc/socket.h. */
+#ifndef FD_TO_SOCKET
+# define FD_TO_SOCKET(fd) (fd)
+# define closemaybesocket(fd) close(fd)
+#endif
+
+#ifndef SOCKET_TO_FD
+# define SOCKET_TO_FD(s) (s)
+# define SOCKET int
#endif
#endif /* HAVE_SOCKETS */
@@ -140,10 +163,16 @@
#undef TANDEM /* AIX defines this in one of its header files */
#endif
-#if defined(__DJGPP__) || defined(__MINGW32__)
+#ifdef __DJGPP__
#define PIPES_SIMULATED
#endif
+#ifdef __MINGW32__
+# ifndef PIPES_SIMULATED
+# define pipe(fds) _pipe(fds, 0, O_NOINHERIT)
+# endif
+#endif
+
#ifdef HAVE_MPFR
/* increment NR or FNR */
#define INCREMENT_REC(X) (do_mpfr && X == (LONG_MAX - 1)) ? \
@@ -265,6 +294,10 @@ init_io()
{
long tmout;
+#ifdef HAVE_SOCKETS
+ /* Only MinGW has a non-trivial implementation of this. */
+ init_sockets();
+#endif
/*
* N.B.: all these hacks are to minimize the effect
* on programs that do not care about timeout.
@@ -587,7 +620,7 @@ iop_close(IOBUF *iop)
|| iop->public.fd == fileno(stderr))
ret = remap_std_file(iop->public.fd);
else
- ret = close(iop->public.fd);
+ ret = closemaybesocket(iop->public.fd);
}
if (ret == -1)
@@ -739,7 +772,12 @@ redirect(NODE *redir_exp, int redirtype, int *errflg)
*/
if ((rp->flag & RED_EOF) != 0 && redirtype == redirect_pipein) {
if (rp->pid != -1)
+#ifdef __MINGW32__
+ /* MinGW cannot wait for any process. */
+ wait_any(rp->pid);
+#else
wait_any(0);
+#endif
}
#endif /* PIPES_SIMULATED */
@@ -1418,7 +1456,7 @@ socketopen(int family, int type, const char *localpname,
&& (clientsocket_fd = accept(socket_fd,
(struct sockaddr *) & remote_addr,
& namelen)) >= 0) {
- close(socket_fd);
+ closemaybesocket(socket_fd);
socket_fd = clientsocket_fd;
break;
}
@@ -1442,7 +1480,7 @@ socketopen(int family, int type, const char *localpname,
nextrres:
if (socket_fd != INVALID_HANDLE)
- close(socket_fd);
+ closemaybesocket(socket_fd);
socket_fd = INVALID_HANDLE;
rres = rres->ai_next;
}
@@ -1634,8 +1672,10 @@ strictopen:
/* On OS/2 and Windows directory access via open() is
not permitted. */
struct stat buf;
+ int l, f;
- if (stat(name, & buf) == 0 && S_ISDIR(buf.st_mode))
+ if (!inetfile(name, &l, &f)
+ && stat(name, & buf) == 0 && S_ISDIR(buf.st_mode))
errno = EISDIR;
}
#endif
@@ -1662,7 +1702,9 @@ two_way_open(const char *str, struct redirect *rp)
fd = devopen(str, "rw");
if (fd == INVALID_HANDLE)
return false;
- rp->output.fp = fdopen(fd, "w");
+ if ((BINMODE & BINMODE_OUTPUT) != 0)
+ os_setbinmode(fd, O_BINARY);
+ rp->output.fp = fdopen(fd, binmode("wb"));
if (rp->output.fp == NULL) {
close(fd);
return false;
@@ -1672,6 +1714,8 @@ two_way_open(const char *str, struct redirect *rp)
rp->output.gawk_fclose(rp->output.fp, rp->output.opaque);
return false;
}
+ if ((BINMODE & BINMODE_INPUT) != 0)
+ os_setbinmode(newfd, O_BINARY);
os_close_on_exec(fd, str, "socket", "to/from");
os_close_on_exec(newfd, str, "socket", "to/from");
rp->iop = iop_alloc(newfd, str, 0);
@@ -1929,8 +1973,11 @@ use_pipes:
int ptoc[2], ctop[2];
int pid;
int save_errno;
-#ifdef __EMX__
+#if defined(__EMX__) || defined(__MINGW32__)
int save_stdout, save_stdin;
+#ifdef __MINGW32__
+ char *qcmd = NULL;
+#endif
#endif
if (pipe(ptoc) < 0)
@@ -1944,7 +1991,7 @@ use_pipes:
return false;
}
-#ifdef __EMX__
+#if defined(__EMX__) || defined(__MINGW32__)
save_stdin = dup(0); /* duplicate stdin */
save_stdout = dup(1); /* duplicate stdout */
@@ -1987,7 +2034,13 @@ use_pipes:
os_close_on_exec(save_stdout, str, "pipe", "from"); /* saved stdout of the parent process */
/* stderr does NOT get dup'ed onto child's stdout */
+#ifdef __EMX__
pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", str, NULL);
+#else /* __MINGW32__ */
+ pid = spawnl(P_NOWAIT, getenv("ComSpec"), "cmd.exe", "/c",
+ qcmd = quote_cmd(str), NULL);
+ efree(qcmd);
+#endif
/* restore stdin and stdout */
close(1);
@@ -2015,7 +2068,7 @@ use_pipes:
return false;
}
-#else /* NOT __EMX__ */
+#else /* NOT __EMX__, NOT __MINGW32__ */
if ((pid = fork()) < 0) {
save_errno = errno;
close(ptoc[0]); close(ptoc[1]);
@@ -2042,9 +2095,13 @@ use_pipes:
execl("/bin/sh", "sh", "-c", str, NULL);
_exit(errno == ENOENT ? 127 : 126);
}
-#endif /* NOT __EMX__ */
+#endif /* NOT __EMX__, NOT __MINGW32__ */
/* parent */
+ if ((BINMODE & BINMODE_INPUT) != 0)
+ os_setbinmode(ctop[0], O_BINARY);
+ if ((BINMODE & BINMODE_OUTPUT) != 0)
+ os_setbinmode(ptoc[1], O_BINARY);
rp->pid = pid;
rp->iop = iop_alloc(ctop[0], str, 0);
find_input_parser(rp->iop);
@@ -2061,7 +2118,7 @@ use_pipes:
return false;
}
- rp->output.fp = fdopen(ptoc[1], "w");
+ rp->output.fp = fdopen(ptoc[1], binmode("w"));
rp->output.mode = "w";
rp->output.name = str;
if (rp->output.fp == NULL) {
@@ -2078,7 +2135,7 @@ use_pipes:
else
find_output_wrapper(& rp->output);
-#ifndef __EMX__
+#if !defined(__EMX__) && !defined(__MINGW32__)
os_close_on_exec(ctop[0], str, "pipe", "from");
os_close_on_exec(ptoc[1], str, "pipe", "from");
@@ -2110,15 +2167,31 @@ wait_any(int interesting) /* pid of interest, if any */
int status = 0;
struct redirect *redp;
- hstat = signal(SIGHUP, SIG_IGN);
istat = signal(SIGINT, SIG_IGN);
+#ifdef __MINGW32__
+ if (interesting < 0) {
+ status = -1;
+ pid = -1;
+ }
+ else
+ pid = _cwait(& status, interesting, 0);
+ if (pid == interesting && pid > 0) {
+ for (redp = red_head; redp != NULL; redp = redp->next)
+ if (interesting == redp->pid) {
+ redp->pid = -1;
+ redp->status = status;
+ break;
+ }
+ }
+#else
+ hstat = signal(SIGHUP, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
for (;;) {
-#ifdef HAVE_SYS_WAIT_H /* POSIX compatible sys/wait.h */
+# ifdef HAVE_SYS_WAIT_H /* POSIX compatible sys/wait.h */
pid = wait(& status);
-#else
+# else
pid = wait((union wait *) & status);
-#endif
+# endif
if (interesting && pid == interesting) {
break;
} else if (pid != -1) {
@@ -2133,8 +2206,9 @@ wait_any(int interesting) /* pid of interest, if any */
break;
}
signal(SIGHUP, hstat);
- signal(SIGINT, istat);
signal(SIGQUIT, qstat);
+#endif
+ signal(SIGINT, istat);
return status;
}
@@ -2145,8 +2219,11 @@ gawk_popen(const char *cmd, struct redirect *rp)
{
int p[2];
int pid;
-#ifdef __EMX__
+#if defined(__EMX__) || defined(__MINGW32__)
int save_stdout;
+#ifdef __MINGW32__
+ char *qcmd = NULL;
+#endif
#endif
/*
@@ -2160,7 +2237,7 @@ gawk_popen(const char *cmd, struct redirect *rp)
if (pipe(p) < 0)
fatal(_("cannot open pipe `%s' (%s)"), cmd, strerror(errno));
-#ifdef __EMX__
+#if defined(__EMX__) || defined(__MINGW32__)
rp->iop = NULL;
save_stdout = dup(1); /* save stdout */
if (save_stdout == -1) {
@@ -2182,8 +2259,14 @@ gawk_popen(const char *cmd, struct redirect *rp)
os_close_on_exec(p[0], cmd, "pipe", "from"); /* pipe output: input of the parent process */
os_close_on_exec(save_stdout, cmd, "pipe", "from"); /* saved stdout of the parent process */
-
+
+#ifdef __EMX__
pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", cmd, NULL);
+#else /* __MINGW32__ */
+ pid = spawnl(P_NOWAIT, getenv("ComSpec"), "cmd.exe", "/c",
+ qcmd = quote_cmd(cmd), NULL);
+ efree(qcmd);
+#endif
/* restore stdout */
close(1);
@@ -2193,7 +2276,7 @@ gawk_popen(const char *cmd, struct redirect *rp)
}
close(save_stdout);
-#else /* NOT __EMX__ */
+#else /* NOT __EMX__, NOT __MINGW32__ */
if ((pid = fork()) == 0) {
if (close(1) == -1)
fatal(_("close of stdout in child failed (%s)"),
@@ -2205,20 +2288,22 @@ gawk_popen(const char *cmd, struct redirect *rp)
execl("/bin/sh", "sh", "-c", cmd, NULL);
_exit(errno == ENOENT ? 127 : 126);
}
-#endif /* NOT __EMX__ */
+#endif /* NOT __EMX__, NOT __MINGW32__ */
if (pid == -1) {
close(p[0]); close(p[1]);
fatal(_("cannot create child process for `%s' (fork: %s)"), cmd, strerror(errno));
}
rp->pid = pid;
-#ifndef __EMX__
+#if !defined(__EMX__) && !defined(__MINGW32__)
if (close(p[1]) == -1) {
close(p[0]);
fatal(_("close of pipe failed (%s)"), strerror(errno));
}
#endif
os_close_on_exec(p[0], cmd, "pipe", "from");
+ if ((BINMODE & BINMODE_INPUT) != 0)
+ os_setbinmode(p[0], O_BINARY);
rp->iop = iop_alloc(p[0], cmd, 0);
find_input_parser(rp->iop);
iop_finish(rp->iop);
@@ -3403,7 +3488,9 @@ get_a_record(char **out, /* pointer to pointer to data */
recm.rt_start = iop->off + recm.len;
/* read more data, break if EOF */
+#ifndef min
#define min(x, y) (x < y ? x : y)
+#endif
/* subtract one in read count to leave room for sentinel */
room_left = iop->end - iop->dataend - 1;
amt_to_read = min(iop->readsize, room_left);
@@ -3741,21 +3828,38 @@ get_read_timeout(IOBUF *iop)
static ssize_t
read_with_timeout(int fd, char *buf, size_t size)
{
-#if ! defined(__MINGW32__) && ! defined(VMS)
+#if ! defined(VMS)
fd_set readfds;
struct timeval tv;
+#ifdef __MINGW32__
+ /*
+ * Only sockets can be read with a timeout. Also, the FD_*
+ * macros work on SOCKET type, not on int file descriptors.
+ */
+ SOCKET s = valid_socket(fd);
+
+ if (!s)
+ return read(fd, buf, size);
+#else
+ int s = fd;
+#endif
tv.tv_sec = read_timeout / 1000;
tv.tv_usec = 1000 * (read_timeout - 1000 * tv.tv_sec);
FD_ZERO(& readfds);
- FD_SET(fd, & readfds);
+ FD_SET(s, & readfds);
errno = 0;
+ /*
+ * Note: the 1st arg of 'select' is ignored on MS-Windows, so
+ * it's not a mistake to pass fd+1 there, although we use
+ * sockets, not file descriptors.
+ */
if (select(fd + 1, & readfds, NULL, NULL, & tv) < 0)
return -1;
- if (FD_ISSET(fd, & readfds))
+ if (FD_ISSET(s, & readfds))
return read(fd, buf, size);
/* else
timed out */
@@ -3767,9 +3871,9 @@ read_with_timeout(int fd, char *buf, size_t size)
errno = EAGAIN;
#endif
return -1;
-#else /* __MINGW32__ || VMS */
+#else /* VMS */
return read(fd, buf, size);
-#endif /* __MINGW32__ || VMS */
+#endif /* VMS */
}
/*
@@ -3805,9 +3909,18 @@ gawk_ferror(FILE *fp, void *opaque)
static int
gawk_fclose(FILE *fp, void *opaque)
{
+ int result;
+#ifdef __MINGW32__
+ SOCKET s = valid_socket (fileno(fp));
+#endif
(void) opaque;
- return fclose(fp);
+ result = fclose(fp);
+#ifdef __MINGW32__
+ if (s && closesocket(s) == SOCKET_ERROR)
+ result = -1;
+#endif
+ return result;
}