Prefer plain 'static' to 'static inline'.
[bpt/emacs.git] / lib-src / etags.c
index 69200b7..aa8c773 100644 (file)
@@ -1,4 +1,4 @@
-/* Tags file maker to go with GNU Emacs           -*- coding: latin-1 -*-
+/* Tags file maker to go with GNU Emacs           -*- coding: utf-8 -*-
 
 Copyright (C) 1984 The Regents of the University of California
 
@@ -28,8 +28,8 @@ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2012
-  Free Software Foundation, Inc.
+Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2013 Free Software
+Foundation, Inc.
 
 This file is not considered part of GNU Emacs.
 
@@ -64,12 +64,12 @@ University of California, as described above. */
  * 1985 Emacs TAGS format by Richard Stallman.
  * 1989 Sam Kendall added C++.
  * 1992 Joseph B. Wells improved C and C++ parsing.
- * 1993 Francesco Potortì reorganized C and C++.
+ * 1993 Francesco Potortì reorganized C and C++.
  * 1994 Line-by-line regexp tags by Tom Tromey.
- * 2001 Nested classes by Francesco Potortì (concept by Mykola Dzyuba).
- * 2002 #line directives by Francesco Potortì.
+ * 2001 Nested classes by Francesco Potortì (concept by Mykola Dzyuba).
+ * 2002 #line directives by Francesco Potortì.
  *
- * Francesco Potortì <pot@gnu.org> has maintained and improved it since 1993.
+ * Francesco Potortì <pot@gnu.org> has maintained and improved it since 1993.
  */
 
 /*
@@ -123,19 +123,9 @@ char pot_etags_version[] = "@(#) pot revision number is 17.38.1.4";
 # undef HAVE_NTGUI
 # undef  DOS_NT
 # define DOS_NT
-# ifndef HAVE_GETCWD
-#   define HAVE_GETCWD
-# endif /* undef HAVE_GETCWD */
-#else /* not WINDOWSNT */
-#endif /* !WINDOWSNT */
+#endif /* WINDOWSNT */
 
 #include <unistd.h>
-#ifndef HAVE_UNISTD_H
-# if defined (HAVE_GETCWD) && !defined (WINDOWSNT)
-    extern char *getcwd (char *buf, size_t size);
-# endif
-#endif /* HAVE_UNISTD_H */
-
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
@@ -152,16 +142,7 @@ char pot_etags_version[] = "@(#) pot revision number is 17.38.1.4";
 # define assert(x) ((void) 0)
 #endif
 
-#ifdef NO_LONG_OPTIONS         /* define this if you don't have GNU getopt */
-# define NO_LONG_OPTIONS TRUE
-# define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
-  extern char *optarg;
-  extern int optind, opterr;
-#else
-# define NO_LONG_OPTIONS FALSE
-# include <getopt.h>
-#endif /* NO_LONG_OPTIONS */
-
+#include <getopt.h>
 #include <regex.h>
 
 /* Define CTAGS to make the program "ctags" compatible with the usual one.
@@ -335,15 +316,7 @@ static void Texinfo_nodes (FILE *);
 static void Yacc_entries (FILE *);
 static void just_read_file (FILE *);
 
-static void print_language_names (void);
-static void print_version (void);
-static void print_help (argument *);
-int main (int, char **);
-
-static compressor *get_compressor_from_suffix (char *, char **);
 static language *get_language_from_langname (const char *);
-static language *get_language_from_interpreter (char *);
-static language *get_language_from_filename (char *, bool);
 static void readline (linebuffer *, FILE *);
 static long readline_internal (linebuffer *, FILE *);
 static bool nocase_tail (const char *);
@@ -365,13 +338,13 @@ static void find_entries (FILE *);
 static void free_tree (node *);
 static void free_fdesc (fdesc *);
 static void pfnote (char *, bool, char *, int, int, long);
-static void make_tag (const char *, int, bool, char *, int, int, long);
 static void invalidate_nodes (fdesc *, node **);
 static void put_entries (node *);
 
 static char *concat (const char *, const char *, const char *);
 static char *skip_spaces (char *);
 static char *skip_non_spaces (char *);
+static char *skip_name (char *);
 static char *savenstr (const char *, int);
 static char *savestr (const char *);
 static char *etags_strchr (const char *, int);
@@ -638,7 +611,8 @@ static const char Lisp_help [] =
 "In Lisp code, any function defined with `defun', any variable\n\
 defined with `defvar' or `defconst', and in general the first\n\
 argument of any expression that starts with `(def' in column zero\n\
-is a tag.";
+is a tag.\n\
+The `--declarations' option tags \"(defvar foo)\" constructs too.";
 
 static const char *Lua_suffixes [] =
   { "lua", "LUA", NULL };
@@ -833,11 +807,10 @@ etags --help --lang=ada.");
 #ifndef VERSION
 # define VERSION "17.38.1.4"
 #endif
-static void
+static _Noreturn void
 print_version (void)
 {
-  /* Makes it easier to update automatically. */
-  char emacs_copyright[] = "Copyright (C) 2012 Free Software Foundation, Inc.";
+  char emacs_copyright[] = COPYRIGHT;
 
   printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);
   puts (emacs_copyright);
@@ -850,7 +823,7 @@ print_version (void)
 # define PRINT_UNDOCUMENTED_OPTIONS_HELP FALSE
 #endif
 
-static void
+static _Noreturn void
 print_help (argument *argbuffer)
 {
   bool help_for_lang = FALSE;
@@ -870,11 +843,7 @@ print_help (argument *argbuffer)
   printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
 \n\
 These are the options accepted by %s.\n", progname, progname);
-  if (NO_LONG_OPTIONS)
-    puts ("WARNING: long option names do not work with this executable,\n\
-as it is not linked with GNU getopt.");
-  else
-    puts ("You may use unambiguous abbreviations for the long option names.");
+  puts ("You may use unambiguous abbreviations for the long option names.");
   puts ("  A - as file name means read names from stdin (one per line).\n\
 Absolute names are stored in the output file as they are.\n\
 Relative ones are stored relative to the output file's directory.\n");
@@ -1066,9 +1035,9 @@ main (int argc, char **argv)
 
   /* When the optstring begins with a '-' getopt_long does not rearrange the
      non-options arguments to be at the end, but leaves them alone. */
-  optstring = concat (NO_LONG_OPTIONS ? "" : "-",
-                     "ac:Cf:Il:o:r:RSVhH",
-                     (CTAGS) ? "BxdtTuvw" : "Di:");
+  optstring = concat ("-ac:Cf:Il:o:r:RSVhH",
+                     (CTAGS) ? "BxdtTuvw" : "Di:",
+                     "");
 
   while ((opt = getopt_long (argc, argv, optstring, longopts, NULL)) != EOF)
     switch (opt)
@@ -2271,10 +2240,6 @@ enum sym_type
   st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef
 };
 
-static unsigned int hash (const char *, unsigned int);
-static struct C_stab_entry * in_word_set (const char *, unsigned int);
-static enum sym_type C_symtype (char *, int, int);
-
 /* Feed stuff between (but not including) %[ and %] lines to:
      gperf -m 5
 %[
@@ -2333,10 +2298,10 @@ and replace lines between %< and %> with its output, then:
 struct C_stab_entry { const char *name; int c_ext; enum sym_type type; };
 /* maximum key range = 33, duplicates = 0 */
 
-static inline unsigned int
-hash (register const char *str, register unsigned int len)
+static int
+hash (const char *str, int len)
 {
-  static unsigned char asso_values[] =
+  static char const asso_values[] =
     {
       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
@@ -2365,15 +2330,15 @@ hash (register const char *str, register unsigned int len)
       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
       35, 35, 35, 35, 35, 35
     };
-  register int hval = len;
+  int hval = len;
 
   switch (hval)
     {
       default:
-        hval += asso_values[(unsigned char)str[2]];
+        hval += asso_values[(unsigned char) str[2]];
       /*FALLTHROUGH*/
       case 2:
-        hval += asso_values[(unsigned char)str[1]];
+        hval += asso_values[(unsigned char) str[1]];
         break;
     }
   return hval;
@@ -2431,11 +2396,11 @@ in_word_set (register const char *str, register unsigned int len)
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
     {
-      register int key = hash (str, len);
+      int key = hash (str, len);
 
       if (key <= MAX_HASH_VALUE && key >= 0)
         {
-          register const char *s = wordlist[key].name;
+          const char *s = wordlist[key].name;
 
           if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
             return &wordlist[key];
@@ -2878,6 +2843,7 @@ consider_token (register char *str, register int len, register int c, int *c_ext
           objdef = omethodtag;
           linebuffer_setlen (&token_name, oldlen + len);
           memcpy (token_name.buffer + oldlen, str, len);
+          token_name.buffer[oldlen + len] = '\0';
           return TRUE;
         }
        return FALSE;
@@ -4292,10 +4258,11 @@ Asm_labels (FILE *inf)
 /*
  * Perl support
  * Perl sub names: /^sub[ \t\n]+[^ \t\n{]+/
+ *                 /^use constant[ \t\n]+[^ \t\n{=,;]+/
  * Perl variable names: /^(my|local).../
  * Original code by Bart Robinson <lomew@cs.utah.edu> (1995)
  * Additions by Michael Ernst <mernst@alum.mit.edu> (1997)
- * Ideas by Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> (2001)
+ * Ideas by Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> (2001)
  */
 static void
 Perl_functions (FILE *inf)
@@ -4314,9 +4281,10 @@ Perl_functions (FILE *inf)
        }
       else if (LOOKING_AT (cp, "sub"))
        {
-         char *pos;
-         char *sp = cp;
+         char *pos, *sp;
 
+       subr:
+         sp = cp;
          while (!notinname (*cp))
            cp++;
          if (cp == sp)
@@ -4339,8 +4307,21 @@ Perl_functions (FILE *inf)
                        lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
              free (name);
            }
+       }
+      else if (LOOKING_AT (cp, "use constant")
+              || LOOKING_AT (cp, "use constant::defer"))
+       {
+         /* For hash style multi-constant like
+               use constant { FOO => 123,
+                              BAR => 456 };
+            only the first FOO is picked up.  Parsing across the value
+            expressions would be difficult in general, due to possible nested
+            hashes, here-documents, etc.  */
+         if (*cp == '{')
+           cp = skip_spaces (cp+1);
+         goto subr;
        }
-       else if (globals)       /* only if we are tagging global vars */
+      else if (globals)        /* only if we are tagging global vars */
        {
          /* Skip a qualifier, if any. */
          bool qual = LOOKING_AT (cp, "my") || LOOKING_AT (cp, "local");
@@ -4651,7 +4632,7 @@ Pascal_functions (FILE *inf)
          /* Check if this is an "extern" declaration. */
          if (*dbp == '\0')
            continue;
-         if (lowcase (*dbp == 'e'))
+         if (lowcase (*dbp) == 'e')
            {
              if (nocase_tail ("extern")) /* superfluous, really! */
                {
@@ -4755,6 +4736,19 @@ Lisp_functions (FILE *inf)
       if (dbp[0] != '(')
        continue;
 
+      /* "(defvar foo)" is a declaration rather than a definition.  */
+      if (! declarations)
+       {
+         char *p = dbp + 1;
+         if (LOOKING_AT (p, "defvar"))
+           {
+             p = skip_name (p); /* past var name */
+             p = skip_spaces (p);
+             if (*p == ')')
+               continue;
+           }
+       }
+
       if (strneq (dbp+1, "def", 3) || strneq (dbp+1, "DEF", 3))
        {
          dbp = skip_non_spaces (dbp);
@@ -5098,7 +5092,7 @@ Texinfo_nodes (FILE *inf)
  * Contents of <title>, <h1>, <h2>, <h3> are tags.
  * Contents of <a name=xxx> are tags with name xxx.
  *
- * Francesco Potortì, 2002.
+ * Francesco Potortì, 2002.
  */
 static void
 HTML_labels (FILE *inf)
@@ -5621,10 +5615,7 @@ analyse_regex (char *regex_arg)
        /* regexfile is a file containing regexps, one per line. */
        regexfp = fopen (regexfile, "r");
        if (regexfp == NULL)
-         {
-           pfatal (regexfile);
-           return;
-         }
+         pfatal (regexfile);
        linebuffer_init (&regexbuf);
        while (readline_internal (&regexbuf, regexfp) > 0)
          analyse_regex (regexbuf.buffer);
@@ -6315,6 +6306,16 @@ skip_non_spaces (char *cp)
   return cp;
 }
 
+/* Skip any chars in the "name" class.*/
+static char *
+skip_name (char *cp)
+{
+  /* '\0' is a notinname() so loop stops there too */
+  while (! notinname (*cp))
+    cp++;
+  return cp;
+}
+
 /* Print error message and exit.  */
 void
 fatal (const char *s1, const char *s2)
@@ -6333,8 +6334,8 @@ pfatal (const char *s1)
 static void
 suggest_asking_for_help (void)
 {
-  fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
-          progname, NO_LONG_OPTIONS ? "-h" : "--help");
+  fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n",
+          progname);
   exit (EXIT_FAILURE);
 }
 
@@ -6372,7 +6373,6 @@ concat (const char *s1, const char *s2, const char *s3)
 static char *
 etags_getcwd (void)
 {
-#ifdef HAVE_GETCWD
   int bufsize = 200;
   char *path = xnew (bufsize, char);
 
@@ -6387,34 +6387,6 @@ etags_getcwd (void)
 
   canonicalize_filename (path);
   return path;
-
-#else /* not HAVE_GETCWD */
-#if MSDOS
-
-  char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS.  */
-
-  getwd (path);
-
-  for (p = path; *p != '\0'; p++)
-    if (*p == '\\')
-      *p = '/';
-    else
-      *p = lowcase (*p);
-
-  return strdup (path);
-#else /* not MSDOS */
-  linebuffer path;
-  FILE *pipe;
-
-  linebuffer_init (&path);
-  pipe = (FILE *) popen ("pwd 2>/dev/null", "r");
-  if (pipe == NULL || readline_internal (&path, pipe) == 0)
-    pfatal ("pwd");
-  pclose (pipe);
-
-  return path.buffer;
-#endif /* not MSDOS */
-#endif /* not HAVE_GETCWD */
 }
 
 /* Return a newly allocated string containing the file name of FILE