aboutsummaryrefslogtreecommitdiff
path: root/usr.bin/ref
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1993-11-01 08:00:00 +0000
committersvn2git <svn2git@FreeBSD.org>1993-11-01 08:00:00 +0000
commit8503f4f13f77abf7adc8f7e329c6f9c1d52b6a20 (patch)
treec5b2ce776438e0a52b492a2ab6ab41360b8ba1f6 /usr.bin/ref
This commit was manufactured to restore the state of the 1.0-RELEASE image. Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'usr.bin/ref')
-rw-r--r--usr.bin/ref/Makefile7
-rw-r--r--usr.bin/ref/ref.188
-rw-r--r--usr.bin/ref/ref.c550
3 files changed, 645 insertions, 0 deletions
diff --git a/usr.bin/ref/Makefile b/usr.bin/ref/Makefile
new file mode 100644
index 000000000000..32de9d5103cd
--- /dev/null
+++ b/usr.bin/ref/Makefile
@@ -0,0 +1,7 @@
+
+PROG= ref
+CFLAGS+=-I${.CURDIR}/../elvis
+SRCS= ref.c
+
+.include <bsd.prog.mk>
+.PATH: ${.CURDIR}/../elvis
diff --git a/usr.bin/ref/ref.1 b/usr.bin/ref/ref.1
new file mode 100644
index 000000000000..e7d2e178f144
--- /dev/null
+++ b/usr.bin/ref/ref.1
@@ -0,0 +1,88 @@
+.TH REF 1
+.SH NAME
+ref - Display a C function header
+.SH SYNOPSIS
+\fBref\fR [-t] [-c \fIclass\fR]... [-f \fIfile\fR]... \fItag\fR
+.SH DESCRIPTION
+\fIref\fP quickly locates and displays the header of a function.
+To do this, \fIref\fR
+looks in the "tags" file for the line that describes the function, and then
+scans the source file for the function.
+When it locates the function, it displays an introductory comment
+(if there is one), the function's declaration, and the declarations of all
+arguments.
+.SH "SEARCH METHOD"
+.PP
+\fIref\fR uses a fairly sophisticated tag look-up algorithm.
+If you supply a filename via \fB-f\fR \fIfile\fR, then elvis first scans
+the tags file for a static tag from that file.
+This search is limited to the tags file in the current directory.
+.PP
+If you supply a classname via \fB-c\fR \fIclass\fR, then elvis searches
+for a tag from that class.
+This search is not limited to the current directory;
+You can supply a list of directories in the environment variable \fITAGPATH\fR,
+and \fIref\fR will search through the "tags" file in each directory until it finds
+a tag in the desired class.
+.PP
+If that fails, \fIref\fR will then try to look up an ordinary global tag.
+This search checks all of the directories listed in \fITAGPATH\fR, too.
+.PP
+If you've given the \fB-t\fR flag, then \fIref\fR will simply output the tag line that
+it found, and then exit.
+Without \fB-t\fR, though, \fIref\fR will search for the tag line.
+It will try to open the source file, which should be in the same directory
+as the tags file where the tag was discovered.
+If the source file doesn't exist, or is unreadable, then \fIref\fR will try to open
+a file called "\fIrefs\fR" in that directory.
+Either way, \fIref\fR will try to locate the tag, and display whatever it finds.
+.SH "INTERACTION WITH ELVIS"
+.PP
+\fIref\fP is used by \fIelvis\fR' shift-K command.
+If the cursor is located on a word such as "splat", in the file "foo.c",
+then \fIelvis\fR will invoke \fIref\fR with the command "ref -f foo.c splat".
+.PP
+If \fIelvis\fR has been compiled with the -DEXTERNAL_TAGS flag, then \fIelvis\fR will
+use \fIref\fR \fB\fRto scan the tags files.
+This is slower than the built-in tag searching, but it allows \fIelvis\fR to access
+the more sophisticated tag lookup provided by \fIref\fR.
+Other than that, external tags should act exactly like internal tags.
+.SH OPTIONS
+.IP \fB-t\fR
+Output tag info, instead of the function header.
+.IP "\fB-f\fR \fIfile\fR"
+The tag might be a static function in \fIfile\fR.
+You can use several -f flags to have \fIref\fR consider static tags from more than one file.
+.IP "\fB-c\fR \fIclass\fR"
+The tag might be a member of class \fIclass\fR.
+You can use several -c flags to have \fIref\fR consider tags from more than one class.
+.SH FILES
+.IP \fBtags\fR
+List of function names and their locations, generated by \fIctags\fR.
+.IP \fBrefs\fR
+Function headers extracted from source files (optional).
+.SH ENVIRONMENT
+.IP \fBTAGPATH\fR
+List of directories to be searched.
+The elements in the list are separated by either
+semicolons (for MS-DOS, Atari TOS, and AmigaDos), or
+by colons (every other operating system).
+For each operating system, \fIref\fR has a built-in default which is probably
+adequate.
+.SH NOTES
+.PP
+You might want to generate a "tags" file the directory that contains the
+source code for standard C library on your system.
+If licensing restrictions prevent you from making the library source readable
+by everybody, then you can have \fIctags\fR generate a "refs" file,
+and make "refs" readable by everybody.
+.PP
+If your system doesn't come with the library source code, then perhaps you
+can produce something workable from the \fIlint\fR libraries.
+.SH "SEE ALSO"
+elvis(1), ctags(1)
+.SH AUTHOR
+.nf
+Steve Kirkendall
+kirkenda@cs.pdx.edu
+.fi
diff --git a/usr.bin/ref/ref.c b/usr.bin/ref/ref.c
new file mode 100644
index 000000000000..0cc105fbea15
--- /dev/null
+++ b/usr.bin/ref/ref.c
@@ -0,0 +1,550 @@
+/* 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 [-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
+ */
+#ifdef __STDC__
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include "config.h"
+
+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 */
+#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 *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? */
+ char *ptr;
+
+
+ /* construct the pathname of the source file */
+ name = entry;
+ strcpy(buf, dir);
+ ptr = buf + strlen(buf);
+#if AMIGA
+ if (ptr[-1] != COLON)
+#endif
+ *ptr++ = SLASH;
+ while (*entry != '\t')
+ {
+ *ptr++ = *entry++;
+ }
+ *entry++ = *ptr = '\0';
+
+ /* searching for string or number? */
+ if (*entry >= '0' && *entry <= '9')
+ {
+ /* given a specific line number */
+ lnum = atol(entry);
+ entry = (char *)0;
+ noargs = 1;
+ }
+ else
+ {
+ /* given a string -- strip off "/^" and "$/\n" */
+ entry += 2;
+ len = strlen(entry) - 2;
+ if (entry[len - 1] == '$')
+ {
+ entry[len - 1] = '\n';
+ }
+ if (!strchr(entry, '('))
+ {
+ noargs = 1;
+ }
+ 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;
+ }
+ name = "refs";
+ }
+
+ /* search the file */
+ for (comment = -1L, thislnum = 0; here = ftell(sfile), thislnum++, 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 == thislnum || (entry && !strncmp(buf, entry, len)))
+ {
+ /* display the filename & line number where found */
+ if (strcmp(dir, "."))
+ printf("%s%c%s, line %ld:\n", dir, SLASH, name, thislnum);
+ else
+ printf("%s, line %ld:\n", name, thislnum);
+
+ /* 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);
+
+ /* are we expected to show argument lines? */
+ if (!noargs)
+ {
+ /* 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 [-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);
+ exit(2);
+}
+
+
+int countcolons(str)
+ char *str;
+{
+ while (*str != ':' && *str)
+ {
+ str++;
+ }
+ if (str[0] != ':')
+ {
+ return 0;
+ }
+ else if (str[1] != ':')
+ {
+ return 1;
+ }
+ return 2;
+}
+
+void 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);
+ }
+
+ /* Give up. If doing tag lookup then exit(0), else exit(1) */
+ exit(!taginfo);
+ /*NOTREACHED*/
+}