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

📄 filter.c

📁 早期freebsd实现
💻 C
字号:
/*- * Copyright (c) 1991, 1993, 1994 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)filter.c	8.32 (Berkeley) 4/14/94";#endif /* not lint */#include <sys/types.h>#include <sys/queue.h>#include <sys/time.h>#include <sys/wait.h>#include <bitstring.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <signal.h>#include <stdio.h>#include <string.h>#include <termios.h>#include <unistd.h>#include "compat.h"#include <db.h>#include <regex.h>#include <pathnames.h>#include "vi.h"#include "excmd.h"static int	filter_ldisplay __P((SCR *, FILE *));/* * filtercmd -- *	Run a range of lines through a filter utility and optionally *	replace the original text with the stdout/stderr output of *	the utility. */intfiltercmd(sp, ep, fm, tm, rp, cmd, ftype)	SCR *sp;	EXF *ep;	MARK *fm, *tm, *rp;	char *cmd;	enum filtertype ftype;{	FILE *ifp, *ofp;		/* GCC: can't be uninitialized. */	pid_t parent_writer_pid, utility_pid;	recno_t lno, nread;	int input[2], output[2], rval, teardown;	char *name;	/* Set return cursor position; guard against a line number of zero. */	*rp = *fm;	if (fm->lno == 0)		rp->lno = 1;	/*	 * There are three different processes running through this code.	 * They are the utility, the parent-writer and the parent-reader.	 * The parent-writer is the process that writes from the file to	 * the utility, the parent reader is the process that reads from	 * the utility.	 *	 * Input and output are named from the utility's point of view.	 * The utility reads from input[0] and the parent(s) write to	 * input[1].  The parent(s) read from output[0] and the utility	 * writes to output[1].	 *	 * In the FILTER_READ case, the utility isn't expected to want	 * input.  Redirect its input from /dev/null.  Otherwise open	 * up utility input pipe.	 */	teardown = 0;	ifp = ofp = NULL;	input[0] = input[1] = output[0] = output[1] = -1;	if (ftype == FILTER_READ) {		if ((input[0] = open(_PATH_DEVNULL, O_RDONLY, 0)) < 0) {			msgq(sp, M_ERR,			    "filter: %s: %s", _PATH_DEVNULL, strerror(errno));			return (1);		}	} else {		if (pipe(input) < 0) {			msgq(sp, M_SYSERR, "pipe");			goto err;		}		if ((ifp = fdopen(input[1], "w")) == NULL) {			msgq(sp, M_SYSERR, "fdopen");			goto err;		}	}	/* Open up utility output pipe. */	if (pipe(output) < 0) {		msgq(sp, M_SYSERR, "pipe");		goto err;	}	if ((ofp = fdopen(output[0], "r")) == NULL) {		msgq(sp, M_SYSERR, "fdopen");		goto err;	}	/*	 * Save ex/vi terminal settings, and restore the original ones.	 * Restoration so that users can do things like ":r! cat /dev/tty".	 */	teardown = !ex_sleave(sp);	/* Fork off the utility process. */	switch (utility_pid = vfork()) {	case -1:			/* Error. */		msgq(sp, M_SYSERR, "vfork");err:		if (input[0] != -1)			(void)close(input[0]);		if (ifp != NULL)			(void)fclose(ifp);		else if (input[1] != -1)			(void)close(input[1]);		if (ofp != NULL)			(void)fclose(ofp);		else if (output[0] != -1)			(void)close(output[0]);		if (output[1] != -1)			(void)close(output[1]);		rval = 1;		goto ret;	case 0:				/* Utility. */		/*		 * The utility has default signal behavior.  Don't bother		 * using sigaction(2) 'cause we want the default behavior.		 */		(void)signal(SIGINT, SIG_DFL);		(void)signal(SIGQUIT, SIG_DFL);		/*		 * Redirect stdin from the read end of the input pipe,		 * and redirect stdout/stderr to the write end of the		 * output pipe.		 */		(void)dup2(input[0], STDIN_FILENO);		(void)dup2(output[1], STDOUT_FILENO);		(void)dup2(output[1], STDERR_FILENO);		/* Close the utility's file descriptors. */		(void)close(input[0]);		(void)close(input[1]);		(void)close(output[0]);		(void)close(output[1]);		if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)			name = O_STR(sp, O_SHELL);		else			++name;		execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);		msgq(sp, M_ERR, "Error: execl: %s: %s",		    O_STR(sp, O_SHELL), strerror(errno));		_exit (127);		/* NOTREACHED */	default:			/* Parent-reader, parent-writer. */		/* Close the pipe ends neither parent will use. */		(void)close(input[0]);		(void)close(output[1]);		break;	}	/*	 * FILTER_READ:	 *	 * Reading is the simple case -- we don't need a parent writer,	 * so the parent reads the output from the read end of the output	 * pipe until it finishes, then waits for the child.  Ex_readfp	 * appends to the MARK, and closes ofp.	 *	 * !!!	 * Set the return cursor to the last line read in.  Historically,	 * this behaves differently from ":r file" command, which leaves	 * the cursor at the first line read in.  Check to make sure that	 * it's not past EOF because we were reading into an empty file.	 */	if (ftype == FILTER_READ) {		rval = ex_readfp(sp, ep, "filter", ofp, fm, &nread, 0);		sp->rptlines[L_ADDED] += nread;		if (fm->lno == 0)			rp->lno = nread;		else			rp->lno += nread;		goto uwait;	}	/*	 * FILTER, FILTER_WRITE	 *	 * Here we need both a reader and a writer.  Temporary files are	 * expensive and we'd like to avoid disk I/O.  Using pipes has the	 * obvious starvation conditions.  It's done as follows:	 *	 *	fork	 *	child	 *		write lines out	 *		exit	 *	parent	 *		FILTER:	 *			read lines into the file	 *			delete old lines	 *		FILTER_WRITE	 *			read and display lines	 *		wait for child	 *	 * XXX	 * We get away without locking the underlying database because we know	 * that none of the records that we're reading will be modified until	 * after we've read them.  This depends on the fact that the current	 * B+tree implementation doesn't balance pages or similar things when	 * it inserts new records.  When the DB code has locking, we should	 * treat vi as if it were multiple applications sharing a database, and	 * do the required locking.  If necessary a work-around would be to do	 * explicit locking in the line.c:file_gline() code, based on the flag	 * set here.	 */	rval = 0;	F_SET(ep, F_MULTILOCK);	switch (parent_writer_pid = fork()) {	case -1:			/* Error. */		rval = 1;		msgq(sp, M_SYSERR, "fork");		(void)close(input[1]);		(void)close(output[0]);		break;	case 0:				/* Parent-writer. */		/*		 * Write the selected lines to the write end of the		 * input pipe.  Ifp is closed by ex_writefp.		 */		(void)close(output[0]);		_exit(ex_writefp(sp, ep, "filter", ifp, fm, tm, NULL, NULL));		/* NOTREACHED */	default:			/* Parent-reader. */		(void)fclose(ifp);		if (ftype == FILTER_WRITE)			/*			 * Read the output from the read end of the output			 * pipe and display it.  Filter_ldisplay closes ofp.			 */			rval = filter_ldisplay(sp, ofp);		else {			/*			 * Read the output from the read end of the output			 * pipe.  Ex_readfp appends to the MARK and closes			 * ofp.			 */			rval = ex_readfp(sp, ep, "filter", ofp, tm, &nread, 0);			sp->rptlines[L_ADDED] += nread;		}		/* Wait for the parent-writer. */		rval |= proc_wait(sp,		    (long)parent_writer_pid, "parent-writer", 1);		/* Delete any lines written to the utility. */		if (ftype == FILTER && rval == 0) {			for (lno = tm->lno; lno >= fm->lno; --lno)				if (file_dline(sp, ep, lno)) {					rval = 1;					break;				}			if (rval == 0)				sp->rptlines[L_DELETED] +=				    (tm->lno - fm->lno) + 1;		}		/*		 * If the filter had no output, we may have just deleted		 * the cursor.  Don't do any real error correction, we'll		 * try and recover later.		 */		 if (rp->lno > 1 && file_gline(sp, ep, rp->lno, NULL) == NULL)			--rp->lno;		break;	}	F_CLR(ep, F_MULTILOCK);uwait:	rval |= proc_wait(sp, (long)utility_pid, cmd, 0);	/* Restore ex/vi terminal settings. */ret:	if (teardown)		ex_rleave(sp);	return (rval);}/* * proc_wait -- *	Wait for one of the processes. * * !!! * The pid_t type varies in size from a short to a long depending on the * system.  It has to be cast into something or the standard promotion * rules get you.  I'm using a long based on the belief that nobody is * going to make it unsigned and it's unlikely to be a quad. */intproc_wait(sp, pid, cmd, okpipe)	SCR *sp;	long pid;	const char *cmd;	int okpipe;{	extern const char *const sys_siglist[];	size_t len;	int pstat;	/* Wait for the utility to finish. */	(void)waitpid((pid_t)pid, &pstat, 0);	/*	 * Display the utility's exit status.  Ignore SIGPIPE from the	 * parent-writer, as that only means that the utility chose to	 * exit before reading all of its input.	 */	if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {		for (; isblank(*cmd); ++cmd);		len = strlen(cmd);		msgq(sp, M_ERR, "%.*s%s: received signal: %s%s.",		    MIN(len, 20), cmd, len > 20 ? "..." : "",		    sys_siglist[WTERMSIG(pstat)],		    WCOREDUMP(pstat) ? "; core dumped" : "");		return (1);	}	if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {		for (; isblank(*cmd); ++cmd);		len = strlen(cmd);		msgq(sp, M_ERR, "%.*s%s: exited with status %d",		    MIN(len, 20), cmd, len > 20 ? "..." : "",		    WEXITSTATUS(pstat));		return (1);	}	return (0);}/* * filter_ldisplay -- *	Display a line output from a utility. * * XXX * This should probably be combined with some of the ex_print() * routines into a single display routine. */static intfilter_ldisplay(sp, fp)	SCR *sp;	FILE *fp;{	EX_PRIVATE *exp;	size_t len;	exp = EXP(sp);	while (!ex_getline(sp, fp, &len)) {		(void)ex_printf(EXCOOKIE, "%.*s\n", (int)len, exp->ibp);		if (ferror(sp->stdfp)) {			msgq(sp, M_SYSERR, NULL);			(void)fclose(fp);			return (1);		}	}	if (fclose(fp)) {		msgq(sp, M_SYSERR, NULL);		return (1);	}	return (0);}

⌨️ 快捷键说明

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