1 /*
2 * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
3 * 2008 Tama Communications Corporation
4 *
5 * This file is part of GNU GLOBAL.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdio.h>
24 #ifdef STDC_HEADERS
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #else
30 #include <strings.h>
31 #endif
32 #ifdef HAVE_CTYPE_H
33 #include <ctype.h>
34 #endif
35 #include "global.h"
36 #include "anchor.h"
37 #include "htags.h"
38 #include "path2url.h"
39
40 static XARGS *anchor_input[GTAGLIM];
41 static struct anchor *table;
42 static VARRAY *vb;
43
44 static struct anchor *start;
45 static struct anchor *curp;
46 static struct anchor *end;
47 static struct anchor *CURRENT;
48
49 /** compare routine for qsort(3) */
50 static int
cmp(const void * s1,const void * s2)51 cmp(const void *s1, const void *s2)
52 {
53 return ((struct anchor *)s1)->lineno - ((struct anchor *)s2)->lineno;
54 }
55 /*
56 * Pointers (as lineno).
57 */
58 static int FIRST;
59 static int LAST;
60 static struct anchor *CURRENTDEF;
61
62 /**
63 * anchor_prepare: setup input stream.
64 *
65 * @param[in] anchor_stream file pointer of path list
66 */
67 void
anchor_prepare(FILE * anchor_stream)68 anchor_prepare(FILE *anchor_stream)
69 {
70 /*
71 * Option table:
72 * We use blank string as null option instead of null string("")
73 * not to change the command length. This length influences
74 * the number of arguments in the xargs processing.
75 */
76 static const char *const options[] = {NULL, " ", "r", "s"};
77 char comline[MAXFILLEN];
78 int db;
79
80 for (db = GTAGS; db < GTAGLIM; db++) {
81 anchor_input[db] = NULL;
82 /*
83 * Htags(1) should not use gtags-parser(1) directly;
84 * it should use global(1) with the -f option instead.
85 * Because gtags-parser is part of the implementation of
86 * gtags(1) and global(1), and htags is only an application
87 * program which uses global(1). If htags depends on
88 * gtags-parser, it will become difficult to change the
89 * implementation of gtags and global.
90 *
91 * Though the output of global -f is not necessarily sorted
92 * by the path, it is guaranteed that the records concerning
93 * the same file are consecutive.
94 */
95 if (gtags_exist[db] == 1) {
96 snprintf(comline, sizeof(comline), "%s -f%s --encode-path=\" \t\" --result=ctags-xid --nofilter=path", quote_shell(global_path), options[db]);
97 anchor_input[db] = xargs_open_with_file(comline, 0, anchor_stream);
98 }
99 }
100 }
101 /**
102 * anchor_load: load anchor table
103 *
104 * @param[in] path path name
105 */
106 void
anchor_load(const char * path)107 anchor_load(const char *path)
108 {
109 int db, current_fid;
110
111 /* Get fid of the path */
112 {
113 const char *p = path2fid(path);
114 if (p == NULL)
115 die("anchor_load: internal error. file '%s' not found in GPATH.", path);
116 current_fid = atoi(p);
117 }
118 FIRST = LAST = 0;
119 end = CURRENT = NULL;
120
121 if (vb == NULL)
122 vb = varray_open(sizeof(struct anchor), 1000);
123 else
124 varray_reset(vb);
125
126 for (db = GTAGS; db < GTAGLIM; db++) {
127 XARGS *xp;
128 char *ctags_xid;
129
130 if ((xp = anchor_input[db]) == NULL)
131 continue;
132 /*
133 * Read from input stream until it reaches end of file
134 * or the line of another file appears.
135 */
136 while ((ctags_xid = xargs_read(xp)) != NULL) {
137 SPLIT ptable;
138 struct anchor *a;
139 int type, fid;
140 const char *ctags_x = parse_xid(ctags_xid, NULL, &fid);
141
142 /*
143 * It is the following file.
144 */
145 if (current_fid != fid) {
146 xargs_unread(xp);
147 break;
148 }
149 if (split(ctags_x, 4, &ptable) < 4) {
150 recover(&ptable);
151 die("too small number of parts in anchor_load().\n'%s'", ctags_x);
152 }
153 if (db == GTAGS) {
154 char *p = ptable.part[PART_LINE].start;
155
156 for (; *p && isspace((unsigned char)*p); p++)
157 ;
158 if (!*p) {
159 recover(&ptable);
160 die("The output of parser is invalid.\n%s", ctags_x);
161 }
162 /*
163 * Function header is applied only to the anchor whoes type is 'D'.
164 * (D: function, M: macro, T: type)
165 */
166 type = 'T';
167 if (*p == '#')
168 type = 'M';
169 else if (locatestring(p, "typedef", MATCH_AT_FIRST))
170 type = 'T';
171 else if ((p = locatestring(p, ptable.part[PART_TAG].start, MATCH_FIRST)) != NULL) {
172 /* skip a tag and the following blanks */
173 p += strlen(ptable.part[PART_TAG].start);
174 for (; *p && isspace((unsigned char)*p); p++)
175 ;
176 if (*p == '(')
177 type = 'D';
178 }
179 } else if (db == GRTAGS)
180 type = 'R';
181 else
182 type = 'Y';
183 /* allocate an entry */
184 a = varray_append(vb);
185 a->lineno = atoi(ptable.part[PART_LNO].start);
186 a->type = type;
187 a->done = 0;
188 settag(a, ptable.part[PART_TAG].start);
189 recover(&ptable);
190 }
191 if (ctags_xid == NULL) {
192 xargs_close(anchor_input[db]);
193 anchor_input[db] = NULL;
194 }
195 }
196 if (vb->length == 0) {
197 table = NULL;
198 } else {
199 int i, used = vb->length;
200 /*
201 * Sort by lineno.
202 */
203 table = varray_assign(vb, 0, 0);
204 qsort(table, used, sizeof(struct anchor), cmp);
205 /*
206 * Setup some lineno.
207 */
208 for (i = 0; i < used; i++)
209 if (table[i].type == 'D')
210 break;
211 if (i < used)
212 FIRST = table[i].lineno;
213 for (i = used - 1; i >= 0; i--)
214 if (table[i].type == 'D')
215 break;
216 if (i >= 0)
217 LAST = table[i].lineno;
218 }
219 /*
220 * Setup loop range.
221 */
222 start = table;
223 curp = NULL;
224 end = &table[vb->length];
225 /* anchor_dump(stderr, 0);*/
226 }
227 /**
228 * anchor_unload: unload anchor table
229 */
230 void
anchor_unload(void)231 anchor_unload(void)
232 {
233 struct anchor *a;
234
235 for (a = start; a && a < end; a++) {
236 if (a->reserve) {
237 free(a->reserve);
238 a->reserve = NULL;
239 }
240 }
241 /* We don't free varray */
242 /* varray_close(vb); */
243 FIRST = LAST = 0;
244 start = curp = end = NULL;
245 }
246 /**
247 * anchor_first: return the first anchor
248 */
249 struct anchor *
anchor_first(void)250 anchor_first(void)
251 {
252 if (!start || start == end)
253 return NULL;
254 CURRENT = start;
255 if (CURRENT->type == 'D')
256 CURRENTDEF = CURRENT;
257 return CURRENT;
258 }
259 /**
260 * anchor_next: return the next anchor
261 */
262 struct anchor *
anchor_next(void)263 anchor_next(void)
264 {
265 if (!start)
266 return NULL;
267 if (++CURRENT >= end)
268 return NULL;
269 if (CURRENT->type == 'D')
270 CURRENTDEF = CURRENT;
271 return CURRENT;
272 }
273 /**
274 * anchor_get: return the specified anchor
275 *
276 * @param[in] name name of anchor
277 * @param[in] length lenght of the name
278 * @param[in] type ==0: not specified,
279 * !=0: D, M, T, R, Y
280 * @param[in] lineno line number
281 */
282 struct anchor *
anchor_get(const char * name,int length,int type,int lineno)283 anchor_get(const char *name, int length, int type, int lineno)
284 {
285 struct anchor *p = curp ? curp : start;
286
287 if (table == NULL)
288 return NULL;
289 if (p->lineno > lineno)
290 return NULL;
291 /*
292 * set pointer to the top of the cluster.
293 */
294 for (; p < end && p->lineno < lineno; p++)
295 ;
296 if (p >= end || p->lineno != lineno)
297 return NULL;
298 curp = p;
299 for (; p < end && p->lineno == lineno; p++)
300 if (!p->done && p->length == length && !strcmp(gettag(p), name))
301 if (!type || p->type == type)
302 return p;
303 return NULL;
304 }
305 /**
306 * define_line: check whether or not this is a define line.
307 *
308 * @param[in] lineno line number
309 * @return 1: definition, 0: not definition
310 * Globals used (output):
311 * curp pointer to the current cluster
312 */
313 int
define_line(int lineno)314 define_line(int lineno)
315 {
316 struct anchor *p = curp ? curp : start;
317
318 if (table == NULL)
319 return 0;
320 if (p->lineno > lineno)
321 return 0;
322 /*
323 * set pointer to the top of the cluster.
324 */
325 for (; p < end && p->lineno < lineno; p++)
326 ;
327 if (p >= end || p->lineno != lineno)
328 return 0;
329 curp = p;
330 for (; p < end && p->lineno == lineno; p++)
331 if (p->type == 'D')
332 return 1;
333 return 0;
334 }
335 /**
336 * anchor_getlinks: return anchor link array
337 * (previous, next, first, last, top, bottom)
338 *
339 * @param[in] lineno line number
340 */
341 int *
anchor_getlinks(int lineno)342 anchor_getlinks(int lineno)
343 {
344 static int ref[A_SIZE];
345 int i;
346
347 for (i = 0; i < A_SIZE; i++)
348 ref[i] = 0;
349 if (lineno >= 1 && start) {
350 struct anchor *c, *p;
351
352 if (CURRENTDEF == NULL) {
353 for (c = start; c < end; c++)
354 if (c->lineno == lineno && c->type == 'D')
355 break;
356 CURRENTDEF = c;
357 } else {
358 for (c = CURRENTDEF; c >= start; c--)
359 if (c->lineno == lineno && c->type == 'D')
360 break;
361 }
362 for (p = c - 1; p >= start; p--)
363 if (p->type == 'D') {
364 ref[A_PREV] = p->lineno;
365 break;
366 }
367 for (p = c + 1; p < end; p++)
368 if (p->type == 'D') {
369 ref[A_NEXT] = p->lineno;
370 break;
371 }
372 }
373 if (FIRST > 0 && lineno != FIRST)
374 ref[A_FIRST] = FIRST;
375 if (LAST > 0 && lineno != LAST)
376 ref[A_LAST] = LAST;
377 if (lineno != 0)
378 ref[A_TOP] = -1;
379 if (lineno != -1)
380 ref[A_BOTTOM] = -2;
381 if (FIRST > 0 && FIRST == LAST) {
382 if (lineno == 0)
383 ref[A_LAST] = 0;
384 if (lineno == -1)
385 ref[A_FIRST] = 0;
386 }
387 return ref;
388 }
389 void
anchor_dump(FILE * op,int lineno)390 anchor_dump(FILE *op, int lineno)
391 {
392 struct anchor *a;
393
394 if (op == NULL)
395 op = stderr;
396 for (a = start; a < end ; a++)
397 if (lineno == 0 || a->lineno == lineno)
398 fprintf(op, "%d %s(%c)\n",
399 a->lineno, gettag(a), a->type);
400 }
401