tags.c revision 60786
1/* 2 * Copyright (C) 1984-2000 Mark Nudelman 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Less License, as specified in the README file. 6 * 7 * For more information about less, or for information on how to 8 * contact the author, see the README file. 9 */ 10 11 12#include "less.h" 13 14#define WHITESP(c) ((c)==' ' || (c)=='\t') 15 16#if TAGS 17 18public char *tags = "tags"; 19 20static char *tagfile; 21static char *tagpattern; 22static int taglinenum; 23static int tagendline; 24 25extern int linenums; 26extern int sigs; 27extern int jump_sline; 28 29/* 30 * Find a tag in the "tags" file. 31 * Sets "tagfile" to the name of the file containing the tag, 32 * and "tagpattern" to the search pattern which should be used 33 * to find the tag. 34 */ 35 public void 36findtag(tag) 37 register char *tag; 38{ 39 char *p; 40 char *q; 41 register FILE *f; 42 register int taglen; 43 int search_char; 44 int err; 45 char tline[TAGLINE_SIZE]; 46 47 p = unquote_file(tags); 48 f = fopen(p, "r"); 49 free(p); 50 if (f == NULL) 51 { 52 error("No tags file", NULL_PARG); 53 tagfile = NULL; 54 return; 55 } 56 57 taglen = strlen(tag); 58 59 /* 60 * Search the tags file for the desired tag. 61 */ 62 while (fgets(tline, sizeof(tline), f) != NULL) 63 { 64 if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen])) 65 continue; 66 67 /* 68 * Found it. 69 * The line contains the tag, the filename and the 70 * location in the file, separated by white space. 71 * The location is either a decimal line number, 72 * or a search pattern surrounded by a pair of delimiters. 73 * Parse the line and extract these parts. 74 */ 75 tagfile = tagpattern = NULL; 76 taglinenum = 0; 77 78 /* 79 * Skip over the whitespace after the tag name. 80 */ 81 p = skipsp(tline+taglen); 82 if (*p == '\0') 83 /* File name is missing! */ 84 continue; 85 86 /* 87 * Save the file name. 88 * Skip over the whitespace after the file name. 89 */ 90 tagfile = p; 91 while (!WHITESP(*p) && *p != '\0') 92 p++; 93 *p++ = '\0'; 94 p = skipsp(p); 95 if (*p == '\0') 96 /* Pattern is missing! */ 97 continue; 98 tagfile = save(tagfile); 99 100 /* 101 * First see if it is a line number. 102 */ 103 taglinenum = getnum(&p, 0, &err); 104 if (err) 105 { 106 /* 107 * No, it must be a pattern. 108 * Delete the initial "^" (if present) and 109 * the final "$" from the pattern. 110 * Delete any backslash in the pattern. 111 */ 112 taglinenum = 0; 113 search_char = *p++; 114 if (*p == '^') 115 p++; 116 tagpattern = (char *) ecalloc(strlen(p)+1, sizeof(char)); 117 q = tagpattern; 118 while (*p != search_char && *p != '\0') 119 { 120 if (*p == '\\') 121 p++; 122 *q++ = *p++; 123 } 124 tagendline = (q[-1] == '$'); 125 if (tagendline) 126 q--; 127 *q = '\0'; 128 } 129 130 fclose(f); 131 return; 132 } 133 fclose(f); 134 error("No such tag in tags file", NULL_PARG); 135 tagfile = NULL; 136} 137 138 public int 139edit_tagfile() 140{ 141 int r; 142 143 if (tagfile == NULL) 144 return (1); 145 r = edit(tagfile); 146 free(tagfile); 147 tagfile = NULL; 148 return (r); 149} 150 151/* 152 * Search for a tag. 153 * This is a stripped-down version of search(). 154 * We don't use search() for several reasons: 155 * - We don't want to blow away any search string we may have saved. 156 * - The various regular-expression functions (from different systems: 157 * regcmp vs. re_comp) behave differently in the presence of 158 * parentheses (which are almost always found in a tag). 159 */ 160 public POSITION 161tagsearch() 162{ 163 POSITION pos, linepos; 164 int linenum; 165 int len; 166 char *line; 167 168 /* 169 * If we have the line number of the tag instead of the pattern, 170 * just use find_pos. 171 */ 172 if (taglinenum) 173 return (find_pos(taglinenum)); 174 175 pos = ch_zero(); 176 linenum = find_linenum(pos); 177 178 for (;;) 179 { 180 /* 181 * Get lines until we find a matching one or 182 * until we hit end-of-file. 183 */ 184 if (ABORT_SIGS()) 185 return (NULL_POSITION); 186 187 /* 188 * Read the next line, and save the 189 * starting position of that line in linepos. 190 */ 191 linepos = pos; 192 pos = forw_raw_line(pos, &line); 193 if (linenum != 0) 194 linenum++; 195 196 if (pos == NULL_POSITION) 197 { 198 /* 199 * We hit EOF without a match. 200 */ 201 error("Tag not found", NULL_PARG); 202 return (NULL_POSITION); 203 } 204 205 /* 206 * If we're using line numbers, we might as well 207 * remember the information we have now (the position 208 * and line number of the current line). 209 */ 210 if (linenums) 211 add_lnum(linenum, pos); 212 213 /* 214 * Test the line to see if we have a match. 215 * Use strncmp because the pattern may be 216 * truncated (in the tags file) if it is too long. 217 * If tagendline is set, make sure we match all 218 * the way to end of line (no extra chars after the match). 219 */ 220 len = strlen(tagpattern); 221 if (strncmp(tagpattern, line, len) == 0 && 222 (!tagendline || line[len] == '\0' || line[len] == '\r')) 223 break; 224 } 225 226 free(tagpattern); 227 tagpattern = NULL; 228 return (linepos); 229} 230 231#endif 232