1 | /* ref2.c */
|
---|
2 |
|
---|
3 | /* This is a totally rewritten version of ref. This version looks for the
|
---|
4 | * desired function name in the "tags" file, and then reads the header out
|
---|
5 | * from the source file. There is no longer any need for a "refs" file.
|
---|
6 | *
|
---|
7 | * Usage: ref [-a] [-t] [-f file] [-c class] tag
|
---|
8 | * Options: -t output tag info, not the description
|
---|
9 | * -f file default filename for static functions
|
---|
10 | * -c class default class names for class functions
|
---|
11 | */
|
---|
12 |
|
---|
13 | #include <stdio.h>
|
---|
14 | #include "config.h"
|
---|
15 | extern char *getenv();
|
---|
16 | extern char *fgets();
|
---|
17 |
|
---|
18 |
|
---|
19 | /* This is the default path that is searched for tags */
|
---|
20 | #if OSK
|
---|
21 | # define DEFTAGPATH ".:/dd/defs:/dd/defs/sys:/dd/usr/src/lib:../lib:/dd/usr/lib"
|
---|
22 | #else
|
---|
23 | # if ANY_UNIX
|
---|
24 | # define DEFTAGPATH ".:/usr/include:/usr/include/sys:/usr/src/lib:../lib:/usr/local/lib"
|
---|
25 | # else
|
---|
26 | # if MSDOS || TOS
|
---|
27 | # define DEFTAGPATH ".;C:\\include;C:\\include\\sys;C:\\lib;..\\lib"
|
---|
28 | # define SEP ';'
|
---|
29 | # else
|
---|
30 | # if AMIGA
|
---|
31 | # define DEFTAGPATH ".;Include:;Include:sys"
|
---|
32 | # define SEP ';'
|
---|
33 | # else /* any other OS */
|
---|
34 | # define DEFTAGPATH "."
|
---|
35 | # endif
|
---|
36 | # endif
|
---|
37 | # endif
|
---|
38 | #endif
|
---|
39 |
|
---|
40 | #ifndef SEP
|
---|
41 | # define SEP ':'
|
---|
42 | #endif
|
---|
43 |
|
---|
44 |
|
---|
45 | /* These variables reflect the command-line options given by the user. */
|
---|
46 | int taginfo; /* boolean: give only the tag info? (not header?) */
|
---|
47 | char *def_file; /* default filename for static functions */
|
---|
48 | char *def_class; /* default classname for class members */
|
---|
49 | int colons; /* #colons in tag: 0=normal, 1=static, 2=member */
|
---|
50 |
|
---|
51 | /* This function checks for a tag in the "tags" file of given directory.
|
---|
52 | * If the tag is found, then it returns a pointer to a static buffer which
|
---|
53 | * contains the filename, a tab character, and a linespec for finding the
|
---|
54 | * the tag. If the tag is not found in the "tags" file, or if the "tags"
|
---|
55 | * file cannot be opened or doesn't exist, then this function returns NULL.
|
---|
56 | */
|
---|
57 | char *cktagdir(tag, dir)
|
---|
58 | char *tag; /* name of the tag to look for */
|
---|
59 | char *dir; /* name of the directory to check */
|
---|
60 | {
|
---|
61 | char buf[BLKSIZE];
|
---|
62 | static char found[BLKSIZE];
|
---|
63 | FILE *tfile;
|
---|
64 | int len;
|
---|
65 |
|
---|
66 | #if AMIGA
|
---|
67 | if (dir[strlen(dir) - 1] == COLON)
|
---|
68 | sprintf(buf, "%s%s", dir, TAGS); /* no slash after colon. */
|
---|
69 | else
|
---|
70 | #endif
|
---|
71 | /* construct the name of the "tags" file in this directory */
|
---|
72 | sprintf(buf, "%s%c%s", dir, SLASH, TAGS);
|
---|
73 |
|
---|
74 | /* Try to open the tags file. Return NULL if can't open */
|
---|
75 | #if AMIGA
|
---|
76 | if (buf[0] == '.' && buf[1] == SLASH)
|
---|
77 | tfile = fopen(&buf[2], "r");
|
---|
78 | else
|
---|
79 | #endif
|
---|
80 | tfile = fopen(buf, "r");
|
---|
81 | if (!tfile)
|
---|
82 | {
|
---|
83 | return (char *)0;
|
---|
84 | }
|
---|
85 |
|
---|
86 | /* compute the length of the tagname once */
|
---|
87 | len = strlen(tag);
|
---|
88 |
|
---|
89 | /* read lines until we get the one for this tag */
|
---|
90 | found[0] = '\0';
|
---|
91 | while (fgets(buf, sizeof buf, tfile))
|
---|
92 | {
|
---|
93 | /* is this the one we want? */
|
---|
94 | if (!strncmp(buf, tag, len) && buf[len] == '\t')
|
---|
95 | {
|
---|
96 | /* we've found a match -- remember it */
|
---|
97 | strcpy(found, buf);
|
---|
98 |
|
---|
99 | /* if there is no default file, or this match is in
|
---|
100 | * the default file, then we've definitely found the
|
---|
101 | * one we want. Break out of the loop now.
|
---|
102 | */
|
---|
103 | if (!def_file || !strncmp(&buf[len + 1], def_file, strlen(def_file)))
|
---|
104 | {
|
---|
105 | break;
|
---|
106 | }
|
---|
107 | }
|
---|
108 | }
|
---|
109 |
|
---|
110 | /* we're through reading */
|
---|
111 | fclose(tfile);
|
---|
112 |
|
---|
113 | /* if there's anything in found[], use it */
|
---|
114 | if (found[0])
|
---|
115 | {
|
---|
116 | return &found[len + 1];
|
---|
117 | }
|
---|
118 |
|
---|
119 | /* else we didn't find it */
|
---|
120 | return (char *)0;
|
---|
121 | }
|
---|
122 |
|
---|
123 | /* This function reads a single textline from a binary file. It returns
|
---|
124 | * the number of bytes read, or 0 at EOF.
|
---|
125 | */
|
---|
126 | int getline(buf, limit, fp)
|
---|
127 | char *buf; /* buffer to read into */
|
---|
128 | int limit; /* maximum characters to read */
|
---|
129 | FILE *fp; /* binary stream to read from */
|
---|
130 | {
|
---|
131 | int bytes; /* number of bytes read so far */
|
---|
132 | int ch; /* single character from file */
|
---|
133 |
|
---|
134 | for (bytes = 0, ch = 0; ch != '\n' && --limit > 0 && (ch = getc(fp)) != EOF; bytes++)
|
---|
135 | {
|
---|
136 | #if MSDOS || TOS
|
---|
137 | /* since this is a binary file, we'll need to manually strip CR's */
|
---|
138 | if (ch == '\r')
|
---|
139 | {
|
---|
140 | continue;
|
---|
141 | }
|
---|
142 | #endif
|
---|
143 | *buf++ = ch;
|
---|
144 | }
|
---|
145 | *buf = '\0';
|
---|
146 |
|
---|
147 | return bytes;
|
---|
148 | }
|
---|
149 |
|
---|
150 |
|
---|
151 | /* This function reads a source file, looking for a given tag. If it finds
|
---|
152 | * the tag, then it displays it and returns TRUE. Otherwise it returns FALSE.
|
---|
153 | * To display the tag, it attempts to output any introductory comment, the
|
---|
154 | * tag line itself, and any arguments. Arguments are assumed to immediately
|
---|
155 | * follow the tag line, and start with whitespace. Comments are assumed to
|
---|
156 | * start with lines that begin with "/*", "//", "(*", or "--", and end at the
|
---|
157 | * tag line or at a blank line.
|
---|
158 | */
|
---|
159 | int lookup(dir, entry)
|
---|
160 | char *dir; /* name of the directory that contains the source */
|
---|
161 | char *entry; /* source filename, <Tab>, linespec */
|
---|
162 | {
|
---|
163 | char buf[BLKSIZE]; /* pathname of sourcefile */
|
---|
164 | long lnum; /* line number */
|
---|
165 | long here; /* seek position where current line began */
|
---|
166 | long comment; /* seek position of introductory comment, or -1L */
|
---|
167 | FILE *sfile; /* used for reading the source file */
|
---|
168 | int len; /* length of string */
|
---|
169 | char *ptr;
|
---|
170 |
|
---|
171 |
|
---|
172 | /* construct the pathname of the source file */
|
---|
173 | strcpy(buf, dir);
|
---|
174 | ptr = buf + strlen(buf);
|
---|
175 | #if AMIGA
|
---|
176 | if (ptr[-1] != COLON)
|
---|
177 | #endif
|
---|
178 | *ptr++ = SLASH;
|
---|
179 | while (*entry != '\t')
|
---|
180 | {
|
---|
181 | *ptr++ = *entry++;
|
---|
182 | }
|
---|
183 | *ptr = '\0';
|
---|
184 | entry++;
|
---|
185 |
|
---|
186 | /* searching for string or number? */
|
---|
187 | if (*entry >= '0' && *entry <= '9')
|
---|
188 | {
|
---|
189 | /* given a specific line number */
|
---|
190 | lnum = atol(entry);
|
---|
191 | entry = (char *)0;
|
---|
192 | }
|
---|
193 | else
|
---|
194 | {
|
---|
195 | /* given a string -- strip off "/^" and "$/\n" */
|
---|
196 | entry += 2;
|
---|
197 | len = strlen(entry) - 2;
|
---|
198 | if (entry[len - 1] == '$')
|
---|
199 | {
|
---|
200 | entry[len - 1] = '\n';
|
---|
201 | }
|
---|
202 | lnum = 0L;
|
---|
203 | }
|
---|
204 |
|
---|
205 | /* Open the file. Note that we open the file in binary mode even
|
---|
206 | * though we know it is a text file, because ftell() and fseek()
|
---|
207 | * don't work on text files.
|
---|
208 | */
|
---|
209 | #if MSDOS || TOS
|
---|
210 | sfile = fopen(buf, "rb");
|
---|
211 | #else
|
---|
212 | # if AMIGA
|
---|
213 | if (buf[0] == '.' && buf[1] == SLASH)
|
---|
214 | sfile = fopen(&buf[2], "r");
|
---|
215 | else
|
---|
216 | # endif
|
---|
217 | sfile = fopen(buf, "r");
|
---|
218 | #endif
|
---|
219 | if (!sfile)
|
---|
220 | {
|
---|
221 | /* can't open the real source file. Try "refs" instead */
|
---|
222 | #if AMIGA
|
---|
223 | if (dir[strlen(dir) - 1] == COLON)
|
---|
224 | sprintf(buf, "%srefs", dir);
|
---|
225 | else
|
---|
226 | #endif
|
---|
227 | sprintf(buf, "%s%crefs", dir, SLASH);
|
---|
228 | #if MSDOS || TOS
|
---|
229 | sfile = fopen(buf, "rb");
|
---|
230 | #else
|
---|
231 | # if AMIGA
|
---|
232 | if (buf[0] == '.' && buf[1] == SLASH)
|
---|
233 | sfile = fopen(&buf[2], "r");
|
---|
234 | else
|
---|
235 | # endif
|
---|
236 | sfile = fopen(buf, "r");
|
---|
237 | #endif
|
---|
238 | if (!sfile)
|
---|
239 | {
|
---|
240 | /* failed! */
|
---|
241 | return 0;
|
---|
242 | }
|
---|
243 | }
|
---|
244 |
|
---|
245 | /* search the file */
|
---|
246 | for (comment = -1L; here = ftell(sfile), getline(buf, BLKSIZE, sfile) > 0; )
|
---|
247 | {
|
---|
248 | /* Is this the start/end of a comment? */
|
---|
249 | if (comment == -1L)
|
---|
250 | {
|
---|
251 | /* starting a comment? */
|
---|
252 | if (buf[0] == '/' && buf[1] == '*'
|
---|
253 | || buf[0] == '/' && buf[1] == '/'
|
---|
254 | || buf[0] == '(' && buf[1] == '*'
|
---|
255 | || buf[0] == '-' && buf[1] == '-')
|
---|
256 | {
|
---|
257 | comment = here;
|
---|
258 | }
|
---|
259 | }
|
---|
260 | else
|
---|
261 | {
|
---|
262 | /* ending a comment? */
|
---|
263 | if (buf[0] == '\n' || buf[0] == '#')
|
---|
264 | {
|
---|
265 | comment = -1L;
|
---|
266 | }
|
---|
267 | }
|
---|
268 |
|
---|
269 | /* is this the tag line? */
|
---|
270 | if (--lnum == 0L || (entry && !strncmp(buf, entry, len)))
|
---|
271 | {
|
---|
272 | /* if there were introductory comments, show them */
|
---|
273 | if (comment != -1L)
|
---|
274 | {
|
---|
275 | fseek(sfile, comment, 0);
|
---|
276 | while (comment != here)
|
---|
277 | {
|
---|
278 | getline(buf, BLKSIZE, sfile);
|
---|
279 | fputs(buf, stdout);
|
---|
280 | comment = ftell(sfile);
|
---|
281 | }
|
---|
282 |
|
---|
283 | /* re-fetch the tag line */
|
---|
284 | fgets(buf, BLKSIZE, sfile);
|
---|
285 | }
|
---|
286 |
|
---|
287 | /* show the tag line */
|
---|
288 | fputs(buf, stdout);
|
---|
289 |
|
---|
290 | /* show any argument lines */
|
---|
291 | while (getline(buf, BLKSIZE, sfile) > 0
|
---|
292 | && buf[0] != '#'
|
---|
293 | && strchr(buf, '{') == (char *)0)
|
---|
294 | {
|
---|
295 | fputs(buf, stdout);
|
---|
296 | }
|
---|
297 |
|
---|
298 | /* Done! Close the file, and return TRUE */
|
---|
299 | fclose(sfile);
|
---|
300 | return 1;
|
---|
301 | }
|
---|
302 | }
|
---|
303 |
|
---|
304 | /* not found -- return FALSE */
|
---|
305 | return 0;
|
---|
306 | }
|
---|
307 |
|
---|
308 | /* This function searches through the entire search path for a given tag.
|
---|
309 | * If it finds the tag, then it displays the info and returns TRUE;
|
---|
310 | * otherwise it returns FALSE.
|
---|
311 | */
|
---|
312 | int find(tag)
|
---|
313 | char *tag; /* the tag to look up */
|
---|
314 | {
|
---|
315 | char *tagpath;
|
---|
316 | char dir[80];
|
---|
317 | char *ptr;
|
---|
318 | int len;
|
---|
319 |
|
---|
320 | if (colons == 1)
|
---|
321 | {
|
---|
322 | /* looking for static function -- only look in current dir */
|
---|
323 | tagpath = ".";
|
---|
324 | }
|
---|
325 | else
|
---|
326 | {
|
---|
327 | /* get the tagpath from the environment. Default to DEFTAGPATH */
|
---|
328 | tagpath = getenv("TAGPATH");
|
---|
329 | if (!tagpath)
|
---|
330 | {
|
---|
331 | tagpath = DEFTAGPATH;
|
---|
332 | }
|
---|
333 | }
|
---|
334 |
|
---|
335 | /* for each entry in the path... */
|
---|
336 | while (*tagpath)
|
---|
337 | {
|
---|
338 | /* Copy the entry into the dir[] buffer */
|
---|
339 | for (ptr = dir; *tagpath && *tagpath != SEP; tagpath++)
|
---|
340 | {
|
---|
341 | *ptr++ = *tagpath;
|
---|
342 | }
|
---|
343 | if (*tagpath == SEP)
|
---|
344 | {
|
---|
345 | tagpath++;
|
---|
346 | }
|
---|
347 |
|
---|
348 | /* if the entry ended with "/tags", then strip that off */
|
---|
349 | len = strlen(TAGS);
|
---|
350 | if (&dir[len] < ptr && ptr[-len - 1] == SLASH && !strncmp(&ptr[-len], TAGS, len))
|
---|
351 | {
|
---|
352 | ptr -= len + 1;
|
---|
353 | }
|
---|
354 |
|
---|
355 | /* if the entry is now an empty string, then assume "." */
|
---|
356 | if (ptr == dir)
|
---|
357 | {
|
---|
358 | *ptr++ = '.';
|
---|
359 | }
|
---|
360 | *ptr = '\0';
|
---|
361 |
|
---|
362 | /* look for the tag in this path. If found, then display it
|
---|
363 | * and exit.
|
---|
364 | */
|
---|
365 | ptr = cktagdir(tag, dir);
|
---|
366 | if (ptr)
|
---|
367 | {
|
---|
368 | /* just supposed to display tag info? */
|
---|
369 | if (taginfo)
|
---|
370 | {
|
---|
371 | /* then do only that! */
|
---|
372 | if (strcmp(dir, "."))
|
---|
373 | {
|
---|
374 | printf("%s%c%s", dir, SLASH, ptr);
|
---|
375 | }
|
---|
376 | else
|
---|
377 | {
|
---|
378 | /* avoid leading "./" if possible */
|
---|
379 | fputs(ptr, stdout);
|
---|
380 | }
|
---|
381 | return 1;
|
---|
382 | }
|
---|
383 | else
|
---|
384 | {
|
---|
385 | /* else look up the declaration of the thing */
|
---|
386 | return lookup(dir, ptr);
|
---|
387 | }
|
---|
388 | }
|
---|
389 | }
|
---|
390 |
|
---|
391 | /* if we get here, then the tag wasn't found anywhere */
|
---|
392 | return 0;
|
---|
393 | }
|
---|
394 |
|
---|
395 | void usage()
|
---|
396 | {
|
---|
397 | fputs("usage: ref [-a] [-t] [-c class] [-f file] tag\n", stderr);
|
---|
398 | fputs(" -a function's args may be flush against left margin\n", stderr);
|
---|
399 | fputs(" -t output tag info, instead of the function header\n", stderr);
|
---|
400 | fputs(" -f File tag might be a static function in File\n", stderr);
|
---|
401 | fputs(" -c Class tag might be a member of class Class\n", stderr);
|
---|
402 | exit(2);
|
---|
403 | }
|
---|
404 |
|
---|
405 |
|
---|
406 | int countcolons(str)
|
---|
407 | char *str;
|
---|
408 | {
|
---|
409 | while (*str != ':' && *str)
|
---|
410 | {
|
---|
411 | str++;
|
---|
412 | }
|
---|
413 | if (str[0] != ':')
|
---|
414 | {
|
---|
415 | return 0;
|
---|
416 | }
|
---|
417 | else if (str[1] != ':')
|
---|
418 | {
|
---|
419 | return 1;
|
---|
420 | }
|
---|
421 | return 2;
|
---|
422 | }
|
---|
423 |
|
---|
424 | int main(argc, argv)
|
---|
425 | int argc;
|
---|
426 | char **argv;
|
---|
427 | {
|
---|
428 | char def_tag[100]; /* used to build tag name with default file/class */
|
---|
429 | int i;
|
---|
430 |
|
---|
431 | /* parse flags */
|
---|
432 | for (i = 1; i < argc && argv[i][0] == '-'; i++)
|
---|
433 | {
|
---|
434 | switch (argv[i][1])
|
---|
435 | {
|
---|
436 | case 't':
|
---|
437 | taginfo = 1;
|
---|
438 | break;
|
---|
439 |
|
---|
440 | case 'f':
|
---|
441 | if (argv[i][2])
|
---|
442 | {
|
---|
443 | def_file = &argv[i][2];
|
---|
444 | }
|
---|
445 | else if (++i < argc)
|
---|
446 | {
|
---|
447 | def_file = argv[i];
|
---|
448 | }
|
---|
449 | else
|
---|
450 | {
|
---|
451 | usage();
|
---|
452 | }
|
---|
453 | break;
|
---|
454 |
|
---|
455 | case 'c':
|
---|
456 | if (argv[i][2])
|
---|
457 | {
|
---|
458 | def_class = &argv[i][2];
|
---|
459 | }
|
---|
460 | else if (++i < argc)
|
---|
461 | {
|
---|
462 | def_class = argv[i];
|
---|
463 | }
|
---|
464 | else
|
---|
465 | {
|
---|
466 | usage();
|
---|
467 | }
|
---|
468 | break;
|
---|
469 |
|
---|
470 | default:
|
---|
471 | usage();
|
---|
472 | }
|
---|
473 | }
|
---|
474 |
|
---|
475 | /* if no tag was given, complain */
|
---|
476 | if (i + 1 != argc)
|
---|
477 | {
|
---|
478 | usage();
|
---|
479 | }
|
---|
480 |
|
---|
481 | /* does the tag have an explicit class or file? */
|
---|
482 | colons = countcolons(argv[i]);
|
---|
483 |
|
---|
484 | /* if not, then maybe try some defaults */
|
---|
485 | if (colons == 0)
|
---|
486 | {
|
---|
487 | /* try a static function in the file first */
|
---|
488 | if (def_file)
|
---|
489 | {
|
---|
490 | sprintf(def_tag, "%s:%s", def_file, argv[i]);
|
---|
491 | colons = 1;
|
---|
492 | if (find(def_tag))
|
---|
493 | {
|
---|
494 | exit(0);
|
---|
495 | }
|
---|
496 | }
|
---|
497 |
|
---|
498 | /* try a member function for a class */
|
---|
499 | if (def_class)
|
---|
500 | {
|
---|
501 | sprintf(def_tag, "%s::%s", def_class, argv[i]);
|
---|
502 | colons = 2;
|
---|
503 | if (find(def_tag))
|
---|
504 | {
|
---|
505 | exit(0);
|
---|
506 | }
|
---|
507 | }
|
---|
508 |
|
---|
509 | /* oh, well */
|
---|
510 | colons = 0;
|
---|
511 | }
|
---|
512 |
|
---|
513 | /* find the tag */
|
---|
514 | if (find(argv[i]))
|
---|
515 | {
|
---|
516 | exit(0);
|
---|
517 | }
|
---|
518 |
|
---|
519 | exit(1);
|
---|
520 | /*NOTREACHED*/
|
---|
521 | }
|
---|