home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
419b.lha
/
GNU_Awk_v2.10_Beta
/
awk7.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-01
|
26KB
|
1,142 lines
/*
* awk7.c - routines for dealing with record input and fields
*/
/*
* Copyright (C) 1986, 1988, 1989 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "awk.h"
#include <fcntl.h>
#if defined(MSDOS)
#include "popen.h"
#endif
extern NODE *concat_exp();
static void do_file();
static int get_rs();
static IOBUF *nextfile();
static int re_split();
static int get_a_record();
static int iop_close();
static IOBUF *iop_alloc();
static void close_one();
static int close_fp();
static int getline_redirect = 0;/* "getline <file" being executed */
static char *line_buf = NULL; /* holds current input line */
static int line_alloc = 0; /* current allocation for line_buf */
static char *parse_extent; /* marks where to restart parse of record */
static int parse_high_water=0; /* field number that we have parsed so far */
static char f_empty[] = "";
static char *save_fs = " "; /* save current value of FS when line is read,
* to be used in deferred parsing
*/
extern NODE *ARGC_node;
extern NODE *ARGV_node;
int field_num; /* save number of field in get_lhs */
NODE **fields_arr; /* array of pointers to the field nodes */
NODE node0; /* node for $0 which never gets free'd */
int node0_valid = 1; /* $(>0) has not been changed yet */
void
init_fields()
{
emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields");
node0.type = Node_val;
node0.stref = 0;
node0.flags = (STR|PERM); /* never free buf */
fields_arr[0] = &node0;
}
/*
* Danger! Must only be called for fields we know have just been blanked, or
* fields we know don't exist yet.
*/
/*ARGSUSED*/
static void
set_field(num, str, len, dummy)
int num;
char *str;
int len;
NODE *dummy; /* not used -- just to make interface same as set_element */
{
NODE *n;
int t;
static int nf_high_water = 0;
if (num > nf_high_water) {
erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field");
nf_high_water = num;
}
/* fill in fields that don't exist */
for (t = parse_high_water + 1; t < num; t++)
fields_arr[t] = Nnull_string;
n = make_string(str, len);
fields_arr[num] = n;
parse_high_water = num;
}
/* Someone assigned a value to $(something). Fix up $0 to be right */
static void
rebuild_record()
{
register int tlen;
register NODE *tmp;
NODE *ofs;
char *ops;
register char *cops;
register NODE **ptr, **maxp;
maxp = 0;
tlen = 0;
ofs = force_string(OFS_node->var_value);
ptr = &fields_arr[parse_high_water];
while (ptr > &fields_arr[0]) {
tmp = force_string(*ptr);
tlen += tmp->stlen;
if (tmp->stlen && !maxp)
maxp = ptr;
ptr--;
}
if (maxp) {
tlen += ((maxp - fields_arr) - 1) * ofs->stlen;
emalloc(ops, char *, tlen + 1, "fix_fields");
cops = ops;
for (ptr = &fields_arr[1]; ptr <= maxp; ptr++) {
tmp = force_string(*ptr);
bcopy(tmp->stptr, cops, tmp->stlen);
cops += tmp->stlen;
if (ptr != maxp) {
bcopy(ofs->stptr, cops, ofs->stlen);
cops += ofs->stlen;
}
}
} else
ops = "";
tmp = make_string(ops, tlen);
deref = fields_arr[0];
do_deref();
fields_arr[0] = tmp;
}
#ifndef SLOWIO
#define DO_END_OF_BUF len = bp - start;\
while (len > iop->secsiz) {\
erealloc(iop->secbuf, char *, iop->secsiz *= 2, "get");\
}\
bcopy(start, iop->secbuf, len);\
start = iop->secbuf;\
last = start + len;\
iop->cnt = read(iop->fd, iop->buf, iop->size);\
if (iop->cnt < 0)\
return iop->cnt;\
end_data = iop->buf + iop->cnt;\
iop->off = bp = iop->buf;
#define DO_END_OF_DATA iop->cnt = read(iop->fd, end_data, end_buf - end_data);\
if (iop->cnt < 0)\
return iop->cnt;\
end_data += iop->cnt;\
if (iop->cnt == 0)\
break;\
iop->cnt = end_data - iop->buf;
static int
get_a_record(res, iop)
char **res;
IOBUF *iop;
{
register char *end_data;
register char *end_buf;
char *start;
register char *bp;
char *last;
int len;
register char rs = get_rs();
end_data = iop->buf + iop->cnt;
if (iop->off >= end_data) {
iop->cnt = read(iop->fd, iop->buf, iop->size);
if (iop->cnt <= 0)
return iop->cnt = EOF;
end_data = iop->buf + iop->cnt;
iop->off = iop->buf;
}
start = bp = iop->off;
end_buf = iop->buf + iop->size;
if (rs == 0) {
while (!(*bp == '\n' && bp != iop->buf && bp[-1] == '\n')) {
if (++bp == end_buf) {
DO_END_OF_BUF
}
if (bp == end_data) {
DO_END_OF_DATA
}
}
if (*bp == '\n' && bp != start && bp[-1] == '\n')
bp--;
else if (bp != iop->buf && bp[-1] != '\n')
warning("record not terminated");
else
bp--;
iop->off = bp + 2;
} else {
while (*bp++ != rs) {
if (bp == end_buf) {
DO_END_OF_BUF
}
if (bp == end_data) {
DO_END_OF_DATA
}
}
if (*--bp != rs) {
warning("record not terminated");
bp++;
}
iop->off = bp + 1;
}
if (start == iop->secbuf) {
len = bp - iop->buf;
while (len > iop->secsiz) {
erealloc(iop->secbuf, char *, iop->secsiz *= 2, "get2");
}
bcopy(iop->buf, last, len);
bp = last + len;
}
*bp = '\0';
*res = start;
return bp - start;
}
#endif
/*
* This reads in a record from the input file
*/
static int
inrec(iop)
IOBUF *iop;
{
int cnt;
int retval = 0;
#ifndef SLOWIO
cnt = get_a_record(&line_buf, iop);
#else
cnt = get_a_record(fp, &line_buf, &line_alloc);
#endif
if (cnt == EOF) {
cnt = 0;
retval = 1;
} else {
if (!getline_redirect) {
assign_number(&NR_node->var_value,
NR_node->var_value->numbr + 1.0);
assign_number(&FNR_node->var_value,
FNR_node->var_value->numbr + 1.0);
}
}
set_record(line_buf, cnt);
return retval;
}
/*
* setup $0, but defer parsing rest of line until reference is made to $(>0)
* or to NF. At that point, parse only as much as necessary.
*/
void
set_record(buf, cnt)
char *buf;
int cnt;
{
register int i;
assign_number(&NF_node->var_value, (AWKNUM)-1);
for (i = 1; i <= parse_high_water; i++) {
deref = fields_arr[i];
do_deref();
}
parse_high_water = 0;
node0_valid = 1;
if (buf == line_buf) {
deref = fields_arr[0];
do_deref();
save_fs = get_fs();
node0.type = Node_val;
node0.stptr = buf;
node0.stlen = cnt;
node0.stref = 1;
node0.flags = (STR|PERM); /* never free buf */
fields_arr[0] = &node0;
}
}
NODE **
get_field(num, assign)
int num;
int assign; /* this field is on the LHS of an assign */
{
int n;
/*
* if requesting whole line but some other field has been altered,
* then the whole line must be rebuilt
*/
if (num == 0 && node0_valid == 0) {
/* first, parse remainder of input record */
n = parse_fields(HUGE-1, &parse_extent,
node0.stlen - (parse_extent - node0.stptr),
save_fs, set_field, (NODE *)NULL);
assign_number(&NF_node->var_value, (AWKNUM)n);
rebuild_record();
return &fields_arr[0];
}
if (num > 0 && assign)
node0_valid = 0;
if (num <= parse_high_water) /* we have already parsed this field */
return &fields_arr[num];
if (parse_high_water == 0 && num > 0) /* starting at the beginning */
parse_extent = fields_arr[0]->stptr;
/*
* parse up to num fields, calling set_field() for each, and saving
* in parse_extent the point where the parse left off
*/
n = parse_fields(num, &parse_extent,
fields_arr[0]->stlen - (parse_extent-fields_arr[0]->stptr),
save_fs, set_field, (NODE *)NULL);
if (num == HUGE-1)
num = n;
if (n < num) { /* requested field number beyond end of record;
* set_field will just extend the number of fields,
* with empty fields
*/
set_field(num, f_empty, 0, (NODE *) NULL);
/*
* if this field is onthe LHS of an assignment, then we want to
* set NF to this value, below
*/
if (assign)
n = num;
}
/*
* if we reached the end of the record, set NF to the number of fields
* so far. Note that num might actually refer to a field that
* is beyond the end of the record, but we won't set NF to that value at
* this point, since this is only a reference to the field and NF
* only gets set if the field is assigned to -- in this case n has
* been set to num above
*/
if (*parse_extent == '\0')
assign_number(&NF_node->var_value, (AWKNUM)n);
return &fields_arr[num];
}
/*
* this is called both from get_field() and from do_split()
*/
int
parse_fields(up_to, buf, len, fs, set, n)
int up_to; /* parse only up to this field number */
char **buf; /* on input: string to parse; on output: point to start next */
int len;
register char *fs;
void (*set) (); /* routine to set the value of the parsed field */
NODE *n;
{
char *s = *buf;
register char *field;
register char *scan;
register char *end = s + len;
int NF = parse_high_water;
if (up_to == HUGE)
NF = 0;
if (*fs && *(fs + 1) != '\0') { /* fs is a regexp */
struct re_registers reregs;
scan = s;
while (re_split(scan, end - scan, fs, &reregs) != -1 &&
NF < up_to) {
(*set)(++NF, scan, reregs.start[0], n);
scan += reregs.end[0];
}
if (NF != up_to && scan <= end) {
(*set)(++NF, scan, end - scan, n);
scan = end;
}
*buf = scan;
return (NF);
}
for (scan = s; scan < end && NF < up_to; scan++) {
/*
* special case: fs is single space, strip leading
* whitespace
*/
if (*fs == ' ') {
while ((*scan == ' ' || *scan == '\t') && scan < end)
scan++;
if (scan >= end)
break;
}
field = scan;
if (*fs == ' ')
while (*scan != ' ' && *scan != '\t' && scan < end)
scan++;
else {
while (*scan != *fs && scan < end)
scan++;
if (scan == end-1 && *scan == *fs) {
(*set)(++NF, field, scan - field, n);
field = scan;
}
}
(*set)(++NF, field, scan - field, n);
if (scan == end)
break;
}
*buf = scan;
return NF;
}
static int
re_split(buf, len, fs, reregs)
char *buf, *fs;
int len;
struct re_registers *reregs;
{
typedef struct re_pattern_buffer RPAT;
static RPAT *rp;
static char *last_fs = NULL;
if ((last_fs != NULL && !STREQ(fs, last_fs))
|| (rp && ! strict && ((IGNORECASE_node->var_value->numbr != 0)
^ (rp->translate != NULL))))
{
/* fs has changed or IGNORECASE has changed */
free(rp->buffer);
free(rp->fastmap);
free((char *) rp);
free(last_fs);
last_fs = NULL;
}
if (last_fs == NULL) { /* first time */
emalloc(rp, RPAT *, sizeof(RPAT), "re_split");
bzero((char *) rp, sizeof(RPAT));
emalloc(rp->buffer, char *, 8, "re_split");
rp->allocated = 8;
emalloc(rp->fastmap, char *, 256, "re_split");
emalloc(last_fs, char *, strlen(fs) + 1, "re_split");
(void) strcpy(last_fs, fs);
if (! strict && IGNORECASE_node->var_value->numbr != 0.0)
rp->translate = casetable;
else
rp->translate = NULL;
if (re_compile_pattern(fs, strlen(fs), rp) != NULL)
fatal("illegal regular expression for FS: `%s'", fs);
}
return re_search(rp, buf, len, 0, len, reregs);
}
#ifdef SLOWIO
static int /* count of chars read or EOF */
get_a_record(fp, bp, sizep)
FILE *fp;
char **bp; /* *bp points to beginning of line on return */
int *sizep; /* *sizep is current allocation of *bp */
{
register char *buf; /* buffer; realloced if necessary */
int bsz; /* current buffer size */
register char *cur; /* current position in buffer */
register char *buf_end; /* end of buffer */
register int rs; /* rs is the current record separator */
register int c;
bsz = *sizep;
buf = *bp;
if (!buf) {
emalloc(buf, char *, 128, "get_a_record");
bsz = 128;
}
rs = get_rs();
buf_end = buf + bsz;
cur = buf;
if (rs == 0) {
while ((c = getc(fp)) != EOF) {
if (c == '\n' && cur != buf && cur[-1] == '\n') {
cur--;
break;
}
*cur++ = c;
if (cur == buf_end) {
erealloc(buf, char *, bsz * 2, "get_a_record");
cur = buf + bsz;
bsz *= 2;
buf_end = buf + bsz;
}
}
if (c == EOF && cur != buf && cur[-1] == '\n')
cur--;
} else {
while ((c = getc(fp)) != EOF) {
if (c == rs)
break;
*cur++ = c;
if (cur == buf_end) {
erealloc(buf, char *, bsz * 2, "get_a_record");
cur = buf + bsz;
bsz *= 2;
buf_end = buf + bsz;
}
}
}
*cur = '\0';
*bp = buf;
*sizep = bsz;
if (c == EOF && cur == buf)
return EOF;
return cur - buf;
}
#endif
NODE *
do_getline(tree)
NODE *tree;
{
IOBUF *iop;
int cnt;
NODE **lhs;
int redir_error = 0;
if (tree->rnode == NULL) { /* no redirection */
iop = nextfile();
if (iop == NULL) /* end of input */
return tmp_number((AWKNUM) 0.0);
}
if (tree->rnode != NULL) { /* with redirection */
iop = redirect(tree->rnode, &redir_error)->iop;
if (iop == NULL && redir_error) /* failed redirect */
return tmp_number((AWKNUM) -1.0);
getline_redirect++;
}
if (tree->lnode == NULL) { /* no optional var. -- read in $0 */
if (inrec(iop) != 0) {
getline_redirect = 0;
return tmp_number((AWKNUM) 0.0);
}
} else { /* read in a named variable */
char *s = NULL;
int n = 0;
lhs = get_lhs(tree->lnode, 1);
#ifdef SLOWIO
cnt = get_a_record(fp, &s, &n);
#else
cnt = get_a_record(&s, iop);
#endif
if (!getline_redirect) {
assign_number(&NR_node->var_value,
NR_node->var_value->numbr + 1.0);
assign_number(&FNR_node->var_value,
FNR_node->var_value->numbr + 1.0);
}
if (cnt == EOF) {
getline_redirect = 0;
free(s);
return tmp_number((AWKNUM) 0.0);
}
*lhs = make_string(s, strlen(s));
/*free(s);*/
do_deref();
/* we may have to regenerate $0 here! */
if (field_num == 0)
set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
field_num = -1;
}
getline_redirect = 0;
return tmp_number((AWKNUM) 1.0);
}
/*
* We can't dereference a variable until after we've given it its new value.
* This variable points to the value we have to free up
*/
NODE *deref;
/*
* This returns a POINTER to a node pointer. get_lhs(ptr) is the current
* value of the var, or where to store the var's new value
*/
NODE **
get_lhs(ptr, assign)
NODE *ptr;
int assign; /* this is being called for the LHS of an assign. */
{
register NODE **aptr;
NODE *n;
#ifdef DEBUG
if (ptr == NULL)
cant_happen();
#endif
deref = NULL;
field_num = -1;
switch (ptr->type) {
case Node_var:
case Node_var_array:
if (ptr == NF_node && (int) NF_node->var_value->numbr == -1)
(void) get_field(HUGE-1, assign); /* parse record */
deref = ptr->var_value;
#ifdef DEBUG
if (deref->type != Node_val)
cant_happen();
if (deref->flags == 0)
cant_happen();
#endif
return &(ptr->var_value);
case Node_param_list:
n = stack_ptr[ptr->param_cnt];
#ifdef DEBUG
deref = n->var_value;
if (deref->type != Node_val)
cant_happen();
if (deref->flags == 0)
cant_happen();
deref = 0;
#endif
return &(n->var_value);
case Node_field_spec:
field_num = (int) force_number(tree_eval(ptr->lnode));
free_result();
if (field_num < 0)
fatal("attempt to access field %d", field_num);
aptr = get_field(field_num, assign);
deref = *aptr;
return aptr;
case Node_subscript:
n = ptr->lnode;
if (n->type == Node_param_list)
n = stack_ptr[n->param_cnt];
aptr = assoc_lookup(n, concat_exp(ptr->rnode));
deref = *aptr;
#ifdef DEBUG
if (deref->type != Node_val)
cant_happen();
if (deref->flags == 0)
cant_happen();
#endif
return aptr;
case Node_func:
fatal ("`%s' is a function, assignment is not allowed",
ptr->lnode->param);
}
return 0;
}
void
do_deref()
{
if (deref == NULL)
return;
if (deref == Nnull_string) {
deref = 0;
return;
}
#ifdef DEBUG
if (deref->flags == 0)
cant_happen();
#endif
if ((deref->flags & MALLOC) || (deref->flags & TEMP)) {
#ifdef DEBUG
if (deref->flags & PERM)
cant_happen();
#endif
if (deref->flags & STR) {
if (deref->stref > 0 && deref->stref != 255)
deref->stref--;
if (deref->stref > 0) {
deref->flags &= ~TEMP;
deref = 0;
return;
}
free(deref->stptr);
}
freenode(deref);
}
deref = 0;
}
static IOBUF *
nextfile()
{
static int i = 1;
static int files = 0;
static IOBUF *curfile = NULL;
char *arg;
char *cp;
int fd = -1;
if (curfile != NULL && curfile->cnt != EOF)
return curfile;
for (; i < (int) (ARGC_node->lnode->numbr); i++) {
arg = (*assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)))->stptr;
if (*arg == '\0')
continue;
cp = index(arg, '=');
if (cp != NULL) {
*cp++ = '\0';
variable(arg)->var_value = make_string(cp, strlen(cp));
*--cp = '='; /* restore original text of ARGV */
} else {
files++;
if (STREQ(arg, "-"))
fd = 0;
else
fd = open(arg, O_RDONLY);
if (fd == -1)
fatal("cannot open file `%s' for reading (%s)",
arg, sys_errlist[errno]);
/* NOTREACHED */
/* This is a kludge. */
deref = FILENAME_node->var_value;
do_deref();
FILENAME_node->var_value =
make_string(arg, strlen(arg));
FNR_node->var_value->numbr = 0.0;
i++;
break;
}
}
if (files == 0) {
files++;
/* no args. -- use stdin */
/* FILENAME is init'ed to "-" */
/* FNR is init'ed to 0 */
fd = 0;
}
if (fd == -1)
return NULL;
return curfile = iop_alloc(fd);
}
static IOBUF *
iop_alloc(fd)
int fd;
{
IOBUF *iop;
/* rlp900927 -- moved stb declaration inside #if, below */
/*
* System V doesn't have the file system block size in the
* stat structure. So we have to make some sort of reasonable
* guess. We use stdio's BUFSIZ, since that what it was
* meant for in the first place.
*/
#if defined(USG) || defined(MSDOS)
#define DEFBLKSIZE BUFSIZ
#else
struct stat stb;
#define DEFBLKSIZE stb.st_blksize
#endif
if (fd == -1)
return NULL;
emalloc(iop, IOBUF *, sizeof(IOBUF), "nextfile");
/*** APPEND AFTER 768 IN x:awk7.c ***/
#ifdef AMIGA
iop->size = DEFBLKSIZE;
#else
/*** APPEND AFTER 768 IN x:awk7.c ***/
if (isatty(fd))
iop->size = 128;
else if (fstat(fd, &stb) == -1)
fatal("can't stat fd %d", fd);
else if (lseek(fd, 0L, 0) == -1)
iop->size = DEFBLKSIZE;
else
iop->size = stb.st_size < DEFBLKSIZE ?
stb.st_size+1 : DEFBLKSIZE;
/*** APPEND AFTER 777 IN x:awk7.c ***/
#endif
/*** APPEND AFTER 777 IN x:awk7.c ***/
errno = 0;
iop->fd = fd;
emalloc(iop->buf, char *, iop->size, "nextfile");
iop->off = iop->buf;
iop->cnt = 0;
/*** CHANGE 783 IN x:awk7.c TO [787,791] IN awk7.c ***/
#ifdef AMIGA /* I don't completely understand this but it seems to work */
iop->secsiz = iop->size;
#else
iop->secsiz = iop->size < 128 ? iop->size : 128;
#endif
/*** CHANGE 783 IN x:awk7.c TO [787,791] IN awk7.c ***/
emalloc(iop->secbuf, char *, iop->secsiz, "nextfile");
return iop;
}
void
do_input()
{
IOBUF *iop;
extern int exiting;
while ((iop = nextfile()) != NULL) {
do_file(iop);
if (exiting)
break;
}
}
static int
iop_close(iop)
IOBUF *iop;
{
int ret;
ret = close(iop->fd);
if (ret == -1)
warning("close of fd %d failed");
free(iop->buf);
free(iop->secbuf);
free((char *)iop);
return ret == -1 ? 1 : 0;
}
static void
do_file(iop)
IOBUF *iop;
{
/* This is where it spends all its time. The infamous MAIN LOOP */
if (inrec(iop) == 0)
while (interpret(expression_value) && inrec(iop) == 0)
;
(void) iop_close(iop);
}
static int
get_rs()
{
register NODE *tmp;
tmp = force_string(RS_node->var_value);
if (tmp->stlen == 0)
return 0;
return (int) *(tmp->stptr);
}
struct redirect *red_head = NULL;
/* 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;
register FILE *fp;
int tflag;
char *direction = "to";
tflag = 0;
switch (tree->type) {
case Node_redirect_append:
tflag = RED_APPEND;
case Node_redirect_output:
tflag |= (RED_FILE|RED_WRITE);
break;
case Node_redirect_pipe:
tflag = (RED_PIPE|RED_WRITE);
break;
case Node_redirect_pipein:
tflag = (RED_PIPE|RED_READ);
break;
case Node_redirect_input:
tflag = (RED_FILE|RED_READ);
break;
default:
fatal ("invalid tree type %d in redirect()\n", tree->type);
break;
}
tmp = force_string(tree_eval(tree->subnode));
str = tmp->stptr;
for (rp = red_head; rp != NULL; rp = rp->next)
if (rp->flag == tflag && STREQ(rp->value, str))
break;
if (rp == NULL) {
emalloc(rp, struct redirect *, sizeof(struct redirect),
"redirect");
emalloc(str, char *, strlen(tmp->stptr)+1, "redirect");
(void) strcpy(str, tmp->stptr);
rp->value = str;
rp->flag = tflag;
rp->offset = 0;
rp->fp = NULL;
rp->iop = NULL;
/* 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) {
errno = 0;
switch (tree->type) {
case Node_redirect_output:
fp = rp->fp = fdopen(devopen(str, "w"), "w");
break;
case Node_redirect_append:
fp = rp->fp = fdopen(devopen(str, "a"), "a");
break;
/*** APPEND AFTER 902 IN x:awk7.c ***/
#ifndef AMIGA /* we don't know how to do this do we Amy */
/*** APPEND AFTER 902 IN x:awk7.c ***/
case Node_redirect_pipe:
fp = rp->fp = popen(str, "w");
break;
case Node_redirect_pipein:
direction = "from";
/* this should bypass popen() */
rp->iop = iop_alloc(fileno(popen(str, "r")));
break;
/*** APPEND AFTER 910 IN x:awk7.c ***/
#endif
/*** APPEND AFTER 910 IN x:awk7.c ***/
case Node_redirect_input:
direction = "from";
rp->iop = iop_alloc(devopen(str, "r"));
break;
}
if (fp == NULL && rp->iop == NULL) {
/* too many files open -- close one and try again */
if (errno == ENFILE || errno == EMFILE)
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 = 1;
if (tree->type == Node_redirect_output
|| tree->type == Node_redirect_append)
fatal("can't redirect %s `%s'\n",
direction, str);
else
return NULL;
}
}
}
if (rp->offset != 0) /* this file was previously open */
if (fseek(fp, rp->offset, 0) == -1)
fatal("can't seek to %ld on `%s'\n", rp->offset, str);
#ifdef notdef
(void) flush_io(); /* a la SVR4 awk */
#endif
free_temp(tmp);
return rp;
}
static void
close_one()
{
register struct redirect *rp;
register struct redirect *rplast;
/* 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->offset = ftell(rp->fp);
if (fclose(rp->fp))
warning("close of \"%s\" failed (%s).",
rp->value, sys_errlist[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 (STREQ(rp->value, tmp->stptr))
break;
}
free_temp(tmp);
if (rp == NULL) /* no match */
return tmp_number((AWKNUM) 0.0);
return tmp_number((AWKNUM)close_fp(rp));
}
static int
close_fp(rp)
register struct redirect *rp;
{
int status;
if (rp->flag == (RED_PIPE|RED_WRITE))
status = pclose(rp->fp);
else
if (rp->fp)
status = fclose(rp->fp);
else if (rp->iop)
status = iop_close(rp->iop);
/* SVR4 awk checks and warns about status of close */
if (status)
warning("%s close of \"%s\" failed (%s).",
(rp->flag & RED_PIPE) ? "pipe" :
"file", rp->value,
sys_errlist[errno]);
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;
if (fflush(stdout)) {
warning("error writing standard output.");
status++;
}
if (fflush(stderr)) {
warning("error writing standard error.");
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, sys_errlist[errno]);
status++;
}
return status;
}
int
close_io ()
{
register struct redirect *rp;
int status = 0;
for (rp = red_head; rp != NULL; rp = rp->next)
if ((rp->fp && close_fp(rp)) || (rp->iop && iop_close(rp->iop)))
status++;
return status;
}
/* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
int
devopen (name, mode)
char *name, *mode;
{
int openfd = -1;
FILE *fdopen ();
char *cp;
int flag;
switch(mode[0]) {
case 'r': flag = O_RDONLY;
break;
case 'w': flag = O_WRONLY|O_CREAT|O_TRUNC;
break;
case 'a': flag = O_WRONLY|O_APPEND|O_CREAT;
break;
}
#if defined(STRICT) || defined(NO_DEV_FD)
return (open (name, flag, 0666));
#else
if (strict)
return (open (name, flag, 0666));
if (!STREQN (name, "/dev/", 5))
return (open (name, flag, 0666));
else
cp = name + 5;
/* XXX - first three tests ignore mode */
if (STREQ(cp, "stdin"))
return (0);
else if (STREQ(cp, "stdout"))
return (1);
else if (STREQ(cp, "stderr"))
return (2);
else if (STREQN(cp, "fd/", 3)) {
cp += 3;
if (sscanf (cp, "%d", & openfd) == 1 && openfd >= 0)
/* got something */
return openfd;
else
return -1;
} else
return (open (name, flag, 0666));
#endif
}
/*** APPEND AFTER 1108 IN x:awk7.c ***/
#ifdef AMIGA /* those damned pipes again */
pclose(junk)
long junk;
{
return(1);
}
#endif
/*** APPEND AFTER 1108 IN x:awk7.c ***/