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

📄 ex_tag.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * ex_tagdisplay -- *	Display the list of tags. */intex_tagdisplay(sp, ep)	SCR *sp;	EXF *ep;{	EX_PRIVATE *exp;	TAG *tp;	size_t len, maxlen;	int cnt;	char *name;	exp = EXP(sp);	if ((tp = exp->tagq.tqh_first) == NULL) {		(void)ex_printf(EXCOOKIE, "No tags to display.\n");		return (0);	}	/*	 * Figure out the formatting.  MNOC is the maximum	 * number of file name columns before we split the line.	 */#define	MNOC	15	for (maxlen = 0,	    tp = exp->tagq.tqh_first; tp != NULL; tp = tp->q.tqe_next) {		len = strlen(name = tp->frp->name);	/* The original name. */		if (maxlen < len && len < MNOC)			maxlen = len;	}	for (cnt = 1, tp = exp->tagq.tqh_first; tp != NULL;	    ++cnt, tp = tp->q.tqe_next) {		len = strlen(name = tp->frp->name);	/* The original name. */		if (len > maxlen || len + tp->slen > sp->cols)			if (tp == NULL || tp->search == NULL)				(void)ex_printf(EXCOOKIE,				    "%2d %s\n", cnt, name);			else				(void)ex_printf(EXCOOKIE,				     "%2d %s\n** %*.*s %s\n", cnt, name,				     (int)maxlen, (int)maxlen, "", tp->search);		else			if (tp == NULL || tp->search == NULL)				(void)ex_printf(EXCOOKIE, "%2d %*.*s\n",				    cnt, (int)maxlen, (int)len, name);			else				(void)ex_printf(EXCOOKIE, "%2d %*.*s %s\n",				    cnt, (int)maxlen, (int)len, name,				    tp->search);	}	return (0);}/* * ex_tagalloc -- *	Create a new list of tag files. */intex_tagalloc(sp, str)	SCR *sp;	char *str;{	EX_PRIVATE *exp;	TAGF *tp;	size_t len;	char *p, *t;	/* Free current queue. */	exp = EXP(sp);	while ((tp = exp->tagfq.tqh_first) != NULL)		FREETAGF(tp);	/* Create new queue. */	for (p = t = str;; ++p) {		if (*p == '\0' || isblank(*p)) {			if ((len = p - t) > 1) {				MALLOC_RET(sp, tp, TAGF *, sizeof(TAGF));				MALLOC(sp, tp->name, char *, len + 1);				if (tp->name == NULL) {					FREE(tp, sizeof(TAGF));					return (1);				}				memmove(tp->name, t, len);				tp->name[len] = '\0';				tp->flags = 0;				TAILQ_INSERT_TAIL(&exp->tagfq, tp, q);			}			t = p + 1;		}		if (*p == '\0')			 break;	}	return (0);}						/* Free previous queue. *//* * ex_tagfree -- *	Free the tags file list. */intex_tagfree(sp)	SCR *sp;{	EX_PRIVATE *exp;	TAG *tp;	TAGF *tfp;	/* Free up tag information. */	exp = EXP(sp);	while ((tp = exp->tagq.tqh_first) != NULL)		FREETAG(tp);	while ((tfp = exp->tagfq.tqh_first) != NULL)		FREETAGF(tfp);	if (exp->tlast != NULL)		free(exp->tlast);	return (0);}/* * ex_tagcopy -- *	Copy a screen's tag structures. */intex_tagcopy(orig, sp)	SCR *orig, *sp;{	EX_PRIVATE *oexp, *nexp;	TAG *ap, *tp;	TAGF *atfp, *tfp;	/* Copy tag stack. */	oexp = EXP(orig);	nexp = EXP(sp);	for (ap = oexp->tagq.tqh_first; ap != NULL; ap = ap->q.tqe_next) {		MALLOC(sp, tp, TAG *, sizeof(TAG));		if (tp == NULL)			goto nomem;		*tp = *ap;		if (ap->search != NULL &&		    (tp->search = strdup(ap->search)) == NULL)			goto nomem;		TAILQ_INSERT_TAIL(&nexp->tagq, tp, q);	}	/* Copy list of tag files. */	for (atfp = oexp->tagfq.tqh_first;	    atfp != NULL; atfp = atfp->q.tqe_next) {		MALLOC(sp, tfp, TAGF *, sizeof(TAGF));		if (tfp == NULL)			goto nomem;		*tfp = *atfp;		if ((tfp->name = strdup(atfp->name)) == NULL)			goto nomem;		TAILQ_INSERT_TAIL(&nexp->tagfq, tfp, q);	}	/* Copy the last tag. */	if (oexp->tlast != NULL &&	    (nexp->tlast = strdup(oexp->tlast)) == NULL) {nomem:		msgq(sp, M_SYSERR, NULL);		return (1);	}	return (0);}/* * tag_get -- *	Get a tag from the tags files. */static inttag_get(sp, tag, tagp, filep, searchp)	SCR *sp;	char *tag, **tagp, **filep, **searchp;{	struct stat sb;	EX_PRIVATE *exp;	TAGF *tfp;	size_t plen, slen, tlen;	int dne;	char *p, pbuf[MAXPATHLEN];	/*	 * Find the tag, only display missing file messages once, and	 * then only if we didn't find the tag.	 */	dne = 0;	exp = EXP(sp);	for (p = NULL, tfp = exp->tagfq.tqh_first;	    tfp != NULL && p == NULL; tfp = tfp->q.tqe_next) {		errno = 0;		F_CLR(tfp, TAGF_DNE);		if (search(sp, tfp->name, tag, &p))			if (errno == ENOENT) {				if (!F_ISSET(tfp, TAGF_DNE_WARN)) {					dne = 1;					F_SET(tfp, TAGF_DNE);				}			} else				msgq(sp, M_SYSERR, tfp->name);		else			if (p != NULL)				break;	}	if (p == NULL) {		msgq(sp, M_ERR, "%s: tag not found.", tag);		if (dne)			for (tfp = exp->tagfq.tqh_first;			    tfp != NULL; tfp = tfp->q.tqe_next)				if (F_ISSET(tfp, TAGF_DNE)) {					errno = ENOENT;					msgq(sp, M_SYSERR, tfp->name);					F_SET(tfp, TAGF_DNE_WARN);				}		return (1);	}	/*	 * Set the return pointers; tagp points to the tag, and, incidentally	 * the allocated string, filep points to the file name, and searchp	 * points to the search string.  All three are nul-terminated.	 */	for (*tagp = p; *p && !isblank(*p); ++p);	if (*p == '\0')		goto malformed;	for (*p++ = '\0'; isblank(*p); ++p);	for (*filep = p; *p && !isblank(*p); ++p);	if (*p == '\0')		goto malformed;	for (*p++ = '\0'; isblank(*p); ++p);	*searchp = p;	if (*p == '\0') {malformed:	free(*tagp);		msgq(sp, M_ERR, "%s: corrupted tag in %s.", tag, tfp->name);		return (1);	}	/*	 * !!!	 * If the tag file path is a relative path, see if it exists.  If it	 * doesn't, look relative to the tags file path.  It's okay for a tag	 * file to not exist, and, historically, vi simply displayed a "new"	 * file.  However, if the path exists relative to the tag file, it's	 * pretty clear what's happening, so we may as well do it right.	 */	if ((*filep)[0] != '/'	    && stat(*filep, &sb) && (p = strrchr(tfp->name, '/')) != NULL) {		*p = '\0';		plen = snprintf(pbuf, sizeof(pbuf), "%s/%s", tfp->name, *filep);		*p = '/';		if (stat(pbuf, &sb) == 0) {			slen = strlen(*searchp);			tlen = strlen(*tagp);			MALLOC(sp, p, char *, plen + slen + tlen + 5);			if (p != NULL) {				memmove(p, *tagp, tlen);				free(*tagp);				*tagp = p;				*(p += tlen) = '\0';				memmove(++p, pbuf, plen);				*filep = p;				*(p += plen) = '\0';				memmove(++p, *searchp, slen);				*searchp = p;				*(p += slen) = '\0';			}		}	}	return (0);}#define	EQUAL		0#define	GREATER		1#define	LESS		(-1)/* * search -- *	Search a file for a tag. */static intsearch(sp, name, tname, tag)	SCR *sp;	char *name, *tname, **tag;{	struct stat sb;	int fd, len;	char *endp, *back, *front, *map, *p;	if ((fd = open(name, O_RDONLY, 0)) < 0)		return (1);	/*	 * XXX	 * We'd like to test if the file is too big to mmap.  Since we don't	 * know what size or type off_t's or size_t's are, what the largest	 * unsigned integral type is, or what random insanity the local C	 * compiler will perpetrate, doing the comparison in a portable way	 * is flatly impossible.  Hope that malloc fails if the file is too	 * large.	 */	if (fstat(fd, &sb) || (map = mmap(NULL, (size_t)sb.st_size,	    PROT_READ, MAP_PRIVATE, fd, (off_t)0)) == (caddr_t)-1) {		(void)close(fd);		return (1);	}	front = map;	back = front + sb.st_size;	front = binary_search(tname, front, back);	front = linear_search(tname, front, back);	if (front == NULL || (endp = strchr(front, '\n')) == NULL) {		*tag = NULL;		goto done;	}	len = endp - front;	MALLOC(sp, p, char *, len + 1);	if (p == NULL) {		*tag = NULL;		goto done;	}	memmove(p, front, len);	p[len] = '\0';	*tag = p;done:	if (munmap(map, (size_t)sb.st_size))		msgq(sp, M_SYSERR, "munmap");	if (close(fd))		msgq(sp, M_SYSERR, "close");	return (0);}/* * Binary search for "string" in memory between "front" and "back". * * This routine is expected to return a pointer to the start of a line at * *or before* the first word matching "string".  Relaxing the constraint * this way simplifies the algorithm. * * Invariants: * 	front points to the beginning of a line at or before the first *	matching string. * * 	back points to the beginning of a line at or after the first *	matching line. * * Base of the Invariants. * 	front = NULL; *	back = EOF; * * Advancing the Invariants: * * 	p = first newline after halfway point from front to back. * * 	If the string at "p" is not greater than the string to match, *	p is the new front.  Otherwise it is the new back. * * Termination: * * 	The definition of the routine allows it return at any point, *	since front is always at or before the line to print. * * 	In fact, it returns when the chosen "p" equals "back".  This *	implies that there exists a string is least half as long as *	(back - front), which in turn implies that a linear search will *	be no more expensive than the cost of simply printing a string or two. * * 	Trying to continue with binary search at this point would be *	more trouble than it's worth. */#define	SKIP_PAST_NEWLINE(p, back)	while (p < back && *p++ != '\n');static char *binary_search(string, front, back)	register char *string, *front, *back;{	register char *p;	p = front + (back - front) / 2;	SKIP_PAST_NEWLINE(p, back);	while (p != back) {		if (compare(string, p, back) == GREATER)			front = p;		else			back = p;		p = front + (back - front) / 2;		SKIP_PAST_NEWLINE(p, back);	}	return (front);}/* * Find the first line that starts with string, linearly searching from front * to back. * * Return NULL for no such line. * * This routine assumes: * * 	o front points at the first character in a line. *	o front is before or at the first line to be printed. */static char *linear_search(string, front, back)	char *string, *front, *back;{	while (front < back) {		switch (compare(string, front, back)) {		case EQUAL:		/* Found it. */			return (front);		case LESS:		/* No such string. */			return (NULL);		case GREATER:		/* Keep going. */			break;		}		SKIP_PAST_NEWLINE(front, back);	}	return (NULL);}/* * Return LESS, GREATER, or EQUAL depending on how the string1 compares * with string2 (s1 ??? s2). * * 	o Matches up to len(s1) are EQUAL. *	o Matches up to len(s2) are GREATER. * * The string "s1" is null terminated.  The string s2 is '\t', space, (or * "back") terminated. * * !!! * Reasonably modern ctags programs use tabs as separators, not spaces. * However, historic programs did use spaces, and, I got complaints. */static intcompare(s1, s2, back)	register char *s1, *s2, *back;{	for (; *s1 && s2 < back && (*s2 != '\t' && *s2 != ' '); ++s1, ++s2)		if (*s1 != *s2)			return (*s1 < *s2 ? LESS : GREATER);	return (*s1 ? GREATER : s2 < back &&	    (*s2 != '\t' && *s2 != ' ') ? LESS : EQUAL);}

⌨️ 快捷键说明

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