⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * io.c --- routines for dealing with input and output and records *//*  * Copyright (C) 1986, 1988, 1989, 1991, 1992 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. */#include <sys/param.h>#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 atarist#define INVALID_HANDLE (-1)#else#define INVALID_HANDLE  (__SMALLEST_VALID_HANDLE - 1)#endif#if defined(MSDOS) || defined(atarist)#define PIPES_SIMULATED#endifstatic 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));#ifndef PIPES_SIMULATEDstatic int wait_any P((int interesting));#endifstatic IOBUF *gawk_popen P((char *cmd, struct redirect *rp));static IOBUF *iop_open P((char *file, char *how));static int gawk_pclose P((struct redirect *rp));static int do_pathopen P((char *file));extern FILE	*fdopen();extern FILE	*popen();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 */voiddo_nextfile(){	(void) nextfile(1);	longjmp(filebuf, 1);}static IOBUF *nextfile(skipping)int skipping;{	static int i = 1;	static int files = 0;	NODE *arg;	int fd = INVALID_HANDLE;	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 */		/* FILENAME is init'ed to "-" */		/* FNR is init'ed to 0 */		curfile = iop_alloc(fileno(stdin));	}	return curfile;}voidset_FNR(){	FNR = (int) FNR_node->var_value->numbr;}voidset_NR(){	NR = (int) NR_node->var_value->numbr;}/* * This reads in a record from the input file */static intinrec(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 intiop_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;}voiddo_input(){	IOBUF *iop;	extern int exiting;	if (setjmp(filebuf) != 0) {	}	while ((iop = nextfile(0)) != NULL) {		if (inrec(iop) == 0)			while (interpret(expression_value) && inrec(iop) == 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;	char *direction = "to";	char *mode;	int fd;	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, mode);				if (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)				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 voidclose_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));	rp = NULL;	return tmp;}static intclose_redir(rp)register struct redirect *rp;{	int status = 0;	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;		}	}	/* 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,			(rp->flag & RED_PIPE) ? "pipe" :			"file", 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;}intflush_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;}intclose_io (){	register struct redirect *rp;	register struct redirect *next;	int status = 0;	errno = 0;	if (fclose(stdout)) {		warning("error writing standard output (%s).", strerror(errno));		status++;	}	if (fclose(stderr)) {		warning("error writing standard error (%s).", strerror(errno));		status++;	}	for (rp = red_head; rp != NULL; rp = next) {		next = rp->next;		if (close_redir(rp))			status++;		rp = NULL;	}	return status;}/* str2mode --- convert a string mode to an integer mode */static intstr2mode(mode)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:		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. */intdevopen(name, mode)char *name, *mode;{	int openfd = INVALID_HANDLE;	char *cp, *ptr;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -