diff options
Diffstat (limited to 'contrib/less/tags.c')
-rw-r--r-- | contrib/less/tags.c | 757 |
1 files changed, 0 insertions, 757 deletions
diff --git a/contrib/less/tags.c b/contrib/less/tags.c deleted file mode 100644 index ab00faf..0000000 --- a/contrib/less/tags.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright (C) 1984-2007 Mark Nudelman - * - * You may distribute under the terms of either the GNU General Public - * License or the Less License, as specified in the README file. - * - * For more information about less, or for information on how to - * contact the author, see the README file. - */ - - -#include "less.h" - -#define WHITESP(c) ((c)==' ' || (c)=='\t') - -#if TAGS - -public char *tags = "tags"; - -static int total; -static int curseq; - -extern int linenums; -extern int sigs; - -enum tag_result { - TAG_FOUND, - TAG_NOFILE, - TAG_NOTAG, - TAG_NOTYPE, - TAG_INTR -}; - -/* - * Tag type - */ -enum { - 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 POSITION ctagsearch(); -static POSITION gtagsearch(); -static int getentry(); - -/* - * The list of tags generated by the last findgtag() 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 tag *tl_first; - struct tag *tl_last; -}; -#define TAG_END ((struct tag *) &taglist) -static struct taglist taglist = { TAG_END, TAG_END }; -struct tag { - struct tag *next, *prev; /* List links */ - char *tag_file; /* Source file containing the tag */ - LINENUM tag_linenum; /* Appropriate line number in source file */ - char *tag_pattern; /* Pattern used to find the tag */ - char tag_endline; /* True if the pattern includes '$' */ -}; -static struct tag *curtag; - -#define TAG_INS(tp) \ - (tp)->next = TAG_END; \ - (tp)->prev = taglist.tl_last; \ - taglist.tl_last->next = (tp); \ - taglist.tl_last = (tp); - -#define TAG_RM(tp) \ - (tp)->next->prev = (tp)->prev; \ - (tp)->prev->next = (tp)->next; - -/* - * Delete tag structures. - */ - public void -cleantags() -{ - register struct tag *tp; - - /* - * Delete any existing tag list. - * {{ Ideally, we wouldn't do this until after we know that we - * can load some other tag information. }} - */ - while ((tp = taglist.tl_first) != TAG_END) - { - TAG_RM(tp); - free(tp); - } - curtag = NULL; - total = curseq = 0; -} - -/* - * Create a new tag entry. - */ - static struct tag * -maketagent(name, file, linenum, pattern, endline) - char *name; - char *file; - LINENUM linenum; - char *pattern; - int endline; -{ - register struct tag *tp; - - tp = (struct tag *) ecalloc(sizeof(struct tag), 1); - tp->tag_file = (char *) ecalloc(strlen(file) + 1, sizeof(char)); - strcpy(tp->tag_file, file); - tp->tag_linenum = linenum; - tp->tag_endline = endline; - if (pattern == NULL) - tp->tag_pattern = NULL; - else - { - tp->tag_pattern = (char *) ecalloc(strlen(pattern) + 1, sizeof(char)); - strcpy(tp->tag_pattern, pattern); - } - return (tp); -} - -/* - * Get tag mode. - */ - public int -gettagtype() -{ - 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) - { - close(f); - return T_CTAGS; - } - return T_GTAGS; -} - -/* - * 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. - */ - public void -findtag(tag) - register char *tag; -{ - int type = gettagtype(); - enum tag_result result; - - if (type == T_CTAGS) - result = findctag(tag); - else - result = findgtag(tag, type); - switch (result) - { - case TAG_FOUND: - case TAG_INTR: - break; - case TAG_NOFILE: - error("No tags file", NULL_PARG); - break; - case TAG_NOTAG: - error("No such tag in tags file", NULL_PARG); - break; - case TAG_NOTYPE: - error("unknown tag type", NULL_PARG); - break; - } -} - -/* - * Search for a tag. - */ - public POSITION -tagsearch() -{ - if (curtag == NULL) - return (NULL_POSITION); /* No gtags loaded! */ - if (curtag->tag_linenum != 0) - return gtagsearch(); - else - return ctagsearch(); -} - -/* - * Go to the next tag. - */ - public char * -nexttag(n) - int n; -{ - char *tagfile = (char *) NULL; - - while (n-- > 0) - tagfile = nextgtag(); - return tagfile; -} - -/* - * Go to the previous tag. - */ - public char * -prevtag(n) - int n; -{ - char *tagfile = (char *) NULL; - - while (n-- > 0) - tagfile = prevgtag(); - return tagfile; -} - -/* - * Return the total number of tags. - */ - public int -ntags() -{ - return total; -} - -/* - * Return the sequence number of current tag. - */ - public int -curr_tag() -{ - return curseq; -} - -/***************************************************************************** - * ctags - */ - -/* - * Find tags in the "tags" file. - * Sets curtag to the first tag entry. - */ - static enum tag_result -findctag(tag) - register char *tag; -{ - char *p; - register FILE *f; - register int taglen; - LINENUM taglinenum; - char *tagfile; - char *tagpattern; - int tagendline; - int search_char; - int err; - char tline[TAGLINE_SIZE]; - struct tag *tp; - - p = shell_unquote(tags); - f = fopen(p, "r"); - free(p); - if (f == NULL) - return TAG_NOFILE; - - cleantags(); - total = 0; - taglen = strlen(tag); - - /* - * Search the tags file for the desired tag. - */ - while (fgets(tline, sizeof(tline), f) != NULL) - { - if (tline[0] == '!') - /* Skip header of extended format. */ - continue; - if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen])) - continue; - - /* - * Found it. - * The line contains the tag, the filename and the - * location in the file, separated by white space. - * The location is either a decimal line number, - * or a search pattern surrounded by a pair of delimiters. - * Parse the line and extract these parts. - */ - tagpattern = NULL; - - /* - * Skip over the whitespace after the tag name. - */ - p = skipsp(tline+taglen); - if (*p == '\0') - /* File name is missing! */ - continue; - - /* - * Save the file name. - * Skip over the whitespace after the file name. - */ - tagfile = p; - while (!WHITESP(*p) && *p != '\0') - p++; - *p++ = '\0'; - p = skipsp(p); - if (*p == '\0') - /* Pattern is missing! */ - continue; - - /* - * First see if it is a line number. - */ - tagendline = 0; - taglinenum = getnum(&p, 0, &err); - if (err) - { - /* - * No, it must be a pattern. - * Delete the initial "^" (if present) and - * the final "$" from the pattern. - * Delete any backslash in the pattern. - */ - taglinenum = 0; - search_char = *p++; - if (*p == '^') - p++; - tagpattern = p; - while (*p != search_char && *p != '\0') - { - if (*p == '\\') - p++; - p++; - } - tagendline = (p[-1] == '$'); - if (tagendline) - p--; - *p = '\0'; - } - tp = maketagent(tag, tagfile, taglinenum, tagpattern, tagendline); - TAG_INS(tp); - total++; - } - fclose(f); - if (total == 0) - return TAG_NOTAG; - curtag = taglist.tl_first; - curseq = 1; - return TAG_FOUND; -} - -/* - * Edit current tagged file. - */ - public int -edit_tagfile() -{ - if (curtag == NULL) - return (1); - return (edit(curtag->tag_file)); -} - -/* - * Search for a tag. - * This is a stripped-down version of search(). - * We don't use search() for several reasons: - * - We don't want to blow away any search string we may have saved. - * - The various regular-expression functions (from different systems: - * regcmp vs. re_comp) behave differently in the presence of - * parentheses (which are almost always found in a tag). - */ - static POSITION -ctagsearch() -{ - POSITION pos, linepos; - LINENUM linenum; - int len; - char *line; - - pos = ch_zero(); - linenum = find_linenum(pos); - - for (;;) - { - /* - * Get lines until we find a matching one or - * until we hit end-of-file. - */ - if (ABORT_SIGS()) - return (NULL_POSITION); - - /* - * Read the next line, and save the - * starting position of that line in linepos. - */ - linepos = pos; - pos = forw_raw_line(pos, &line, (int *)NULL); - if (linenum != 0) - linenum++; - - if (pos == NULL_POSITION) - { - /* - * We hit EOF without a match. - */ - error("Tag not found", NULL_PARG); - return (NULL_POSITION); - } - - /* - * If we're using line numbers, we might as well - * remember the information we have now (the position - * and line number of the current line). - */ - if (linenums) - add_lnum(linenum, pos); - - /* - * Test the line to see if we have a match. - * Use strncmp because the pattern may be - * truncated (in the tags file) if it is too long. - * If tagendline is set, make sure we match all - * the way to end of line (no extra chars after the match). - */ - len = strlen(curtag->tag_pattern); - if (strncmp(curtag->tag_pattern, line, len) == 0 && - (!curtag->tag_endline || line[len] == '\0' || line[len] == '\r')) - { - curtag->tag_linenum = find_linenum(linepos); - break; - } - } - - 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(tag, type) - char *tag; /* tag to load */ - int type; /* tags 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 - { -#if !HAVE_POPEN - return TAG_NOFILE; -#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 = (char *) ecalloc(strlen(cmd) + strlen(flag) + - strlen(qtag) + 5, sizeof(char)); - sprintf(command, "%s -x%s %s", cmd, flag, qtag); - if (qtag != tag) - free(qtag); - fp = popen(command, "r"); - free(command); -#endif - } - if (fp != NULL) - { - while (fgets(buf, sizeof(buf), fp)) - { - char *name, *file, *line; - int len; - - if (sigs) - { -#if HAVE_POPEN - if (fp != stdin) - pclose(fp); -#endif - 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(name, 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 */ - -/* - * Return the filename required for the next gtag in the queue that was setup - * by findgtag(). The next call to gtagsearch() will try to position at the - * appropriate tag. - */ - static char * -nextgtag() -{ - struct tag *tp; - - if (curtag == NULL) - /* No tag loaded */ - return NULL; - - tp = curtag->next; - if (tp == TAG_END) - { - if (!circular) - return NULL; - /* Wrapped around to the head of the queue */ - curtag = taglist.tl_first; - curseq = 1; - } else - { - curtag = tp; - curseq++; - } - return (curtag->tag_file); -} - -/* - * Return the filename required for the previous gtag in the queue that was - * setup by findgtat(). The next call to gtagsearch() will try to position - * at the appropriate tag. - */ - static char * -prevgtag() -{ - struct tag *tp; - - if (curtag == NULL) - /* No tag loaded */ - return NULL; - - tp = curtag->prev; - if (tp == TAG_END) - { - if (!circular) - return NULL; - /* Wrapped around to the tail of the queue */ - curtag = taglist.tl_last; - curseq = total; - } else - { - curtag = tp; - curseq--; - } - 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 POSITION -gtagsearch() -{ - if (curtag == NULL) - return (NULL_POSITION); /* 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(buf, tag, file, line) - char *buf; /* standard or extended ctags -x format data */ - char **tag; /* name of the tag we actually found */ - char **file; /* file in which to find this tag */ - char **line; /* line number of file where this tag is found */ -{ - char *p = buf; - - for (*tag = p; *p && !IS_SPACE(*p); p++) /* tag name */ - ; - if (*p == 0) - return (-1); - *p++ = 0; - for ( ; *p && IS_SPACE(*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 (!IS_DIGIT(*p)) - { - for ( ; *p && !IS_SPACE(*p); p++) /* (skip tag type) */ - ; - for (; *p && IS_SPACE(*p); p++) /* (skip blanks) */ - ; - } - if (!IS_DIGIT(*p)) - return (-1); - *line = p; /* line number */ - for (*line = p; *p && !IS_SPACE(*p); p++) - ; - if (*p == 0) - return (-1); - *p++ = 0; - for ( ; *p && IS_SPACE(*p); p++) /* (skip blanks) */ - ; - if (*p == 0) - return (-1); - *file = p; /* file name */ - for (*file = p; *p && !IS_SPACE(*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); -} - -#endif |