home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / gnu / emacs-18.59-bin.lha / lib / emacs / 18.59 / etc / etags.c < prev    next >
C/C++ Source or Header  |  1993-05-09  |  34KB  |  1,643 lines

  1. /* Tags file maker to go with GNUmacs
  2.    Copyright (C) 1984, 1987, 1988 Free Software Foundation, Inc. and Ken Arnold
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 1, or (at your option)
  7.     any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. In other words, you are welcome to use, share and improve this program.
  19. You are forbidden to forbid anyone else to use, share and improve
  20. what you give them.   Help stamp out software-hoarding!  */
  21.  
  22. #include <stdio.h>
  23. #include <ctype.h>
  24.  
  25. /* Define the symbol ETAGS to make the program "etags",
  26.  which makes emacs-style tag tables by default.
  27.  Define CTAGS to make the program "ctags" compatible with the usual one.
  28.  Define neither one to get behavior that depends
  29.  on the name with which the program is invoked
  30.  (but we don't normally compile it that way).  */
  31.  
  32. /* On VMS, CTAGS is not useful, so always do ETAGS.  */
  33. #ifdef VMS
  34. #ifndef ETAGS
  35. #define ETAGS
  36. #endif
  37. #endif
  38.  
  39. /* Exit codes for success and failure.  */
  40.  
  41. #ifdef VMS
  42. #define    GOOD    (1)
  43. #define BAD    (0)
  44. #else
  45. #define    GOOD    (0)
  46. #define    BAD    (1)
  47. #endif
  48.  
  49. #define    reg    register
  50. #define    logical    char
  51.  
  52. #define    TRUE    (1)
  53. #define    FALSE    (0)
  54.  
  55. #define    iswhite(arg)    (_wht[arg])    /* T if char is white        */
  56. #define    begtoken(arg)    (_btk[arg])    /* T if char can start token    */
  57. #define    intoken(arg)    (_itk[arg])    /* T if char can be in token    */
  58. #define    endtoken(arg)    (_etk[arg])    /* T if char ends tokens    */
  59. #define    isgood(arg)    (_gd[arg])    /* T if char can be after ')'    */
  60.  
  61. #define    max(I1,I2)    (I1 > I2 ? I1 : I2)
  62.  
  63. /* cause token checking for typedef, struct, union, enum to distinguish
  64.    keywords from identifier-prefixes (e.g. struct vs struct_tag).  */
  65. #define istoken(s, tok, len) (!strncmp(s,tok,len) && endtoken(*((s)+(len))))
  66.  
  67. struct    nd_st {            /* sorting structure            */
  68.     char    *name;            /* function or type name    */
  69.     char    *file;            /* file name            */
  70.     logical f;            /* use pattern or line no    */
  71.     int    lno;            /* line number tag is on    */
  72.     long    cno;            /* character number line starts on */
  73.     char    *pat;            /* search pattern        */
  74.     logical    been_warned;        /* set if noticed dup        */
  75.     struct    nd_st    *left,*right;    /* left and right sons        */
  76. };
  77.  
  78. long    ftell();
  79. typedef    struct    nd_st    NODE;
  80.  
  81. int number; /* tokens found so far on line starting with # (including #) */
  82. logical gotone,                /* found a func already on line    */
  83.                     /* boolean "func" (see init)    */
  84.     _wht[0177],_etk[0177],_itk[0177],_btk[0177],_gd[0177];
  85.  
  86.     /* typedefs are recognized using a simple finite automata,
  87.      * tydef is its state variable.
  88.      */
  89. typedef enum {none, begin, tag_ok, middle, end } TYST;
  90.  
  91. TYST tydef = none;
  92.  
  93. logical next_token_is_func;
  94.  
  95. char    searchar = '/';            /* use /.../ searches         */
  96.  
  97. int    lineno;            /* line number of current line */
  98. long    charno;            /* current character number */
  99. long    linecharno;        /* character number of start of line */
  100.  
  101. char    *curfile,        /* current input file name        */
  102.     *outfile= 0,        /* output file                */
  103.     *white    = " \f\t\n",    /* white chars                */
  104.     *endtk    = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?",
  105.                 /* token ending chars            */
  106.     *begtk    = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",
  107.                 /* token starting chars            */
  108.     *intk    = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789",
  109.                 /* valid in-token chars            */
  110.     *notgd    = ",;";        /* non-valid after-function chars    */
  111.  
  112. int    file_num = 0;        /* current file number            */
  113. int    aflag = 0;        /* -a: append to tags */
  114. int    tflag = 0;        /* -t: create tags for typedefs */
  115. int    uflag = 0;        /* -u: update tags */
  116. int    wflag = 0;        /* -w: suppress warnings */
  117. int    vflag = 0;        /* -v: create vgrind style index output */
  118. int    xflag = 0;        /* -x: create cxref style output */
  119. int    eflag = 0;        /* -e: emacs style output */
  120.  
  121. /* Name this program was invoked with.  */
  122. char *progname;
  123.  
  124. FILE    *inf,            /* ioptr for current input file        */
  125.     *outf;            /* ioptr for tags file            */
  126.  
  127. NODE    *head;            /* the head of the sorted binary tree    */
  128.  
  129. char *savestr();
  130. char *savenstr ();
  131. char *rindex();
  132. char *index();
  133. char *concat ();
  134. void initbuffer ();
  135. long readline ();
  136.  
  137. /* A `struct linebuffer' is a structure which holds a line of text.
  138.  `readline' reads a line from a stream into a linebuffer
  139.  and works regardless of the length of the line.  */
  140.  
  141. struct linebuffer
  142.   {
  143.     long size;
  144.     char *buffer;
  145.   };
  146.  
  147. struct linebuffer lb, lb1;
  148.  
  149. #if 0  /* VMS now provides the `system' function.  */
  150. #ifdef VMS
  151.  
  152. #include <descrip.h>
  153.  
  154. void
  155. system (buf)
  156.      char *buf;
  157. {
  158.   struct dsc$descriptor_s command =
  159.     {
  160.       strlen(buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, buf
  161.     };
  162.  
  163.   LIB$SPAWN(&command);
  164. }
  165. #endif /* VMS */
  166. #endif /* 0 */
  167.  
  168. main(ac,av)
  169.      int    ac;
  170.      char    *av[];
  171. {
  172.   char cmd[100];
  173.   int i;
  174.   int fflag = 0;
  175.   char *this_file;
  176. #ifdef VMS
  177.   char got_err;
  178.  
  179.   extern char *gfnames();
  180.   extern char *massage_name();
  181. #endif
  182.  
  183.   progname = av[0];
  184.  
  185. #ifdef ETAGS
  186.   eflag = 1;
  187. #else
  188.   eflag = 0;
  189. #endif
  190.  
  191.   while (ac > 1 && av[1][0] == '-')
  192.     {
  193.       for (i=1; av[1][i]; i++)
  194.     {
  195.       switch(av[1][i])
  196.         {
  197. #ifndef VMS  /* These options are useful only with ctags,
  198.         and VMS can't input them, so just omit them.  */
  199.         case 'B':
  200.           searchar='?';
  201.           eflag = 0;
  202.           break;
  203.         case 'F':
  204.           searchar='/';
  205.           eflag = 0;
  206.           break;
  207. #endif
  208.         case 'a':
  209.           aflag++;
  210.           break;
  211.         case 'e':
  212.           eflag++;
  213.           break;
  214.         case 'f':
  215.           if (fflag > 0)
  216.         {
  217.           fprintf(stderr,
  218.               "%s: -f flag may only be given once\n", progname);
  219.           goto usage;
  220.         }
  221.           fflag++, ac--; av++;
  222.           if (ac <= 1 || av[1][0] == '\0')
  223.         {
  224.           fprintf(stderr,
  225.               "%s: -f flag must be followed by a filename\n",
  226.               progname);
  227.           goto usage;
  228.         }
  229.           outfile = av[1];
  230.           goto end_loop;
  231.         case 't':
  232.           tflag++;
  233.           break;
  234. #ifndef VMS
  235.         case 'u':
  236.           uflag++;
  237.           eflag = 0;
  238.           break;
  239. #endif
  240.         case 'w':
  241.           wflag++;
  242.           break;
  243.         case 'v':
  244.           vflag++;
  245.           xflag++;
  246.           eflag = 0;
  247.           break;
  248.         case 'x':
  249.           xflag++;
  250.           eflag = 0;
  251.           break;
  252.         default:
  253.           goto usage;
  254.         }
  255.     }
  256.     end_loop: ;
  257.       ac--; av++;
  258.     }
  259.  
  260.   if (ac <= 1)
  261.     {
  262.     usage:
  263. #ifdef VMS
  264.       fprintf (stderr, "Usage: %s [-aetwvx] [-f outfile] file ...\n", progname);
  265. #else
  266.       fprintf (stderr, "Usage: %s [-BFaetuwvx] [-f outfile] file ...\n", progname);
  267. #endif
  268.       exit(BAD);
  269.     }
  270.  
  271.   if (outfile == 0)
  272.     {
  273.       outfile = eflag ? "TAGS" : "tags";
  274.     }
  275.  
  276.   init();            /* set up boolean "functions"        */
  277.  
  278.   initbuffer (&lb);
  279.   initbuffer (&lb1);
  280.   /*
  281.    * loop through files finding functions
  282.    */
  283.   if (eflag)
  284.     {
  285.       outf = fopen (outfile, aflag ? "a" : "w");
  286.       if (!outf)
  287.     {
  288.       fprintf (stderr, "%s: ", progname);
  289.       perror (outfile);
  290.       exit (BAD);
  291.     }
  292.     }
  293.  
  294.   file_num = 1;
  295. #ifdef VMS
  296.   for (ac--, av++;
  297.        (this_file = gfnames (&ac, &av, &got_err)) != NULL; file_num++)
  298.     {
  299.       if (got_err)
  300.     {
  301.       error("Can't find file %s\n", this_file);
  302.       ac--, av++;
  303.     }
  304.       else
  305.     {
  306.       this_file = massage_name (this_file);
  307. #else     
  308.   for (; file_num < ac; file_num++)
  309.     {
  310.       this_file = av[file_num];
  311.       if (1)
  312.     {
  313. #endif
  314.       find_entries (this_file);
  315.       if (eflag)
  316.         {
  317.           fprintf (outf, "\f\n%s,%d\n",
  318.                this_file, total_size_of_entries (head));
  319.           put_entries (head);
  320.           free_tree (head);
  321.           head = NULL;
  322.         }
  323.     }
  324.     }
  325.  
  326.   if (eflag)
  327.     {
  328.       fclose (outf);
  329.       exit (GOOD);
  330.     }
  331.  
  332.   if (xflag)
  333.     {
  334.       put_entries(head);
  335.       exit(GOOD);
  336.     }
  337.   if (uflag)
  338.     {
  339.       for (i=1; i<ac; i++)
  340.     {
  341. #ifdef AMIGA
  342.       rename(outfile, "OTAGS");
  343.       sprintf(cmd, "egrep >%s -v '\t%s\t' OTAGS", outfile, av[i]);
  344.       system(cmd);
  345.       unlink("OTAGS");
  346. #else
  347.       sprintf(cmd,
  348.           "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
  349.