home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
v
/
vim_src.zip
/
TAG.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-12
|
8KB
|
383 lines
/* vi:ts=4:sw=4
*
* VIM - Vi IMitation
*
* Code Contributions By: Bram Moolenaar mool@oce.nl
* Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!watcgl!grwalter
*/
/*
* Code to handle tags and the tag stack
*/
#include "vim.h"
#include "globals.h"
#include "proto.h"
#include "param.h"
#include "mark.h"
#define TAGSTACKSIZE 20
/*
* the taggy struct is used to store the information about a :tag command:
* the tag name and the cursor position BEFORE the :tag command
*/
struct taggy
{
char *tagname; /* tag name */
struct filemark fmark; /* cursor position */
};
/*
* the tagstack grows from 0 upwards:
* entry 0: older
* entry 1: newer
* entry 2: newest
*/
static struct taggy tagstack[TAGSTACKSIZE]; /* the tag stack */
static int tagstackidx = 0; /* index just below active entry */
static int tagstacklen = 0; /* number of tags on the stack */
static int findtag __ARGS((char *));
static char *firsttaborspace __ARGS((char *));
static char bottommsg[] = "at bottom of tag stack";
static char topmsg[] = "at top of tag stack";
/*
* Jump to tag; handling of tag stack
*
* *tag != NUL (:tag): jump to new tag, add to tag stack
* type == 1 (:pop) || type == 2 (CTRL-T): jump to old position
* type == 0 (:tag): jump to old tag
*/
void
dotag(tag, type, count)
char *tag;
int type;
int count;
{
int i;
struct taggy temptag;
if (*tag != NUL) /* new pattern, add to the stack */
{
/*
* if last used entry is not at the top, put it at the top by rotating
* the stack until it is (the newer entries will be at the bottom)
*/
while (tagstackidx < tagstacklen)
{
temptag = tagstack[tagstacklen - 1];
for (i = tagstacklen - 1; i > 0; --i)
tagstack[i] = tagstack[i - 1];
tagstack[0] = temptag;
++tagstackidx;
}
/* if tagstack is full: remove oldest entry */
if (++tagstacklen > TAGSTACKSIZE)
{
tagstacklen = TAGSTACKSIZE;
free(tagstack[0].tagname);
for (i = 1; i < tagstacklen; ++i)
tagstack[i - 1] = tagstack[i];
--tagstackidx;
}
/*
* remember the tag and the position before the jump
*/
tagstack[tagstackidx].tagname = strsave(tag);
tagstack[tagstackidx].fmark.lnum = Curpos.lnum;
tagstack[tagstackidx].fmark.mark.col = Curpos.col;
tagstack[tagstackidx].fmark.mark.ptr = nr2ptr(Curpos.lnum);
tagstack[tagstackidx].fmark.fnum = 0;
}
else if (tagstacklen == 0) /* empty stack */
{
emsg("tag stack empty");
return;
}
else if (type) /* go to older position */
{
if ((tagstackidx -= count) < 0)
{
tagstackidx = 0;
emsg(bottommsg);
}
else if (tagstackidx >= tagstacklen) /* must have been count == 0 */
{
emsg(topmsg);
return;
}
if (tagstack[tagstackidx].fmark.mark.ptr == NULL) /* jump to other file */
{
if (getaltfile(tagstack[tagstackidx].fmark.fnum - 1, tagstack[tagstackidx].fmark.lnum, TRUE))
{
emsg(e_notopen);
return;
}
/* "refresh" this position, so we will not fall off the altfile array */
tagstack[tagstackidx].fmark.fnum = 0;
tagstack[tagstackidx].fmark.mark.ptr = nr2ptr(Curpos.lnum);
}
else
Curpos.lnum = ptr2nr(tagstack[tagstackidx].fmark.mark.ptr, (linenr_t)1);
Curpos.col = tagstack[tagstackidx].fmark.mark.col;
return;
}
else /* go to newer pattern */
{
if ((tagstackidx += count - 1) >= tagstacklen)
{
tagstackidx = tagstacklen - 1;
emsg(topmsg);
}
else if (tagstackidx < 0) /* must have been count == 0 */
{
emsg(bottommsg);
tagstackidx = 0;
return;
}
}
if (findtag(tagstack[tagstackidx].tagname) > 0)
++tagstackidx;
}
/*
* invalidate the line pointer for all tags
* called when abandoning the current file
*/
void
clrtags()
{
int i;
for (i = 0; i < tagstacklen; ++i)
tagstack[i].fmark.mark.ptr = NULL;
}
/*
* increment the file number for all tags
* called when adding a file to the file stack
*/
void
incrtags()
{
int i;
for (i = 0; i < tagstacklen; ++i)
{
#if 0 /* this would take too much time */
if (tagstack[i].fmark.fnum == 0) /* current file */
tagstack[i].fmark.lnum = ptr2nr(tagstack[i].fmark.mark.ptr, 1);
#endif
++tagstack[i].fmark.fnum;
}
}
/*
* decrement the file number for the tags of the current file
* called when not adding the current file name to the file stack
*/
void
decrtags()
{
int i;
for (i = 0; i < tagstacklen; ++i)
if (tagstack[i].fmark.fnum == 1)
tagstack[i].fmark.fnum = 0;
}
/*
* Print the tag stack (use the occasion to update the line numbers)
*/
void
dotags()
{
int i;
char *name;
settmode(0);
outstrn("\n # TO tag FROM line in file\n");
for (i = 0; i < tagstacklen; ++i)
{
if (tagstack[i].tagname != NULL)
{
name = fm_getname(&(tagstack[i].fmark));
if (name == NULL) /* file name not available */
continue;
sprintf(IObuff, "%c%2d %-15s %4ld %s\n",
i == tagstackidx ? '>' : ' ',
i + 1,
tagstack[i].tagname,
tagstack[i].fmark.lnum,
name);
outstrn(IObuff);
}
flushbuf();
}
if (tagstackidx == tagstacklen) /* idx at top of stack */
outstrn(">\n");
settmode(1);
wait_return(TRUE);
}
/*
* findtag(tag) - goto tag
* return 0 for failure, 1 for success
*/
static int
findtag(tag)
char *tag;
{
FILE *tp, *fopen();
char lbuf[LSIZE];
char pbuf[LSIZE]; /* search pattern buffer */
char *fname, *str;
int cmplen;
char *m = NULL;
register char *p;
char *np; /* pointer into file name string */
char sbuf[CMDBUFFSIZE + 1]; /* tag file name */
int i;
if (tag == NULL) /* out of memory condition */
return 0;
if ((cmplen = p_tl) == 0)
cmplen = 999;
/* get stack of tag file names from tags option */
for (np = p_tags; *np; )
{
for (i = 0; i < CMDBUFFSIZE && *np; ++i) /* copy next file name into lbuf */
{
if (*np == ' ')
{
++np;
break;
}
sbuf[i] = *np++;
}
sbuf[i] = 0;
if ((tp = fopen(sbuf, "r")) == NULL)
{
m = "Can't open tags file %s";
goto erret2;
}
while (fgets(lbuf, LSIZE, tp) != NULL)
{
m = "Format error in tags file %s"; /* default error message */
/* find start of file name, after first TAB or space */
fname = firsttaborspace(lbuf);
if (fname == NULL)
goto erret;
*fname++ = '\0';
/* find start of search command, after second TAB or space */
str = firsttaborspace(fname);
if (str == NULL)
goto erret;
*str++ = '\0';
if (strncmp(lbuf, tag, (size_t)cmplen) == 0)
{
fclose(tp);
/*
* Tag found!
* Form a string like "+/^function fname".
* Scan through the search string. If we see a magic
* char, we have to quote it. This lets us use "real"
* implementations of ctags.
*/
p = pbuf;
*p++ = *str++; /* copy the '/' or '?' */
*p++ = *str++; /* copy the '^' */
while (*str)
{
switch (*str)
{
case '\\': if (str[1] == '(') /* remove '\' before '(' */
++str;
else
*p++ = *str++;
break;
case '\n': *p++ = pbuf[0]; /* copy '/' or '?' */
*p++ = 'n'; /* no setpcmark() for search */
break;
/*
* if string ends in search character: skip it
* else escape it with '\'
*/
case '/':
case '?': if (*str == pbuf[0] && str[1] == '\n')
{
++str;
continue;
}
case '^':
case '*':
case '.': *p++ = '\\';
break;
}
*p++ = *str++;
}
*p = NUL;
RedrawingDisabled = TRUE;
if ((i = getfile(fname, TRUE)) <= 0)
{
set_want_col = TRUE;
RedrawingDisabled = FALSE;
dosearch(pbuf[0] == '/' ? FORWARD : BACKWARD, pbuf + 1, FALSE, 1L);
if (p_im && i == -1)
stuffReadbuff("\033\007i"); /* ESC CTRL-G i */
else
stuffReadbuff("\007"); /* CTRL-G */
return 1;
}
RedrawingDisabled = FALSE;
return 0;
}
}
m = NULL;
erret:
fclose(tp);
erret2:
if (m)
{
smsg(m, sbuf);
sleep(1);
}
}
if (m == NULL)
emsg("tag not found");
return 0;
}
/*
* find first TAB or space
*/
static char *
firsttaborspace(str)
char *str;
{
char *p1, *p2;
p1 = strchr(str, TAB); /* find first TAB */
p2 = strchr(str, ' '); /* find first space */
if (p1 == NULL || (p2 != NULL && p2 < p1))
return p2; /* space comes first */
return p1;
}