home *** CD-ROM | disk | FTP | other *** search
- /* ref2.c */
-
- /* This is a totally rewritten version of ref. This version looks for the
- * desired function name in the "tags" file, and then reads the header out
- * from the source file. There is no longer any need for a "refs" file.
- *
- * Usage: ref [-a] [-t] [-f file] [-c class] tag
- * Options: -t output tag info, not the description
- * -f file default filename for static functions
- * -c class default class names for class functions
- */
-
- #include <stdio.h>
- #include "config.h"
- extern char *getenv();
- extern char *fgets();
-
-
- /* This is the default path that is searched for tags */
- #if OSK
- # define DEFTAGPATH ".:/dd/defs:/dd/defs/sys:/dd/usr/src/lib:../lib:/dd/usr/lib"
- #else
- # if ANY_UNIX
- # define DEFTAGPATH ".:/usr/include:/usr/include/sys:/usr/src/lib:../lib:/usr/local/lib"
- # else
- # if MSDOS || TOS
- # define DEFTAGPATH ".;C:\\include;C:\\include\\sys;C:\\lib;..\\lib"
- # define SEP ';'
- # else
- # if AMIGA
- # define DEFTAGPATH ".;Include:;Include:sys"
- # define SEP ';'
- # else /* any other OS */
- # define DEFTAGPATH "."
- # endif
- # endif
- # endif
- #endif
-
- #ifndef SEP
- # define SEP ':'
- #endif
-
-
- /* These variables reflect the command-line options given by the user. */
- int taginfo; /* boolean: give only the tag info? (not header?) */
- char *def_file; /* default filename for static functions */
- char *def_class; /* default classname for class members */
- int colons; /* #colons in tag: 0=normal, 1=static, 2=member */
-
- /* This function checks for a tag in the "tags" file of given directory.
- * If the tag is found, then it returns a pointer to a static buffer which
- * contains the filename, a tab character, and a linespec for finding the
- * the tag. If the tag is not found in the "tags" file, or if the "tags"
- * file cannot be opened or doesn't exist, then this function returns NULL.
- */
- char *cktagdir(tag, dir)
- char *tag; /* name of the tag to look for */
- char *dir; /* name of the directory to check */
- {
- char buf[BLKSIZE];
- static char found[BLKSIZE];
- FILE *tfile;
- int len;
-
- #if AMIGA
- if (dir[strlen(dir) - 1] == COLON)
- sprintf(buf, "%s%s", dir, TAGS); /* no slash after colon. */
- else
- #endif
- /* construct the name of the "tags" file in this directory */
- sprintf(buf, "%s%c%s", dir, SLASH, TAGS);
-
- /* Try to open the tags file. Return NULL if can't open */
- #if AMIGA
- if (buf[0] == '.' && buf[1] == SLASH)
- tfile = fopen(&buf[2], "r");
- else
- #endif
- tfile = fopen(buf, "r");
- if (!tfile)
- {
- return (char *)0;
- }
-
- /* compute the length of the tagname once */
- len = strlen(tag);
-
- /* read lines until we get the one for this tag */
- found[0] = '\0';
- while (fgets(buf, sizeof buf, tfile))
- {
- /* is this the one we want? */
- if (!strncmp(buf, tag, len) && buf[len] == '\t')
- {
- /* we've found a match -- remember it */
- strcpy(found, buf);
-
- /* if there is no default file, or this match is in
- * the default file, then we've definitely found the
- * one we want. Break out of the loop now.
- */
- if (!def_file || !strncmp(&buf[len + 1], def_file, strlen(def_file)))
- {
- break;
- }
- }
- }
-
- /* we're through reading */
- fclose(tfile);
-
- /* if there's anything in found[], use it */
- if (found[0])
- {
- return &found[len + 1];
- }
-
- /* else we didn't find it */
- return (char *)0;
- }
-
- /* This function reads a single textline from a binary file. It returns
- * the number of bytes read, or 0 at EOF.
- */
- int getline(buf, limit, fp)
- char *buf; /* buffer to read into */
- int limit; /* maximum characters to read */
- FILE *fp; /* binary stream to read from */
- {
- int bytes; /* number of bytes read so far */
- int ch; /* single character from file */
-
- for (bytes = 0, ch = 0; ch != '\n' && --limit > 0 && (ch = getc(fp)) != EOF; bytes++)
- {
- #if MSDOS || TOS
- /* since this is a binary file, we'll need to manually strip CR's */
- if (ch == '\r')
- {
- continue;
- }
- #endif
- *buf++ = ch;
- }
- *buf = '\0';
-
- return bytes;
- }
-
-
- /* This function reads a source file, looking for a given tag. If it finds
- * the tag, then it displays it and returns TRUE. Otherwise it returns FALSE.
- * To display the tag, it attempts to output any introductory comment, the
- * tag line itself, and any arguments. Arguments are assumed to immediately
- * follow the tag line, and start with whitespace. Comments are assumed to
- * start with lines that begin with "/*", "//", "(*", or "--", and end at the
- * tag line or at a blank line.
- */
- int lookup(dir, entry)
- char *dir; /* name of the directory that contains the source */
- char *entry; /* source filename, <Tab>, linespec */
- {
- char buf[BLKSIZE]; /* pathname of sourcefile */
- long lnum; /* line number */
- long here; /* seek position where current line began */
- long comment; /* seek position of introductory comment, or -1L */
- FILE *sfile; /* used for reading the source file */
- int len; /* length of string */
- char *ptr;
-
-
- /* construct the pathname of the source file */
- strcpy(buf, dir);
- ptr = buf + strlen(buf);
- #if AMIGA
- if (ptr[-1] != COLON)
- #endif
- *ptr++ = SLASH;
- while (*entry != '\t')
- {
- *ptr++ = *entry++;
- }
- *ptr = '\0';
- entry++;
-
- /* searching for string or number? */
- if (*entry >= '0' && *entry <= '9')
- {
- /* given a specific line number */
- lnum = atol(entry);
- entry = (char *)0;
- }
- else
- {
- /* given a string -- strip off "/^" and "$/\n" */
- entry += 2;
- len = strlen(entry) - 2;
- if (entry[len - 1] == '$')
- {
- entry[len - 1] = '\n';
- }
- lnum = 0L;
- }
-
- /* Open the file. Note that we open the file in binary mode even
- * though we know it is a text file, because ftell() and fseek()
- * don't work on text files.
- */
- #if MSDOS || TOS
- sfile = fopen(buf, "rb");
- #else
- # if AMIGA
- if (buf[0] == '.' && buf[1] == SLASH)
- sfile = fopen(&buf[2], "r");
- else
- # endif
- sfile = fopen(buf, "r");
- #endif
- if (!sfile)
- {
- /* can't open the real source file. Try "refs" instead */
- #if AMIGA
- if (dir[strlen(dir) - 1] == COLON)
- sprintf(buf, "%srefs", dir);
- else
- #endif
- sprintf(buf, "%s%crefs", dir, SLASH);
- #if MSDOS || TOS
- sfile = fopen(buf, "rb");
- #else
- # if AMIGA
- if (buf[0] == '.' && buf[1] == SLASH)
- sfile = fopen(&buf[2], "r");
- else
- # endif
- sfile = fopen(buf, "r");
- #endif
- if (!sfile)
- {
- /* failed! */
- return 0;
- }
- }
-
- /* search the file */
- for (comment = -1L; here = ftell(sfile), getline(buf, BLKSIZE, sfile) > 0; )
- {
- /* Is this the start/end of a comment? */
- if (comment == -1L)
- {
- /* starting a comment? */
- if (buf[0] == '/' && buf[1] == '*'
- || buf[0] == '/' && buf[1] == '/'
- || buf[0] == '(' && buf[1] == '*'
- || buf[0] == '-' && buf[1] == '-')
- {
- comment = here;
- }
- }
- else
- {
- /* ending a comment? */
- if (buf[0] == '\n' || buf[0] == '#')
- {
- comment = -1L;
- }
- }
-
- /* is this the tag line? */
- if (--lnum == 0L || (entry && !strncmp(buf, entry, len)))
- {
- /* if there were introductory comments, show them */
- if (comment != -1L)
- {
- fseek(sfile, comment, 0);
- while (comment != here)
- {
- getline(buf, BLKSIZE, sfile);
- fputs(buf, stdout);
- comment = ftell(sfile);
- }
-
- /* re-fetch the tag line */
- fgets(buf, BLKSIZE, sfile);
- }
-
- /* show the tag line */
- fputs(buf, stdout);
-
- /* show any argument lines */
- while (getline(buf, BLKSIZE, sfile) > 0
- && buf[0] != '#'
- && strchr(buf, '{') == (char *)0)
- {
- fputs(buf, stdout);
- }
-
- /* Done! Close the file, and return TRUE */
- fclose(sfile);
- return 1;
- }
- }
-
- /* not found -- return FALSE */
- return 0;
- }
-
- /* This function searches through the entire search path for a given tag.
- * If it finds the tag, then it displays the info and returns TRUE;
- * otherwise it returns FALSE.
- */
- int find(tag)
- char *tag; /* the tag to look up */
- {
- char *tagpath;
- char dir[80];
- char *ptr;
- int len;
-
- if (colons == 1)
- {
- /* looking for static function -- only look in current dir */
- tagpath = ".";
- }
- else
- {
- /* get the tagpath from the environment. Default to DEFTAGPATH */
- tagpath = getenv("TAGPATH");
- if (!tagpath)
- {
- tagpath = DEFTAGPATH;
- }
- }
-
- /* for each entry in the path... */
- while (*tagpath)
- {
- /* Copy the entry into the dir[] buffer */
- for (ptr = dir; *tagpath && *tagpath != SEP; tagpath++)
- {
- *ptr++ = *tagpath;
- }
- if (*tagpath == SEP)
- {
- tagpath++;
- }
-
- /* if the entry ended with "/tags", then strip that off */
- len = strlen(TAGS);
- if (&dir[len] < ptr && ptr[-len - 1] == SLASH && !strncmp(&ptr[-len], TAGS, len))
- {
- ptr -= len + 1;
- }
-
- /* if the entry is now an empty string, then assume "." */
- if (ptr == dir)
- {
- *ptr++ = '.';
- }
- *ptr = '\0';
-
- /* look for the tag in this path. If found, then display it
- * and exit.
- */
- ptr = cktagdir(tag, dir);
- if (ptr)
- {
- /* just supposed to display tag info? */
- if (taginfo)
- {
- /* then do only that! */
- if (strcmp(dir, "."))
- {
- printf("%s%c%s", dir, SLASH, ptr);
- }
- else
- {
- /* avoid leading "./" if possible */
- fputs(ptr, stdout);
- }
- return 1;
- }
- else
- {
- /* else look up the declaration of the thing */
- return lookup(dir, ptr);
- }
- }
- }
-
- /* if we get here, then the tag wasn't found anywhere */
- return 0;
- }
-
- void usage()
- {
- fputs("usage: ref [-a] [-t] [-c class] [-f file] tag\n", stderr);
- fputs(" -a function's args may be flush against left margin\n", stderr);
- fputs(" -t output tag info, instead of the function header\n", stderr);
- fputs(" -f File tag might be a static function in File\n", stderr);
- fputs(" -c Class tag might be a member of class Class\n", stderr);
- exit(2);
- }
-
-
- int countcolons(str)
- char *str;
- {
- while (*str != ':' && *str)
- {
- str++;
- }
- if (str[0] != ':')
- {
- return 0;
- }
- else if (str[1] != ':')
- {
- return 1;
- }
- return 2;
- }
-
- int main(argc, argv)
- int argc;
- char **argv;
- {
- char def_tag[100]; /* used to build tag name with default file/class */
- int i;
-
- /* parse flags */
- for (i = 1; i < argc && argv[i][0] == '-'; i++)
- {
- switch (argv[i][1])
- {
- case 't':
- taginfo = 1;
- break;
-
- case 'f':
- if (argv[i][2])
- {
- def_file = &argv[i][2];
- }
- else if (++i < argc)
- {
- def_file = argv[i];
- }
- else
- {
- usage();
- }
- break;
-
- case 'c':
- if (argv[i][2])
- {
- def_class = &argv[i][2];
- }
- else if (++i < argc)
- {
- def_class = argv[i];
- }
- else
- {
- usage();
- }
- break;
-
- default:
- usage();
- }
- }
-
- /* if no tag was given, complain */
- if (i + 1 != argc)
- {
- usage();
- }
-
- /* does the tag have an explicit class or file? */
- colons = countcolons(argv[i]);
-
- /* if not, then maybe try some defaults */
- if (colons == 0)
- {
- /* try a static function in the file first */
- if (def_file)
- {
- sprintf(def_tag, "%s:%s", def_file, argv[i]);
- colons = 1;
- if (find(def_tag))
- {
- exit(0);
- }
- }
-
- /* try a member function for a class */
- if (def_class)
- {
- sprintf(def_tag, "%s::%s", def_class, argv[i]);
- colons = 2;
- if (find(def_tag))
- {
- exit(0);
- }
- }
-
- /* oh, well */
- colons = 0;
- }
-
- /* find the tag */
- if (find(argv[i]))
- {
- exit(0);
- }
-
- exit(1);
- /*NOTREACHED*/
- }
-