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