version 1.14, 2015/11/07 18:07:44 |
version 1.15, 2015/11/08 08:53:49 |
|
|
TAG_INTR |
TAG_INTR |
}; |
}; |
|
|
/* |
static enum tag_result findctag(char *); |
* Tag type |
static char *nextctag(void); |
*/ |
static char *prevctag(void); |
enum { |
static off_t ctagsearch(void); |
T_CTAGS, /* 'tags': standard and extended format (ctags) */ |
|
T_CTAGS_X, /* stdin: cross reference format (ctags) */ |
|
T_GTAGS, /* 'GTAGS': function defenition (global) */ |
|
T_GRTAGS, /* 'GRTAGS': function reference (global) */ |
|
T_GSYMS, /* 'GSYMS': other symbols (global) */ |
|
T_GPATH /* 'GPATH': path name (global) */ |
|
}; |
|
|
|
static enum tag_result findctag(); |
|
static enum tag_result findgtag(); |
|
static char *nextgtag(); |
|
static char *prevgtag(); |
|
static off_t ctagsearch(); |
|
static off_t gtagsearch(); |
|
static int getentry(); |
|
|
|
/* |
/* |
* The list of tags generated by the last findgtag() call. |
* The list of tags generated by the last findctag() call. |
* |
|
* Use either pattern or line number. |
|
* findgtag() always uses line number, so pattern is always NULL. |
|
* findctag() uses either pattern (in which case line number is 0), |
|
* or line number (in which case pattern is NULL). |
|
*/ |
*/ |
struct taglist { |
struct taglist { |
struct tag *tl_first; |
struct tag *tl_first; |
|
|
} |
} |
|
|
/* |
/* |
* Get tag mode. |
|
*/ |
|
static int |
|
gettagtype(void) |
|
{ |
|
int f; |
|
|
|
if (strcmp(tags, "GTAGS") == 0) |
|
return (T_GTAGS); |
|
if (strcmp(tags, "GRTAGS") == 0) |
|
return (T_GRTAGS); |
|
if (strcmp(tags, "GSYMS") == 0) |
|
return (T_GSYMS); |
|
if (strcmp(tags, "GPATH") == 0) |
|
return (T_GPATH); |
|
if (strcmp(tags, "-") == 0) |
|
return (T_CTAGS_X); |
|
f = open(tags, OPEN_READ); |
|
if (f >= 0) { |
|
(void) close(f); |
|
return (T_CTAGS); |
|
} |
|
return (T_GTAGS); |
|
} |
|
|
|
/* |
|
* Find tags in tag file. |
* Find tags in tag file. |
* Find a tag in the "tags" file. |
|
* Sets "tag_file" to the name of the file containing the tag, |
|
* and "tagpattern" to the search pattern which should be used |
|
* to find the tag. |
|
*/ |
*/ |
void |
void |
findtag(char *tag) |
findtag(char *tag) |
{ |
{ |
int type = gettagtype(); |
|
enum tag_result result; |
enum tag_result result; |
|
|
if (type == T_CTAGS) |
result = findctag(tag); |
result = findctag(tag); |
|
else |
|
result = findgtag(tag, type); |
|
switch (result) { |
switch (result) { |
case TAG_FOUND: |
case TAG_FOUND: |
case TAG_INTR: |
case TAG_INTR: |
|
|
tagsearch(void) |
tagsearch(void) |
{ |
{ |
if (curtag == NULL) |
if (curtag == NULL) |
return (-1); /* No gtags loaded! */ |
return (-1); /* No tags loaded! */ |
if (curtag->tag_linenum != 0) |
if (curtag->tag_linenum != 0) |
return (gtagsearch()); |
return (find_pos(curtag->tag_linenum)); |
else |
return (ctagsearch()); |
return (ctagsearch()); |
|
} |
} |
|
|
/* |
/* |
|
|
char *tagfile = NULL; |
char *tagfile = NULL; |
|
|
while (n-- > 0) |
while (n-- > 0) |
tagfile = nextgtag(); |
tagfile = nextctag(); |
return (tagfile); |
return (tagfile); |
} |
} |
|
|
|
|
char *tagfile = NULL; |
char *tagfile = NULL; |
|
|
while (n-- > 0) |
while (n-- > 0) |
tagfile = prevgtag(); |
tagfile = prevctag(); |
return (tagfile); |
return (tagfile); |
} |
} |
|
|
|
|
} |
} |
|
|
/* |
/* |
* ctags |
|
*/ |
|
|
|
/* |
|
* Find tags in the "tags" file. |
* Find tags in the "tags" file. |
* Sets curtag to the first tag entry. |
* Sets curtag to the first tag entry. |
*/ |
*/ |
|
|
return (linepos); |
return (linepos); |
} |
} |
|
|
/* |
|
* gtags |
|
*/ |
|
|
|
/* |
|
* Find tags in the GLOBAL's tag file. |
|
* The findgtag() will try and load information about the requested tag. |
|
* It does this by calling "global -x tag" and storing the parsed output |
|
* for future use by gtagsearch(). |
|
* Sets curtag to the first tag entry. |
|
*/ |
|
static enum tag_result |
|
findgtag(char *tag, int type) |
|
{ |
|
char buf[256]; |
|
FILE *fp; |
|
struct tag *tp; |
|
|
|
if (type != T_CTAGS_X && tag == NULL) |
|
return (TAG_NOFILE); |
|
|
|
cleantags(); |
|
total = 0; |
|
|
|
/* |
|
* If type == T_CTAGS_X then read ctags's -x format from stdin |
|
* else execute global(1) and read from it. |
|
*/ |
|
if (type == T_CTAGS_X) { |
|
fp = stdin; |
|
/* Set tag default because we cannot read stdin again. */ |
|
tags = "tags"; |
|
} else { |
|
char *command; |
|
char *flag; |
|
char *qtag; |
|
char *cmd = lgetenv("LESSGLOBALTAGS"); |
|
|
|
if (cmd == NULL || *cmd == '\0') |
|
return (TAG_NOFILE); |
|
/* Get suitable flag value for global(1). */ |
|
switch (type) { |
|
case T_GTAGS: |
|
flag = ""; |
|
break; |
|
case T_GRTAGS: |
|
flag = "r"; |
|
break; |
|
case T_GSYMS: |
|
flag = "s"; |
|
break; |
|
case T_GPATH: |
|
flag = "P"; |
|
break; |
|
default: |
|
return (TAG_NOTYPE); |
|
} |
|
|
|
/* Get our data from global(1). */ |
|
qtag = shell_quote(tag); |
|
if (qtag == NULL) |
|
qtag = tag; |
|
command = easprintf("%s -x%s %s", cmd, flag, qtag); |
|
if (qtag != tag) |
|
free(qtag); |
|
fp = popen(command, "r"); |
|
free(command); |
|
} |
|
if (fp != NULL) { |
|
while (fgets(buf, sizeof (buf), fp)) { |
|
char *name, *file, *line; |
|
int len; |
|
|
|
if (sigs) { |
|
if (fp != stdin) |
|
pclose(fp); |
|
return (TAG_INTR); |
|
} |
|
len = strlen(buf); |
|
if (len > 0 && buf[len-1] == '\n') { |
|
buf[len-1] = '\0'; |
|
} else { |
|
int c; |
|
do { |
|
c = fgetc(fp); |
|
} while (c != '\n' && c != EOF); |
|
} |
|
|
|
if (getentry(buf, &name, &file, &line)) { |
|
/* |
|
* Couldn't parse this line for some reason. |
|
* We'll just pretend it never happened. |
|
*/ |
|
break; |
|
} |
|
|
|
/* Make new entry and add to list. */ |
|
tp = maketagent(file, (LINENUM) atoi(line), NULL, 0); |
|
TAG_INS(tp); |
|
total++; |
|
} |
|
if (fp != stdin) { |
|
if (pclose(fp)) { |
|
curtag = NULL; |
|
total = curseq = 0; |
|
return (TAG_NOFILE); |
|
} |
|
} |
|
} |
|
|
|
/* Check to see if we found anything. */ |
|
tp = taglist.tl_first; |
|
if (tp == TAG_END) |
|
return (TAG_NOTAG); |
|
curtag = tp; |
|
curseq = 1; |
|
return (TAG_FOUND); |
|
} |
|
|
|
static int circular = 0; /* 1: circular tag structure */ |
static int circular = 0; /* 1: circular tag structure */ |
|
|
/* |
/* |
* Return the filename required for the next gtag in the queue that was setup |
* Return the filename required for the next tag in the queue that was setup |
* by findgtag(). The next call to gtagsearch() will try to position at the |
* by findctag(). The next call to ctagsearch() will try to position at the |
* appropriate tag. |
* appropriate tag. |
*/ |
*/ |
static char * |
static char * |
nextgtag(void) |
nextctag(void) |
{ |
{ |
struct tag *tp; |
struct tag *tp; |
|
|
|
|
} |
} |
|
|
/* |
/* |
* Return the filename required for the previous gtag in the queue that was |
* Return the filename required for the previous ctag in the queue that was |
* setup by findgtat(). The next call to gtagsearch() will try to position |
* setup by findctag(). The next call to ctagsearch() will try to position |
* at the appropriate tag. |
* at the appropriate tag. |
*/ |
*/ |
static char * |
static char * |
prevgtag(void) |
prevctag(void) |
{ |
{ |
struct tag *tp; |
struct tag *tp; |
|
|
|
|
curseq--; |
curseq--; |
} |
} |
return (curtag->tag_file); |
return (curtag->tag_file); |
} |
|
|
|
/* |
|
* Position the current file at at what is hopefully the tag that was chosen |
|
* using either findtag() or one of nextgtag() and prevgtag(). Returns -1 |
|
* if it was unable to position at the tag, 0 if successful. |
|
*/ |
|
static off_t |
|
gtagsearch(void) |
|
{ |
|
if (curtag == NULL) |
|
return (-1); /* No gtags loaded! */ |
|
return (find_pos(curtag->tag_linenum)); |
|
} |
|
|
|
/* |
|
* The getentry() parses both standard and extended ctags -x format. |
|
* |
|
* [standard format] |
|
* <tag> <lineno> <file> <image> |
|
* +------------------------------------------------ |
|
* |main 30 main.c main(argc, argv) |
|
* |func 21 subr.c func(arg) |
|
* |
|
* The following commands write this format. |
|
* o Traditinal Ctags with -x option |
|
* o Global with -x option |
|
* See <http://www.gnu.org/software/global/global.html> |
|
* |
|
* [extended format] |
|
* <tag> <type> <lineno> <file> <image> |
|
* +---------------------------------------------------------- |
|
* |main function 30 main.c main(argc, argv) |
|
* |func function 21 subr.c func(arg) |
|
* |
|
* The following commands write this format. |
|
* o Exuberant Ctags with -x option |
|
* See <http://ctags.sourceforge.net> |
|
* |
|
* Returns 0 on success, -1 on error. |
|
* The tag, file, and line will each be NUL-terminated pointers |
|
* into buf. |
|
*/ |
|
static int |
|
getentry(char *buf, char **tag, char **file, char **line) |
|
{ |
|
char *p = buf; |
|
|
|
for (*tag = p; *p && !isspace(*p); p++) /* tag name */ |
|
; |
|
if (*p == 0) |
|
return (-1); |
|
*p++ = 0; |
|
for (; *p && isspace(*p); p++) /* (skip blanks) */ |
|
; |
|
if (*p == 0) |
|
return (-1); |
|
/* |
|
* If the second part begin with other than digit, |
|
* it is assumed tag type. Skip it. |
|
*/ |
|
if (!isdigit(*p)) { |
|
for (; *p && !isspace(*p); p++) /* (skip tag type) */ |
|
; |
|
for (; *p && isspace(*p); p++) /* (skip blanks) */ |
|
; |
|
} |
|
if (!isdigit(*p)) |
|
return (-1); |
|
*line = p; /* line number */ |
|
for (*line = p; *p && !isspace(*p); p++) |
|
; |
|
if (*p == 0) |
|
return (-1); |
|
*p++ = 0; |
|
for (; *p && isspace(*p); p++) /* (skip blanks) */ |
|
; |
|
if (*p == 0) |
|
return (-1); |
|
*file = p; /* file name */ |
|
for (*file = p; *p && !isspace(*p); p++) |
|
; |
|
if (*p == 0) |
|
return (-1); |
|
*p = 0; |
|
|
|
/* value check */ |
|
if (strlen(*tag) && strlen(*line) && strlen(*file) && atoi(*line) > 0) |
|
return (0); |
|
return (-1); |
|
} |
} |