232 lines
4.6 KiB
C
232 lines
4.6 KiB
C
|
/*
|
||
|
* Copyright (C) 1984-2000 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 char *tagfile;
|
||
|
static char *tagpattern;
|
||
|
static int taglinenum;
|
||
|
static int tagendline;
|
||
|
|
||
|
extern int linenums;
|
||
|
extern int sigs;
|
||
|
extern int jump_sline;
|
||
|
|
||
|
/*
|
||
|
* Find a tag in the "tags" file.
|
||
|
* Sets "tagfile" 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;
|
||
|
{
|
||
|
char *p;
|
||
|
char *q;
|
||
|
register FILE *f;
|
||
|
register int taglen;
|
||
|
int search_char;
|
||
|
int err;
|
||
|
char tline[TAGLINE_SIZE];
|
||
|
|
||
|
p = unquote_file(tags);
|
||
|
f = fopen(p, "r");
|
||
|
free(p);
|
||
|
if (f == NULL)
|
||
|
{
|
||
|
error("No tags file", NULL_PARG);
|
||
|
tagfile = NULL;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
taglen = strlen(tag);
|
||
|
|
||
|
/*
|
||
|
* Search the tags file for the desired tag.
|
||
|
*/
|
||
|
while (fgets(tline, sizeof(tline), f) != NULL)
|
||
|
{
|
||
|
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.
|
||
|
*/
|
||
|
tagfile = tagpattern = NULL;
|
||
|
taglinenum = 0;
|
||
|
|
||
|
/*
|
||
|
* 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;
|
||
|
tagfile = save(tagfile);
|
||
|
|
||
|
/*
|
||
|
* First see if it is a line number.
|
||
|
*/
|
||
|
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 = (char *) ecalloc(strlen(p)+1, sizeof(char));
|
||
|
q = tagpattern;
|
||
|
while (*p != search_char && *p != '\0')
|
||
|
{
|
||
|
if (*p == '\\')
|
||
|
p++;
|
||
|
*q++ = *p++;
|
||
|
}
|
||
|
tagendline = (q[-1] == '$');
|
||
|
if (tagendline)
|
||
|
q--;
|
||
|
*q = '\0';
|
||
|
}
|
||
|
|
||
|
fclose(f);
|
||
|
return;
|
||
|
}
|
||
|
fclose(f);
|
||
|
error("No such tag in tags file", NULL_PARG);
|
||
|
tagfile = NULL;
|
||
|
}
|
||
|
|
||
|
public int
|
||
|
edit_tagfile()
|
||
|
{
|
||
|
int r;
|
||
|
|
||
|
if (tagfile == NULL)
|
||
|
return (1);
|
||
|
r = edit(tagfile);
|
||
|
free(tagfile);
|
||
|
tagfile = NULL;
|
||
|
return (r);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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).
|
||
|
*/
|
||
|
public POSITION
|
||
|
tagsearch()
|
||
|
{
|
||
|
POSITION pos, linepos;
|
||
|
int linenum;
|
||
|
int len;
|
||
|
char *line;
|
||
|
|
||
|
/*
|
||
|
* If we have the line number of the tag instead of the pattern,
|
||
|
* just use find_pos.
|
||
|
*/
|
||
|
if (taglinenum)
|
||
|
return (find_pos(taglinenum));
|
||
|
|
||
|
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);
|
||
|
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(tagpattern);
|
||
|
if (strncmp(tagpattern, line, len) == 0 &&
|
||
|
(!tagendline || line[len] == '\0' || line[len] == '\r'))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
free(tagpattern);
|
||
|
tagpattern = NULL;
|
||
|
return (linepos);
|
||
|
}
|
||
|
|
||
|
#endif
|