1 /*
2  * Copyright (c) 1984,1985,1989,1994,1995  Mark Nudelman
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice in the documentation and/or other materials provided with
12  *    the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
20  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 
28 #include "less.h"
29 
30 #define	WHITESP(c)	((c)==' ' || (c)=='\t')
31 
32 #if TAGS
33 
34 public char *tagfile;
35 public char *tags = "tags";
36 
37 static char *tagpattern;
38 static int taglinenum;
39 
40 extern int linenums;
41 extern int sigs;
42 extern int jump_sline;
43 
44 /*
45  * Find a tag in the "tags" file.
46  * Sets "tagfile" to the name of the file containing the tag,
47  * and "tagpattern" to the search pattern which should be used
48  * to find the tag.
49  */
50 	public void
findtag(tag)51 findtag(tag)
52 	register char *tag;
53 {
54 	char *p;
55 	char *q;
56 	register FILE *f;
57 	register int taglen;
58 	int search_char;
59 	int err;
60 	static char tline[200];
61 
62 	if ((f = fopen(tags, "r")) == NULL)
63 	{
64 		error("No tags file", NULL_PARG);
65 		tagfile = NULL;
66 		return;
67 	}
68 
69 	taglen = strlen(tag);
70 
71 	/*
72 	 * Search the tags file for the desired tag.
73 	 */
74 	while (fgets(tline, sizeof(tline), f) != NULL)
75 	{
76 		if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen]))
77 			continue;
78 
79 		/*
80 		 * Found it.
81 		 * The line contains the tag, the filename and the
82 		 * location in the file, separated by white space.
83 		 * The location is either a decimal line number,
84 		 * or a search pattern surrounded by a pair of delimiters.
85 		 * Parse the line and extract these parts.
86 		 */
87 		tagfile = tagpattern = NULL;
88 		taglinenum = 0;
89 
90 		/*
91 		 * Skip over the whitespace after the tag name.
92 		 */
93 		p = skipsp(tline+taglen);
94 		if (*p == '\0')
95 			/* File name is missing! */
96 			continue;
97 
98 		/*
99 		 * Save the file name.
100 		 * Skip over the whitespace after the file name.
101 		 */
102 		tagfile = p;
103 		while (!WHITESP(*p) && *p != '\0')
104 			p++;
105 		*p++ = '\0';
106 		p = skipsp(p);
107 		if (*p == '\0')
108 			/* Pattern is missing! */
109 			continue;
110 
111 		/*
112 		 * First see if it is a line number.
113 		 */
114 		taglinenum = getnum(&p, 0, &err);
115 		if (err)
116 		{
117 			/*
118 			 * No, it must be a pattern.
119 			 * Delete the initial "^" (if present) and
120 			 * the final "$" from the pattern.
121 			 * Delete any backslash in the pattern.
122 			 */
123 			taglinenum = 0;
124 			search_char = *p++;
125 			if (*p == '^')
126 				p++;
127 			tagpattern = q = p;
128 			while (*p != search_char && *p != '\0')
129 			{
130 				if (*p == '\\')
131 					p++;
132 				*q++ = *p++;
133 			}
134 			if (q[-1] == '$')
135 				q--;
136 			*q = '\0';
137 		}
138 
139 		fclose(f);
140 		return;
141 	}
142 	fclose(f);
143 	error("No such tag in tags file", NULL_PARG);
144 	tagfile = NULL;
145 }
146 
147 /*
148  * Search for a tag.
149  * This is a stripped-down version of search().
150  * We don't use search() for several reasons:
151  *   -	We don't want to blow away any search string we may have saved.
152  *   -	The various regular-expression functions (from different systems:
153  *	regcmp vs. re_comp) behave differently in the presence of
154  *	parentheses (which are almost always found in a tag).
155  */
156 	public POSITION
tagsearch()157 tagsearch()
158 {
159 	POSITION pos, linepos;
160 	int linenum;
161 	char *line;
162 
163 	/*
164 	 * If we have the line number of the tag instead of the pattern,
165 	 * just use find_pos.
166 	 */
167 	if (taglinenum)
168 		return (find_pos(taglinenum));
169 
170 	pos = ch_zero();
171 	linenum = find_linenum(pos);
172 
173 	for (;;)
174 	{
175 		/*
176 		 * Get lines until we find a matching one or
177 		 * until we hit end-of-file.
178 		 */
179 		if (ABORT_SIGS())
180 			return (NULL_POSITION);
181 
182 		/*
183 		 * Read the next line, and save the
184 		 * starting position of that line in linepos.
185 		 */
186 		linepos = pos;
187 		pos = forw_raw_line(pos, &line);
188 		if (linenum != 0)
189 			linenum++;
190 
191 		if (pos == NULL_POSITION)
192 		{
193 			/*
194 			 * We hit EOF without a match.
195 			 */
196 			error("Tag not found", NULL_PARG);
197 			return (NULL_POSITION);
198 		}
199 
200 		/*
201 		 * If we're using line numbers, we might as well
202 		 * remember the information we have now (the position
203 		 * and line number of the current line).
204 		 */
205 		if (linenums)
206 			add_lnum(linenum, pos);
207 
208 		/*
209 		 * Test the line to see if we have a match.
210 		 * Use strncmp because the pattern may be
211 		 * truncated (in the tags file) if it is too long.
212 		 */
213 		if (strncmp(tagpattern, line, strlen(tagpattern)) == 0)
214 			break;
215 	}
216 
217 	return (linepos);
218 }
219 
220 #endif
221