2 * Copyright (C) 1984-2012 Mark Nudelman
3 * Modified for use with illumos by Garrett D'Amore.
4 * Copyright 2014 Garrett D'Amore <garrett@damore.org>
6 * You may distribute under the terms of either the GNU General Public
7 * License or the Less License, as specified in the README file.
9 * For more information, see the README file.
14 #define WHITESP(c) ((c) == ' ' || (c) == '\t')
22 extern volatile sig_atomic_t sigs
;
32 static enum tag_result
findctag(char *);
33 static char *nextctag(void);
34 static char *prevctag(void);
35 static off_t
ctagsearch(void);
38 * The list of tags generated by the last findctag() call.
44 #define TAG_END ((struct tag *)&taglist)
45 static struct taglist taglist
= { TAG_END
, TAG_END
};
47 struct tag
*next
, *prev
; /* List links */
48 char *tag_file
; /* Source file containing the tag */
49 off_t tag_linenum
; /* Appropriate line number in source file */
50 char *tag_pattern
; /* Pattern used to find the tag */
51 int tag_endline
; /* True if the pattern includes '$' */
53 static struct tag
*curtag
;
56 (tp)->next = TAG_END; \
57 (tp)->prev = taglist.tl_last; \
58 taglist.tl_last->next = (tp); \
59 taglist.tl_last = (tp);
62 (tp)->next->prev = (tp)->prev; \
63 (tp)->prev->next = (tp)->next;
66 * Delete tag structures.
74 * Delete any existing tag list.
75 * {{ Ideally, we wouldn't do this until after we know that we
76 * can load some other tag information. }}
78 while ((tp
= taglist
.tl_first
) != TAG_END
) {
81 free(tp
->tag_pattern
);
89 * Create a new tag entry.
92 maketagent(char *file
, off_t linenum
, char *pattern
, int endline
)
96 tp
= ecalloc(sizeof (struct tag
), 1);
97 tp
->tag_file
= estrdup(file
);
98 tp
->tag_linenum
= linenum
;
99 tp
->tag_endline
= endline
;
101 tp
->tag_pattern
= NULL
;
103 tp
->tag_pattern
= estrdup(pattern
);
108 * Find tags in tag file.
113 enum tag_result result
;
115 result
= findctag(tag
);
121 error("No tags file", NULL
);
124 error("No such tag in tags file", NULL
);
127 error("unknown tag type", NULL
);
139 return (-1); /* No tags loaded! */
140 if (curtag
->tag_linenum
!= 0)
141 return (find_pos(curtag
->tag_linenum
));
142 return (ctagsearch());
146 * Go to the next tag.
151 char *tagfile
= NULL
;
154 tagfile
= nextctag();
159 * Go to the previous tag.
164 char *tagfile
= NULL
;
167 tagfile
= prevctag();
172 * Return the total number of tags.
181 * Return the sequence number of current tag.
190 * Find tags in the "tags" file.
191 * Sets curtag to the first tag entry.
193 static enum tag_result
205 char tline
[TAGLINE_SIZE
];
208 p
= shell_unquote(tags
);
216 taglen
= strlen(tag
);
219 * Search the tags file for the desired tag.
221 while (fgets(tline
, sizeof (tline
), f
) != NULL
) {
223 /* Skip header of extended format. */
225 if (strncmp(tag
, tline
, taglen
) != 0 || !WHITESP(tline
[taglen
]))
230 * The line contains the tag, the filename and the
231 * location in the file, separated by white space.
232 * The location is either a decimal line number,
233 * or a search pattern surrounded by a pair of delimiters.
234 * Parse the line and extract these parts.
239 * Skip over the whitespace after the tag name.
241 p
= skipsp(tline
+taglen
);
243 /* File name is missing! */
247 * Save the file name.
248 * Skip over the whitespace after the file name.
251 while (!WHITESP(*p
) && *p
!= '\0')
256 /* Pattern is missing! */
260 * First see if it is a line number.
263 taglinenum
= getnum(&p
, 0, &err
);
266 * No, it must be a pattern.
267 * Delete the initial "^" (if present) and
268 * the final "$" from the pattern.
269 * Delete any backslash in the pattern.
276 while (*p
!= search_char
&& *p
!= '\0') {
281 tagendline
= (p
[-1] == '$');
286 tp
= maketagent(tagfile
, taglinenum
, tagpattern
, tagendline
);
293 curtag
= taglist
.tl_first
;
299 * Edit current tagged file.
306 return (edit(curtag
->tag_file
));
311 * This is a stripped-down version of search().
312 * We don't use search() for several reasons:
313 * - We don't want to blow away any search string we may have saved.
314 * - The various regular-expression functions (from different systems:
315 * regcmp vs. re_comp) behave differently in the presence of
316 * parentheses (which are almost always found in a tag).
327 linenum
= find_linenum(pos
);
331 * Get lines until we find a matching one or
332 * until we hit end-of-file.
338 * Read the next line, and save the
339 * starting position of that line in linepos.
342 pos
= forw_raw_line(pos
, &line
, (int *)NULL
);
348 * We hit EOF without a match.
350 error("Tag not found", NULL
);
355 * If we're using line numbers, we might as well
356 * remember the information we have now (the position
357 * and line number of the current line).
360 add_lnum(linenum
, pos
);
363 * Test the line to see if we have a match.
364 * Use strncmp because the pattern may be
365 * truncated (in the tags file) if it is too long.
366 * If tagendline is set, make sure we match all
367 * the way to end of line (no extra chars after the match).
369 len
= strlen(curtag
->tag_pattern
);
370 if (strncmp(curtag
->tag_pattern
, line
, len
) == 0 &&
371 (!curtag
->tag_endline
|| line
[len
] == '\0' ||
372 line
[len
] == '\r')) {
373 curtag
->tag_linenum
= find_linenum(linepos
);
381 static int circular
= 0; /* 1: circular tag structure */
384 * Return the filename required for the next tag in the queue that was setup
385 * by findctag(). The next call to ctagsearch() will try to position at the
401 /* Wrapped around to the head of the queue */
402 curtag
= taglist
.tl_first
;
408 return (curtag
->tag_file
);
412 * Return the filename required for the previous ctag in the queue that was
413 * setup by findctag(). The next call to ctagsearch() will try to position
414 * at the appropriate tag.
429 /* Wrapped around to the tail of the queue */
430 curtag
= taglist
.tl_last
;
436 return (curtag
->tag_file
);