home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / apps / text_ed / elv16b2 / st / ref.c < prev    next >
C/C++ Source or Header  |  1992-05-13  |  12KB  |  539 lines

  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. #ifndef __STDC__
  28. extern char    *getenv P_((char *));
  29. #endif
  30.  
  31.  
  32. /* This is the default path that is searched for tags */
  33. #if OSK
  34. # define DEFTAGPATH ".:/dd/defs:/dd/defs/sys:/dd/usr/src/lib:../lib:/dd/usr/lib"
  35. #else
  36. # if ANY_UNIX
  37. #  define DEFTAGPATH ".:/usr/include:/usr/include/sys:/usr/src/lib:../lib:/usr/local/lib"
  38. # else
  39. #  if MSDOS || TOS || MINT
  40. #   if MINT
  41. #    define DEFTAGPATH ".;/usr/include;/usr/include/sys;/usr/src/lib;../lib;/usr/local/lib"
  42. #   else
  43. #    define DEFTAGPATH ".;C:\\include;C:\\include\\sys;C:\\lib;..\\lib"
  44. #   endif
  45. #   define SEP ';'
  46. #  else
  47. #   if AMIGA
  48. #    define DEFTAGPATH ".;Include:;Include:sys"
  49. #    define SEP ';'
  50. #   else /* any other OS */
  51. #    define DEFTAGPATH "."
  52. #   endif
  53. #  endif
  54. # endif
  55. #endif
  56.  
  57. #ifndef SEP
  58. # define SEP ':'
  59. #endif
  60.  
  61.  
  62. /* These variables reflect the command-line options given by the user. */
  63. int    taginfo;    /* boolean: give only the tag info? (not header?) */
  64. char    *def_file;    /* default filename for static functions */
  65. char    *def_class;    /* default classname for class members */
  66. int    colons;        /* #colons in tag: 0=normal, 1=static, 2=member */
  67.  
  68. /* This function checks for a tag in the "tags" file of given directory.
  69.  * If the tag is found, then it returns a pointer to a static buffer which
  70.  * contains the filename, a tab character, and a linespec for finding the
  71.  * the tag.  If the tag is not found in the "tags" file, or if the "tags"
  72.  * file cannot be opened or doesn't exist, then this function returns NULL.
  73.  */
  74. char *cktagdir(tag, dir)
  75.     char    *tag;    /* name of the tag to look for */
  76.     char    *dir;    /* name of the directory to check */
  77. {
  78.     char    buf[BLKSIZE];
  79.     static char found[BLKSIZE];
  80.     FILE    *tfile;
  81.     int    len;
  82.  
  83. #if AMIGA
  84.     if (dir[strlen(dir) - 1] == COLON)
  85.         sprintf(buf, "%s%s", dir, TAGS);   /* no slash after colon. */
  86.     else
  87. #endif
  88.     /* construct the name of the "tags" file in this directory */
  89.     sprintf(buf, "%s%c%s", dir, SLASH, TAGS);
  90.  
  91.     /* Try to open the tags file.  Return NULL if can't open */
  92. #if AMIGA
  93.     if (buf[0] == '.' && buf[1] == SLASH)
  94.         tfile = fopen(&buf[2], "r");
  95.     else
  96. #endif
  97.     tfile = fopen(buf, "r");
  98.     if (!tfile)
  99.     {
  100.         return (char *)0;
  101.     }
  102.  
  103.     /* compute the length of the tagname once */
  104.     len = strlen(tag);
  105.  
  106.     /* read lines until we get the one for this tag */
  107.     found[0] = '\0';
  108.     while (fgets(buf, (int) sizeof buf, tfile))
  109.     {
  110.         /* is this the one we want? */
  111.         if (!strncmp(buf, tag, len) && buf[len] == '\t')
  112.         {
  113.             /* we've found a match -- remember it */
  114.             strcpy(found, buf);
  115.  
  116.             /* if there is no default file, or this match is in
  117.              * the default file, then we've definitely found the
  118.              * one we want.  Break out of the loop now.
  119.              */
  120.             if (!def_file || !strncmp(&buf[len + 1], def_file, strlen(def_file)))
  121.             {
  122.                 break;
  123.             }
  124.         }
  125.     }
  126.  
  127.     /* we're through reading */
  128.     fclose(tfile);
  129.  
  130.     /* if there's anything in found[], use it */
  131.     if (found[0])
  132.     {
  133.         return &found[len + 1];
  134.     }
  135.  
  136.     /* else we didn't find it */
  137.     return (char *)0;
  138. }
  139.  
  140. /* This function reads a single textline from a binary file.  It returns
  141.  * the number of bytes read, or 0 at EOF.
  142.  */
  143. int getline(buf, limit, fp)
  144.     char    *buf;    /* buffer to read into */
  145.     int    limit;    /* maximum characters to read */
  146.     FILE    *fp;    /* binary stream to read from */
  147. {
  148.     int    bytes;    /* number of bytes read so far */
  149.     int    ch;    /* single character from file */
  150.  
  151.     for (bytes = 0, ch = 0; ch != '\n' && --limit > 0 && (ch = getc(fp)) != EOF; bytes++)
  152.     {
  153. #if MSDOS || TOS || MINT
  154.         /* since this is a binary file, we'll need to manually strip CR's */
  155.         if (ch == '\r')
  156.         {
  157.             continue;
  158.         }
  159. #endif
  160.         *buf++ = ch;
  161.     }
  162.     *buf = '\0';
  163.  
  164.     return bytes;
  165. }
  166.  
  167.  
  168. /* This function reads a source file, looking for a given tag.  If it finds
  169.  * the tag, then it displays it and returns TRUE.  Otherwise it returns FALSE.
  170.  * To display the tag, it attempts to output any introductory comment, the
  171.  * tag line itself, and any arguments.  Arguments are assumed to immediately
  172.  * follow the tag line, and start with whitespace.  Comments are assumed to
  173.  * start with lines that begin with "/*", "//", "(*", or "--", and end at the
  174.  * tag line or at a blank line.
  175.  */
  176. int lookup(dir, entry)
  177.     char    *dir;    /* name of the directory that contains the source */
  178.     char    *entry;    /* source filename, <Tab>, linespec */
  179. {
  180.     char    buf[BLKSIZE];    /* pathname of sourcefile */
  181.     long    lnum;        /* line number */
  182.     long    here;        /* seek position where current line began */
  183.     long    comment;    /* seek position of introductory comment, or -1L */
  184.     FILE    *sfile;        /* used for reading the source file */
  185.     int    len;        /* length of string */
  186.     char    *ptr;
  187.  
  188.  
  189.     /* construct the pathname of the source file */
  190.     strcpy(buf, dir);
  191.     ptr = buf + strlen(buf);
  192. #if AMIGA
  193.     if (ptr[-1] != COLON)
  194. #endif
  195.     *ptr++ = SLASH;
  196.     while (*entry != '\t')
  197.     {
  198.         *ptr++ = *entry++;
  199.     }
  200.     *ptr = '\0';
  201.     entry++;
  202.  
  203.     /* searching for string or number? */
  204.     if (*entry >= '0' && *entry <= '9')
  205.     {
  206.         /* given a specific line number */
  207.         lnum = atol(entry);
  208.         entry = (char *)0;
  209.     }
  210.     else
  211.     {
  212.         /* given a string -- strip off "/^" and "$/\n" */
  213.         entry += 2;
  214.         len = strlen(entry) - 2;
  215.         if (entry[len - 1] == '$')
  216.         {
  217.             entry[len - 1] = '\n';
  218.         }
  219.         lnum = 0L;
  220.     }
  221.  
  222.     /* Open the file.  Note that we open the file in binary mode even
  223.      * though we know it is a text file, because ftell() and fseek()
  224.      * don't work on text files.
  225.      */
  226. #if MSDOS || TOS || MINT
  227.     sfile = fopen(buf, "rb");
  228. #else
  229. # if AMIGA
  230.     if (buf[0] == '.' && buf[1] == SLASH)
  231.         sfile = fopen(&buf[2], "r");
  232.     else
  233. # endif
  234.     sfile = fopen(buf, "r");
  235. #endif
  236.     if (!sfile)
  237.     {
  238.         /* can't open the real source file.  Try "refs" instead */
  239. #if AMIGA
  240.         if (dir[strlen(dir) - 1] == COLON)
  241.             sprintf(buf, "%srefs", dir);
  242.         else
  243. #endif
  244.         sprintf(buf, "%s%crefs", dir, SLASH);
  245. #if MSDOS || TOS || MINT
  246.         sfile = fopen(buf, "rb");
  247. #else
  248. # if AMIGA
  249.         if (buf[0] == '.' && buf[1] == SLASH)
  250.             sfile = fopen(&buf[2], "r");
  251.         else
  252. # endif
  253.         sfile = fopen(buf, "r");
  254. #endif
  255.         if (!sfile)
  256.         {
  257.             /* failed! */
  258.             return 0;
  259.         }
  260.     }
  261.  
  262.     /* search the file */
  263.     for (comment = -1L; here = ftell(sfile), getline(buf, BLKSIZE, sfile) > 0; )
  264.     {
  265.         /* Is this the start/end of a comment? */
  266.         if (comment == -1L)
  267.         {
  268.             /* starting a comment? */
  269.             if (buf[0] == '/' && buf[1] == '*'
  270.              || buf[0] == '/' && buf[1] == '/'
  271.              || buf[0] == '(' && buf[1] == '*'
  272.              || buf[0] == '-' && buf[1] == '-')
  273.             {
  274.                 comment = here;
  275.             }
  276.         }
  277.         else
  278.         {
  279.             /* ending a comment? */
  280.             if (buf[0] == '\n' || buf[0] == '#')
  281.             {
  282.                 comment = -1L;
  283.             }
  284.         }
  285.  
  286.         /* is this the tag line? */
  287.         if (--lnum == 0L || (entry && !strncmp(buf, entry, len)))
  288.         {
  289.             /* if there were introductory comments, show them */
  290.             if (comment != -1L)
  291.             {
  292.                 fseek(sfile, comment, 0);
  293.                 while (comment != here)
  294.                 {
  295.                     getline(buf, BLKSIZE, sfile);
  296.                     fputs(buf, stdout);
  297.                     comment = ftell(sfile);
  298.                 }
  299.  
  300.                 /* re-fetch the tag line */
  301.                 fgets(buf, BLKSIZE, sfile);
  302.             }
  303.  
  304.             /* show the tag line */
  305.             fputs(buf, stdout);
  306.  
  307.             /* show any argument lines */
  308.             while (getline(buf, BLKSIZE, sfile) > 0
  309.                 && buf[0] != '#'
  310.                 && strchr(buf, '{') == (char *)0)
  311.             {
  312.                 fputs(buf, stdout);
  313.             }
  314.  
  315.             /* Done!  Close the file, and return TRUE */
  316.             fclose(sfile);
  317.             return 1;
  318.         }
  319.     }
  320.  
  321.     /* not found -- return FALSE */
  322.     return 0;
  323. }
  324.  
  325. /* This function searches through the entire search path for a given tag.
  326.  * If it finds the tag, then it displays the info and returns TRUE;
  327.  * otherwise it returns FALSE.
  328.  */
  329. int find(tag)
  330.     char    *tag;    /* the tag to look up */
  331. {
  332.     char    *tagpath;
  333.     char    dir[80];
  334.     char    *ptr;
  335.     int    len;
  336.  
  337.     if (colons == 1)
  338.     {
  339.         /* looking for static function -- only look in current dir */
  340.         tagpath = ".";
  341.     }
  342.     else
  343.     {
  344.         /* get the tagpath from the environment.  Default to DEFTAGPATH */
  345.         tagpath = getenv("TAGPATH");
  346.         if (!tagpath)
  347.         {
  348.             tagpath = DEFTAGPATH;
  349.         }
  350.     }
  351.  
  352.     /* for each entry in the path... */
  353.     while (*tagpath)
  354.     {
  355.         /* Copy the entry into the dir[] buffer */
  356.         for (ptr = dir; *tagpath && *tagpath != SEP; tagpath++)
  357.         {
  358.             *ptr++ = *tagpath;
  359.         }
  360.         if (*tagpath == SEP)
  361.         {
  362.             tagpath++;
  363.         }
  364.  
  365.         /* if the entry ended with "/tags", then strip that off */
  366.         len = strlen(TAGS);
  367.         if (&dir[len] < ptr && ptr[-len - 1] == SLASH && !strncmp(&ptr[-len], TAGS, len))
  368.         {
  369.             ptr -= len + 1;
  370.         }
  371.  
  372.         /* if the entry is now an empty string, then assume "." */
  373.         if (ptr == dir)
  374.         {
  375.             *ptr++ = '.';
  376.         }
  377.         *ptr = '\0';
  378.  
  379.         /* look for the tag in this path.  If found, then display it
  380.          * and exit.
  381.          */
  382.         ptr = cktagdir(tag, dir);
  383.         if (ptr)
  384.         {
  385.             /* just supposed to display tag info? */
  386.             if (taginfo)
  387.             {
  388.                 /* then do only that! */
  389.                 if (strcmp(dir, "."))
  390.                 {
  391.                     printf("%s%c%s", dir, SLASH, ptr);
  392.                 }
  393.                 else
  394.                 {
  395.                     /* avoid leading "./" if possible */
  396.                     fputs(ptr, stdout);
  397.                 }
  398.                 return 1;
  399.             }
  400.             else
  401.             {
  402.                 /* else look up the declaration of the thing */
  403.                 return lookup(dir, ptr);
  404.             }
  405.         }
  406.     }
  407.  
  408.     /* if we get here, then the tag wasn't found anywhere */
  409.     return 0;
  410. }
  411.  
  412. void usage()
  413. {
  414.     fputs("usage: ref [-a] [-t] [-c class] [-f file] tag\n", stderr);
  415.     fputs("   -a        function's args may be flush against left margin\n", stderr);
  416.     fputs("   -t        output tag info, instead of the function header\n", stderr);
  417.     fputs("   -f File   tag might be a static function in File\n", stderr);
  418.     fputs("   -c Class  tag might be a member of class Class\n", stderr);
  419.     exit(2);
  420. }
  421.  
  422.  
  423. int countcolons(str)
  424.     char    *str;
  425. {
  426.     while (*str != ':' && *str)
  427.     {
  428.         str++;
  429.     }
  430.     if (str[0] != ':')
  431.     {
  432.         return 0;
  433.     }
  434.     else if (str[1] != ':')
  435.     {
  436.         return 1;
  437.     }
  438.     return 2;
  439. }
  440.  
  441. void main(argc, argv)
  442.     int    argc;
  443.     char    **argv;
  444. {
  445.     char    def_tag[100];    /* used to build tag name with default file/class */
  446.     int    i;
  447.  
  448.     /* parse flags */
  449.     for (i = 1; i < argc && argv[i][0] == '-'; i++)
  450.     {
  451.         switch (argv[i][1])
  452.         {
  453.           case 't':
  454.             taginfo = 1;
  455.             break;
  456.  
  457.           case 'f':
  458.             if (argv[i][2])
  459.             {
  460.                 def_file = &argv[i][2];
  461.             }
  462.             else if (++i < argc)
  463.             {
  464.                 def_file = argv[i];
  465.             }
  466.             else
  467.             {
  468.                 usage();
  469.             }
  470.             break;
  471.  
  472.           case 'c':
  473.             if (argv[i][2])
  474.             {
  475.                 def_class = &argv[i][2];
  476.             }
  477.             else if (++i < argc)
  478.             {
  479.                 def_class = argv[i];
  480.             }
  481.             else
  482.             {
  483.                 usage();
  484.             }
  485.             break;
  486.  
  487.           default:
  488.             usage();
  489.         }
  490.     }
  491.  
  492.     /* if no tag was given, complain */
  493.     if (i + 1 != argc)
  494.     {
  495.         usage();
  496.     }
  497.  
  498.     /* does the tag have an explicit class or file? */
  499.     colons = countcolons(argv[i]);
  500.  
  501.     /* if not, then maybe try some defaults */
  502.     if (colons == 0)
  503.     {
  504.         /* try a static function in the file first */
  505.         if (def_file)
  506.         {
  507.             sprintf(def_tag, "%s:%s", def_file, argv[i]);
  508.             colons = 1;
  509.             if (find(def_tag))
  510.             {
  511.                 exit(0);
  512.             }
  513.         }
  514.  
  515.         /* try a member function for a class */
  516.         if (def_class)
  517.         {
  518.             sprintf(def_tag, "%s::%s", def_class, argv[i]);
  519.             colons = 2;
  520.             if (find(def_tag))
  521.             {
  522.                 exit(0);
  523.             }
  524.         }
  525.  
  526.         /* oh, well */
  527.         colons = 0;
  528.     }
  529.  
  530.     /* find the tag */
  531.     if (find(argv[i]))
  532.     {
  533.         exit(0);
  534.     }
  535.  
  536.     exit(1);
  537.     /*NOTREACHED*/
  538. }
  539.