This is ref.c in view mode; [Download] [Up]
/* ref.c */ char id_ref[] = "$Id: ref.c,v 2.8 1996/09/21 02:12:31 steve Exp $"; /* This program looks for a givne tag in the "tags" file, and then tries to * locate the definition in the original source file, and display it. If the * original source file is unreadable then it looks for it in a file named * "refs". * * Usage: ref [-t] [-x] [-f file] [-c class] tag * Options: -t output tag info, not the definition * -x require exact match * -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 "elvis.h" #define JUST_DIRPATH #include "osdir.c" #ifndef BLKSIZE # define BLKSIZE 512 #endif #ifndef TAGS # define TAGS "tags" #endif #ifndef REFS # define REFS "refs" #endif 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 || OS2 # define DEFTAGPATH ".;C:\\include;C:\\include\\sys;C:\\lib;..\\lib" # define OSPATHDELIM ';' # else # if AMIGA # define DEFTAGPATH ".;Include:;Include:sys" # define OSPATHDELIM ';' # else /* any other OS */ # define DEFTAGPATH "." # endif # endif # endif #endif #ifndef OSPATHDELIM # define OSPATHDELIM ':' #endif /* These variables reflect the command-line options given by the user. */ int taginfo; /* boolean: give only the tag info? (not header?) */ int exact; /* boolean: require exact match? */ 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; unsigned len; char *scan; /* first try to open a "tags" file in the directory. If that fails, * then try to open dir as a regular file itself. */ tfile = fopen(dirpath(dir, TAGS), "r"); if (!tfile) { tfile = fopen(dir, "r"); if (!tfile) { return (char *)0; } /* If we get here, the "dir" variable must contain the name of * a file, not a directory. Get the directory name from it. */ strcpy(dir, dirdir(dir)); } /* 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; } } /* does it maybe match the stuff after the colons? */ if (!exact) { scan = strchr(buf, '\t'); if (scan && (unsigned int)(scan - buf) > len && scan[-(int)len - 1] == ':' && !strncmp(tag, scan - len, len)) { strcpy(found, buf); len = (int)(scan - buf); 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 || OS2 /* 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 */ unsigned len = 0; /* length of string */ int noargs = 0; /* boolean: don't show lines after tag line? */ unsigned i, j; /* skip past the name, to find the linespec */ name = entry; do { if (!*entry) { printf("malformed tag line: \"%s\"\n", name); } } while (*entry++ != '\t'); entry[-1] = '\0'; /* construct the pathname of the source file */ strcpy(buf, dirpath(dir, name)); /* searching for regexp 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'; } /* delete backslashes used for quoting characters */ for (i = j = 0; i < len; ) { if (entry[i] == '\\' && i + 1 < len && strchr("\\?/", entry[i + 1])) { i++; } entry[j++] = entry[i++]; } len = j; /* decide whether we'll need to show following lines */ if (!strchr(entry, '(')) { noargs = 1; } lnum = 0L; } /* Open the file. */ sfile = fopen(buf, "rb"); if (!sfile) { /* can't open the real source file. Try "refs" instead */ strcpy(buf, dirpath(dir, REFS)); sfile = fopen(buf, "rb"); 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 tag line? */ if (lnum == thislnum || (entry && !strncmp(buf, entry, len))) { /* display the filename & line number where found */ printf("%s, line %ld:\n", dirpath(dir, 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; } /* 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] == '-') || (strlen(buf) >= 2 && buf[strlen(buf) - 2] == '{')) { comment = here; } } else { /* ending a comment? */ if (buf[0] == '\n' || buf[0] == '#' || buf[0] == '}' || (unsigned)buf[0] >= 'A') { comment = -1L; } } } /* 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; 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 != OSPATHDELIM; tagpath++) { *ptr++ = *tagpath; } if (*tagpath == OSPATHDELIM) { tagpath++; } /* 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! */ printf("%s\n", dirpath(dir, ptr)); 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] [-x] [-c class] [-f file] tag\n", stderr); fputs(" -t output tag info, instead of the function header\n", stderr); fputs(" -x require exact match, including colons\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); fputs("Report bugs to kirkenda@cs.pdx.edu\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; /* detect special GNU flags */ if (argc >= 2) { if (!strcmp(argv[1], "-v") || !strcmp(argv[1], "-version") || !strcmp(argv[1], "--version")) { printf("ref (elvis) %s\n", VERSION); #ifdef COPY1 puts(COPY1); #endif #ifdef COPY2 puts(COPY2); #endif #ifdef COPY3 puts(COPY3); #endif #ifdef COPY4 puts(COPY4); #endif exit(0); } } /* parse flags */ for (i = 1; i < argc && argv[i][0] == '-'; i++) { switch (argv[i][1]) { case 't': taginfo = 1; break; case 'x': exact = 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; } else /* at least one colon was given */ { /* this implies -x */ exact = 1; } /* find the tag */ if (find(argv[i])) { exit(0); } /* Give up. If doing tag lookup then exit(0), else exit(1) */ exit(!taginfo); /*NOTREACHED*/ }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.