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