summaryrefslogtreecommitdiffstats
path: root/contrib/awk/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/awk/io.c')
-rw-r--r--contrib/awk/io.c1305
1 files changed, 446 insertions, 859 deletions
diff --git a/contrib/awk/io.c b/contrib/awk/io.c
index 7589185..a83fc9d 100644
--- a/contrib/awk/io.c
+++ b/contrib/awk/io.c
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1976, 1988, 1989, 1991-2001 the Free Software Foundation, Inc.
+ * Copyright (C) 1976, 1988, 1989, 1991-2000 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Programming Language.
@@ -21,9 +21,12 @@
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $FreeBSD$
*/
#include "awk.h"
+#undef HAVE_MMAP /* for now, probably forever */
#ifdef HAVE_SYS_PARAM_H
#undef RE_DUP_MAX /* avoid spurious conflict w/regex.h */
@@ -34,6 +37,13 @@
#include <sys/wait.h>
#endif /* HAVE_SYS_WAIT_H */
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#ifndef MAP_FAILED
+#define MAP_FAILED ((caddr_t) -1)
+#endif /* ! defined (MAP_FAILED) */
+#endif /* HAVE_MMAP */
+
#ifndef O_RDONLY
#include <fcntl.h>
#endif
@@ -41,65 +51,32 @@
#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
#endif
-#ifdef HAVE_SOCKETS
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#else
-#include <socket.h>
-#endif /* HAVE_SYS_SOCKET_H */
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#else
-#include <in.h>
-#endif /* HAVE_NETINET_IN_H */
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif /* HAVE_NETDB_H */
-#endif /* HAVE_SOCKETS */
-
#if ! defined(S_ISREG) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
-#ifndef ENFILE
-#define ENFILE EMFILE
-#endif
-
-extern int MRL;
-
-#ifdef HAVE_SOCKETS
-enum inet_prot { INET_NONE, INET_TCP, INET_UDP, INET_RAW };
-
-#ifndef SHUT_RD
-#define SHUT_RD 0
+#if ! defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
-#ifndef SHUT_WR
-#define SHUT_WR 1
-#endif
-
-#ifndef SHUT_RDWR
-#define SHUT_RDWR 2
+#ifndef ENFILE
+#define ENFILE EMFILE
#endif
-#endif /* HAVE_SOCKETS */
-
#ifdef atarist
#include <stddef.h>
#endif
-#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(TANDEM)
+#if defined(MSDOS) || defined(OS2) || defined(WIN32)
#define PIPES_SIMULATED
#endif
-typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type;
-
static IOBUF *nextfile P((int skipping));
static int inrec P((IOBUF *iop));
static int iop_close P((IOBUF *iop));
struct redirect *redirect P((NODE *tree, int *errflg));
static void close_one P((void));
-static int close_redir P((struct redirect *rp, int exitwarn, two_way_close_type how));
+static int close_redir P((struct redirect *rp, int exitwarn));
#ifndef PIPES_SIMULATED
static int wait_any P((int interesting));
#endif
@@ -109,14 +86,16 @@ static IOBUF *iop_alloc P((int fd, const char *name, IOBUF *buf));
static int gawk_pclose P((struct redirect *rp));
static int do_pathopen P((const char *file));
static int get_a_record P((char **out, IOBUF *iop, int rs, Regexp *RSre, int *errcode));
+#ifdef HAVE_MMAP
+static int mmap_get_record P((char **out, IOBUF *iop, int rs, Regexp *RSre, int *errcode));
+#endif /* HAVE_MMAP */
static int str2mode P((const char *mode));
static void spec_setup P((IOBUF *iop, int len, int allocate));
static int specfdopen P((IOBUF *iop, const char *name, const char *mode));
static int pidopen P((IOBUF *iop, const char *name, const char *mode));
static int useropen P((IOBUF *iop, const char *name, const char *mode));
-static int two_way_open P((char *str, struct redirect *rp));
-#if defined(HAVE_POPEN_H)
+#if defined (HAVE_POPEN_H)
#include "popen.h"
#endif
@@ -135,27 +114,6 @@ extern NODE **fields_arr;
static jmp_buf filebuf; /* for do_nextfile() */
-#if defined(MSDOS) || defined(OS2)
-static const char *
-binmode(char *mode)
-{
- switch (mode[0]) {
- case 'r':
- if ((BINMODE & 1) != 0)
- mode = "rb";
- break;
- case 'w':
- case 'a':
- if ((BINMODE & 2) != 0)
- mode = (mode[0] == 'w' ? "wb" : "ab");
- break;
- }
- return mode;
-}
-#else
-#define binmode(mode) (mode)
-#endif
-
#ifdef VMS
/* File pointers have an extra level of indirection, and there are cases where
`stdin' can be null. That can crash gawk if fileno() is used as-is. */
@@ -177,7 +135,8 @@ do_nextfile()
/* nextfile --- move to the next input data file */
static IOBUF *
-nextfile(int skipping)
+nextfile(skipping)
+int skipping;
{
static long i = 1;
static int files = 0;
@@ -200,7 +159,7 @@ nextfile(int skipping)
return curfile;
}
for (; i < (long) (ARGC_node->lnode->numbr); i++) {
- arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i), FALSE);
+ arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i));
if (arg->stlen == 0)
continue;
arg->stptr[arg->stlen] = '\0';
@@ -211,7 +170,7 @@ nextfile(int skipping)
if (! arg_assign(arg->stptr)) {
files++;
fname = arg->stptr;
- curfile = iop_open(fname, binmode("r"), &mybuf);
+ curfile = iop_open(fname, "r", &mybuf);
if (curfile == NULL)
goto give_up;
curfile->flag |= IOP_NOFREE_OBJ;
@@ -229,7 +188,7 @@ nextfile(int skipping)
/* FNR is init'ed to 0 */
FILENAME_node->var_value = make_string("-", 1);
fname = "-";
- curfile = iop_open(fname, binmode("r"), &mybuf);
+ curfile = iop_open(fname, "r", &mybuf);
if (curfile == NULL)
goto give_up;
curfile->flag |= IOP_NOFREE_OBJ;
@@ -237,7 +196,7 @@ nextfile(int skipping)
return curfile;
give_up:
- fatal(_("cannot open file `%s' for reading (%s)"),
+ fatal("cannot open file `%s' for reading (%s)",
fname, strerror(errno));
/* NOTREACHED */
return 0;
@@ -262,14 +221,16 @@ set_NR()
/* inrec --- This reads in a record from the input file */
static int
-inrec(IOBUF *iop)
+inrec(iop)
+IOBUF *iop;
{
char *begin;
register int cnt;
int retval = 0;
if ((cnt = iop->cnt) != EOF)
- cnt = get_a_record(&begin, iop, RS->stptr[0], RS_regexp, NULL);
+ cnt = (*(iop->getrec))
+ (&begin, iop, RS->stptr[0], RS_regexp, NULL);
if (cnt == EOF) {
cnt = 0;
retval = 1;
@@ -285,7 +246,8 @@ inrec(IOBUF *iop)
/* iop_close --- close an open IOP */
static int
-iop_close(IOBUF *iop)
+iop_close(iop)
+IOBUF *iop;
{
int ret;
@@ -311,13 +273,14 @@ iop_close(IOBUF *iop)
/* Don't close standard files or else crufty code elsewhere will lose */
if (iop->fd == fileno(stdin)
|| iop->fd == fileno(stdout)
- || iop->fd == fileno(stderr))
+ || iop->fd == fileno(stderr)
+ || (iop->flag & IOP_MMAPPED) != 0)
ret = 0;
else
ret = close(iop->fd);
if (ret == -1)
- warning(_("close of fd %d (`%s') failed (%s)"), iop->fd,
+ warning("close of fd %d (`%s') failed (%s)", iop->fd,
iop->name, strerror(errno));
if ((iop->flag & IOP_NO_FREE) == 0) {
/*
@@ -336,7 +299,12 @@ iop_close(IOBUF *iop)
fields_arr[0] = t;
reset_record();
}
- free(iop->buf);
+ if ((iop->flag & IOP_MMAPPED) == 0)
+ free(iop->buf);
+#ifdef HAVE_MMAP
+ else
+ (void) munmap(iop->buf, iop->size);
+#endif
}
if ((iop->flag & IOP_NOFREE_OBJ) == 0)
free((char *) iop);
@@ -358,37 +326,21 @@ do_input()
if (inrec(iop) == 0)
while (interpret(expression_value) && inrec(iop) == 0)
continue;
+#ifdef C_ALLOCA
+ /* recover any space from C based alloca */
+ (void) alloca(0);
+#endif
if (exiting)
break;
}
}
-/* redflags2str --- turn redirection flags into a string, for debugging */
-
-char *
-redflags2str(int flags)
-{
- static struct flagtab redtab[] = {
- { RED_FILE, "RED_FILE" },
- { RED_PIPE, "RED_PIPE" },
- { RED_READ, "RED_READ" },
- { RED_WRITE, "RED_WRITE" },
- { RED_APPEND, "RED_APPEND" },
- { RED_NOBUF, "RED_NOBUF" },
- { RED_EOF, "RED_EOF" },
- { RED_TWOWAY, "RED_TWOWAY" },
- { RED_SOCKET, "RED_SOCKET" },
- { RED_TCP, "RED_TCP" },
- { 0, NULL }
- };
-
- return genflags2str(flags, redtab);
-}
-
/* redirect --- Redirection for printf and print commands */
struct redirect *
-redirect(NODE *tree, int *errflg)
+redirect(tree, errflg)
+NODE *tree;
+int *errflg;
{
register NODE *tmp;
register struct redirect *rp;
@@ -424,57 +376,31 @@ redirect(NODE *tree, int *errflg)
tflag = (RED_FILE|RED_READ);
what = "<";
break;
- case Node_redirect_twoway:
- tflag = (RED_READ|RED_WRITE|RED_TWOWAY);
- what = "|&";
- break;
default:
- fatal(_("invalid tree type %s in redirect()"),
- nodetype2str(tree->type));
+ fatal("invalid tree type %d in redirect()", tree->type);
break;
}
tmp = tree_eval(tree->subnode);
if (do_lint && (tmp->flags & STR) == 0)
- lintwarn(_("expression in `%s' redirection only has numeric value"),
+ warning("expression in `%s' redirection only has numeric value",
what);
tmp = force_string(tmp);
str = tmp->stptr;
if (str == NULL || *str == '\0')
- fatal(_("expression for `%s' redirection has null string value"),
+ fatal("expression for `%s' redirection has null string value",
what);
if (do_lint
&& (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen)))
- lintwarn(_("filename `%s' for `%s' redirection may be result of logical expression"), str, what);
-
-#ifdef HAVE_SOCKETS
- if (STREQN(str, "/inet/", 6)) {
- tflag |= RED_SOCKET;
- if (STREQN(str + 6, "tcp/", 4))
- tflag |= RED_TCP; /* use shutdown when closing */
- }
-#endif /* HAVE_SOCKETS */
-
- for (rp = red_head; rp != NULL; rp = rp->next) {
+ warning("filename `%s' for `%s' redirection may be result of logical expression", str, what);
+ for (rp = red_head; rp != NULL; rp = rp->next)
if (strlen(rp->value) == tmp->stlen
&& STREQN(rp->value, str, tmp->stlen)
&& ((rp->flag & ~(RED_NOBUF|RED_EOF)) == tflag
|| (outflag != 0
- && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) {
-
- int rpflag = (rp->flag & ~(RED_NOBUF|RED_EOF));
- int newflag = (tflag & ~(RED_NOBUF|RED_EOF));
-
- if (do_lint && rpflag != newflag)
- lintwarn(
- _("unnecessary mixing of `>' and `>>' for file `%.*s'"),
- tmp->stlen, rp->value);
-
+ && (rp->flag & (RED_FILE|RED_WRITE)) == outflag)))
break;
- }
- }
-
if (rp == NULL) {
emalloc(rp, struct redirect *, sizeof(struct redirect),
"redirect");
@@ -495,7 +421,6 @@ redirect(NODE *tree, int *errflg)
red_head = rp;
} else
str = rp->value; /* get \0 terminated string */
-
while (rp->fp == NULL && rp->iop == NULL) {
if (rp->flag & RED_EOF)
/*
@@ -507,48 +432,31 @@ redirect(NODE *tree, int *errflg)
errno = 0;
switch (tree->type) {
case Node_redirect_output:
- mode = binmode("w");
+ mode = "w";
if ((rp->flag & RED_USED) != 0)
- mode = (rp->mode[1] == 'b') ? "ab" : "a";
+ mode = "a";
break;
case Node_redirect_append:
- mode = binmode("a");
+ mode = "a";
break;
case Node_redirect_pipe:
/* synchronize output before new pipe */
(void) flush_io();
- os_restore_mode(fileno(stdin));
- if ((rp->fp = popen(str, binmode("w"))) == NULL)
- fatal(_("can't open pipe `%s' for output (%s)"),
+ if ((rp->fp = popen(str, "w")) == NULL)
+ fatal("can't open pipe (\"%s\") for output (%s)",
str, strerror(errno));
- /* set close-on-exec */
- os_close_on_exec(fileno(rp->fp), str, "pipe", "to");
rp->flag |= RED_NOBUF;
break;
case Node_redirect_pipein:
direction = "from";
if (gawk_popen(str, rp) == NULL)
- fatal(_("can't open pipe `%s' for input (%s)"),
+ fatal("can't open pipe (\"%s\") for input (%s)",
str, strerror(errno));
break;
case Node_redirect_input:
direction = "from";
- rp->iop = iop_open(str, binmode("r"), NULL);
- break;
- case Node_redirect_twoway:
- direction = "to/from";
- if (!two_way_open(str, rp)) {
-#ifdef HAVE_SOCKETS
- /* multiple messages make life easier for translators */
- if (STREQN(str, "/inet/", 6))
- fatal(_("can't open two way socket `%s' for input/output (%s)"),
- str, strerror(errno));
- else
-#endif
- fatal(_("can't open two way pipe `%s' for input/output (%s)"),
- str, strerror(errno));
- }
+ rp->iop = iop_open(str, "r", NULL);
break;
default:
cant_happen();
@@ -564,16 +472,7 @@ redirect(NODE *tree, int *errflg)
else if (fd == fileno(stderr))
rp->fp = stderr;
else {
-#if defined(F_GETFL) && defined(O_APPEND)
- int fd_flags;
-
- fd_flags = fcntl(fd, F_GETFL);
- if (fd_flags != -1 && (fd_flags & O_APPEND) == O_APPEND)
- rp->fp = fdopen(fd, binmode("a"));
- else
-#endif
- rp->fp = fdopen(fd, (char *) mode);
- rp->mode = (char *) mode;
+ rp->fp = fdopen(fd, (char *) mode);
/* don't leak file descriptors */
if (rp->fp == NULL)
close(fd);
@@ -595,7 +494,9 @@ redirect(NODE *tree, int *errflg)
/* too many files open -- close one and try again */
if (errno == EMFILE || errno == ENFILE)
close_one();
-#if defined __MINGW32__ || defined solaris
+#if defined __MINGW32__ || defined HAVE_MMAP
+ /* this works for solaris 2.5, not sunos */
+ /* it is also needed for MINGW32 */
else if (errno == 0) /* HACK! */
close_one();
#endif
@@ -619,15 +520,10 @@ redirect(NODE *tree, int *errflg)
if (errflg != NULL)
*errflg = errno;
if (tree->type == Node_redirect_output
- || tree->type == Node_redirect_append) {
- /* multiple messages make life easier for translators */
- if (*direction == 'f')
- fatal(_("can't redirect from `%s' (%s)"),
- str, strerror(errno));
- else
- fatal(_("can't redirect to `%s' (%s)"),
- str, strerror(errno));
- } else {
+ || tree->type == Node_redirect_append)
+ fatal("can't redirect %s `%s' (%s)",
+ direction, str, strerror(errno));
+ else {
free_temp(tmp);
return NULL;
}
@@ -641,7 +537,9 @@ redirect(NODE *tree, int *errflg)
/* getredirect --- find the struct redirect for this file or pipe */
struct redirect *
-getredirect(char *str, int len)
+getredirect(str, len)
+char *str;
+int len;
{
struct redirect *rp;
@@ -660,13 +558,6 @@ close_one()
register struct redirect *rp;
register struct redirect *rplast = NULL;
- static short warned = FALSE;
-
- if (do_lint && ! warned) {
- warned = TRUE;
- lintwarn(_("reached system limit for open files: starting to multiplex file descriptors"));
- }
-
/* go to end of list first, to pick up least recently used entry */
for (rp = red_head; rp != NULL; rp = rp->next)
rplast = rp;
@@ -676,39 +567,26 @@ close_one()
rp->flag |= RED_USED;
errno = 0;
if (/* do_lint && */ fclose(rp->fp) != 0)
- warning(_("close of `%s' failed (%s)."),
+ warning("close of \"%s\" failed (%s).",
rp->value, strerror(errno));
rp->fp = NULL;
break;
}
if (rp == NULL)
/* surely this is the only reason ??? */
- fatal(_("too many pipes or input files open"));
+ fatal("too many pipes or input files open");
}
/* do_close --- completely close an open file or pipe */
NODE *
-do_close(NODE *tree)
+do_close(tree)
+NODE *tree;
{
- NODE *tmp, *tmp2;
+ NODE *tmp;
register struct redirect *rp;
- two_way_close_type how = CLOSE_ALL; /* default */
-
- tmp = force_string(tree_eval(tree->lnode)); /* 1st arg: redir to close */
-
- if (tree->rnode != NULL) {
- /* 2nd arg if present: "to" or "from" for two-way pipe */
- /* DO NOT use _() on the strings here! */
- tmp2 = force_string(tree->rnode->lnode);
- if (strcasecmp(tmp2->stptr, "to") == 0)
- how = CLOSE_TO;
- else if (strcasecmp(tmp2->stptr, "from") == 0)
- how = CLOSE_FROM;
- else
- fatal(_("close: second argument must be `to' or `from'"));
- free_temp(tmp2);
- }
+
+ tmp = force_string(tree_eval(tree->subnode));
for (rp = red_head; rp != NULL; rp = rp->next) {
if (strlen(rp->value) == tmp->stlen
@@ -716,24 +594,22 @@ do_close(NODE *tree)
break;
}
- if (rp == NULL) { /* no match, return -1 */
- char *cp;
-
- if (do_lint)
- lintwarn(_("close: `%.*s' is not an open file, pipe or co-process"),
+ if (rp == NULL) { /* no match */
+ /* icky special case: close(FILENAME) called. */
+ if (tree->subnode == FILENAME_node
+ || (tmp->stlen == FILENAME_node->var_value->stlen
+ && STREQN(tmp->stptr, FILENAME_node->var_value->stptr, tmp->stlen))) {
+ (void) nextfile(TRUE);
+ } else if (do_lint)
+ warning("close: `%.*s' is not an open file or pipe",
tmp->stlen, tmp->stptr);
- /* update ERRNO manually, using errno = ENOENT is a stretch. */
- cp = _("close of redirection that was never opened");
- unref(ERRNO_node->var_value);
- ERRNO_node->var_value = make_string(cp, strlen(cp));
-
free_temp(tmp);
- return tmp_number((AWKNUM) -1.0);
+ return tmp_number((AWKNUM) 0.0);
}
free_temp(tmp);
fflush(stdout); /* synchronize regular output */
- tmp = tmp_number((AWKNUM) close_redir(rp, FALSE, how));
+ tmp = tmp_number((AWKNUM) close_redir(rp, FALSE));
rp = NULL;
return tmp;
}
@@ -741,63 +617,33 @@ do_close(NODE *tree)
/* close_redir --- close an open file or pipe */
static int
-close_redir(register struct redirect *rp, int exitwarn, two_way_close_type how)
+close_redir(rp, exitwarn)
+register struct redirect *rp;
+int exitwarn;
{
int status = 0;
+ char *what;
if (rp == NULL)
return 0;
if (rp->fp == stdout || rp->fp == stderr)
return 0;
-
- if (do_lint && (rp->flag & RED_TWOWAY) == 0 && how != CLOSE_ALL)
- lintwarn(_("close: redirection `%s' not opened with `|&', second argument ignored"),
- rp->value);
-
errno = 0;
- if ((rp->flag & RED_TWOWAY) != 0) { /* two-way pipe */
- /* write end: */
- if ((how == CLOSE_ALL || how == CLOSE_TO) && rp->fp != NULL) {
-#ifdef HAVE_SOCKETS
- if ((rp->flag & RED_TCP) != 0)
- (void) shutdown(fileno(rp->fp), SHUT_WR);
-#endif /* HAVE_SOCKETS */
- status = fclose(rp->fp);
- rp->fp = NULL;
- }
-
- /* read end: */
- if (how == CLOSE_ALL || how == CLOSE_FROM) {
- if ((rp->flag & RED_SOCKET) != 0 && rp->iop != NULL) {
-#ifdef HAVE_SOCKETS
- if ((rp->flag & RED_TCP) != 0)
- (void) shutdown(rp->iop->fd, SHUT_RD);
-#endif /* HAVE_SOCKETS */
- (void) iop_close(rp->iop);
- } else
- status = gawk_pclose(rp);
-
- rp->iop = NULL;
- }
- } else if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) { /* write to pipe */
+ if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
status = pclose(rp->fp);
- if ((BINMODE & 1) != 0)
- os_setbinmode(fileno(stdin), O_BINARY);
-
- rp->fp = NULL;
- } else if (rp->fp != NULL) { /* write to file */
+ else if (rp->fp != NULL)
status = fclose(rp->fp);
- rp->fp = NULL;
- } else if (rp->iop != NULL) { /* read from pipe/file */
- if ((rp->flag & RED_PIPE) != 0) /* read from pipe */
+ else if (rp->iop != NULL) {
+ if ((rp->flag & RED_PIPE) != 0)
status = gawk_pclose(rp);
- /* gawk_pclose sets rp->iop to null */
- else { /* read from file */
+ else {
status = iop_close(rp->iop);
rp->iop = NULL;
}
}
+ what = ((rp->flag & RED_PIPE) != 0) ? "pipe" : "file";
+
/* SVR4 awk checks and warns about status of close */
if (status != 0) {
char *s = strerror(errno);
@@ -806,55 +652,29 @@ close_redir(register struct redirect *rp, int exitwarn, two_way_close_type how)
* Too many people have complained about this.
* As of 2.15.6, it is now under lint control.
*/
- if (do_lint) {
- if ((rp->flag & RED_PIPE) != 0)
- lintwarn(_("failure status (%d) on pipe close of `%s' (%s)"),
- status, rp->value, s);
- else
- lintwarn(_("failure status (%d) on file close of `%s' (%s)"),
- status, rp->value, s);
- }
+ if (do_lint)
+ warning("failure status (%d) on %s close of \"%s\" (%s)",
+ status, what, rp->value, s);
if (! do_traditional) {
/* set ERRNO too so that program can get at it */
- update_ERRNO();
+ unref(ERRNO_node->var_value);
+ ERRNO_node->var_value = make_string(s, strlen(s));
}
}
- if (exitwarn) {
- /*
- * Don't use lintwarn() here. If lint warnings are fatal,
- * doing so prevents us from closing other open redirections.
- *
- * Using multiple full messages instead of string parameters
- * for the types makes message translation easier.
- */
- if ((rp->flag & RED_SOCKET) != 0)
- warning(_("no explicit close of socket `%s' provided"),
- rp->value);
- else if ((rp->flag & RED_TWOWAY) != 0)
- warning(_("no explicit close of co-process `%s' provided"),
- rp->value);
- else if ((rp->flag & RED_PIPE) != 0)
- warning(_("no explicit close of pipe `%s' provided"),
- rp->value);
- else
- warning(_("no explicit close of file `%s' provided"),
- rp->value);
- }
-
- /* remove it from the list if closing both or both ends have been closed */
- if (how == CLOSE_ALL || (rp->iop == NULL && rp->fp == NULL)) {
- if (rp->next != NULL)
- rp->next->prev = rp->prev;
- if (rp->prev != NULL)
- rp->prev->next = rp->next;
- else
- red_head = rp->next;
- free(rp->value);
- free((char *) rp);
- }
+ if (exitwarn)
+ warning("no explicit close of %s `%s' provided",
+ what, rp->value);
+ if (rp->next != NULL)
+ rp->next->prev = rp->prev;
+ if (rp->prev != NULL)
+ rp->prev->next = rp->next;
+ else
+ red_head = rp->next;
+ free(rp->value);
+ free((char *) rp);
return status;
}
@@ -868,31 +688,23 @@ flush_io()
errno = 0;
if (fflush(stdout)) {
- warning(_("error writing standard output (%s)"), strerror(errno));
+ warning("error writing standard output (%s)", strerror(errno));
status++;
}
if (fflush(stderr)) {
- warning(_("error writing standard error (%s)"), strerror(errno));
+ warning("error writing standard error (%s)", strerror(errno));
status++;
}
for (rp = red_head; rp != NULL; rp = rp->next)
/* flush both files and pipes, what the heck */
if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
if (fflush(rp->fp)) {
- if (rp->flag & RED_PIPE)
- warning(_("pipe flush of `%s' failed (%s)."),
- rp->value, strerror(errno));
- else if (rp->flag & RED_TWOWAY)
- warning(_("co-process flush of pipe to `%s' failed (%s)."),
- rp->value, strerror(errno));
- else
- warning(_("file flush of `%s' failed (%s)."),
- rp->value, strerror(errno));
+ warning("%s flush of \"%s\" failed (%s).",
+ (rp->flag & RED_PIPE) ? "pipe" :
+ "file", rp->value, strerror(errno));
status++;
}
}
- if (status != 0)
- status = -1; /* canonicalize it */
return status;
}
@@ -912,7 +724,7 @@ close_io()
* close_redir() will print a message if needed
* if do_lint, warn about lack of explicit close
*/
- if (close_redir(rp, do_lint, CLOSE_ALL))
+ if (close_redir(rp, do_lint))
status++;
rp = NULL;
}
@@ -922,11 +734,11 @@ close_io()
* them, we just flush them, and do that across the board.
*/
if (fflush(stdout)) {
- warning(_("error writing standard output (%s)"), strerror(errno));
+ warning("error writing standard output (%s)", strerror(errno));
status++;
}
if (fflush(stderr)) {
- warning(_("error writing standard error (%s)"), strerror(errno));
+ warning("error writing standard error (%s)", strerror(errno));
status++;
}
return status;
@@ -935,167 +747,31 @@ close_io()
/* str2mode --- convert a string mode to an integer mode */
static int
-str2mode(const char *mode)
+str2mode(mode)
+const char *mode;
{
int ret;
- const char *second = & mode[1];
-
- if (*second == 'b')
- second++;
switch(mode[0]) {
case 'r':
ret = O_RDONLY;
- if (*second == '+' || *second == 'w')
- ret = O_RDWR;
break;
case 'w':
ret = O_WRONLY|O_CREAT|O_TRUNC;
- if (*second == '+' || *second == 'r')
- ret = O_RDWR|O_CREAT|O_TRUNC;
break;
case 'a':
ret = O_WRONLY|O_APPEND|O_CREAT;
- if (*second == '+')
- ret = O_RDWR|O_APPEND|O_CREAT;
break;
default:
ret = 0; /* lint */
cant_happen();
}
- if (strchr(mode, 'b') != NULL)
- ret |= O_BINARY;
return ret;
}
-#ifdef HAVE_SOCKETS
-/* socketopen --- open a socket and set it into connected state */
-
-int
-socketopen(enum inet_prot type, int localport, int remoteport, char *remotehostname)
-{
- struct hostent *hp = gethostbyname(remotehostname);
- struct sockaddr_in local_addr, remote_addr;
- int socket_fd;
- int any_remote_host = strcmp(remotehostname, "0");
-
- socket_fd = INVALID_HANDLE;
- switch (type) {
- case INET_TCP:
- if (localport != 0 || remoteport != 0) {
- int on = 1;
-#ifdef SO_LINGER
- struct linger linger;
-
- memset(& linger, '\0', sizeof(linger));
-#endif
- socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR,
- (char *) & on, sizeof(on));
-#ifdef SO_LINGER
- linger.l_onoff = 1;
- linger.l_linger = 30; /* linger for 30/100 second */
- setsockopt(socket_fd, SOL_SOCKET, SO_LINGER,
- (char *) & linger, sizeof(linger));
-#endif
- }
- break;
- case INET_UDP:
- if (localport != 0 || remoteport != 0)
- socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- break;
- case INET_RAW:
-#ifdef SOCK_RAW
- if (localport == 0 && remoteport == 0)
- socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
-#endif
- break;
- case INET_NONE:
- /* fall through */
- default:
- cant_happen();
- break;
- }
-
- if (socket_fd < 0 || socket_fd == INVALID_HANDLE
- || (hp == NULL && any_remote_host != 0))
- return INVALID_HANDLE;
-
- local_addr.sin_family = remote_addr.sin_family = AF_INET;
- local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- remote_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- local_addr.sin_port = htons(localport);
- remote_addr.sin_port = htons(remoteport);
- if (bind(socket_fd, (struct sockaddr *) &local_addr, sizeof(local_addr)) == 0) {
- if (any_remote_host != 0) { /* not ANY => create a client */
- if (type == INET_TCP || type == INET_UDP) {
- memcpy(&remote_addr.sin_addr, hp->h_addr,
- sizeof(remote_addr.sin_addr));
- if (connect(socket_fd,
- (struct sockaddr *) &remote_addr,
- sizeof(remote_addr)) != 0) {
- close(socket_fd);
- if (localport == 0)
- socket_fd = INVALID_HANDLE;
- else
- socket_fd = socketopen(type, localport, 0, "0");
- }
- } else {
- /* /inet/raw client not ready yet */
- fatal(_("/inet/raw client not ready yet, sorry"));
- if (geteuid() != 0)
- fatal(_("only root may use `/inet/raw'."));
- }
- } else { /* remote host is ANY => create a server */
- if (type == INET_TCP) {
- int clientsocket_fd = INVALID_HANDLE;
- int namelen = sizeof(remote_addr);
-
- if (listen(socket_fd, 1) >= 0
- && (clientsocket_fd = accept(socket_fd,
- (struct sockaddr *) &remote_addr,
- &namelen)) >= 0) {
- close(socket_fd);
- socket_fd = clientsocket_fd;
- } else {
- close(socket_fd);
- socket_fd = INVALID_HANDLE;
- }
- } else if (type == INET_UDP) {
- char buf[10];
- int readle;
-
-#ifdef MSG_PEEK
- if (recvfrom(socket_fd, buf, 1, MSG_PEEK,
- (struct sockaddr *) & remote_addr,
- & readle) < 1
- || readle != sizeof(remote_addr)
- || connect(socket_fd,
- (struct sockaddr *)& remote_addr,
- readle) != 0) {
- close(socket_fd);
- socket_fd = INVALID_HANDLE;
- }
-#endif
- } else {
- /* /inet/raw server not ready yet */
- fatal(_("/inet/raw server not ready yet, sorry"));
- if (geteuid() != 0)
- fatal(_("only root may use `/inet/raw'."));
- }
- }
- } else {
- close(socket_fd);
- socket_fd = INVALID_HANDLE;
- }
-
- return socket_fd;
-}
-#endif /* HAVE_SOCKETS */
-
/* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
/*
@@ -1105,38 +781,33 @@ socketopen(enum inet_prot type, int localport, int remoteport, char *remotehostn
* no sense to use them for output.
*/
-/*
- * Strictly speaking, "name" is not a "const char *" because we temporarily
- * change the string.
- */
-
int
-devopen(const char *name, const char *mode)
+devopen(name, mode)
+const char *name, *mode;
{
int openfd;
- char *cp;
+ const char *cp;
char *ptr;
int flag = 0;
+ struct stat buf;
extern double strtod();
flag = str2mode(mode);
if (STREQ(name, "-"))
- return fileno(stdin);
-
- openfd = INVALID_HANDLE;
+ openfd = fileno(stdin);
+ else
+ openfd = INVALID_HANDLE;
if (do_traditional)
goto strictopen;
- if ((openfd = os_devopen(name, flag)) != INVALID_HANDLE) {
- os_close_on_exec(openfd, name, "file", "");
+ if ((openfd = os_devopen(name, flag)) >= 0)
return openfd;
- }
-
- if (STREQN(name, "/dev/", 5)) {
- cp = (char *) name + 5;
+ if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
+ cp = name + 5;
+
if (STREQ(cp, "stdin") && (flag & O_ACCMODE) == O_RDONLY)
openfd = fileno(stdin);
else if (STREQ(cp, "stdout") && (flag & O_ACCMODE) == O_WRONLY)
@@ -1149,115 +820,14 @@ devopen(const char *name, const char *mode)
if (openfd <= INVALID_HANDLE || ptr == cp)
openfd = INVALID_HANDLE;
}
- /* do not set close-on-exec for inherited fd's */
- if (openfd != INVALID_HANDLE)
- return openfd;
- } else if (STREQN(name, "/inet/", 6)) {
-#ifdef HAVE_SOCKETS
- /* /inet/protocol/localport/hostname/remoteport */
- enum inet_prot protocol = INET_NONE;
- int localport, remoteport;
- char *hostname;
- char *hostnameslastcharp;
- char *localpname;
- char proto[4];
- struct servent *service;
-
- cp = (char *) name + 6;
- /* which protocol? */
- if (STREQN(cp, "tcp/", 4))
- protocol = INET_TCP;
- else if (STREQN(cp, "udp/", 4))
- protocol = INET_UDP;
- else if (STREQN(cp, "raw/", 4))
- protocol = INET_RAW;
- else
- fatal(_("no (known) protocol supplied in special filename `%s'"),
- name);
-
- proto[0] = cp[0];
- proto[1] = cp[1];
- proto[2] = cp[2];
- proto[3] = '\0';
- cp += 4;
-
- /* which localport? */
- localpname = cp;
- while (*cp != '/' && *cp != '\0')
- cp++;
- /*
- * Require a port, let them explicitly put 0 if
- * they don't care.
- */
- if (*cp != '/' || cp == localpname)
- fatal(_("special file name `%s' is incomplete"), name);
- /* We change the special file name temporarily because we
- * need a 0-terminated string here for conversion with atoi().
- * By using atoi() the use of decimal numbers is enforced.
- */
- *cp = '\0';
-
- localport = atoi(localpname);
- if (strcmp(localpname, "0") != 0
- && (localport <= 0 || localport > 65535)) {
- service = getservbyname(localpname, proto);
- if (service == NULL)
- fatal(_("local port invalid in `%s'"), name);
- else
- localport = ntohs(service->s_port);
- }
- *cp = '/';
-
- /* which hostname? */
- cp++;
- hostname = cp;
- while (*cp != '/' && *cp != '\0')
- cp++;
- if (*cp != '/' || cp == hostname)
- fatal(_("must supply a remote hostname to `/inet'"));
- *cp = '\0';
- hostnameslastcharp = cp;
-
- /* which remoteport? */
- cp++;
- /*
- * The remote port ends the special file name.
- * This means there already is a 0 at the end of the string.
- * Therefore no need to patch any string ending.
- *
- * Here too, require a port, let them explicitly put 0 if
- * they don't care.
- */
- if (*cp == '\0')
- fatal(_("must supply a remote port to `/inet'"));
- remoteport = atoi(cp);
- if (strcmp(cp, "0") != 0
- && (remoteport <= 0 || remoteport > 65535)) {
- service = getservbyname(cp, proto);
- if (service == NULL)
- fatal(_("remote port invalid in `%s'"), name);
- else
- remoteport = ntohs(service->s_port);
- }
-
- /* Open Sesame! */
- openfd = socketopen(protocol, localport, remoteport, hostname);
- *hostnameslastcharp = '/';
-
-#else /* ! HAVE_SOCKETS */
- fatal(_("TCP/IP communications are not supported"));
-#endif /* HAVE_SOCKETS */
}
strictopen:
if (openfd == INVALID_HANDLE)
openfd = open(name, flag, 0666);
- if (openfd != INVALID_HANDLE) {
- if (os_isdir(openfd))
- fatal(_("file `%s' is a directory"), name);
-
- os_close_on_exec(openfd, name, "file", "");
- }
+ if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
+ if (S_ISDIR(buf.st_mode))
+ fatal("file `%s' is a directory", name);
return openfd;
}
@@ -1265,7 +835,10 @@ strictopen:
/* spec_setup --- setup an IOBUF for a special internal file */
static void
-spec_setup(IOBUF *iop, int len, int allocate)
+spec_setup(iop, len, allocate)
+IOBUF *iop;
+int len;
+int allocate;
{
char *cp;
@@ -1284,12 +857,15 @@ spec_setup(IOBUF *iop, int len, int allocate)
iop->end = iop->buf + len;
iop->fd = -1;
iop->flag = IOP_IS_INTERNAL;
+ iop->getrec = get_a_record;
}
/* specfdopen --- open an fd special file */
static int
-specfdopen(IOBUF *iop, const char *name, const char *mode)
+specfdopen(iop, name, mode)
+IOBUF *iop;
+const char *name, *mode;
{
int fd;
IOBUF *tp;
@@ -1318,13 +894,12 @@ specfdopen(IOBUF *iop, const char *name, const char *mode)
/* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */
static int
-pidopen(IOBUF *iop, const char *name, const char *mode)
+pidopen(iop, name, mode)
+IOBUF *iop;
+const char *name, *mode;
{
char tbuf[BUFSIZ];
int i;
- const char *cp = name + 5;
-
- warning(_("use `PROCINFO[\"%s\"]' instead of `%s'"), cp, name);
if (name[6] == 'g')
sprintf(tbuf, "%d\n", (int) getpgrp(getpgrp_arg()));
@@ -1351,7 +926,9 @@ pidopen(IOBUF *iop, const char *name, const char *mode)
*/
static int
-useropen(IOBUF *iop, const char *name, const char *mode)
+useropen(iop, name, mode)
+IOBUF *iop;
+const char *name, *mode;
{
char tbuf[BUFSIZ], *cp;
int i;
@@ -1360,15 +937,13 @@ useropen(IOBUF *iop, const char *name, const char *mode)
int ngroups;
#endif
- warning(_("use `PROCINFO[...]' instead of `/dev/user'"));
-
sprintf(tbuf, "%d %d %d %d", (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid());
cp = tbuf + strlen(tbuf);
#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0
ngroups = getgroups(NGROUPS_MAX, groupset);
if (ngroups == -1)
- fatal(_("could not find groups: %s"), strerror(errno));
+ fatal("could not find groups: %s", strerror(errno));
for (i = 0; i < ngroups; i++) {
*cp++ = ' ';
@@ -1388,10 +963,13 @@ useropen(IOBUF *iop, const char *name, const char *mode)
/* iop_open --- handle special and regular files for input */
static IOBUF *
-iop_open(const char *name, const char *mode, IOBUF *iop)
+iop_open(name, mode, iop)
+const char *name, *mode;
+IOBUF *iop;
{
int openfd = INVALID_HANDLE;
int flag = 0;
+ struct stat buf;
static struct internal {
const char *name;
int compare;
@@ -1402,7 +980,6 @@ iop_open(const char *name, const char *mode, IOBUF *iop)
{ "/dev/stdin", 10, specfdopen },
{ "/dev/stdout", 11, specfdopen },
{ "/dev/stderr", 11, specfdopen },
- { "/inet/", 6, specfdopen },
{ "/dev/pid", 8, pidopen },
{ "/dev/ppid", 9, pidopen },
{ "/dev/pgrpid", 11, pidopen },
@@ -1412,11 +989,15 @@ iop_open(const char *name, const char *mode, IOBUF *iop)
flag = str2mode(mode);
+ /*
+ * FIXME: remove the stat call, and always process these files
+ * internally.
+ */
if (STREQ(name, "-"))
openfd = fileno(stdin);
else if (do_traditional)
goto strictopen;
- else if (STREQN(name, "/dev/", 5) || STREQN(name, "/inet/", 6)) {
+ else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) {
int i;
for (i = 0; i < devcount; i++) {
@@ -1429,185 +1010,30 @@ iop_open(const char *name, const char *mode, IOBUF *iop)
} else if ((*table[i].fp)(iop, name, mode) == 0)
return iop;
else {
- warning(_("could not open `%s', mode `%s'"),
+ warning("could not open %s, mode `%s'",
name, mode);
return NULL;
}
}
}
- /* not in table, fall through to regular code */
}
strictopen:
if (openfd == INVALID_HANDLE)
openfd = open(name, flag, 0666);
- if (openfd != INVALID_HANDLE) {
- if (os_isdir(openfd))
- fatal(_("file `%s' is a directory"), name);
-
- os_close_on_exec(openfd, name, "file", "");
- }
+ if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0)
+ if (S_ISDIR(buf.st_mode))
+ fatal("file `%s' is a directory", name);
return iop_alloc(openfd, name, iop);
}
-/* two_way_open --- open a two way communications channel */
-
-static int
-two_way_open(char *str, struct redirect *rp)
-{
-#ifdef HAVE_SOCKETS
- /* case 1: socket */
- if (STREQN(str, "/inet/", 6)) {
- int fd, newfd;
-
- fd = devopen(str, "rw");
- if (fd == INVALID_HANDLE)
- return FALSE;
- rp->fp = fdopen(fd, "w");
- if (rp->fp == NULL) {
- close(fd);
- return FALSE;
- }
- newfd = dup(fd);
- if (newfd < 0) {
- fclose(rp->fp);
- return FALSE;
- }
- os_close_on_exec(newfd, str, "socket", "to/from");
- rp->iop = iop_alloc(newfd, str, NULL);
- if (rp->iop == NULL) {
- fclose(rp->fp);
- return FALSE;
- }
- rp->flag |= RED_SOCKET;
- return TRUE;
- }
-#endif /* HAVE_SOCKETS */
-
-#ifdef HAVE_PORTALS
- /* case 1.5: portal */
- if (STREQN(str, "/p/", 3)) {
- int fd, newfd;
-
- fd = open(str, O_RDWR);
- if (fd == INVALID_HANDLE)
- return FALSE;
- rp->fp = fdopen(fd, "w");
- if (rp->fp == NULL) {
- close(fd);
- return FALSE;
- }
- newfd = dup(fd);
- if (newfd < 0) {
- fclose(rp->fp);
- return FALSE;
- }
- os_close_on_exec(newfd, str, "portal", "to/from");
- rp->iop = iop_alloc(newfd, str, NULL);
- if (rp->iop == NULL) {
- fclose(rp->fp);
- return FALSE;
- }
- rp->flag |= RED_SOCKET;
- return TRUE;
- }
-#endif /* HAVE_PORTALS */
-
-#ifndef PIPES_SIMULATED /* real pipes */
- /* case 2: two way pipe to a child process */
- {
- int ptoc[2], ctop[2];
- int pid;
- int save_errno;
-
- if (pipe(ptoc) < 0)
- return FALSE; /* errno set, diagnostic from caller */
-
- if (pipe(ctop) < 0) {
- save_errno = errno;
- close(ptoc[0]);
- close(ptoc[1]);
- errno = save_errno;
- return FALSE;
- }
-
- if ((pid = fork()) < 0) {
- save_errno = errno;
- close(ptoc[0]); close(ptoc[1]);
- close(ctop[0]); close(ctop[1]);
- errno = save_errno;
- return FALSE;
- }
-
- if (pid == 0) { /* child */
- if (close(1) == -1)
- fatal(_("close of stdout in child failed (%s)"),
- strerror(errno));
- if (dup(ctop[1]) != 1)
- fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
- if (close(0) == -1)
- fatal(_("close of stdin in child failed (%s)"),
- strerror(errno));
- if (dup(ptoc[0]) != 0)
- fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno));
- if ( close(ptoc[0]) == -1 || close(ptoc[1]) == -1
- || close(ctop[0]) == -1 || close(ctop[1]) == -1)
- fatal(_("close of pipe failed (%s)"), strerror(errno));
- /* stderr does NOT get dup'ed onto child's stdout */
- execl("/bin/sh", "sh", "-c", str, NULL);
- _exit(127);
- }
-
- /* parent */
- rp->pid = pid;
- rp->iop = iop_alloc(ctop[0], str, NULL);
- if (rp->iop == NULL) {
- (void) close(ctop[0]);
- (void) close(ctop[1]);
- (void) close(ptoc[0]);
- (void) close(ptoc[1]);
- (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */
- return FALSE;
- }
- rp->fp = fdopen(ptoc[1], "w");
- if (rp->fp == NULL) {
- iop_close(rp->iop);
- rp->iop = NULL;
- (void) close(ctop[0]);
- (void) close(ctop[1]);
- (void) close(ptoc[0]);
- (void) close(ptoc[1]);
- (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */
- return FALSE;
- }
- if (fcntl(ctop[0], F_SETFD, 1) < 0) {
- warning(_("pipe from `%s': could not set close-on-exec (fcntl: %s)"),
- str, strerror(errno));;
- }
- if (fcntl(ptoc[1], F_SETFD, 1) < 0) {
- warning(_("pipe to `%s': could not set close-on-exec (fcntl: %s)"),
- str, strerror(errno));;
- }
- (void) close(ptoc[0]);
- (void) close(ctop[1]);
- return TRUE;
- }
-
-#else /*PIPES_SIMULATED*/
-
- fatal(_("`|&' not supported"));
- /*NOTREACHED*/
- return FALSE;
-
-#endif
-}
-
#ifndef PIPES_SIMULATED /* real pipes */
/* wait_any --- wait for a child process, close associated pipe */
static int
-wait_any(int interesting) /* pid of interest, if any */
+wait_any(interesting)
+int interesting; /* pid of interest, if any */
{
RETSIGTYPE (*hstat)(), (*istat)(), (*qstat)();
int pid;
@@ -1646,7 +1072,9 @@ wait_any(int interesting) /* pid of interest, if any */
/* gawk_popen --- open an IOBUF on a child process */
static IOBUF *
-gawk_popen(char *cmd, struct redirect *rp)
+gawk_popen(cmd, rp)
+char *cmd;
+struct redirect *rp;
{
int p[2];
register int pid;
@@ -1659,24 +1087,23 @@ gawk_popen(char *cmd, struct redirect *rp)
/*(void) wait_any(0);*/ /* wait for outstanding processes */
if (pipe(p) < 0)
- fatal(_("cannot open pipe `%s' (%s)"), cmd, strerror(errno));
+ fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
if ((pid = fork()) == 0) {
if (close(1) == -1)
- fatal(_("close of stdout in child failed (%s)"),
+ fatal("close of stdout in child failed (%s)",
strerror(errno));
if (dup(p[1]) != 1)
- fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno));
+ fatal("dup of pipe failed (%s)", strerror(errno));
if (close(p[0]) == -1 || close(p[1]) == -1)
- fatal(_("close of pipe failed (%s)"), strerror(errno));
+ fatal("close of pipe failed (%s)", strerror(errno));
execl("/bin/sh", "sh", "-c", cmd, NULL);
_exit(127);
}
if (pid == -1)
- fatal(_("cannot create child process for `%s' (fork: %s)"), cmd, strerror(errno));
+ fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno));
rp->pid = pid;
if (close(p[1]) == -1)
- fatal(_("close of pipe failed (%s)"), strerror(errno));
- os_close_on_exec(p[0], cmd, "pipe", "from");
+ fatal("close of pipe failed (%s)", strerror(errno));
rp->iop = iop_alloc(p[0], cmd, NULL);
if (rp->iop == NULL)
(void) close(p[0]);
@@ -1686,18 +1113,18 @@ gawk_popen(char *cmd, struct redirect *rp)
/* gawk_pclose --- close an open child pipe */
static int
-gawk_pclose(struct redirect *rp)
+gawk_pclose(rp)
+struct redirect *rp;
{
- if (rp->iop != NULL)
- (void) iop_close(rp->iop);
+ (void) iop_close(rp->iop);
rp->iop = NULL;
/* process previously found, return stored status */
if (rp->pid == -1)
- return (rp->status >> 8) + ((rp->status &0xFF) ? 128 + (rp->status & 0xF) : 0);
+ return (rp->status >> 8) & 0xFF;
rp->status = wait_any(rp->pid);
rp->pid = -1;
- return (rp->status >> 8) + ((rp->status &0xFF) ? 128 + (rp->status & 0xF) : 0);
+ return (rp->status >> 8) & 0xFF;
}
#else /* PIPES_SIMULATED */
@@ -1707,22 +1134,19 @@ gawk_pclose(struct redirect *rp)
* except if popen() provides real pipes too
*/
-#if defined(VMS) || defined(OS2) || defined (MSDOS) || defined(WIN32) || defined(TANDEM)
+#if defined(VMS) || defined(OS2) || defined (MSDOS) || defined(WIN32)
/* gawk_popen --- open an IOBUF on a child process */
static IOBUF *
-gawk_popen(char *cmd, struct redirect *rp)
+gawk_popen(cmd, rp)
+char *cmd;
+struct redirect *rp;
{
FILE *current;
- os_restore_mode(fileno(stdin));
- current = popen(cmd, binmode("r"));
- if ((BINMODE & 1) != 0)
- os_setbinmode(fileno(stdin), O_BINARY);
- if (current == NULL)
+ if ((current = popen(cmd, "r")) == NULL)
return NULL;
- os_close_on_exec(fileno(current), cmd, "pipe", "from");
rp->iop = iop_alloc(fileno(current), cmd, NULL);
if (rp->iop == NULL) {
(void) pclose(current);
@@ -1735,20 +1159,19 @@ gawk_popen(char *cmd, struct redirect *rp)
/* gawk_pclose --- close an open child pipe */
static int
-gawk_pclose(struct redirect *rp)
+gawk_pclose(rp)
+struct redirect *rp;
{
int rval, aval, fd = rp->iop->fd;
- if (rp->iop != NULL) {
- rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */
- rval = iop_close(rp->iop);
- }
+ rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */
+ rval = iop_close(rp->iop);
rp->iop = NULL;
aval = pclose(rp->ifp);
rp->ifp = NULL;
return (rval < 0 ? rval : aval);
}
-#else /* not (VMS || OS2 || MSDOS || TANDEM) */
+#else /* not (VMS || OS2 || MSDOS) */
static struct pipeinfo {
char *command;
@@ -1758,7 +1181,9 @@ static struct pipeinfo {
/* gawk_popen --- open an IOBUF on a child process */
static IOBUF *
-gawk_popen(char *cmd, struct redirect *rp)
+gawk_popen(cmd, rp)
+char *cmd;
+struct redirect *rp;
{
extern char *strdup P((const char *));
int current;
@@ -1774,7 +1199,6 @@ gawk_popen(char *cmd, struct redirect *rp)
return NULL;
pipes[current].name = name;
pipes[current].command = strdup(cmd);
- os_close_on_exec(current, cmd, "pipe", "from");
rp->iop = iop_alloc(current, name, NULL);
if (rp->iop == NULL)
(void) close(current);
@@ -1784,13 +1208,13 @@ gawk_popen(char *cmd, struct redirect *rp)
/* gawk_pclose --- close an open child pipe */
static int
-gawk_pclose(struct redirect *rp)
+gawk_pclose(rp)
+struct redirect *rp;
{
int cur = rp->iop->fd;
- int rval = 0;
+ int rval;
- if (rp->iop != NULL)
- rval = iop_close(rp->iop);
+ rval = iop_close(rp->iop);
rp->iop = NULL;
/* check for an open file */
@@ -1802,14 +1226,15 @@ gawk_pclose(struct redirect *rp)
free(pipes[cur].command);
return rval;
}
-#endif /* not (VMS || OS2 || MSDOS || TANDEM) */
+#endif /* not (VMS || OS2 || MSDOS) */
#endif /* PIPES_SIMULATED */
/* do_getline --- read in a line, into var and with redirection, as needed */
NODE *
-do_getline(NODE *tree)
+do_getline(tree)
+NODE *tree;
{
struct redirect *rp = NULL;
IOBUF *iop;
@@ -1827,9 +1252,13 @@ do_getline(NODE *tree)
rp = redirect(tree->rnode, &redir_error);
if (rp == NULL && redir_error) { /* failed redirect */
- if (! do_traditional)
- update_ERRNO();
+ if (! do_traditional) {
+ s = strerror(redir_error);
+ unref(ERRNO_node->var_value);
+ ERRNO_node->var_value =
+ make_string(s, strlen(s));
+ }
return tmp_number((AWKNUM) -1.0);
}
iop = rp->iop;
@@ -1837,11 +1266,14 @@ do_getline(NODE *tree)
return tmp_number((AWKNUM) 0.0);
}
errcode = 0;
- cnt = get_a_record(&s, iop, RS->stptr[0], RS_regexp, &errcode);
+ cnt = (*(iop->getrec))(&s, iop, RS->stptr[0], RS_regexp, &errcode);
if (errcode != 0) {
- if (! do_traditional)
- update_ERRNO();
+ if (! do_traditional) {
+ s = strerror(errcode);
+ unref(ERRNO_node->var_value);
+ ERRNO_node->var_value = make_string(s, strlen(s));
+ }
return tmp_number((AWKNUM) -1.0);
}
if (cnt == EOF) {
@@ -1851,7 +1283,7 @@ do_getline(NODE *tree)
* reading from a pipe; otherwise
* gawk_pclose will not be called.
*/
- if ((rp->flag & (RED_PIPE|RED_TWOWAY)) == 0) {
+ if ((rp->flag & RED_PIPE) == 0) {
(void) iop_close(iop);
rp->iop = NULL;
}
@@ -1870,7 +1302,7 @@ do_getline(NODE *tree)
Func_ptr after_assign = NULL;
NODE **lhs;
- lhs = get_lhs(tree->lnode, &after_assign, FALSE);
+ lhs = get_lhs(tree->lnode, &after_assign);
unref(*lhs);
*lhs = make_string(s, cnt);
(*lhs)->flags |= MAYBE_NUM;
@@ -1885,7 +1317,8 @@ do_getline(NODE *tree)
/* pathopen --- pathopen with default file extension handling */
int
-pathopen(const char *file)
+pathopen(file)
+const char *file;
{
int fd = do_pathopen(file);
@@ -1918,7 +1351,8 @@ pathopen(const char *file)
/* do_pathopen --- search $AWKPATH for source file */
static int
-do_pathopen(const char *file)
+do_pathopen(file)
+const char *file;
{
static const char *savepath = NULL;
static int first = TRUE;
@@ -1978,7 +1412,8 @@ do_pathopen(const char *file)
int bufsize = 8192;
void
-fatal(char *s)
+fatal(s)
+char *s;
{
printf("%s\n", s);
exit(1);
@@ -1988,7 +1423,10 @@ fatal(char *s)
/* iop_alloc --- allocate an IOBUF structure for an open fd */
static IOBUF *
-iop_alloc(int fd, const char *name, IOBUF *iop)
+iop_alloc(fd, name, iop)
+int fd;
+const char *name;
+IOBUF *iop;
{
struct stat sbuf;
@@ -2001,16 +1439,63 @@ iop_alloc(int fd, const char *name, IOBUF *iop)
iop->flag |= IOP_IS_TTY;
iop->size = optimal_bufsize(fd, & sbuf);
if (do_lint && S_ISREG(sbuf.st_mode) && sbuf.st_size == 0)
- lintwarn(_("data file `%s' is empty"), name);
+ warning("data file `%s' is empty", name);
iop->secsiz = -2;
errno = 0;
iop->fd = fd;
iop->off = iop->buf = NULL;
iop->cnt = 0;
iop->name = name;
+ iop->getrec = get_a_record;
+#ifdef HAVE_MMAP
+ /* Use mmap only for regular files with positive sizes.
+ The size must fit into size_t, so that mmap works correctly.
+ Also, it must fit into int, so that iop->cnt won't overflow. */
+ if (S_ISREG(sbuf.st_mode) && sbuf.st_size > 0
+ && sbuf.st_size == (size_t) sbuf.st_size
+ && sbuf.st_size == (int) sbuf.st_size) {
+ register char *cp;
+
+ iop->buf = iop->off = mmap((caddr_t) 0, sbuf.st_size,
+ PROT_READ|PROT_WRITE, MAP_PRIVATE,
+ fd, 0L);
+ /* cast is for buggy compilers (e.g. DEC OSF/1) */
+ if (iop->buf == (caddr_t)MAP_FAILED) {
+ iop->buf = iop->off = NULL;
+ goto out;
+ }
+
+ iop->flag |= IOP_MMAPPED;
+ iop->size = sbuf.st_size;
+ iop->secsiz = 0;
+ iop->end = iop->buf + iop->size;
+ iop->cnt = sbuf.st_size;
+ iop->getrec = mmap_get_record;
+ (void) close(fd);
+ iop->fd = INVALID_HANDLE;
+
+#if defined(HAVE_MADVISE) && defined(MADV_SEQUENTIAL)
+ madvise(iop->buf, iop->size, MADV_SEQUENTIAL);
+#endif
+ /*
+ * The following is a really gross hack.
+ * We want to ensure that we have a copy of the input
+ * data that won't go away, on the off chance that someone
+ * will truncate the data file we've just mmap'ed.
+ * So, we go through and touch each page, forcing the
+ * system to give us a private copy. A page size of 512
+ * guarantees this will work, even on the least common
+ * denominator system (like, oh say, a VAX).
+ */
+ for (cp = iop->buf; cp < iop->end; cp += 512)
+ *cp = *cp;
+ }
+out:
+#endif /* HAVE_MMAP */
return iop;
}
+/* These macros used by both record reading routines */
#define set_RT_to_null() \
(void)(! do_traditional && (unref(RT_node->var_value), \
RT_node->var_value = Nnull_string))
@@ -2039,11 +1524,12 @@ iop_alloc(int fd, const char *name, IOBUF *iop)
*/
static int
-get_a_record(char **out, /* pointer to pointer to data */
- IOBUF *iop, /* input IOP */
- register int grRS, /* first char in RS->stptr */
- Regexp *RSre, /* regexp for RS */
- int *errcode) /* pointer to error variable */
+get_a_record(out, iop, grRS, RSre, errcode)
+char **out; /* pointer to pointer to data */
+IOBUF *iop; /* input IOP */
+register int grRS; /* first char in RS->stptr */
+Regexp *RSre; /* regexp for RS */
+int *errcode; /* pointer to error variable */
{
register char *bp = iop->off;
char *bufend;
@@ -2054,21 +1540,11 @@ get_a_record(char **out, /* pointer to pointer to data */
int continuing = FALSE, continued = FALSE; /* used for re matching */
int onecase;
-#ifdef TANDEM
- char *mend;
-#endif
-
-#ifdef TANDEM
-#define not_past_end() (bp < mend)
-#else
-#define not_past_end() (1)
-#endif
-
/* first time through */
if (RS_null_re == NULL) {
RS_null_re = make_regexp("\n\n+", 3, TRUE, TRUE);
if (RS_null_re == NULL)
- fatal(_("internal error: file `%s', line %d\n"),
+ fatal("internal error: file `%s', line %d\n",
__FILE__, __LINE__);
}
@@ -2078,21 +1554,14 @@ get_a_record(char **out, /* pointer to pointer to data */
return EOF;
}
-#ifdef TANDEM
- if (MRL)
- mend = start + MRL;
- else
- mend = (char *) LONG_MAX;
-#endif
-
if (RS_is_null) /* special case: RS == "" */
rs = '\n';
else
rs = (char) grRS;
- onecase = (IGNORECASE && ISALPHA(rs));
+ onecase = (IGNORECASE && isalpha(rs));
if (onecase)
- rs = casetable[(unsigned char) rs];
+ rs = casetable[rs];
/* set up sentinel */
if (iop->buf) {
@@ -2142,10 +1611,6 @@ get_a_record(char **out, /* pointer to pointer to data */
}
bp = iop->end = iop->off = iop->buf + iop->secsiz;
start = bp - len;
-#ifdef TANDEM
- if (MRL)
- mend = start + MRL;
-#endif
if (oldbuf != NULL) {
free(oldbuf);
oldbuf = NULL;
@@ -2170,7 +1635,7 @@ get_a_record(char **out, /* pointer to pointer to data */
iop->cnt = EOF;
break;
} else
- fatal(_("error reading input file `%s': %s"),
+ fatal("error reading input file `%s': %s",
iop->name, strerror(errno));
} else if (iop->cnt == 0) {
/*
@@ -2222,14 +1687,6 @@ get_a_record(char **out, /* pointer to pointer to data */
* that until we try to add more to the buffer. Thus, we
* set a flag to indicate, that if eof really does happen,
* don't break early.
- *
- * Still more subtlety. Suppose RS is a multi-character regexp,
- * but it doesn't have the metacharacters that would let it
- * match an arbitrary number of characters. So it's an exact
- * string match. We need to check for this, in the case where
- * there is an exact match at the end, and NOT read more
- * data. Otherwise, this might bite us for an interactive
- * networking program that uses CR-LF as the line terminator.
*/
continuing = FALSE;
if (rsre != NULL) {
@@ -2258,34 +1715,20 @@ get_a_record(char **out, /* pointer to pointer to data */
/* case 3, regex match at exact end */
if (start + REEND(rsre, start) >= iop->end) {
if (iop->cnt != EOF) {
- /*
- * Only do the test if not at EOF
- */
- int isstring;
-
- isstring = reisstring(RS->stptr,
- RS->stlen, rsre, start);
- if (isstring == FALSE) {
- bp = iop->end;
- continuing = continued = TRUE;
- continue;
- }
+ bp = iop->end;
+ continuing = continued = TRUE;
+ continue;
}
}
/* got a match! */
/*
* Leading newlines at the beginning of the file
* should be ignored. Whew!
+ *
+ * Is this code ever executed?
*/
- if (RS_is_null && *start == '\n') {
- /*
- * have to catch the case of a
- * single newline at the front of
- * the record, which the regex
- * doesn't. gurr.
- */
- while (*start == '\n' && start < iop->end)
- start++;
+ if (RS_is_null && RESTART(rsre, start) == 0) {
+ start += REEND(rsre, start);
goto again;
}
bp = start + RESTART(rsre, start);
@@ -2296,10 +1739,10 @@ get_a_record(char **out, /* pointer to pointer to data */
}
/* search for RS, #2, RS = <single char> */
if (onecase) {
- while (casetable[(unsigned char) *bp++] != rs && not_past_end())
+ while (casetable[(int) *bp++] != rs)
continue;
} else {
- while (*bp++ != rs && not_past_end())
+ while (*bp++ != rs)
continue;
}
set_RT(bp - 1, 1);
@@ -2321,12 +1764,15 @@ get_a_record(char **out, /* pointer to pointer to data */
}
if (do_traditional || rsre == NULL) {
- iop->off = bp;
+ char *bstart;
+
+ bstart = iop->off = bp;
bp--;
- if (onecase ? casetable[(unsigned char) *bp] != rs : *bp != rs)
+ if (onecase ? casetable[(int) *bp] != rs : *bp != rs) {
bp++;
- if (MRL == 0)
- *bp = '\0';
+ bstart = bp;
+ }
+ *bp = '\0';
} else if (RS_is_null && iop->cnt == EOF) {
/*
* special case, delete trailing newlines,
@@ -2343,7 +1789,9 @@ get_a_record(char **out, /* pointer to pointer to data */
#ifdef TEST
int
-main(int argc, char *argv[])
+main(argc, argv)
+int argc;
+char *argv[];
{
IOBUF *iop;
char *out;
@@ -2364,6 +1812,145 @@ main(int argc, char *argv[])
}
#endif
+#ifdef HAVE_MMAP
+/* mmap_get_record --- pull a record out of a memory-mapped file */
+
+static int
+mmap_get_record(out, iop, grRS, RSre, errcode)
+char **out; /* pointer to pointer to data */
+IOBUF *iop; /* input IOP */
+register int grRS; /* first char in RS->stptr */
+Regexp *RSre; /* regexp for RS */
+int *errcode; /* pointer to error variable */
+{
+ register char *bp = iop->off;
+ char *start = iop->off; /* beginning of record */
+ int rs;
+ static Regexp *RS_null_re = NULL;
+ Regexp *rsre = NULL;
+ int onecase;
+ register char *end = iop->end;
+ int cnt;
+
+ /* first time through */
+ if (RS_null_re == NULL) {
+ RS_null_re = make_regexp("\n\n+", 3, TRUE, TRUE);
+ if (RS_null_re == NULL)
+ fatal("internal error: file `%s', line %d\n",
+ __FILE__, __LINE__);
+ }
+
+ if (iop->off >= iop->end) { /* previous record was last */
+ *out = NULL;
+ set_RT_to_null();
+ iop->cnt = EOF; /* tested by higher level code */
+ return EOF;
+ }
+
+ if (RS_is_null) /* special case: RS == "" */
+ rs = '\n';
+ else
+ rs = (char) grRS;
+
+ onecase = (IGNORECASE && isalpha(rs));
+ if (onecase)
+ rs = casetable[rs];
+
+ /* if RS = "", skip leading newlines at the front of the file */
+ if (RS_is_null && iop->off == iop->buf) {
+ for (bp = iop->off; *bp == '\n'; bp++)
+ continue;
+
+ if (bp != iop->off)
+ iop->off = start = bp;
+ }
+
+ /*
+ * Regexp based searching. Either RS = "" or RS = <regex>
+ * See comments in get_a_record.
+ */
+ if (! do_traditional && RSre != NULL) /* regexp */
+ rsre = RSre;
+ else if (RS_is_null) /* RS = "" */
+ rsre = RS_null_re;
+ else
+ rsre = NULL;
+
+ /*
+ * Look for regexp match of RS. Non-match conditions are:
+ * 1. No match at all
+ * 2. Match of a null string
+ * 3. Match ends at exact end of buffer
+ *
+ * #1 means that the record ends the file
+ * and there is no text that actually matched RS.
+ *
+ * #2: is probably like #1.
+ *
+ * #3 is simple; since we have the whole file mapped, it's
+ * the last record in the file.
+ */
+ if (rsre != NULL) {
+ if (research(rsre, start, 0, iop->end - start, TRUE) == -1
+ || RESTART(rsre, start) == REEND(rsre, start)) {
+ /* no matching text, we have the record */
+ *out = start;
+ iop->off = iop->end; /* all done with the record */
+ set_RT_to_null();
+ /* special case, don't allow trailing newlines */
+ if (RS_is_null && *(iop->end - 1) == '\n')
+ return iop->end - start - 1;
+ else
+ return iop->end - start;
+
+ }
+ /* have a match */
+ *out = start;
+ bp = start + RESTART(rsre, start);
+ set_RT(bp, REEND(rsre, start) - RESTART(rsre, start));
+ *bp = '\0';
+ iop->off = start + REEND(rsre, start);
+ return bp - start;
+ }
+
+ /*
+ * RS = "?", i.e., one character based searching.
+ *
+ * Alas, we can't just plug the sentinel character in at
+ * the end of the mmapp'ed file ( *(iop->end) = rs; ). This
+ * works if we're lucky enough to have a file that does not
+ * take up all of its last disk block. But if we end up with
+ * file whose size is an even multiple of the disk block size,
+ * assigning past the end of it delivers a SIGBUS. So, we have to
+ * add the extra test in the while loop at the front that looks
+ * for going past the end of the mapped object. Sigh.
+ */
+ /* search for RS, #2, RS = <single char> */
+ if (onecase) {
+ while (bp < end && casetable[*bp++] != rs)
+ continue;
+ } else {
+ while (bp < end && *bp++ != rs)
+ continue;
+ }
+ cnt = (bp - start) - 1;
+ if (bp >= iop->end) {
+ /* at end, may have actually seen rs, or may not */
+ if (*(bp-1) == rs)
+ set_RT(bp - 1, 1); /* real RS seen */
+ else {
+ cnt++;
+ set_RT_to_null();
+ }
+ } else
+ set_RT(bp - 1, 1);
+
+ iop->off = bp;
+ *out = start;
+ return cnt;
+}
+#endif /* HAVE_MMAP */
+
/* set_RS --- update things as appropriate when RS is set */
void
@@ -2389,7 +1976,7 @@ set_RS()
RS_regexp = make_regexp(RS->stptr, RS->stlen, IGNORECASE, TRUE);
if (do_lint && ! warned) {
- lintwarn(_("multicharacter value of `RS' is a gawk extension"));
+ warning("multicharacter value of `RS' is not portable");
warned = TRUE;
}
}
OpenPOWER on IntegriCloud