]> code.delx.au - gnu-emacs/blobdiff - lib-src/etags.c
* lisp/net/tramp-gvfs.el (tramp-gvfs-mount-spec): Fix typo.
[gnu-emacs] / lib-src / etags.c
index ff75de4565906507a140260a94147eedfc806b42..1c85a79289694f46ceb18f607b2ea67dd8879026 100644 (file)
@@ -35,8 +35,8 @@ This file is not considered part of GNU Emacs.
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -112,7 +112,6 @@ char pot_etags_version[] = "@(#) pot revision number is 17.38.1.4";
 
 #ifdef WINDOWSNT
 # include <direct.h>
-# define MAXPATHLEN _MAX_PATH
 # undef HAVE_NTGUI
 # undef  DOS_NT
 # define DOS_NT
@@ -680,8 +679,8 @@ static const char *Objc_suffixes [] =
 static const char Objc_help [] =
 "In Objective C code, tags include Objective C definitions for classes,\n\
 class categories, methods and protocols.  Tags for variables and\n\
-functions in classes are named 'CLASS::VARIABLE' and 'CLASS::FUNCTION'.\n\
-(Use --help --lang=c --lang=objc --lang=java for full help.)";
+functions in classes are named 'CLASS::VARIABLE' and 'CLASS::FUNCTION'.\
+\n(Use --help --lang=c --lang=objc --lang=java for full help.)";
 
 static const char *Pascal_suffixes [] =
   { "p", "pas", NULL };
@@ -729,7 +728,9 @@ static const char Python_help [] =
 generate a tag.";
 
 static const char *Ruby_suffixes [] =
-  { "rb", "ruby", NULL };
+  { "rb", "ru", "rbw", NULL };
+static const char *Ruby_filenames [] =
+  { "Rakefile", "Thorfile", NULL };
 static const char Ruby_help [] =
   "In Ruby code, 'def' or 'class' or 'module' at the beginning of\n\
 a line generate a tag.  Constants also generate a tag.";
@@ -813,7 +814,7 @@ static language lang_names [] =
   { "proc",      no_lang_help,   plain_C_entries,   plain_C_suffixes   },
   { "prolog",    Prolog_help,    Prolog_functions,  Prolog_suffixes    },
   { "python",    Python_help,    Python_functions,  Python_suffixes    },
-  { "ruby",      Ruby_help,      Ruby_functions,    Ruby_suffixes      },
+  { "ruby",      Ruby_help,Ruby_functions,Ruby_suffixes,Ruby_filenames },
   { "scheme",    Scheme_help,    Scheme_functions,  Scheme_suffixes    },
   { "tex",       TeX_help,       TeX_commands,      TeX_suffixes       },
   { "texinfo",   Texinfo_help,   Texinfo_nodes,     Texinfo_suffixes   },
@@ -957,8 +958,7 @@ Relative ones are stored relative to the output file's directory.\n");
        Do not create tag entries for global variables in some\n\
        languages.  This makes the tags file smaller.");
 
-  if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
-    puts ("--no-line-directive\n\
+  puts ("--no-line-directive\n\
         Ignore #line preprocessor directives in C and derived languages.");
 
   if (CTAGS)
@@ -970,11 +970,12 @@ Relative ones are stored relative to the output file's directory.\n");
        in some languages.");
 
   puts ("-Q, --class-qualify\n\
-        Qualify tag names with their class name in C++, ObjC, and Java.\n\
+        Qualify tag names with their class name in C++, ObjC, Java, and Perl.\n\
         This produces tag names of the form \"class::member\" for C++,\n\
         \"class(category)\" for Objective C, and \"class.member\" for Java.\n\
         For Objective C, this also produces class methods qualified with\n\
-        their arguments, as in \"foo:bar:baz:more\".");
+        their arguments, as in \"foo:bar:baz:more\".\n\
+        For Perl, this produces \"package::member\".");
   puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\
         Make a tag for each line matching a regular expression pattern\n\
        in the following files.  {LANGUAGE}REGEXP uses REGEXP for LANGUAGE\n\
@@ -1341,7 +1342,7 @@ main (int argc, char **argv)
     {
       char *cmd =
        xmalloc (strlen (tagfile) + whatlen_max +
-                sizeof "mv..OTAGS;fgrep -v '\t\t' OTAGS >;rm OTAGS");
+                sizeof "mv..OTAGS;grep -Fv '\t\t' OTAGS >;rm OTAGS");
       for (i = 0; i < current_arg; ++i)
        {
          switch (argbuffer[i].arg_type)
@@ -1354,7 +1355,7 @@ main (int argc, char **argv)
            }
          char *z = stpcpy (cmd, "mv ");
          z = stpcpy (z, tagfile);
-         z = stpcpy (z, " OTAGS;fgrep -v '\t");
+         z = stpcpy (z, " OTAGS;grep -Fv '\t");
          z = stpcpy (z, argbuffer[i].what);
          z = stpcpy (z, "\t' OTAGS >");
          z = stpcpy (z, tagfile);
@@ -1484,8 +1485,16 @@ get_language_from_filename (char *file, int case_sensitive)
 {
   language *lang;
   const char **name, **ext, *suffix;
+  char *slash;
 
   /* Try whole file name first. */
+  slash = strrchr (file, '/');
+  if (slash != NULL)
+    file = slash + 1;
+#ifdef DOS_NT
+  else if (file[0] && file[1] == ':')
+    file += 2;
+#endif
   for (lang = lang_names; lang->name != NULL; lang++)
     if (lang->filenames != NULL)
       for (name = lang->filenames; *name != NULL; name++)
@@ -4060,13 +4069,13 @@ Yacc_entries (FILE *inf)
   ((assert ("" kw), true)   /* syntax error if not a literal string */ \
    && strneq ((cp), kw, sizeof (kw)-1)         /* cp points at kw */   \
    && notinname ((cp)[sizeof (kw)-1])          /* end of kw */         \
-   && ((cp) = skip_spaces ((cp)+sizeof (kw)-1))) /* skip spaces */
+   && ((cp) = skip_spaces ((cp) + sizeof (kw) - 1), true)) /* skip spaces */
 
 /* Similar to LOOKING_AT but does not use notinname, does not skip */
 #define LOOKING_AT_NOCASE(cp, kw) /* the keyword is a literal string */        \
   ((assert ("" kw), true) /* syntax error if not a literal string */   \
    && strncaseeq ((cp), kw, sizeof (kw)-1)     /* cp points at kw */   \
-   && ((cp) += sizeof (kw)-1))                 /* skip spaces */
+   && ((cp) += sizeof (kw) - 1, true))         /* skip spaces */
 
 /*
  * Read a file, but do no processing.  This is used to do regexp
@@ -4525,10 +4534,21 @@ Perl_functions (FILE *inf)
            continue;           /* nothing found */
          pos = strchr (sp, ':');
          if (pos && pos < cp && pos[1] == ':')
-           /* The name is already qualified. */
-           make_tag (sp, cp - sp, true,
-                     lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
-         else
+           {
+             /* The name is already qualified. */
+             if (!class_qualify)
+               {
+                 char *q = pos + 2, *qpos;
+                 while ((qpos = strchr (q, ':')) != NULL
+                        && qpos < cp
+                        && qpos[1] == ':')
+                   q = qpos + 2;
+                 sp = q;
+               }
+             make_tag (sp, cp - sp, true,
+                       lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
+           }
+         else if (class_qualify)
            /* Qualify it. */
            {
              char savechar, *name;
@@ -4541,6 +4561,9 @@ Perl_functions (FILE *inf)
                        lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
              free (name);
            }
+         else
+           make_tag (sp, cp - sp, true,
+                     lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
        }
       else if (LOOKING_AT (cp, "use constant")
               || LOOKING_AT (cp, "use constant::defer"))
@@ -4621,6 +4644,7 @@ static void
 Ruby_functions (FILE *inf)
 {
   char *cp = NULL;
+  bool reader = false, writer = false, alias = false, continuation = false;
 
   LOOP_ON_INPUT_LINES (inf, lb, cp)
     {
@@ -4629,7 +4653,9 @@ Ruby_functions (FILE *inf)
       char *name;
 
       cp = skip_spaces (cp);
-      if (c_isalpha (*cp) && c_isupper (*cp)) /* constants */
+      if (!continuation
+         /* Constants.  */
+         && c_isalpha (*cp) && c_isupper (*cp))
        {
          char *bp, *colon = NULL;
 
@@ -4643,7 +4669,7 @@ Ruby_functions (FILE *inf)
          if (cp > name + 1)
            {
              bp = skip_spaces (cp);
-             if (*bp == '=' && c_isspace (bp[1]))
+             if (*bp == '=' && !(bp[1] == '=' || bp[1] == '>'))
                {
                  if (colon && !c_isspace (colon[1]))
                    name = colon + 1;
@@ -4652,12 +4678,14 @@ Ruby_functions (FILE *inf)
                }
            }
        }
-      else if ((is_method = LOOKING_AT (cp, "def")) /* module/class/method */
-              || (is_class = LOOKING_AT (cp, "class"))
-              || LOOKING_AT (cp, "module"))
+      else if (!continuation
+              /* Modules, classes, methods.  */
+              && ((is_method = LOOKING_AT (cp, "def"))
+                  || (is_class = LOOKING_AT (cp, "class"))
+                  || LOOKING_AT (cp, "module")))
        {
          const char self_name[] = "self.";
-         const size_t self_size1 = sizeof ("self.") - 1;
+         const size_t self_size1 = sizeof (self_name) - 1;
 
          name = cp;
 
@@ -4689,6 +4717,91 @@ Ruby_functions (FILE *inf)
          make_tag (name, cp - name, true,
                    lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
        }
+      else
+       {
+         /* Tag accessors and aliases.  */
+
+         if (!continuation)
+           reader = writer = alias = false;
+
+         while (*cp && *cp != '#')
+           {
+             if (!continuation)
+               {
+                 reader = writer = alias = false;
+                 if (LOOKING_AT (cp, "attr_reader"))
+                   reader = true;
+                 else if (LOOKING_AT (cp, "attr_writer"))
+                   writer = true;
+                 else if (LOOKING_AT (cp, "attr_accessor"))
+                   {
+                     reader = true;
+                     writer = true;
+                   }
+                 else if (LOOKING_AT (cp, "alias_method"))
+                   alias = true;
+               }
+             if (reader || writer || alias)
+               {
+                 do {
+                   char *np;
+
+                   cp = skip_spaces (cp);
+                   if (*cp == '(')
+                     cp = skip_spaces (cp + 1);
+                   np = cp;
+                   cp = skip_name (cp);
+                   if (*np != ':')
+                     continue;
+                   np++;
+                   if (reader)
+                     {
+                       make_tag (np, cp - np, true,
+                                 lb.buffer, cp - lb.buffer + 1,
+                                 lineno, linecharno);
+                       continuation = false;
+                     }
+                   if (writer)
+                     {
+                       size_t name_len = cp - np + 1;
+                       char *wr_name = xnew (name_len + 1, char);
+
+                       memcpy (wr_name, np, name_len - 1);
+                       memcpy (wr_name + name_len - 1, "=", 2);
+                       pfnote (wr_name, true, lb.buffer, cp - lb.buffer + 1,
+                               lineno, linecharno);
+                       continuation = false;
+                     }
+                   if (alias)
+                     {
+                       if (!continuation)
+                         make_tag (np, cp - np, true,
+                                   lb.buffer, cp - lb.buffer + 1,
+                                   lineno, linecharno);
+                       continuation = false;
+                       while (*cp && *cp != '#' && *cp != ';')
+                         {
+                           if (*cp == ',')
+                             continuation = true;
+                           else if (!c_isspace (*cp))
+                             continuation = false;
+                           cp++;
+                         }
+                       if (*cp == ';')
+                         continuation = false;
+                     }
+                   cp = skip_spaces (cp);
+                 } while ((alias
+                           ? (*cp == ',')
+                           : (continuation = (*cp == ',')))
+                          && (cp = skip_spaces (cp + 1), *cp && *cp != '#'));
+               }
+             if (*cp != '#')
+               cp = skip_name (cp);
+             while (*cp && *cp != '#' && notinname (*cp))
+               cp++;
+           }
+       }
     }
 }