diff options
Diffstat (limited to 'gnu/usr.bin/awk/io.c')
| -rw-r--r-- | gnu/usr.bin/awk/io.c | 1283 |
1 files changed, 0 insertions, 1283 deletions
diff --git a/gnu/usr.bin/awk/io.c b/gnu/usr.bin/awk/io.c deleted file mode 100644 index 7f9255641150..000000000000 --- a/gnu/usr.bin/awk/io.c +++ /dev/null @@ -1,1283 +0,0 @@ -/* - * io.c --- routines for dealing with input and output and records - */ - -/* - * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 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 2 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 GAWK; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if !defined(VMS) && !defined(VMS_POSIX) && !defined(_MSC_VER) -#include <sys/param.h> -#endif -#include "awk.h" - -#ifndef O_RDONLY -#include <fcntl.h> -#endif - -#if !defined(S_ISDIR) && defined(S_IFDIR) -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif - -#ifndef ENFILE -#define ENFILE EMFILE -#endif - -#ifndef atarist -#define INVALID_HANDLE (-1) -#else -#define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1) -#endif - -#if defined(MSDOS) || defined(OS2) || defined(atarist) -#define PIPES_SIMULATED -#endif - -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)); -#ifndef PIPES_SIMULATED -static int wait_any P((int interesting)); -#endif -static IOBUF *gawk_popen P((char *cmd, struct redirect *rp)); -static IOBUF *iop_open P((const char *file, const char *how)); -static int gawk_pclose P((struct redirect *rp)); -static int do_pathopen P((const char *file)); -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)); - -extern FILE *fdopen(); - -#if defined (MSDOS) -#include "popen.h" -#define popen(c,m) os_popen(c,m) -#define pclose(f) os_pclose(f) -#elif defined (OS2) /* OS/2, but not family mode */ -#if defined (_MSC_VER) -#define popen(c,m) _popen(c,m) -#define pclose(f) _pclose(f) -#endif -#else -extern FILE *popen(); -#endif - -static struct redirect *red_head = NULL; - -extern int output_is_tty; -extern NODE *ARGC_node; -extern NODE *ARGV_node; -extern NODE *ARGIND_node; -extern NODE *ERRNO_node; -extern NODE **fields_arr; - -static jmp_buf filebuf; /* for do_nextfile() */ - -/* do_nextfile --- implement gawk "next file" extension */ - -void -do_nextfile() -{ - (void) nextfile(1); - longjmp(filebuf, 1); -} - -static IOBUF * -nextfile(skipping) -int skipping; -{ - static int i = 1; - static int files = 0; - NODE *arg; - static IOBUF *curfile = NULL; - - if (skipping) { - if (curfile != NULL) - iop_close(curfile); - curfile = NULL; - return NULL; - } - if (curfile != NULL) { - if (curfile->cnt == EOF) { - (void) iop_close(curfile); - curfile = NULL; - } else - return curfile; - } - for (; i < (int) (ARGC_node->lnode->numbr); i++) { - arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)); - if (arg->stptr[0] == '\0') - continue; - arg->stptr[arg->stlen] = '\0'; - if (! do_unix) { - ARGIND_node->var_value->numbr = i; - ARGIND_node->var_value->flags = NUM|NUMBER; - } - if (!arg_assign(arg->stptr)) { - files++; - curfile = iop_open(arg->stptr, "r"); - if (curfile == NULL) - fatal("cannot open file `%s' for reading (%s)", - arg->stptr, strerror(errno)); - /* NOTREACHED */ - /* This is a kludge. */ - unref(FILENAME_node->var_value); - FILENAME_node->var_value = dupnode(arg); - FNR = 0; - i++; - break; - } - } - if (files == 0) { - files++; - /* no args. -- use stdin */ - /* FNR is init'ed to 0 */ - FILENAME_node->var_value = make_string("-", 1); - curfile = iop_alloc(fileno(stdin)); - } - return curfile; -} - -void -set_FNR() -{ - FNR = (long) FNR_node->var_value->numbr; -} - -void -set_NR() -{ - NR = (long) NR_node->var_value->numbr; -} - -/* - * This reads in a record from the input file - */ -static int -inrec(iop) -IOBUF *iop; -{ - char *begin; - register int cnt; - int retval = 0; - - cnt = get_a_record(&begin, iop, *RS, NULL); - if (cnt == EOF) { - cnt = 0; - retval = 1; - } else { - NR += 1; - FNR += 1; - } - set_record(begin, cnt, 1); - - return retval; -} - -static int -iop_close(iop) -IOBUF *iop; -{ - int ret; - - if (iop == NULL) - return 0; - errno = 0; - -#ifdef _CRAY - /* Work around bug in UNICOS popen */ - if (iop->fd < 3) - ret = 0; - else -#endif - /* save these for re-use; don't free the storage */ - if ((iop->flag & IOP_IS_INTERNAL) != 0) { - iop->off = iop->buf; - iop->end = iop->buf + strlen(iop->buf); - iop->cnt = 0; - iop->secsiz = 0; - return 0; - } - - /* 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)) - ret = 0; - else - ret = close(iop->fd); - if (ret == -1) - warning("close of fd %d failed (%s)", iop->fd, strerror(errno)); - if ((iop->flag & IOP_NO_FREE) == 0) { - /* - * be careful -- $0 may still reference the buffer even though - * an explicit close is being done; in the future, maybe we - * can do this a bit better - */ - if (iop->buf) { - if ((fields_arr[0]->stptr >= iop->buf) - && (fields_arr[0]->stptr < iop->end)) { - NODE *t; - - t = make_string(fields_arr[0]->stptr, - fields_arr[0]->stlen); - unref(fields_arr[0]); - fields_arr [0] = t; - reset_record (); - } - free(iop->buf); - } - free((char *)iop); - } - return ret == -1 ? 1 : 0; -} - -void -do_input() -{ - IOBUF *iop; - extern int exiting; - - (void) setjmp(filebuf); - - while ((iop = nextfile(0)) != NULL) { - if (inrec(iop) == 0) - while (interpret(expression_value) && inrec(iop) == 0) - continue; - /* recover any space from C based alloca */ - (void) alloca(0); - - if (exiting) - break; - } -} - -/* Redirection for printf and print commands */ -struct redirect * -redirect(tree, errflg) -NODE *tree; -int *errflg; -{ - register NODE *tmp; - register struct redirect *rp; - register char *str; - int tflag = 0; - int outflag = 0; - const char *direction = "to"; - const char *mode; - int fd; - const char *what = NULL; - - switch (tree->type) { - case Node_redirect_append: - tflag = RED_APPEND; - /* FALL THROUGH */ - case Node_redirect_output: - outflag = (RED_FILE|RED_WRITE); - tflag |= outflag; - if (tree->type == Node_redirect_output) - what = ">"; - else - what = ">>"; - break; - case Node_redirect_pipe: - tflag = (RED_PIPE|RED_WRITE); - what = "|"; - break; - case Node_redirect_pipein: - tflag = (RED_PIPE|RED_READ); - what = "|"; - break; - case Node_redirect_input: - tflag = (RED_FILE|RED_READ); - what = "<"; - break; - default: - fatal ("invalid tree type %d in redirect()", tree->type); - break; - } - tmp = tree_eval(tree->subnode); - if (do_lint && ! (tmp->flags & STR)) - 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", - what); - if (do_lint - && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen))) - 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 - && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) - break; - if (rp == NULL) { - emalloc(rp, struct redirect *, sizeof(struct redirect), - "redirect"); - emalloc(str, char *, tmp->stlen+1, "redirect"); - memcpy(str, tmp->stptr, tmp->stlen); - str[tmp->stlen] = '\0'; - rp->value = str; - rp->flag = tflag; - rp->fp = NULL; - rp->iop = NULL; - rp->pid = 0; /* unlikely that we're worried about init */ - rp->status = 0; - /* maintain list in most-recently-used first order */ - if (red_head) - red_head->prev = rp; - rp->prev = NULL; - rp->next = red_head; - red_head = rp; - } - while (rp->fp == NULL && rp->iop == NULL) { - if (rp->flag & RED_EOF) - /* encountered EOF on file or pipe -- must be cleared - * by explicit close() before reading more - */ - return rp; - mode = NULL; - errno = 0; - switch (tree->type) { - case Node_redirect_output: - mode = "w"; - if (rp->flag & RED_USED) - mode = "a"; - break; - case Node_redirect_append: - mode = "a"; - break; - case Node_redirect_pipe: - if ((rp->fp = popen(str, "w")) == NULL) - fatal("can't open pipe (\"%s\") for output (%s)", - str, strerror(errno)); - 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)", - str, strerror(errno)); - break; - case Node_redirect_input: - direction = "from"; - rp->iop = iop_open(str, "r"); - break; - default: - cant_happen(); - } - if (mode != NULL) { - fd = devopen(str, mode); - if (fd > INVALID_HANDLE) { - if (fd == fileno(stdin)) - rp->fp = stdin; - else if (fd == fileno(stdout)) - rp->fp = stdout; - else if (fd == fileno(stderr)) - rp->fp = stderr; - else { - rp->fp = fdopen(fd, (char *) mode); - /* don't leak file descriptors */ - if (rp->fp == NULL) - close(fd); - } - if (rp->fp != NULL && isatty(fd)) - rp->flag |= RED_NOBUF; - } - } - if (rp->fp == NULL && rp->iop == NULL) { - /* too many files open -- close one and try again */ - if (errno == EMFILE || errno == ENFILE) - close_one(); - else { - /* - * Some other reason for failure. - * - * On redirection of input from a file, - * just return an error, so e.g. getline - * can return -1. For output to file, - * complain. The shell will complain on - * a bad command to a pipe. - */ - *errflg = errno; - if (tree->type == Node_redirect_output - || tree->type == Node_redirect_append) - fatal("can't redirect %s `%s' (%s)", - direction, str, strerror(errno)); - else { - free_temp(tmp); - return NULL; - } - } - } - } - free_temp(tmp); - return rp; -} - -static void -close_one() -{ - register struct redirect *rp; - register struct redirect *rplast = NULL; - - /* go to end of list first, to pick up least recently used entry */ - for (rp = red_head; rp != NULL; rp = rp->next) - rplast = rp; - /* now work back up through the list */ - for (rp = rplast; rp != NULL; rp = rp->prev) - if (rp->fp && (rp->flag & RED_FILE)) { - rp->flag |= RED_USED; - errno = 0; - if (fclose(rp->fp)) - 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"); -} - -NODE * -do_close(tree) -NODE *tree; -{ - NODE *tmp; - register struct redirect *rp; - - tmp = force_string(tree_eval(tree->subnode)); - for (rp = red_head; rp != NULL; rp = rp->next) { - if (strlen(rp->value) == tmp->stlen - && STREQN(rp->value, tmp->stptr, tmp->stlen)) - break; - } - free_temp(tmp); - if (rp == NULL) /* no match */ - return tmp_number((AWKNUM) 0.0); - fflush(stdout); /* synchronize regular output */ - tmp = tmp_number((AWKNUM)close_redir(rp, 0)); - rp = NULL; - return tmp; -} - -static int -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; - errno = 0; - if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) - status = pclose(rp->fp); - else if (rp->fp) - status = fclose(rp->fp); - else if (rp->iop) { - if (rp->flag & RED_PIPE) - status = gawk_pclose(rp); - else { - status = iop_close(rp->iop); - rp->iop = NULL; - } - } - - what = (rp->flag & RED_PIPE) ? "pipe" : "file"; - - if (exitwarn) - warning("no explicit close of %s \"%s\" provided", - what, rp->value); - - /* SVR4 awk checks and warns about status of close */ - if (status) { - char *s = strerror(errno); - - warning("failure status (%d) on %s close of \"%s\" (%s)", - status, what, rp->value, s); - - if (! do_unix) { - /* set ERRNO too so that program can get at it */ - unref(ERRNO_node->var_value); - ERRNO_node->var_value = make_string(s, strlen(s)); - } - } - if (rp->next) - rp->next->prev = rp->prev; - if (rp->prev) - rp->prev->next = rp->next; - else - red_head = rp->next; - free(rp->value); - free((char *)rp); - return status; -} - -int -flush_io () -{ - register struct redirect *rp; - int status = 0; - - errno = 0; - if (fflush(stdout)) { - warning("error writing standard output (%s).", strerror(errno)); - status++; - } - if (fflush(stderr)) { - 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)) { - warning("%s flush of \"%s\" failed (%s).", - (rp->flag & RED_PIPE) ? "pipe" : - "file", rp->value, strerror(errno)); - status++; - } - } - return status; -} - -int -close_io () -{ - register struct redirect *rp; - register struct redirect *next; - int status = 0; - - errno = 0; - for (rp = red_head; rp != NULL; rp = next) { - next = rp->next; - /* close_redir() will print a message if needed */ - /* if do_lint, warn about lack of explicit close */ - if (close_redir(rp, do_lint)) - status++; - rp = NULL; - } - /* - * Some of the non-Unix os's have problems doing an fclose - * on stdout and stderr. Since we don't really need to close - * them, we just flush them, and do that across the board. - */ - if (fflush(stdout)) { - warning("error writing standard output (%s).", strerror(errno)); - status++; - } - if (fflush(stderr)) { - warning("error writing standard error (%s).", strerror(errno)); - status++; - } - return status; -} - -/* str2mode --- convert a string mode to an integer mode */ - -static int -str2mode(mode) -const char *mode; -{ - int ret; - - switch(mode[0]) { - case 'r': - ret = O_RDONLY; - break; - - case 'w': - ret = O_WRONLY|O_CREAT|O_TRUNC; - break; - - case 'a': - ret = O_WRONLY|O_APPEND|O_CREAT; - break; - - default: - ret = 0; /* lint */ - cant_happen(); - } - return ret; -} - -/* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */ - -/* - * This separate version is still needed for output, since file and pipe - * output is done with stdio. iop_open() handles input with IOBUFs of - * more "special" files. Those files are not handled here since it makes - * no sense to use them for output. - */ - -int -devopen(name, mode) -const char *name, *mode; -{ - int openfd = INVALID_HANDLE; - const char *cp; - char *ptr; - int flag = 0; - struct stat buf; - extern double strtod(); - - flag = str2mode(mode); - - if (do_unix) - goto strictopen; - -#ifdef VMS - if ((openfd = vms_devopen(name, flag)) >= 0) - return openfd; -#endif /* VMS */ - - if (STREQ(name, "-")) - openfd = fileno(stdin); - else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) { - cp = name + 5; - - if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY) - openfd = fileno(stdin); - else if (STREQ(cp, "stdout") && (flag & O_WRONLY) == O_WRONLY) - openfd = fileno(stdout); - else if (STREQ(cp, "stderr") && (flag & O_WRONLY) == O_WRONLY) - openfd = fileno(stderr); - else if (STREQN(cp, "fd/", 3)) { - cp += 3; - openfd = (int)strtod(cp, &ptr); - if (openfd <= INVALID_HANDLE || ptr == cp) - openfd = INVALID_HANDLE; - } - } - -strictopen: - if (openfd == INVALID_HANDLE) - openfd = open(name, flag, 0666); - if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) - if (S_ISDIR(buf.st_mode)) - fatal("file `%s' is a directory", name); - return openfd; -} - - -/* spec_setup --- setup an IOBUF for a special internal file */ - -static void -spec_setup(iop, len, allocate) -IOBUF *iop; -int len; -int allocate; -{ - char *cp; - - if (allocate) { - emalloc(cp, char *, len+2, "spec_setup"); - iop->buf = cp; - } else { - len = strlen(iop->buf); - iop->buf[len++] = '\n'; /* get_a_record clobbered it */ - iop->buf[len] = '\0'; /* just in case */ - } - iop->off = iop->buf; - iop->cnt = 0; - iop->secsiz = 0; - iop->size = len; - iop->end = iop->buf + len; - iop->fd = -1; - iop->flag = IOP_IS_INTERNAL; -} - -/* specfdopen --- open a fd special file */ - -static int -specfdopen(iop, name, mode) -IOBUF *iop; -const char *name, *mode; -{ - int fd; - IOBUF *tp; - - fd = devopen(name, mode); - if (fd == INVALID_HANDLE) - return INVALID_HANDLE; - tp = iop_alloc(fd); - if (tp == NULL) - return INVALID_HANDLE; - *iop = *tp; - iop->flag |= IOP_NO_FREE; - free(tp); - return 0; -} - -/* - * Following mess will improve in 2.16; this is written to avoid - * long lines, avoid splitting #if with backslash, and avoid #elif - * to maximize portability. - */ -#ifndef GETPGRP_NOARG -#if defined(__svr4__) || defined(BSD4_4) || defined(_POSIX_SOURCE) -#define GETPGRP_NOARG -#else -#if defined(i860) || defined(_AIX) || defined(hpux) || defined(VMS) -#define GETPGRP_NOARG -#else -#if defined(OS2) || defined(MSDOS) || defined(AMIGA) || defined(atarist) -#define GETPGRP_NOARG -#endif -#endif -#endif -#endif - -#ifdef GETPGRP_NOARG -#define getpgrp_ARG /* nothing */ -#else -#define getpgrp_ARG getpid() -#endif - -/* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */ - -static int -pidopen(iop, name, mode) -IOBUF *iop; -const char *name, *mode; -{ - char tbuf[BUFSIZ]; - int i; - - if (name[6] == 'g') - sprintf(tbuf, "%d\n", getpgrp( getpgrp_ARG )); - else if (name[6] == 'i') - sprintf(tbuf, "%d\n", getpid()); - else - sprintf(tbuf, "%d\n", getppid()); - i = strlen(tbuf); - spec_setup(iop, i, 1); - strcpy(iop->buf, tbuf); - return 0; -} - -/* useropen --- "open" /dev/user */ - -/* - * /dev/user creates a record as follows: - * $1 = getuid() - * $2 = geteuid() - * $3 = getgid() - * $4 = getegid() - * If multiple groups are supported, the $5 through $NF are the - * supplementary group set. - */ - -static int -useropen(iop, name, mode) -IOBUF *iop; -const char *name, *mode; -{ - char tbuf[BUFSIZ], *cp; - int i; -#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0 -#if defined(atarist) || defined(__svr4__) || defined(__osf__) || defined(__FreeBSD__) - gid_t groupset[NGROUPS_MAX]; -#else - int groupset[NGROUPS_MAX]; -#endif - int ngroups; -#endif - - sprintf(tbuf, "%d %d %d %d", getuid(), geteuid(), getgid(), 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)); - - for (i = 0; i < ngroups; i++) { - *cp++ = ' '; - sprintf(cp, "%d", (int)groupset[i]); - cp += strlen(cp); - } -#endif - *cp++ = '\n'; - *cp++ = '\0'; - - - i = strlen(tbuf); - spec_setup(iop, i, 1); - strcpy(iop->buf, tbuf); - return 0; -} - -/* iop_open --- handle special and regular files for input */ - -static IOBUF * -iop_open(name, mode) -const char *name, *mode; -{ - int openfd = INVALID_HANDLE; - int flag = 0; - struct stat buf; - IOBUF *iop; - static struct internal { - const char *name; - int compare; - int (*fp) P((IOBUF*,const char *,const char *)); - IOBUF iob; - } table[] = { - { "/dev/fd/", 8, specfdopen }, - { "/dev/stdin", 10, specfdopen }, - { "/dev/stdout", 11, specfdopen }, - { "/dev/stderr", 11, specfdopen }, - { "/dev/pid", 8, pidopen }, - { "/dev/ppid", 9, pidopen }, - { "/dev/pgrpid", 11, pidopen }, - { "/dev/user", 9, useropen }, - }; - int devcount = sizeof(table) / sizeof(table[0]); - - flag = str2mode(mode); - - if (do_unix) - goto strictopen; - - if (STREQ(name, "-")) - openfd = fileno(stdin); - else if (STREQN(name, "/dev/", 5) && stat((char *) name, &buf) == -1) { - int i; - - for (i = 0; i < devcount; i++) { - if (STREQN(name, table[i].name, table[i].compare)) { - iop = & table[i].iob; - - if (iop->buf != NULL) { - spec_setup(iop, 0, 0); - return iop; - } else if ((*table[i].fp)(iop, name, mode) == 0) - return iop; - else { - warning("could not open %s, mode `%s'", - name, mode); - return NULL; - } - } - } - } - -strictopen: - if (openfd == INVALID_HANDLE) - openfd = open(name, flag, 0666); - if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) - if ((buf.st_mode & S_IFMT) == S_IFDIR) - fatal("file `%s' is a directory", name); - iop = iop_alloc(openfd); - return iop; -} - -#ifndef PIPES_SIMULATED - /* real pipes */ -static int -wait_any(interesting) -int interesting; /* pid of interest, if any */ -{ - SIGTYPE (*hstat)(), (*istat)(), (*qstat)(); - int pid; - int status = 0; - struct redirect *redp; - extern int errno; - - hstat = signal(SIGHUP, SIG_IGN); - istat = signal(SIGINT, SIG_IGN); - qstat = signal(SIGQUIT, SIG_IGN); - for (;;) { -#ifdef NeXT - pid = wait((union wait *)&status); -#else - pid = wait(&status); -#endif /* NeXT */ - if (interesting && pid == interesting) { - break; - } else if (pid != -1) { - for (redp = red_head; redp != NULL; redp = redp->next) - if (pid == redp->pid) { - redp->pid = -1; - redp->status = status; - if (redp->fp) { - pclose(redp->fp); - redp->fp = 0; - } - if (redp->iop) { - (void) iop_close(redp->iop); - redp->iop = 0; - } - break; - } - } - if (pid == -1 && errno == ECHILD) - break; - } - signal(SIGHUP, hstat); - signal(SIGINT, istat); - signal(SIGQUIT, qstat); - return(status); -} - -static IOBUF * -gawk_popen(cmd, rp) -char *cmd; -struct redirect *rp; -{ - int p[2]; - register int pid; - - /* used to wait for any children to synchronize input and output, - * but this could cause gawk to hang when it is started in a pipeline - * and thus has a child process feeding it input (shell dependant) - */ - /*(void) wait_any(0);*/ /* wait for outstanding processes */ - - if (pipe(p) < 0) - 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)", - strerror(errno)); - if (dup(p[1]) != 1) - 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)); - if (close(0) == -1) - fatal("close of stdin in child failed (%s)", - strerror(errno)); - execl("/bin/sh", "sh", "-c", cmd, 0); - _exit(127); - } - if (pid == -1) - 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)); - return (rp->iop = iop_alloc(p[0])); -} - -static int -gawk_pclose(rp) -struct redirect *rp; -{ - (void) iop_close(rp->iop); - rp->iop = NULL; - - /* process previously found, return stored status */ - if (rp->pid == -1) - return (rp->status >> 8) & 0xFF; - rp->status = wait_any(rp->pid); - rp->pid = -1; - return (rp->status >> 8) & 0xFF; -} - -#else /* PIPES_SIMULATED */ - /* use temporary file rather than pipe */ - /* except if popen() provides real pipes too */ - -#if defined(VMS) || defined(OS2) || defined (MSDOS) -static IOBUF * -gawk_popen(cmd, rp) -char *cmd; -struct redirect *rp; -{ - FILE *current; - - if ((current = popen(cmd, "r")) == NULL) - return NULL; - return (rp->iop = iop_alloc(fileno(current))); -} - -static int -gawk_pclose(rp) -struct redirect *rp; -{ - int rval, aval, fd = rp->iop->fd; - FILE *kludge = fdopen(fd, (char *) "r"); /* pclose needs FILE* w/ right fileno */ - - rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */ - rval = iop_close(rp->iop); - rp->iop = NULL; - aval = pclose(kludge); - return (rval < 0 ? rval : aval); -} -#else /* VMS || OS2 || MSDOS */ - -static -struct { - char *command; - char *name; -} pipes[_NFILE]; - -static IOBUF * -gawk_popen(cmd, rp) -char *cmd; -struct redirect *rp; -{ - extern char *strdup(const char *); - int current; - char *name; - static char cmdbuf[256]; - - /* get a name to use. */ - if ((name = tempnam(".", "pip")) == NULL) - return NULL; - sprintf(cmdbuf,"%s > %s", cmd, name); - system(cmdbuf); - if ((current = open(name,O_RDONLY)) == INVALID_HANDLE) - return NULL; - pipes[current].name = name; - pipes[current].command = strdup(cmd); - rp->iop = iop_alloc(current); - return (rp->iop = iop_alloc(current)); -} - -static int -gawk_pclose(rp) -struct redirect *rp; -{ - int cur = rp->iop->fd; - int rval; - - rval = iop_close(rp->iop); - rp->iop = NULL; - - /* check for an open file */ - if (pipes[cur].name == NULL) - return -1; - unlink(pipes[cur].name); - free(pipes[cur].name); - pipes[cur].name = NULL; - free(pipes[cur].command); - return rval; -} -#endif /* VMS || OS2 || MSDOS */ - -#endif /* PIPES_SIMULATED */ - -NODE * -do_getline(tree) -NODE *tree; -{ - struct redirect *rp = NULL; - IOBUF *iop; - int cnt = EOF; - char *s = NULL; - int errcode; - - while (cnt == EOF) { - if (tree->rnode == NULL) { /* no redirection */ - iop = nextfile(0); - if (iop == NULL) /* end of input */ - return tmp_number((AWKNUM) 0.0); - } else { - int redir_error = 0; - - rp = redirect(tree->rnode, &redir_error); - if (rp == NULL && redir_error) { /* failed redirect */ - if (! do_unix) { - 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; - if (iop == NULL) /* end of input */ - return tmp_number((AWKNUM) 0.0); - } - errcode = 0; - cnt = get_a_record(&s, iop, *RS, & errcode); - if (! do_unix && errcode != 0) { - 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) { - if (rp) { - /* - * Don't do iop_close() here if we are - * reading from a pipe; otherwise - * gawk_pclose will not be called. - */ - if (!(rp->flag & RED_PIPE)) { - (void) iop_close(iop); - rp->iop = NULL; - } - rp->flag |= RED_EOF; /* sticky EOF */ - return tmp_number((AWKNUM) 0.0); - } else - continue; /* try another file */ - } - if (!rp) { - NR += 1; - FNR += 1; - } - if (tree->lnode == NULL) /* no optional var. */ - set_record(s, cnt, 1); - else { /* assignment to variable */ - Func_ptr after_assign = NULL; - NODE **lhs; - - lhs = get_lhs(tree->lnode, &after_assign); - unref(*lhs); - *lhs = make_string(s, strlen(s)); - (*lhs)->flags |= MAYBE_NUM; - /* we may have to regenerate $0 here! */ - if (after_assign) - (*after_assign)(); - } - } - return tmp_number((AWKNUM) 1.0); -} - -int -pathopen (file) -const char *file; -{ - int fd = do_pathopen(file); - -#ifdef DEFAULT_FILETYPE - if (! do_unix && fd <= INVALID_HANDLE) { - char *file_awk; - int save = errno; -#ifdef VMS - int vms_save = vaxc$errno; -#endif - - /* append ".awk" and try again */ - emalloc(file_awk, char *, strlen(file) + - sizeof(DEFAULT_FILETYPE) + 1, "pathopen"); - sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE); - fd = do_pathopen(file_awk); - free(file_awk); - if (fd <= INVALID_HANDLE) { - errno = save; -#ifdef VMS - vaxc$errno = vms_save; -#endif - } - } -#endif /*DEFAULT_FILETYPE*/ - - return fd; -} - -static int -do_pathopen (file) -const char *file; -{ - static const char *savepath = DEFPATH; /* defined in config.h */ - static int first = 1; - const char *awkpath; - char *cp, trypath[BUFSIZ]; - int fd; - - if (STREQ(file, "-")) - return (0); - - if (do_unix) - return (devopen(file, "r")); - - if (first) { - first = 0; - if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath) - savepath = awkpath; /* used for restarting */ - } - awkpath = savepath; - - /* some kind of path name, no search */ -#ifdef VMS /* (strchr not equal implies either or both not NULL) */ - if (strchr(file, ':') != strchr(file, ']') - || strchr(file, '>') != strchr(file, '/')) -#else /*!VMS*/ -#if defined(MSDOS) || defined(OS2) - if (strchr(file, '/') != strchr(file, '\\') - || strchr(file, ':') != NULL) -#else - if (strchr(file, '/') != NULL) -#endif /*MSDOS*/ -#endif /*VMS*/ - return (devopen(file, "r")); - -#if defined(MSDOS) || defined(OS2) - _searchenv(file, "AWKPATH", trypath); - if (trypath[0] == '\0') - _searchenv(file, "PATH", trypath); - return (trypath[0] == '\0') ? 0 : devopen(trypath, "r"); -#else - do { - trypath[0] = '\0'; - /* this should take into account limits on size of trypath */ - for (cp = trypath; *awkpath && *awkpath != ENVSEP; ) - *cp++ = *awkpath++; - - if (cp != trypath) { /* nun-null element in path */ - /* add directory punctuation only if needed */ -#ifdef VMS - if (strchr(":]>/", *(cp-1)) == NULL) -#else -#if defined(MSDOS) || defined(OS2) - if (strchr(":\\/", *(cp-1)) == NULL) -#else - if (*(cp-1) != '/') -#endif -#endif - *cp++ = '/'; - /* append filename */ - strcpy (cp, file); - } else - strcpy (trypath, file); - if ((fd = devopen(trypath, "r")) >= 0) - return (fd); - - /* no luck, keep going */ - if(*awkpath == ENVSEP && awkpath[1] != '\0') - awkpath++; /* skip colon */ - } while (*awkpath); - /* - * You might have one of the awk - * paths defined, WITHOUT the current working directory in it. - * Therefore try to open the file in the current directory. - */ - return (devopen(file, "r")); -#endif -} |
