|
|
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.