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

📄 search.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1992, 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[] = "@(#)search.c	8.41 (Berkeley) 4/6/94";#endif /* not lint */#include <sys/types.h>#include <sys/queue.h>#include <sys/time.h>#include <bitstring.h>#include <ctype.h>#include <errno.h>#include <limits.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <termios.h>#include <unistd.h>#include "compat.h"#include <db.h>#include <regex.h>#include "vi.h"static int	check_delta __P((SCR *, EXF *, long, recno_t));static int	ctag_conv __P((SCR *, char **, int *));static int	get_delta __P((SCR *, char **, long *, u_int *));static int	resetup __P((SCR *, regex_t **, enum direction,		    char *, char **, long *, u_int *));/* * resetup -- *	Set up a search for a regular expression. */static intresetup(sp, rep, dir, ptrn, epp, deltap, flagp)	SCR *sp;	regex_t **rep;	enum direction dir;	char *ptrn, **epp;	long *deltap;	u_int *flagp;{	u_int flags;	int delim, eval, re_flags, replaced;	char *p, *t;	/* Set return information the default. */	*deltap = 0;	/*	 * Use saved pattern if no pattern supplied, or if only a delimiter	 * character is supplied.  Only the pattern was saved, historic vi	 * did not reuse any delta supplied.	 */	flags = *flagp;	if (ptrn == NULL)		goto prev;	if (ptrn[1] == '\0') {		if (epp != NULL)			*epp = ptrn + 1;		goto prev;	}	if (ptrn[0] == ptrn[1] && ptrn[2] == '\0') {		if (epp != NULL)			*epp = ptrn + 2;prev:		if (!F_ISSET(sp, S_SRE_SET)) {			msgq(sp, M_ERR, "No previous search pattern.");			return (1);		}		*rep = &sp->sre;		/* Empty patterns set the direction. */		if (LF_ISSET(SEARCH_SET)) {			F_SET(sp, S_SRE_SET);			sp->searchdir = dir;			sp->sre = **rep;		}		return (0);	}	re_flags = 0;				/* Set RE flags. */	if (O_ISSET(sp, O_EXTENDED))		re_flags |= REG_EXTENDED;	if (O_ISSET(sp, O_IGNORECASE))		re_flags |= REG_ICASE;	if (LF_ISSET(SEARCH_PARSE)) {		/* Parse the string. */		/* Set delimiter. */		delim = *ptrn++;		/* Find terminating delimiter, handling escaped delimiters. */		for (p = t = ptrn;;) {			if (p[0] == '\0' || p[0] == delim) {				if (p[0] == delim)					++p;				*t = '\0';				break;			}			if (p[1] == delim && p[0] == '\\')				++p;			*t++ = *p++;		}		/*		 * If characters after the terminating delimiter, it may		 * be an error, or may be an offset.  In either case, we		 * return the end of the string, whatever it may be.		 */		if (*p) {			if (get_delta(sp, &p, deltap, flagp))				return (1);			if (*p && LF_ISSET(SEARCH_TERM)) {				msgq(sp, M_ERR,			"Characters after search string and/or delta.");				return (1);			}		}		if (epp != NULL)			*epp = p;		/* Check for "/   " or other such silliness. */		if (*ptrn == '\0')			goto prev;		if (re_conv(sp, &ptrn, &replaced))			return (1);	} else if (LF_ISSET(SEARCH_TAG)) {		if (ctag_conv(sp, &ptrn, &replaced))			return (1);		re_flags &= ~(REG_EXTENDED | REG_ICASE);	}	/* Compile the RE. */	if (eval = regcomp(*rep, ptrn, re_flags))		re_error(sp, eval, *rep);	else if (LF_ISSET(SEARCH_SET)) {		F_SET(sp, S_SRE_SET);		sp->searchdir = dir;		sp->sre = **rep;	}	/* Free up any extra memory. */	if (replaced)		FREE_SPACE(sp, ptrn, 0);	return (eval);}/* * ctag_conv -- *	Convert a tags search path into something that the POSIX *	1003.2 RE functions can handle. */static intctag_conv(sp, ptrnp, replacedp)	SCR *sp;	char **ptrnp;	int *replacedp;{	size_t blen, len;	int lastdollar;	char *bp, *p, *t;	*replacedp = 0;	len = strlen(p = *ptrnp);	/* Max memory usage is 2 times the length of the string. */	GET_SPACE_RET(sp, bp, blen, len * 2);	t = bp;	/* The last charcter is a '/' or '?', we just strip it. */	if (p[len - 1] == '/' || p[len - 1] == '?')		p[len - 1] = '\0';	/* The next-to-last character is a '$', and it's magic. */	if (p[len - 2] == '$') {		lastdollar = 1;		p[len - 2] = '\0';	} else		lastdollar = 0;	/* The first character is a '/' or '?', we just strip it. */	if (p[0] == '/' || p[0] == '?')		++p;	/* The second character is a '^', and it's magic. */	if (p[0] == '^')		*t++ = *p++;	/*	 * Escape every other magic character we can find, stripping the	 * backslashes ctags inserts to escape the search delimiter	 * characters.	 */	while (p[0]) {		/* Ctags escapes the search delimiter characters. */		if (p[0] == '\\' && (p[1] == '/' || p[1] == '?'))			++p;		else if (strchr("^.[]$*", p[0]))			*t++ = '\\';		*t++ = *p++;	}	if (lastdollar)		*t++ = '$';	*t++ = '\0';	*ptrnp = bp;	*replacedp = 1;	return (0);}#define	EMPTYMSG	"File empty; nothing to search."#define	EOFMSG		"Reached end-of-file without finding the pattern."#define	NOTFOUND	"Pattern not found."#define	SOFMSG		"Reached top-of-file without finding the pattern."#define	WRAPMSG		"Search wrapped."intf_search(sp, ep, fm, rm, ptrn, eptrn, flagp)	SCR *sp;	EXF *ep;	MARK *fm, *rm;	char *ptrn, **eptrn;	u_int *flagp;{	regmatch_t match[1];	regex_t *re, lre;	recno_t lno;	size_t coff, len;	long delta;	u_int flags;	int btear, eval, itear, rval, wrapped;	char *l;	if (file_lline(sp, ep, &lno))		return (1);	flags = *flagp;	if (lno == 0) {		if (LF_ISSET(SEARCH_MSG))			msgq(sp, M_INFO, EMPTYMSG);		return (1);	}	re = &lre;	if (resetup(sp, &re, FORWARD, ptrn, eptrn, &delta, flagp))		return (1);	/*	 * Start searching immediately after the cursor.  If at the end of the	 * line, start searching on the next line.  This is incompatible (read	 * bug fix) with the historic vi -- searches for the '$' pattern never	 * moved forward, and "-t foo" didn't work if "foo" was the first thing	 * in the file.	 */	if (LF_ISSET(SEARCH_FILE)) {		lno = 1;		coff = 0;	} else {		if ((l = file_gline(sp, ep, fm->lno, &len)) == NULL) {			GETLINE_ERR(sp, fm->lno);			return (1);		}		if (fm->cno + 1 >= len) {			if (fm->lno == lno) {				if (!O_ISSET(sp, O_WRAPSCAN)) {					if (LF_ISSET(SEARCH_MSG))						msgq(sp, M_INFO, EOFMSG);					return (1);				}				lno = 1;			} else				lno = fm->lno + 1;			coff = 0;		} else {			lno = fm->lno;			coff = fm->cno + 1;		}	}	/* Set up busy message, interrupts. */	btear = F_ISSET(sp, S_EXSILENT) ? 0 : !busy_on(sp, "Searching...");	itear = !intr_init(sp);	for (rval = 1, wrapped = 0;; ++lno, coff = 0) {		if (F_ISSET(sp, S_INTERRUPTED)) {			msgq(sp, M_INFO, "Interrupted.");			break;		}		if (wrapped && lno > fm->lno ||		    (l = file_gline(sp, ep, lno, &len)) == NULL) {			if (wrapped) {				if (LF_ISSET(SEARCH_MSG))					msgq(sp, M_INFO, NOTFOUND);				break;			}			if (!O_ISSET(sp, O_WRAPSCAN)) {				if (LF_ISSET(SEARCH_MSG))					msgq(sp, M_INFO, EOFMSG);				break;			}			lno = 0;			wrapped = 1;			continue;		}		/* If already at EOL, just keep going. */		if (len && coff == len)			continue;		/* Set the termination. */		match[0].rm_so = coff;		match[0].rm_eo = len;#if defined(DEBUG) && 0		TRACE(sp, "F search: %lu from %u to %u\n",		    lno, coff, len ? len - 1 : len);#endif		/* Search the line. */		eval = regexec(re, l, 1, match,		    (match[0].rm_so == 0 ? 0 : REG_NOTBOL) | REG_STARTEND);		if (eval == REG_NOMATCH)			continue;		if (eval != 0) {			re_error(sp, eval, re);			break;		}		/* Warn if wrapped. */		if (wrapped && O_ISSET(sp, O_WARN) && LF_ISSET(SEARCH_MSG))			msgq(sp, M_VINFO, WRAPMSG);		/*		 * If an offset, see if it's legal.  It's possible to match		 * past the end of the line with $, so check for that case.		 */		if (delta) {			if (check_delta(sp, ep, delta, lno))				break;			rm->lno = delta + lno;			rm->cno = 0;		} else {#if defined(DEBUG) && 0			TRACE(sp, "found: %qu to %qu\n",			    match[0].rm_so, match[0].rm_eo);#endif			rm->lno = lno;			rm->cno = match[0].rm_so;			/*			 * If a change command, it's possible to move beyond			 * the end of a line.  Historic vi generally got this			 * wrong (try "c?$<cr>").  Not all that sure this gets			 * it right, there are lots of strange cases.			 */			if (!LF_ISSET(SEARCH_EOL) && rm->cno >= len)				rm->cno = len ? len - 1 : 0;		}		rval = 0;		break;	}	/* Turn off busy message, interrupts. */	if (btear)		busy_off(sp);	if (itear)		intr_end(sp);	return (rval);}intb_search(sp, ep, fm, rm, ptrn, eptrn, flagp)	SCR *sp;	EXF *ep;	MARK *fm, *rm;	char *ptrn, **eptrn;	u_int *flagp;{	regmatch_t match[1];	regex_t *re, lre;	recno_t lno;	size_t coff, len, last;	long delta;	u_int flags;	int btear, eval, itear, rval, wrapped;

⌨️ 快捷键说明

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