source: trunk/minix/commands/elvis/ref.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 10.9 KB
Line 
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"
15extern char *getenv();
16extern 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. */
46int taginfo; /* boolean: give only the tag info? (not header?) */
47char *def_file; /* default filename for static functions */
48char *def_class; /* default classname for class members */
49int 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 */
57char *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 */
126int 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 */
159int 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 */
312int 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
395void 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
406int 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
424int 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}
Note: See TracBrowser for help on using the repository browser.