home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD2.bin
/
bbs
/
gnu
/
gawk-2.15.5-src.lha
/
gawk-2.15.5
/
io.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-12
|
29KB
|
1,287 lines
/*
* 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-