/* 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 [-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
extern char *cktagdir
P_((char *, char *));
extern int getline
P_((char *, int, FILE *));
extern int lookup
P_((char *, char *));
extern int find
P_((char *));
extern void usage
P_((void));
extern int countcolons
P_((char *));
extern void main
P_((int, char **));
/* This is the default path that is searched for tags */
# define DEFTAGPATH ".:/dd/defs:/dd/defs/sys:/dd/usr/src/lib:../lib:/dd/usr/lib"
# define DEFTAGPATH ".:/usr/include:/usr/include/sys:/usr/src/lib:../lib:/usr/local/lib"
# define DEFTAGPATH ".;C:\\include;C:\\include\\sys;C:\\lib;..\\lib"
# define DEFTAGPATH ".;Include:;Include:sys"
# else /* any other OS */
/* 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 *tag
; /* name of the tag to look for */
char *dir
; /* name of the directory to check */
static char found
[BLKSIZE
];
if (dir
[strlen(dir
) - 1] == COLON
)
sprintf(buf
, "%s%s", dir
, TAGS
); /* no slash after colon. */
/* 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 (buf
[0] == '.' && buf
[1] == SLASH
)
tfile
= fopen(&buf
[2], "r");
/* compute the length of the tagname once */
/* read lines until we get the one for this tag */
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 */
/* 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
)))
/* we're through reading */
/* if there's anything in found[], use it */
/* else we didn't find it */
/* 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
++)
/* since this is a binary file, we'll need to manually strip CR's */
/* 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.
char *dir
; /* name of the directory that contains the source */
char *entry
; /* source filename, <Tab>, linespec */
char *name
; /* basename of source file */
char buf
[BLKSIZE
]; /* pathname of source file */
long lnum
; /* desired line number */
long thislnum
; /* current 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 */
int noargs
= 0; /* boolean: don't show lines after tag line? */
/* construct the pathname of the source file */
/* searching for string or number? */
if (*entry
>= '0' && *entry
<= '9')
/* given a specific line number */
/* given a string -- strip off "/^" and "$/\n" */
if (entry
[len
- 1] == '$')
/* 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.
sfile
= fopen(buf
, "rb");
if (buf
[0] == '.' && buf
[1] == SLASH
)
sfile
= fopen(&buf
[2], "r");
/* can't open the real source file. Try "refs" instead */
if (dir
[strlen(dir
) - 1] == COLON
)
sprintf(buf
, "%srefs", dir
);
sprintf(buf
, "%s%crefs", dir
, SLASH
);
sfile
= fopen(buf
, "rb");
if (buf
[0] == '.' && buf
[1] == SLASH
)
sfile
= fopen(&buf
[2], "r");
for (comment
= -1L, thislnum
= 0; here
= ftell(sfile
), thislnum
++, getline(buf
, BLKSIZE
, sfile
) > 0; )
/* Is this the start/end of a comment? */
/* starting a comment? */
if (buf
[0] == '/' && buf
[1] == '*'
|| buf
[0] == '/' && buf
[1] == '/'
|| buf
[0] == '(' && buf
[1] == '*'
|| buf
[0] == '-' && buf
[1] == '-')
if (buf
[0] == '\n' || buf
[0] == '#')
/* is this the tag line? */
if (lnum
== thislnum
|| (entry
&& !strncmp(buf
, entry
, len
)))
/* display the filename & line number where found */
printf("%s%c%s, line %ld:\n", dir
, SLASH
, name
, thislnum
);
printf("%s, line %ld:\n", name
, thislnum
);
/* if there were introductory comments, show them */
fseek(sfile
, comment
, 0);
getline(buf
, BLKSIZE
, sfile
);
/* re-fetch the tag line */
fgets(buf
, BLKSIZE
, sfile
);
/* are we expected to show argument lines? */
/* show any argument lines */
while (getline(buf
, BLKSIZE
, sfile
) > 0
&& strchr(buf
, '{') == (char *)0)
/* Done! Close the file, and return TRUE */
/* not found -- return FALSE */
/* 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.
char *tag
; /* the tag to look up */
/* looking for static function -- only look in current dir */
/* get the tagpath from the environment. Default to DEFTAGPATH */
tagpath
= getenv("TAGPATH");
/* for each entry in the path... */
/* Copy the entry into the dir[] buffer */
for (ptr
= dir
; *tagpath
&& *tagpath
!= SEP
; tagpath
++)
/* if the entry ended with "/tags", then strip that off */
if (&dir
[len
] < ptr
&& ptr
[-len
- 1] == SLASH
&& !strncmp(&ptr
[-len
], TAGS
, len
))
/* if the entry is now an empty string, then assume "." */
/* look for the tag in this path. If found, then display it
ptr
= cktagdir(tag
, dir
);
/* just supposed to display tag info? */
printf("%s%c%s", dir
, SLASH
, ptr
);
/* avoid leading "./" if possible */
/* else look up the declaration of the thing */
/* if we get here, then the tag wasn't found anywhere */
fputs("usage: ref [-t] [-c class] [-f file] tag\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
);
while (*str
!= ':' && *str
)
char def_tag
[100]; /* used to build tag name with default file/class */
for (i
= 1; i
< argc
&& argv
[i
][0] == '-'; i
++)
/* if no tag was given, complain */
/* does the tag have an explicit class or file? */
colons
= countcolons(argv
[i
]);
/* if not, then maybe try some defaults */
/* try a static function in the file first */
sprintf(def_tag
, "%s:%s", def_file
, argv
[i
]);
/* try a member function for a class */
sprintf(def_tag
, "%s::%s", def_class
, argv
[i
]);
/* Give up. If doing tag lookup then exit(0), else exit(1) */