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.
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
15 extern char *getenv();
19 /* This is the default path that is searched for tags */
21 # define DEFTAGPATH ".:/dd/defs:/dd/defs/sys:/dd/usr/src/lib:../lib:/dd/usr/lib"
24 # define DEFTAGPATH ".:/usr/include:/usr/include/sys:/usr/src/lib:../lib:/usr/local/lib"
27 # define DEFTAGPATH ".;C:\\include;C:\\include\\sys;C:\\lib;..\\lib"
31 # define DEFTAGPATH ".;Include:;Include:sys"
33 # else /* any other OS */
34 # define DEFTAGPATH "."
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 */
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.
57 char *cktagdir(tag
, dir
)
58 char *tag
; /* name of the tag to look for */
59 char *dir
; /* name of the directory to check */
62 static char found
[BLKSIZE
];
67 if (dir
[strlen(dir
) - 1] == COLON
)
68 sprintf(buf
, "%s%s", dir
, TAGS
); /* no slash after colon. */
71 /* construct the name of the "tags" file in this directory */
72 sprintf(buf
, "%s%c%s", dir
, SLASH
, TAGS
);
74 /* Try to open the tags file. Return NULL if can't open */
76 if (buf
[0] == '.' && buf
[1] == SLASH
)
77 tfile
= fopen(&buf
[2], "r");
80 tfile
= fopen(buf
, "r");
86 /* compute the length of the tagname once */
89 /* read lines until we get the one for this tag */
91 while (fgets(buf
, sizeof buf
, tfile
))
93 /* is this the one we want? */
94 if (!strncmp(buf
, tag
, len
) && buf
[len
] == '\t')
96 /* we've found a match -- remember it */
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.
103 if (!def_file
|| !strncmp(&buf
[len
+ 1], def_file
, strlen(def_file
)))
110 /* we're through reading */
113 /* if there's anything in found[], use it */
116 return &found
[len
+ 1];
119 /* else we didn't find it */
123 /* This function reads a single textline from a binary file. It returns
124 * the number of bytes read, or 0 at EOF.
127 /* Avoid name pollution with stdio's getline. */
128 #define getline ref_getline
130 int getline(buf
, limit
, fp
)
131 char *buf
; /* buffer to read into */
132 int limit
; /* maximum characters to read */
133 FILE *fp
; /* binary stream to read from */
135 int bytes
; /* number of bytes read so far */
136 int ch
; /* single character from file */
138 for (bytes
= 0, ch
= 0; ch
!= '\n' && --limit
> 0 && (ch
= getc(fp
)) != EOF
; bytes
++)
141 /* since this is a binary file, we'll need to manually strip CR's */
155 /* This function reads a source file, looking for a given tag. If it finds
156 * the tag, then it displays it and returns TRUE. Otherwise it returns FALSE.
157 * To display the tag, it attempts to output any introductory comment, the
158 * tag line itself, and any arguments. Arguments are assumed to immediately
159 * follow the tag line, and start with whitespace. Comments are assumed to
160 * start with lines that begin with "/ *", "//", "(*", or "--", and end at the
161 * tag line or at a blank line.
163 int lookup(dir
, entry
)
164 char *dir
; /* name of the directory that contains the source */
165 char *entry
; /* source filename, <Tab>, linespec */
167 char buf
[BLKSIZE
]; /* pathname of sourcefile */
168 long lnum
; /* line number */
169 long here
; /* seek position where current line began */
170 long comment
; /* seek position of introductory comment, or -1L */
171 FILE *sfile
; /* used for reading the source file */
172 int len
; /* length of string */
176 /* construct the pathname of the source file */
178 ptr
= buf
+ strlen(buf
);
180 if (ptr
[-1] != COLON
)
183 while (*entry
!= '\t')
190 /* searching for string or number? */
191 if (*entry
>= '0' && *entry
<= '9')
193 /* given a specific line number */
199 /* given a string -- strip off "/^" and "$/\n" */
201 len
= strlen(entry
) - 2;
202 if (entry
[len
- 1] == '$')
204 entry
[len
- 1] = '\n';
209 /* Open the file. Note that we open the file in binary mode even
210 * though we know it is a text file, because ftell() and fseek()
211 * don't work on text files.
214 sfile
= fopen(buf
, "rb");
217 if (buf
[0] == '.' && buf
[1] == SLASH
)
218 sfile
= fopen(&buf
[2], "r");
221 sfile
= fopen(buf
, "r");
225 /* can't open the real source file. Try "refs" instead */
227 if (dir
[strlen(dir
) - 1] == COLON
)
228 sprintf(buf
, "%srefs", dir
);
231 sprintf(buf
, "%s%crefs", dir
, SLASH
);
233 sfile
= fopen(buf
, "rb");
236 if (buf
[0] == '.' && buf
[1] == SLASH
)
237 sfile
= fopen(&buf
[2], "r");
240 sfile
= fopen(buf
, "r");
249 /* search the file */
250 for (comment
= -1L; here
= ftell(sfile
), getline(buf
, BLKSIZE
, sfile
) > 0; )
252 /* Is this the start/end of a comment? */
255 /* starting a comment? */
256 if (buf
[0] == '/' && buf
[1] == '*'
257 || buf
[0] == '/' && buf
[1] == '/'
258 || buf
[0] == '(' && buf
[1] == '*'
259 || buf
[0] == '-' && buf
[1] == '-')
266 /* ending a comment? */
267 if (buf
[0] == '\n' || buf
[0] == '#')
273 /* is this the tag line? */
274 if (--lnum
== 0L || (entry
&& !strncmp(buf
, entry
, len
)))
276 /* if there were introductory comments, show them */
279 fseek(sfile
, comment
, 0);
280 while (comment
!= here
)
282 getline(buf
, BLKSIZE
, sfile
);
284 comment
= ftell(sfile
);
287 /* re-fetch the tag line */
288 fgets(buf
, BLKSIZE
, sfile
);
291 /* show the tag line */
294 /* show any argument lines */
295 while (getline(buf
, BLKSIZE
, sfile
) > 0
297 && strchr(buf
, '{') == (char *)0)
302 /* Done! Close the file, and return TRUE */
308 /* not found -- return FALSE */
312 /* This function searches through the entire search path for a given tag.
313 * If it finds the tag, then it displays the info and returns TRUE;
314 * otherwise it returns FALSE.
317 char *tag
; /* the tag to look up */
326 /* looking for static function -- only look in current dir */
331 /* get the tagpath from the environment. Default to DEFTAGPATH */
332 tagpath
= getenv("TAGPATH");
335 tagpath
= DEFTAGPATH
;
339 /* for each entry in the path... */
342 /* Copy the entry into the dir[] buffer */
343 for (ptr
= dir
; *tagpath
&& *tagpath
!= SEP
; tagpath
++)
352 /* if the entry ended with "/tags", then strip that off */
354 if (&dir
[len
] < ptr
&& ptr
[-len
- 1] == SLASH
&& !strncmp(&ptr
[-len
], TAGS
, len
))
359 /* if the entry is now an empty string, then assume "." */
366 /* look for the tag in this path. If found, then display it
369 ptr
= cktagdir(tag
, dir
);
372 /* just supposed to display tag info? */
375 /* then do only that! */
376 if (strcmp(dir
, "."))
378 printf("%s%c%s", dir
, SLASH
, ptr
);
382 /* avoid leading "./" if possible */
389 /* else look up the declaration of the thing */
390 return lookup(dir
, ptr
);
395 /* if we get here, then the tag wasn't found anywhere */
401 fputs("usage: ref [-a] [-t] [-c class] [-f file] tag\n", stderr
);
402 fputs(" -a function's args may be flush against left margin\n", stderr
);
403 fputs(" -t output tag info, instead of the function header\n", stderr
);
404 fputs(" -f File tag might be a static function in File\n", stderr
);
405 fputs(" -c Class tag might be a member of class Class\n", stderr
);
413 while (*str
!= ':' && *str
)
421 else if (str
[1] != ':')
432 char def_tag
[100]; /* used to build tag name with default file/class */
436 for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++)
447 def_file
= &argv
[i
][2];
462 def_class
= &argv
[i
][2];
479 /* if no tag was given, complain */
485 /* does the tag have an explicit class or file? */
486 colons
= countcolons(argv
[i
]);
488 /* if not, then maybe try some defaults */
491 /* try a static function in the file first */
494 sprintf(def_tag
, "%s:%s", def_file
, argv
[i
]);
502 /* try a member function for a class */
505 sprintf(def_tag
, "%s::%s", def_class
, argv
[i
]);