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

📄 ex_tag.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1992, 1993, 1994 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * David Hitz of Auspex Systems, Inc. * * 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[] = "@(#)ex_tag.c	8.40 (Berkeley) 3/22/94";#endif /* not lint */#include <sys/param.h>#include <sys/mman.h>#include <sys/queue.h>#include <sys/stat.h>#include <sys/time.h>#include <bitstring.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <signal.h>#include <stddef.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"#include "excmd.h"#include "tag.h"static char	*binary_search __P((char *, char *, char *));static int	 compare __P((char *, char *, char *));static char	*linear_search __P((char *, char *, char *));static int	 search __P((SCR *, char *, char *, char **));static int	 tag_get __P((SCR *, char *, char **, char **, char **));/* * ex_tagfirst -- *	The tag code can be entered from main, i.e. "vi -t tag". */intex_tagfirst(sp, tagarg)	SCR *sp;	char *tagarg;{	FREF *frp;	MARK m;	long tl;	u_int flags;	int sval;	char *p, *tag, *name, *search;	/* Taglength may limit the number of characters. */	if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(tagarg) > tl)		tagarg[tl] = '\0';	/* Get the tag information. */	if (tag_get(sp, tagarg, &tag, &name, &search))		return (1);	/* Create the file entry. */	if ((frp = file_add(sp, NULL, name, 0)) == NULL)		return (1);	if (file_init(sp, frp, NULL, 0))		return (1);	/*	 * !!!	 * The historic tags file format (from a long, long time ago...)	 * used a line number, not a search string.  I got complaints, so	 * people are still using the format.	 */	if (isdigit(search[0])) {		m.lno = atoi(search);		m.cno = 0;	} else {		/*		 * Search for the tag; cheap fallback for C functions if		 * the name is the same but the arguments have changed.		 */		m.lno = 1;		m.cno = 0;		flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM;		sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags);		if (sval && (p = strrchr(search, '(')) != NULL) {			p[1] = '\0';			sval = f_search(sp, sp->ep,			    &m, &m, search, NULL, &flags);		}		if (sval)			msgq(sp, M_ERR, "%s: search pattern not found.", tag);	}	/* Set up the screen. */	frp->lno = m.lno;	frp->cno = m.cno;	F_SET(frp, FR_CURSORSET);	/* Might as well make this the default tag. */	if ((EXP(sp)->tlast = strdup(tagarg)) == NULL) {		msgq(sp, M_SYSERR, NULL);		return (1);	}	return (0);}/* Free a tag or tagf structure from a queue. */#define	FREETAG(tp) {							\	TAILQ_REMOVE(&exp->tagq, (tp), q);				\	if ((tp)->search != NULL)					\		free((tp)->search);					\	FREE((tp), sizeof(TAGF));					\}#define	FREETAGF(tfp) {							\	TAILQ_REMOVE(&exp->tagfq, (tfp), q);				\	free((tfp)->name);						\	FREE((tfp), sizeof(TAGF));					\}/* * ex_tagpush -- :tag [file] *	Move to a new tag. * * The tags stacks in nvi are a bit tricky.  Each tag contains a file name, * search string, and line/column numbers.  The search string is only used * for the first access and for user display.  The first record on the stack * is the place where we first did a tag, so it has no search string.  The * second record is the first tag, and so on.  Note, this means that the * "current" tag is always on the stack.  Each tag has a line/column which is * the location from which the user tagged the following TAG entry, and which * is used as the return location. */intex_tagpush(sp, ep, cmdp)	SCR *sp;	EXF *ep;	EXCMDARG *cmdp;{	enum {TC_CHANGE, TC_CURRENT} which;	EX_PRIVATE *exp;	FREF *frp;	MARK m;	TAG *tp;	u_int flags;	int sval;	long tl;	char *name, *p, *search, *tag;	exp = EXP(sp);	switch (cmdp->argc) {	case 1:		if (exp->tlast != NULL)			FREE(exp->tlast, strlen(exp->tlast) + 1);		if ((exp->tlast = strdup(cmdp->argv[0]->bp)) == NULL) {			msgq(sp, M_SYSERR, NULL);			return (1);		}		break;	case 0:		if (exp->tlast == NULL) {			msgq(sp, M_ERR, "No previous tag entered.");			return (1);		}		break;	default:		abort();	}	/* Taglength may limit the number of characters. */	if ((tl = O_VAL(sp, O_TAGLENGTH)) != 0 && strlen(exp->tlast) > tl)		exp->tlast[tl] = '\0';	/* Get the tag information. */	if (tag_get(sp, exp->tlast, &tag, &name, &search))		return (1);	/* Get the (possibly new) FREF structure. */	if ((frp = file_add(sp, sp->frp, name, 1)) == NULL)		goto modify_err;	if (sp->frp == frp)		which = TC_CURRENT;	else {		MODIFY_GOTO(sp, sp->ep, F_ISSET(cmdp, E_FORCE));		which = TC_CHANGE;	}	/*	 * Get a tag structure -- if this is the first tag, push it on the	 * stack as a placeholder and get another tag structure.  Set the	 * line/column of the most recent element on the stack to be the	 * current values, including the file pointer.  Then push the new	 * TAG onto the stack with the new file and search string for user	 * display.	 */	CALLOC(sp, tp, TAG *, 1, sizeof(TAG));	if (tp != NULL && exp->tagq.tqh_first == NULL) {		TAILQ_INSERT_HEAD(&exp->tagq, tp, q);		CALLOC(sp, tp, TAG *, 1, sizeof(TAG));	}	if (exp->tagq.tqh_first != NULL) {		exp->tagq.tqh_first->frp = sp->frp;		exp->tagq.tqh_first->lno = sp->lno;		exp->tagq.tqh_first->cno = sp->cno;	}	if (tp != NULL) {		if ((tp->search = strdup(search)) == NULL)			msgq(sp, M_SYSERR, NULL);		else			tp->slen = strlen(search);		tp->frp = frp;		TAILQ_INSERT_HEAD(&exp->tagq, tp, q);	}	/* Switch files. */	if (which == TC_CHANGE && file_init(sp, frp, NULL, 0)) {		if (tp != NULL)			FREETAG(tp);		/* Handle special, first-tag case. */		if (exp->tagq.tqh_first->q.tqe_next == NULL)			TAILQ_REMOVE(&exp->tagq, exp->tagq.tqh_first, q);modify_err:	free(tag);		return (1);	}	/*	 * !!!	 * Historic vi accepted a line number as well as a search	 * string, and people are apparently still using the format.	 */	if (isdigit(search[0])) {		m.lno = atoi(search);		m.cno = 0;		sval = 0;	} else {		/*		 * Search for the tag; cheap fallback for C functions		 * if the name is the same but the arguments have changed.		 */		m.lno = 1;		m.cno = 0;		flags = SEARCH_FILE | SEARCH_TAG | SEARCH_TERM;		sval = f_search(sp, sp->ep, &m, &m, search, NULL, &flags);		if (sval && (p = strrchr(search, '(')) != NULL) {			p[1] = '\0';			sval = f_search(sp, sp->ep,			     &m, &m, search, NULL, &flags);			p[1] = '(';		}		if (sval)			msgq(sp, M_ERR, "%s: search pattern not found.", tag);	}	free(tag);	switch (which) {	case TC_CHANGE:		frp->lno = m.lno;		frp->cno = m.cno;		F_SET(frp, FR_CURSORSET);		F_SET(sp, S_FSWITCH);		break;	case TC_CURRENT:		if (sval)			return (1);		sp->lno = m.lno;		sp->cno = m.cno;		break;	}	return (0);}/* * ex_tagpop -- :tagp[op][!] [number | file] *	Pop the tag stack. */intex_tagpop(sp, ep, cmdp)	SCR *sp;	EXF *ep;	EXCMDARG *cmdp;{	EX_PRIVATE *exp;	TAG *ntp, *tp;	long off;	size_t arglen;	char *arg, *p, *t;	/* Check for an empty stack. */	exp = EXP(sp);	if (exp->tagq.tqh_first == NULL) {		msgq(sp, M_INFO, "The tags stack is empty.");		return (1);	}	switch (cmdp->argc) {	case 0:				/* Pop one tag. */		ntp = exp->tagq.tqh_first;		break;	case 1:				/* Name or number. */		arg = cmdp->argv[0]->bp;		off = strtol(arg, &p, 10);		if (*p == '\0') {			if (off < 1)				return (0);			for (tp = exp->tagq.tqh_first;			    tp != NULL && --off > 1; tp = tp->q.tqe_next);			if (tp == NULL) {				msgq(sp, M_ERR,"Less than %s entries on the tags stack; use :display to see the tags stack.",				    arg);				return (1);			}			ntp = tp;		} else {			arglen = strlen(arg);			for (tp = exp->tagq.tqh_first;			    tp != NULL; ntp = tp, tp = tp->q.tqe_next) {				/* Use the user's original file name. */				p = tp->frp->name;				if ((t = strrchr(p, '/')) == NULL)					t = p;				else					++t;				if (!strncmp(arg, t, arglen))					break;			}			if (tp == NULL) {				msgq(sp, M_ERR,"No file named %s on the tags stack; use :display to see the tags stack.",				    arg);				return (1);			}		}		break;	default:		abort();	}	/* Update the cursor from the saved TAG information. */	tp = ntp->q.tqe_next;	if (tp->frp == sp->frp) {		sp->lno = tp->lno;		sp->cno = tp->cno;	} else {		MODIFY_RET(sp, ep, F_ISSET(cmdp, E_FORCE));		if (file_init(sp, tp->frp, NULL, 0))			return (1);		tp->frp->lno = tp->lno;		tp->frp->cno = tp->cno;		F_SET(sp->frp, FR_CURSORSET);		F_SET(sp, S_FSWITCH);	}	/* Pop entries off the queue up to ntp. */	for (;;) {		tp = exp->tagq.tqh_first;		FREETAG(tp);		if (tp == ntp)			break;	}	/* If returning to the first tag, the stack is now empty. */	if (exp->tagq.tqh_first->q.tqe_next == NULL)		TAILQ_REMOVE(&exp->tagq, exp->tagq.tqh_first, q);	return (0);}/* * ex_tagtop -- :tagt[op][!] *	Clear the tag stack. */intex_tagtop(sp, ep, cmdp)	SCR *sp;	EXF *ep;	EXCMDARG *cmdp;{	EX_PRIVATE *exp;	TAG *tp;	/* Find oldest saved information. */	exp = EXP(sp);	for (tp = exp->tagq.tqh_first;	    tp != NULL && tp->q.tqe_next != NULL; tp = tp->q.tqe_next);	if (tp == NULL) {		msgq(sp, M_INFO, "The tags stack is empty.");		return (1);	}	/* If not switching files, it's easy; else do the work. */	if (tp->frp == sp->frp) {		sp->lno = tp->lno;		sp->cno = tp->cno;	} else {		MODIFY_RET(sp, sp->ep, F_ISSET(cmdp, E_FORCE));		if (file_init(sp, tp->frp, NULL, 0))			return (1);		tp->frp->lno = tp->lno;		tp->frp->cno = tp->cno;		F_SET(sp->frp, FR_CURSORSET);		F_SET(sp, S_FSWITCH);	}	/* Empty out the queue. */	while ((tp = exp->tagq.tqh_first) != NULL)		FREETAG(tp);	return (0);}

⌨️ 快捷键说明

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