include: reduce default stack size
[minix.git] / commands / elvis / ref.c
blobc830464aec247c7e82871f49b630bcd80757c7d9
1 /* ref2.c */
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
13 #include <stdio.h>
14 #include "config.h"
15 extern char *getenv();
16 extern char *fgets();
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
40 #ifndef SEP
41 # define SEP ':'
42 #endif
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 */
61 char buf[BLKSIZE];
62 static char found[BLKSIZE];
63 FILE *tfile;
64 int len;
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);
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)
83 return (char *)0;
86 /* compute the length of the tagname once */
87 len = strlen(tag);
89 /* read lines until we get the one for this tag */
90 found[0] = '\0';
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 */
97 strcpy(found, buf);
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)))
105 break;
110 /* we're through reading */
111 fclose(tfile);
113 /* if there's anything in found[], use it */
114 if (found[0])
116 return &found[len + 1];
119 /* else we didn't find it */
120 return (char *)0;
123 /* This function reads a single textline from a binary file. It returns
124 * the number of bytes read, or 0 at EOF.
126 #ifdef __NBSD_LIBC
127 /* Avoid name pollution with stdio's getline. */
128 #define getline ref_getline
129 #endif
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++)
140 #if MSDOS || TOS
141 /* since this is a binary file, we'll need to manually strip CR's */
142 if (ch == '\r')
144 continue;
146 #endif
147 *buf++ = ch;
149 *buf = '\0';
151 return bytes;
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 */
173 char *ptr;
176 /* construct the pathname of the source file */
177 strcpy(buf, dir);
178 ptr = buf + strlen(buf);
179 #if AMIGA
180 if (ptr[-1] != COLON)
181 #endif
182 *ptr++ = SLASH;
183 while (*entry != '\t')
185 *ptr++ = *entry++;
187 *ptr = '\0';
188 entry++;
190 /* searching for string or number? */
191 if (*entry >= '0' && *entry <= '9')
193 /* given a specific line number */
194 lnum = atol(entry);
195 entry = (char *)0;
197 else
199 /* given a string -- strip off "/^" and "$/\n" */
200 entry += 2;
201 len = strlen(entry) - 2;
202 if (entry[len - 1] == '$')
204 entry[len - 1] = '\n';
206 lnum = 0L;
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.
213 #if MSDOS || TOS
214 sfile = fopen(buf, "rb");
215 #else
216 # if AMIGA
217 if (buf[0] == '.' && buf[1] == SLASH)
218 sfile = fopen(&buf[2], "r");
219 else
220 # endif
221 sfile = fopen(buf, "r");
222 #endif
223 if (!sfile)
225 /* can't open the real source file. Try "refs" instead */
226 #if AMIGA
227 if (dir[strlen(dir) - 1] == COLON)
228 sprintf(buf, "%srefs", dir);
229 else
230 #endif
231 sprintf(buf, "%s%crefs", dir, SLASH);
232 #if MSDOS || TOS
233 sfile = fopen(buf, "rb");
234 #else
235 # if AMIGA
236 if (buf[0] == '.' && buf[1] == SLASH)
237 sfile = fopen(&buf[2], "r");
238 else
239 # endif
240 sfile = fopen(buf, "r");
241 #endif
242 if (!sfile)
244 /* failed! */
245 return 0;
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? */
253 if (comment == -1L)
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] == '-')
261 comment = here;
264 else
266 /* ending a comment? */
267 if (buf[0] == '\n' || buf[0] == '#')
269 comment = -1L;
273 /* is this the tag line? */
274 if (--lnum == 0L || (entry && !strncmp(buf, entry, len)))
276 /* if there were introductory comments, show them */
277 if (comment != -1L)
279 fseek(sfile, comment, 0);
280 while (comment != here)
282 getline(buf, BLKSIZE, sfile);
283 fputs(buf, stdout);
284 comment = ftell(sfile);
287 /* re-fetch the tag line */
288 fgets(buf, BLKSIZE, sfile);
291 /* show the tag line */
292 fputs(buf, stdout);
294 /* show any argument lines */
295 while (getline(buf, BLKSIZE, sfile) > 0
296 && buf[0] != '#'
297 && strchr(buf, '{') == (char *)0)
299 fputs(buf, stdout);
302 /* Done! Close the file, and return TRUE */
303 fclose(sfile);
304 return 1;
308 /* not found -- return FALSE */
309 return 0;
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.
316 int find(tag)
317 char *tag; /* the tag to look up */
319 char *tagpath;
320 char dir[80];
321 char *ptr;
322 int len;
324 if (colons == 1)
326 /* looking for static function -- only look in current dir */
327 tagpath = ".";
329 else
331 /* get the tagpath from the environment. Default to DEFTAGPATH */
332 tagpath = getenv("TAGPATH");
333 if (!tagpath)
335 tagpath = DEFTAGPATH;
339 /* for each entry in the path... */
340 while (*tagpath)
342 /* Copy the entry into the dir[] buffer */
343 for (ptr = dir; *tagpath && *tagpath != SEP; tagpath++)
345 *ptr++ = *tagpath;
347 if (*tagpath == SEP)
349 tagpath++;
352 /* if the entry ended with "/tags", then strip that off */
353 len = strlen(TAGS);
354 if (&dir[len] < ptr && ptr[-len - 1] == SLASH && !strncmp(&ptr[-len], TAGS, len))
356 ptr -= len + 1;
359 /* if the entry is now an empty string, then assume "." */
360 if (ptr == dir)
362 *ptr++ = '.';
364 *ptr = '\0';
366 /* look for the tag in this path. If found, then display it
367 * and exit.
369 ptr = cktagdir(tag, dir);
370 if (ptr)
372 /* just supposed to display tag info? */
373 if (taginfo)
375 /* then do only that! */
376 if (strcmp(dir, "."))
378 printf("%s%c%s", dir, SLASH, ptr);
380 else
382 /* avoid leading "./" if possible */
383 fputs(ptr, stdout);
385 return 1;
387 else
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 */
396 return 0;
399 void usage()
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);
406 exit(2);
410 int countcolons(str)
411 char *str;
413 while (*str != ':' && *str)
415 str++;
417 if (str[0] != ':')
419 return 0;
421 else if (str[1] != ':')
423 return 1;
425 return 2;
428 int main(argc, argv)
429 int argc;
430 char **argv;
432 char def_tag[100]; /* used to build tag name with default file/class */
433 int i;
435 /* parse flags */
436 for (i = 1; i < argc && argv[i][0] == '-'; i++)
438 switch (argv[i][1])
440 case 't':
441 taginfo = 1;
442 break;
444 case 'f':
445 if (argv[i][2])
447 def_file = &argv[i][2];
449 else if (++i < argc)
451 def_file = argv[i];
453 else
455 usage();
457 break;
459 case 'c':
460 if (argv[i][2])
462 def_class = &argv[i][2];
464 else if (++i < argc)
466 def_class = argv[i];
468 else
470 usage();
472 break;
474 default:
475 usage();
479 /* if no tag was given, complain */
480 if (i + 1 != argc)
482 usage();
485 /* does the tag have an explicit class or file? */
486 colons = countcolons(argv[i]);
488 /* if not, then maybe try some defaults */
489 if (colons == 0)
491 /* try a static function in the file first */
492 if (def_file)
494 sprintf(def_tag, "%s:%s", def_file, argv[i]);
495 colons = 1;
496 if (find(def_tag))
498 exit(0);
502 /* try a member function for a class */
503 if (def_class)
505 sprintf(def_tag, "%s::%s", def_class, argv[i]);
506 colons = 2;
507 if (find(def_tag))
509 exit(0);
513 /* oh, well */
514 colons = 0;
517 /* find the tag */
518 if (find(argv[i]))
520 exit(0);
523 exit(1);
524 /*NOTREACHED*/