]> git.eshelyaron.com Git - emacs.git/commitdiff
* etags.c (Cplusplus_suffixes): Add .M suffix for Objective C++.
authorFrancesco Potortì <pot@gnu.org>
Thu, 7 Dec 1995 09:10:54 +0000 (09:10 +0000)
committerFrancesco Potortì <pot@gnu.org>
Thu, 7 Dec 1995 09:10:54 +0000 (09:10 +0000)
(gperf): Added keywords for Objective C and GNU macros.
(sym_type): Added values to account for Objective C and GNU macros.
(begtk): The '@' character can start a token.
(objdef, methodlen, objtag): New variables for Objective C.
(consider_token, C_entries): Added code for Objective C.
(plain_C_suffixes): Add .m and .lm for Objective C.
(Yacc_suffixes): Add .ym for Objective yacc.
(GROW_LINEBUFFER): New macro.
(consider_token, C_entries, Pascal_functions): Use the new macro.
(consider_token): Take one more argument.  Caller changed.
(consider_token): Use the hashing function to spot GNU macros.
(C_entries): Consider // as a comment start even in plain C for
the sake of Objective C parsing.
(pfnote): Don't make a tag for ctags if there is no name.
(getit, Asm_labels, Perl_functions, Pascal_functions, L_getit,
get_scheme, prolog_getit): Name the tag in ctags mode.
(pfnote): Truncate ctags lines to 50 chars, like it worked once.
(Perl_interpreters): Accept "@PERL@" as an interpreter.
(suggest_asking_for_help): New function.
(main, get_language_from_name): Use suggest_asking_for_help.
(main): Let get_language_from_name make language existence check.
(streq, strneq): Check the arguments #if DEBUG.

lib-src/etags.c

index 61218c90f1dc8ac4e11fdf3527a87368b5101d6b..7a7c30b157d0652bc0ffa9114762953495103e1f 100644 (file)
@@ -25,17 +25,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  *     Gnu Emacs TAGS format and modifications by RMS?
  *     Sam Kendall added C++.
  *     Francesco Potorti` reorganised C and C++ based on work by Joe Wells.
-#ifdef ETAGS_REGEXPS
  *     Regexp tags by Tom Tromey.
-#endif
  *
  *     Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer.
  */
 
-char pot_etags_version[] = "@(#) pot revision number is 11.45";
+char pot_etags_version[] = "@(#) pot revision number is 11.53";
 
 #define        TRUE    1
 #define        FALSE   0
+
 #ifndef DEBUG
 # define DEBUG FALSE
 #endif
@@ -102,8 +101,8 @@ extern int errno;
 #define C_STAR 0x00003         /* C* */
 #define YACC   0x10000         /* yacc file */
 
-#define streq(s,t)     (strcmp (s, t) == 0)
-#define strneq(s,t,n)  (strncmp (s, t, n) == 0)
+#define streq(s,t)     ((DEBUG &&!(s)&&!(t)&&(abort(),1)) || !strcmp(s,t))
+#define strneq(s,t,n)  ((DEBUG &&!(s)&&!(t)&&(abort(),1)) || !strncmp(s,t,n))
 
 #define lowcase(c)     tolower ((unsigned char)c)
 
@@ -129,7 +128,7 @@ extern int errno;
 typedef int logical;
 
 typedef struct nd_st
-{                              /* sorting structure                    */
+{                              /* sorting structure            */
   char *name;                  /* function or type name        */
   char *file;                  /* file name                    */
   logical is_func;             /* use pattern or line no       */
@@ -194,6 +193,7 @@ void add_regex ();
 #endif
 void add_node ();
 void error ();
+void suggest_asking_for_help ();
 void fatal (), pfatal ();
 void find_entries ();
 void free_tree ();
@@ -228,6 +228,9 @@ NODE *head;                 /* the head of the binary tree of tags */
  * `readline' reads a line from a stream into a linebuffer and works
  * regardless of the length of the line.
  */
+#define GROW_LINEBUFFER(buf,toksize)                                   \
+while (buf.size < toksize)                                             \
+  buf.buffer = (char *) xrealloc (buf.buffer, buf.size *= 2)
 struct linebuffer
 {
   long size;
@@ -235,7 +238,7 @@ struct linebuffer
 };
 
 struct linebuffer lb;          /* the current line */
-struct linebuffer token_name;  /* used by C_entries as temporary area */
+struct linebuffer token_name;  /* used by C_entries as temporary area */
 struct
 {
   long linepos;
@@ -245,12 +248,14 @@ struct
 /* boolean "functions" (see init)      */
 logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
 char
- *white = " \f\t\n\013",       /* white chars                          */
- *endtk = " \t\n\013\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars */
-                               /* token starting chars                 */
- *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~",
-                               /* valid in-token chars                 */
- *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
+  /* white chars */
+  *white = " \f\t\n\013",
+  /* token ending chars */
+  *endtk = " \t\n\013\"'#()[]{}=-+%*/&|^~!<>;,.:?",
+  /* token starting chars */
+  *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
+  /* valid in-token chars */
+  *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
 
 logical append_to_tagfile;     /* -a: append to tags */
 /* The following three default to TRUE for etags, but to FALSE for ctags.  */
@@ -334,52 +339,45 @@ char *Asm_suffixes [] = { "a",    /* Unix assembler */
 char *default_C_suffixes [] =
   { "c", "h", NULL };
 
-/* C++ file */
+/* .M is for Objective C++ files. */
 char *Cplusplus_suffixes [] =
-  { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx", NULL };
+  { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx", "M", NULL};
 
-/* C* file */
 char *Cstar_suffixes [] =
   { "cs", "hs", NULL };
 
-/* Fortran */
 char *Fortran_suffixes [] =
   { "F", "f", "f90", "for", NULL };
 
-/* Lisp source code */
 char *Lisp_suffixes [] =
   { "cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL };
 
-/* Pascal file */
 char *Pascal_suffixes [] =
   { "p", "pas", NULL };
 
-/* Perl file */
 char *Perl_suffixes [] =
   { "pl", "pm", NULL };
 char *Perl_interpreters [] =
-  { "perl", NULL };
+  { "perl", "@PERL@", NULL };
 
-/* Pro*C file. */
 char *plain_C_suffixes [] =
-  { "pc", NULL };
+  { "pc",                      /* Pro*C file */
+    "m",                       /* Objective C file */
+    "lm",                      /* Objective lex file */
+     NULL };
 
-/* Prolog source code */
 char *Prolog_suffixes [] =
   { "prolog", NULL };
 
-/* Scheme source code */
-/* FIXME Can't do the `SCM' or `scm' prefix with a version number */
+/* Can't do the `SCM' or `scm' prefix with a version number. */
 char *Scheme_suffixes [] =
   { "SCM", "SM", "oak", "sch", "scheme", "scm", "sm", "t", NULL };
 
-/* TeX/LaTeX source code */
 char *TeX_suffixes [] =
-  { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };
+  { "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL };
 
-/* Yacc file */
 char *Yacc_suffixes [] =
-  { "y", NULL };
+  { "y", "ym", NULL };         /* .ym is Objective yacc file */
 
 /* Table of language names and corresponding functions, file suffixes
    and interpreter names.
@@ -395,22 +393,22 @@ struct lang_entry
 
 struct lang_entry lang_names [] =
 {
-  { "asm", Asm_labels, Asm_suffixes },
-  { "c", default_C_entries, default_C_suffixes },
-  { "c++", Cplusplus_entries, Cplusplus_suffixes },
-  { "c*", Cstar_entries, Cstar_suffixes },
-  { "fortran", Fortran_functions, Fortran_suffixes },
-  { "lisp", Lisp_functions, Lisp_suffixes },
-  { "pascal", Pascal_functions, Pascal_suffixes },
-  { "perl", Perl_functions, Perl_suffixes, Perl_interpreters },
-  { "proc", plain_C_entries, plain_C_suffixes },
-  { "prolog", Prolog_functions, Prolog_suffixes },
-  { "scheme" , Scheme_functions, Scheme_suffixes },
-  { "tex", TeX_functions, TeX_suffixes },
-  { "yacc", Yacc_entries, Yacc_suffixes },
-  { "auto", NULL },            /* default guessing scheme */
-  { "none", just_read_file },  /* regexp matching only */
-  { NULL, NULL }               /* end of list */
+  { "asm",     Asm_labels,         Asm_suffixes,         NULL              },
+  { "c",       default_C_entries,   default_C_suffixes,          NULL              },
+  { "c++",     Cplusplus_entries,   Cplusplus_suffixes,          NULL              },
+  { "c*",      Cstar_entries,      Cstar_suffixes,       NULL              },
+  { "fortran", Fortran_functions,   Fortran_suffixes,    NULL              },
+  { "lisp",    Lisp_functions,     Lisp_suffixes,        NULL              },
+  { "pascal",  Pascal_functions,    Pascal_suffixes,     NULL              },
+  { "perl",    Perl_functions,     Perl_suffixes,        Perl_interpreters },
+  { "proc",    plain_C_entries,            plain_C_suffixes,     NULL              },
+  { "prolog",  Prolog_functions,    Prolog_suffixes,     NULL              },
+  { "scheme",  Scheme_functions,    Scheme_suffixes,     NULL              },
+  { "tex",     TeX_functions,      TeX_suffixes,         NULL              },
+  { "yacc",    Yacc_entries,       Yacc_suffixes,        NULL              },
+  { "auto", NULL },             /* default guessing scheme */
+  { "none", just_read_file },   /* regexp matching only */
+  { NULL, NULL }                /* end of list */
 };
 
 \f
@@ -763,7 +761,7 @@ main (argc, argv)
            {
              fprintf (stderr, "%s: -%c option may only be given once.\n",
                       progname, opt);
-             goto usage;
+             suggest_asking_for_help ();
            }
          tagfile = optarg;
          break;
@@ -773,12 +771,6 @@ main (argc, argv)
          break;
        case 'l':
          argbuffer[current_arg].function = get_language_from_name (optarg);
-         if (argbuffer[current_arg].function == NULL)
-           {
-             fprintf (stderr, "%s: language \"%s\" not recognized.\n",
-                      progname, optarg);
-             goto usage;
-           }
          argbuffer[current_arg].arg_type = at_language;
          ++current_arg;
          break;
@@ -831,7 +823,7 @@ main (argc, argv)
          break;
 #endif /* CTAGS */
        default:
-         goto usage;
+         suggest_asking_for_help ();
        }
     }
 
@@ -846,11 +838,7 @@ main (argc, argv)
   if (nincluded_files == 0 && file_count == 0)
     {
       fprintf (stderr, "%s: No input files specified.\n", progname);
-
-    usage:
-      fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n",
-              progname);
-      exit (BAD);
+      suggest_asking_for_help ();
     }
 
   if (tagfile == NULL)
@@ -992,15 +980,22 @@ get_language_from_name (name)
 {
   struct lang_entry *lang;
 
-  if (name == NULL)
-    return NULL;
-  for (lang = lang_names; lang->name != NULL; lang++)
-    {
-      if (streq (name, lang->name))
-       return lang->function;
-    }
+  if (name != NULL)
+    for (lang = lang_names; lang->name != NULL; lang++)
+      {
+       if (streq (name, lang->name))
+         return lang->function;
+      }
 
-  return NULL;
+  fprintf (stderr, "%s: language \"%s\" not recognized.\n",
+          progname, optarg);
+  suggest_asking_for_help ();
+
+  /* This point should never be reached.  The function should either
+     return a function pointer  or never return.  Note that a NULL
+     pointer cannot be considered as an error, as it means that the
+     language has not been explicitely imposed by the user ("auto"). */
+  return NULL;                 /* avoid warnings from compiler */
 }
 
 
@@ -1145,6 +1140,7 @@ find_entries (file, inf)
   NODE *old_last_node;
   extern NODE *last_node;
 
+
   /* Memory leakage here: the memory block pointed by curfile is never
      released.  The amount of memory leaked here is the sum of the
      lengths of the input file names. */
@@ -1222,14 +1218,19 @@ find_entries (file, inf)
 /* Record a tag. */
 void
 pfnote (name, is_func, linestart, linelen, lno, cno)
-     char *name;               /* tag name, if different from definition */
+     char *name;               /* tag name, or NULL if unnamed */
      logical is_func;          /* tag is a function */
      char *linestart;          /* start of the line where tag is */
      int linelen;              /* length of the line where tag is */
      int lno;                  /* line number */
      long cno;                 /* character number */
 {
-  register NODE *np = xnew (1, NODE);
+  register NODE *np;
+
+  if (CTAGS && name == NULL)
+    return;
+
+  np = xnew (1, NODE);
 
   /* If ctags mode, change name "main" to M<thisfilename>. */
   if (CTAGS && !cxref_style && streq (name, "main"))
@@ -1253,7 +1254,15 @@ pfnote (name, is_func, linestart, linelen, lno, cno)
      uncomment the +1 below. */
   np->cno = cno /* + 1 */ ;
   np->left = np->right = NULL;
-  np->pat = savenstr (linestart, ((CTAGS && !cxref_style) ? 50 : linelen));
+  if (CTAGS && !cxref_style)
+    {
+      if (strlen (linestart) < 50)
+       np->pat = concat (linestart, "$", "");
+      else
+       np->pat = savenstr (linestart, 50);
+    }
+  else
+    np->pat = savenstr (linestart, linelen);
 
   add_node (np, &head);
 }
@@ -1369,36 +1378,44 @@ put_entries (node)
        fprintf (tagf, "%s\177%d,%d\n",
                 node->pat, node->lno, node->cno);
     }
-  else if (!cxref_style)
+  else
     {
-      fprintf (tagf, "%s\t%s\t",
-              node->name, node->file);
-
-      if (node->is_func)
-       {                       /* a function */
-         putc (searchar, tagf);
-         putc ('^', tagf);
+      if (node->name == NULL)
+       error ("internal error: NULL name in ctags mode.", 0);
 
-         for (sp = node->pat; *sp; sp++)
-           {
-             if (*sp == '\\' || *sp == searchar)
-               putc ('\\', tagf);
-             putc (*sp, tagf);
-           }
-         putc (searchar, tagf);
+      if (cxref_style)
+       {
+         if (vgrind_style)
+           fprintf (stdout, "%s %s %d\n",
+                    node->name, node->file, (node->lno + 63) / 64);
+         else
+           fprintf (stdout, "%-16s %3d %-16s %s\n",
+                    node->name, node->lno, node->file, node->pat);
        }
       else
-       {                       /* a typedef; text pattern inadequate */
-         fprintf (tagf, "%d", node->lno);
+       {
+         fprintf (tagf, "%s\t%s\t", node->name, node->file);
+
+         if (node->is_func)
+           {                   /* a function */
+             putc (searchar, tagf);
+             putc ('^', tagf);
+
+             for (sp = node->pat; *sp; sp++)
+               {
+                 if (*sp == '\\' || *sp == searchar)
+                   putc ('\\', tagf);
+                 putc (*sp, tagf);
+               }
+             putc (searchar, tagf);
+           }
+         else
+           {                   /* a typedef; text pattern inadequate */
+             fprintf (tagf, "%d", node->lno);
+           }
+         putc ('\n', tagf);
        }
-      putc ('\n', tagf);
     }
-  else if (vgrind_style)
-    fprintf (stdout, "%s %s %d\n",
-            node->name, node->file, (node->lno + 63) / 64);
-  else
-    fprintf (stdout, "%-16s %3d %-16s %s\n",
-            node->name, node->lno, node->file, node->pat);
 
   /* Output subentries that follow this one */
   put_entries (node->right);
@@ -1454,7 +1471,8 @@ total_size_of_entries (node)
  */
 enum sym_type
 {
-  st_none, st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
+  st_none, st_C_objprot, st_C_objimpl, st_C_objend, st_C_gnumacro,
+  st_C_struct, st_C_enum, st_C_define, st_C_typedef, st_C_typespec,
 };
 
 /* Feed stuff between (but not including) %[ and %] lines to:
@@ -1462,6 +1480,10 @@ enum sym_type
 %[
 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
 %%
+@interface,    0,      st_C_objprot
+@protocol,     0,      st_C_objprot
+@implementation,0,     st_C_objimpl
+@end,          0,      st_C_objend
 class,         C_PLPL, st_C_struct
 domain,        C_STAR, st_C_struct
 union,         0,      st_C_struct
@@ -1483,6 +1505,15 @@ extern,          0,      st_C_typespec
 static,        0,      st_C_typespec
 const,         0,      st_C_typespec
 volatile,      0,      st_C_typespec
+# DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
+DEFUN,         0,      st_C_gnumacro
+SYSCALL,       0,      st_C_gnumacro
+ENTRY,         0,      st_C_gnumacro
+PSEUDO,                0,      st_C_gnumacro
+# These are defined inside C functions, so currently they are not met.
+# EXFUN used in glibc, DEFVAR_* in emacs.
+#EXFUN,                0,      st_C_gnumacro
+#DEFVAR_,      0,      st_C_gnumacro
 %]
 and replace lines between %< and %> with its output. */
 /*%<*/
@@ -1493,12 +1524,12 @@ and replace lines between %< and %> with its output. */
 struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
 
 #define MIN_WORD_LENGTH 3
-#define MAX_WORD_LENGTH 8
-#define MIN_HASH_VALUE 10
-#define MAX_HASH_VALUE 62
+#define MAX_WORD_LENGTH 15
+#define MIN_HASH_VALUE 7
+#define MAX_HASH_VALUE 63
 /*
-   21 keywords
-   53 is the maximum key range
+   29 keywords
+   57 is the maximum key range
 */
 
 static int
@@ -1508,19 +1539,19 @@ hash (str, len)
 {
   static unsigned char hash_table[] =
     {
-     62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-     62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-     62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-     62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-     62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-     62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-     62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-     62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-     62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
-     62, 62, 62, 62, 62, 62, 62,  2, 62,  7,
-      6,  9, 15, 30, 62, 24, 62, 62,  1, 24,
-      7, 27, 13, 62, 19, 26, 18, 27,  1, 62,
-     62, 62, 62, 62, 62, 62, 62, 62,
+     63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+     63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+     63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+     63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+     63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+     63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+     63, 63, 63, 63, 17, 63, 63, 63,  4, 14,
+      4, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+      8, 63, 63,  0, 23, 63, 63, 63, 63, 63,
+     63, 63, 63, 63, 63, 63, 63, 28, 63, 28,
+     10, 31, 27, 18, 63,  6, 63, 63, 26,  1,
+     11,  2, 29, 63, 29, 16, 26, 13, 15, 63,
+     63, 63, 63, 63, 63, 63, 63, 63,
   };
   return len + hash_table[str[2]] + hash_table[str[0]];
 }
@@ -1533,43 +1564,47 @@ in_word_set  (str, len)
 
   static struct C_stab_entry  wordlist[] =
     {
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
-      {"",},
-      {"volatile",     0,      st_C_typespec},
-      {"",},
-      {"long",         0,      st_C_typespec},
-      {"char",         0,      st_C_typespec},
-      {"class",        C_PLPL, st_C_struct},
-      {"",}, {"",}, {"",}, {"",},
-      {"const",        0,      st_C_typespec},
-      {"",}, {"",}, {"",}, {"",},
-      {"auto",         0,      st_C_typespec},
-      {"",}, {"",},
-      {"define",       0,      st_C_define},
-      {"",},
-      {"void",         0,      st_C_typespec},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+      {"SYSCALL",      0,      st_C_gnumacro},
+      {"",}, {"",}, {"",}, {"",}, {"",},
+      {"DEFUN",                0,      st_C_gnumacro},
       {"",}, {"",}, {"",},
-      {"extern",       0,      st_C_typespec},
-      {"static",       0,      st_C_typespec},
-      {"",},
       {"domain",       C_STAR, st_C_struct},
-      {"",},
-      {"typedef",      0,      st_C_typedef},
+      {"",}, {"",}, {"",}, {"",}, {"",},
+      {"short",        0,      st_C_typespec},
+      {"union",        0,      st_C_struct},
+      {"void",         0,      st_C_typespec},
+      {"",}, {"",},
+      {"PSEUDO",               0,      st_C_gnumacro},
       {"double",       0,      st_C_typespec},
-      {"enum",         0,      st_C_enum},
-      {"",}, {"",}, {"",}, {"",},
+      {"",}, {"",},
+      {"@end",                 0,      st_C_objend},
+      {"@implementation", 0,   st_C_objimpl},
+      {"float",        0,      st_C_typespec},
       {"int",          0,      st_C_typespec},
       {"",},
-      {"float",        0,      st_C_typespec},
+      {"unsigned",     0,      st_C_typespec},
+      {"@interface",   0,      st_C_objprot},
+      {"",},
+      {"signed",       0,      st_C_typespec},
+      {"long",         0,      st_C_typespec},
+      {"ENTRY",                0,      st_C_gnumacro},
+      {"define",       0,      st_C_define},
+      {"const",        0,      st_C_typespec},
       {"",}, {"",}, {"",},
+      {"enum",         0,      st_C_enum},
+      {"volatile",     0,      st_C_typespec},
+      {"static",       0,      st_C_typespec},
       {"struct",       0,      st_C_struct},
-      {"",}, {"",}, {"",}, {"",},
-      {"union",        0,      st_C_struct},
-      {"",},
-      {"short",        0,      st_C_typespec},
+      {"",}, {"",}, {"",},
+      {"@protocol",    0,      st_C_objprot},
       {"",}, {"",},
-      {"unsigned",     0,      st_C_typespec},
-      {"signed",       0,      st_C_typespec},
+      {"auto",         0,      st_C_typespec},
+      {"",},
+      {"char",         0,      st_C_typespec},
+      {"class",        C_PLPL, st_C_struct},
+      {"typedef",      0,      st_C_typedef},
+      {"extern",       0,      st_C_typespec},
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -1580,7 +1615,7 @@ in_word_set  (str, len)
         {
           register char *s = wordlist[key].name;
 
-          if (*s == *str && strneq (str + 1, s + 1, len - 1))
+          if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
             return &wordlist[key];
         }
     }
@@ -1605,7 +1640,7 @@ C_symtype(str, len, c_ext)
   * C functions are recognized using a simple finite automaton.
   * funcdef is its state variable.
   */
-typedef enum
+enum
 {
   fnone,                       /* nothing seen */
   ftagseen,                    /* function-like tag seen */
@@ -1613,23 +1648,21 @@ typedef enum
   finlist,                     /* in parameter list */
   flistseen,                   /* after parameter list */
   fignore                      /* before open brace */
-} FUNCST;
-FUNCST funcdef;
+} funcdef;
 
 
  /*
   * typedefs are recognized using a simple finite automaton.
   * typeddef is its state variable.
   */
-typedef enum
+enum
 {
   tnone,                       /* nothing seen */
   ttypedseen,                  /* typedef keyword seen */
   tinbody,                     /* inside typedef body */
   tend,                                /* just before typedef tag */
   tignore                      /* junk after typedef tag */
-} TYPEDST;
-TYPEDST typdef;
+} typdef;
 
 
  /*
@@ -1637,15 +1670,14 @@ TYPEDST typdef;
   * using another simple finite automaton.  `structdef' is its state
   * variable.
   */
-typedef enum
+enum
 {
   snone,                       /* nothing seen yet */
   skeyseen,                    /* struct-like keyword seen */
   stagseen,                    /* struct-like tag seen */
   scolonseen,                  /* colon seen after struct-like tag */
   sinbody                      /* in struct body: recognize member func defs*/
-} STRUCTST;
-STRUCTST structdef;
+} structdef;
 
 /*
  * When structdef is stagseen, scolonseen, or sinbody, structtag is the
@@ -1655,17 +1687,40 @@ STRUCTST structdef;
 char *structtag = "<uninited>";
 enum sym_type structtype;
 
+/*
+ * When objdef is different from onone, objtag is the name of the class.
+ */
+char *objtag = "<uninited>";
+
 /*
  * Yet another little state machine to deal with preprocessor lines.
  */
-typedef enum
+enum
 {
   dnone,                       /* nothing seen */
   dsharpseen,                  /* '#' seen as first char on line */
   ddefineseen,                 /* '#' and 'define' seen */
   dignorerest                  /* ignore rest of line */
-} DEFINEST;
-DEFINEST definedef;
+} definedef;
+
+/*
+ * State machine for Objective C protocols and implementations.
+ */
+enum
+{
+  onone,                       /* nothing seen */
+  oprotocol,                   /* @interface or @protocol seen */
+  oimplementation,             /* @implementations seen */
+  otagseen,                    /* class name seen */
+  oparenseen,                  /* parenthesis before category seen */
+  ocatseen,                    /* category name seen */
+  oinbody,                     /* in @implementation body */
+  omethodsign,                 /* in @implementation body, after +/- */
+  omethodtag,                  /* after method name */
+  omethodcolon,                        /* after method colon */
+  omethodparm,                 /* after method parameter */
+  oignore,                     /* wait for @end */
+} objdef;
 
 /*
  * Set this to TRUE, and the next token considered is called a function.
@@ -1678,6 +1733,11 @@ logical next_token_is_func;
  */
 logical yacc_rules;
 
+/*
+ * methodlen is the length of the method name stored in token_name.
+ */
+int methodlen;
+
 /*
  * consider_token ()
  *     checks to see if the current token is at the start of a
@@ -1697,16 +1757,18 @@ logical yacc_rules;
  *     structdef               IN OUT
  *     definedef               IN OUT
  *     typdef                  IN OUT
+ *     objdef                  IN OUT
  *     next_token_is_func      IN OUT
  */
 
 logical
-consider_token (str, len, c, c_ext, cblev, is_func)
+consider_token (str, len, c, c_ext, cblev, parlev, is_func)
      register char *str;       /* IN: token pointer */
      register int len;         /* IN: token length */
      register char c;          /* IN: first char after the token */
      int c_ext;                        /* IN: C extensions mask */
      int cblev;                        /* IN: curly brace level */
+     int parlev;               /* IN: parenthesis level */
      logical *is_func;         /* OUT: function found */
 {
   enum sym_type toktype = C_symtype (str, len, c_ext);
@@ -1831,22 +1893,11 @@ consider_token (str, len, c, c_ext, cblev, is_func)
     }
 
   /* Detect GNU macros. */
-  if (definedef == dnone)
-    if (strneq (str, "DEFUN", len)     /* Used in emacs */
-#if FALSE
-          These are defined inside C functions, so currently they
-          are not met anyway.
-       || strneq (str, "EXFUN", len) /* Used in glibc */
-       || strneq (str, "DEFVAR_", 7) /* Used in emacs */
-#endif
-       || strneq (str, "SYSCALL", len) /* Used in glibc (mach) */
-       || strneq (str, "ENTRY", len) /* Used in glibc */
-       || strneq (str, "PSEUDO", len)) /* Used in glibc */
-
-      {
-       next_token_is_func = TRUE;
-       return FALSE;
-      }
+  if (definedef == dnone && toktype == st_C_gnumacro)
+    {
+      next_token_is_func = TRUE;
+      return FALSE;
+    }
   if (next_token_is_func)
     {
       next_token_is_func = FALSE;
@@ -1855,6 +1906,78 @@ consider_token (str, len, c, c_ext, cblev, is_func)
       return TRUE;
     }
 
+  /*
+   * Detecting Objective C constructs.
+   */
+  switch (objdef)
+    {
+    case onone:
+      switch (toktype)
+       {
+       case st_C_objprot:
+         objdef = oprotocol;
+         return FALSE;
+       case st_C_objimpl:
+         objdef = oimplementation;
+         return FALSE;
+       }
+      break;
+    case oimplementation:
+      /* Save the class tag for functions that may be defined inside. */
+      objtag = savenstr (str, len);
+      objdef = oinbody;
+      return FALSE;
+    case oprotocol:
+      /* Save the class tag for categories. */
+      objtag = savenstr (str, len);
+      objdef = otagseen;
+      *is_func = TRUE;
+      return TRUE;
+    case oparenseen:
+      objdef = ocatseen;
+      *is_func = TRUE;
+      return TRUE;
+    case oinbody:
+      break;
+    case omethodsign:
+      if (parlev == 0)
+       {
+         objdef = omethodtag;
+         methodlen = len;
+         GROW_LINEBUFFER (token_name, methodlen+1);
+         strncpy (token_name.buffer, str, len);
+         token_name.buffer[methodlen] = '\0';
+         return TRUE;
+       }
+      return FALSE;
+    case omethodcolon:
+      if (parlev == 0)
+       objdef = omethodparm;
+      return FALSE;
+    case omethodparm:
+      if (parlev == 0)
+       {
+         objdef = omethodtag;
+         methodlen =+ len;
+         GROW_LINEBUFFER (token_name, methodlen+1);
+         strncat (token_name.buffer, str, len);
+         return TRUE;
+       }
+      return FALSE;
+    case oignore:
+      if (toktype == st_C_objend)
+       {
+         /* Memory leakage here: the string pointed by objtag is
+            never released, because many tests would be needed to
+            avoid breaking on incorrect input code.  The amount of
+            memory leaked here is the sum of the lenghts of the
+            class tags.
+         free (objtag); */
+         objdef = onone;
+       }
+      return FALSE;
+    }
+
   /* A function? */
   switch (toktype)
     {
@@ -1922,16 +2045,14 @@ do {                                                                    \
   definedef = dnone;                                                   \
 } while (0)
 
+/* Ideally this macro should never be called wihen tok.valid is FALSE,
+   but this would mean that the state machines always guess right. */
 #define make_tag(isfun)  do \
-{                                                                      \
-  if (tok.valid)                                                       \
-    {                                                                  \
-      char *name = NULL;                                               \
-      if (tok.named)                                                   \
-       name = savestr (token_name.buffer);                             \
-      pfnote (name, isfun, tok.buffer, tok.linelen, tok.lineno, tok.linepos); \
-    }                                                                  \
-  else if (DEBUG) abort ();                                            \
+if (tok.valid) {                                                       \
+  char *name = NULL;                                                   \
+  if (CTAGS || tok.named)                                              \
+    name = savestr (token_name.buffer);                                        \
+  pfnote (name, isfun, tok.buffer, tok.linelen, tok.lineno, tok.linepos); \
   tok.valid = FALSE;                                                   \
 } while (0)
 
@@ -1959,7 +2080,8 @@ C_entries (c_ext, inf)
   lp = curlb.buffer;
   *lp = 0;
 
-  definedef = dnone; funcdef = fnone; typdef = tnone; structdef = snone;
+  funcdef = fnone; typdef = tnone; structdef = snone;
+  definedef = dnone; objdef = onone;
   next_token_is_func = yacc_rules = FALSE;
   midtoken = inquote = inchar = incomm = quotednl = FALSE;
   tok.valid = savetok.valid = FALSE;
@@ -2052,9 +2174,9 @@ C_entries (c_ext, inf)
                incomm = TRUE;
                continue;
              }
-           else if (cplpl && *lp == '/')
+           else if (/* cplpl && */ *lp == '/')
              {
-               c = 0;
+               c = '\0';
                break;
              }
            else
@@ -2114,7 +2236,7 @@ C_entries (c_ext, inf)
            {
              if (endtoken (c))
                {
-                 if (cplpl && c == ':' && *lp == ':' && begtoken(*(lp + 1)))
+                 if (c == ':' && cplpl && *lp == ':' && begtoken(*(lp + 1)))
                    {
                      /*
                       * This handles :: in the middle, but not at the
@@ -2128,37 +2250,43 @@ C_entries (c_ext, inf)
                      logical is_func = FALSE;
 
                      if (yacc_rules
-                         || consider_token (newlb.buffer + tokoff, toklen,
-                                            c, c_ext, cblev, &is_func))
+                         || consider_token (newlb.buffer + tokoff, toklen, c,
+                                            c_ext, cblev, parlev, &is_func))
                        {
                          if (structdef == sinbody
                              && definedef == dnone
                              && is_func)
                            /* function defined in C++ class body */
                            {
-                             int strsize = strlen(structtag) + 2 + toklen + 1;
-                             while (token_name.size < strsize)
-                               {
-                                 token_name.size *= 2;
-                                 token_name.buffer
-                                   = (char *) xrealloc (token_name.buffer,
-                                                        token_name.size);
-                               }
+                             GROW_LINEBUFFER (token_name,
+                                              strlen(structtag)+2+toklen+1);
                              strcpy (token_name.buffer, structtag);
                              strcat (token_name.buffer, "::");
                              strncat (token_name.buffer,
                                       newlb.buffer+tokoff, toklen);
                              tok.named = TRUE;
                            }
+                         else if (objdef == ocatseen)
+                           /* Objective C category */
+                           {
+                             GROW_LINEBUFFER (token_name,
+                                              strlen(objtag)+2+toklen+1);
+                             strcpy (token_name.buffer, objtag);
+                             strcat (token_name.buffer, "(");
+                             strncat (token_name.buffer,
+                                      newlb.buffer+tokoff, toklen);
+                             strcat (token_name.buffer, ")");
+                             tok.named = TRUE;
+                           }
+                         else if (objdef == omethodtag
+                                  || objdef == omethodparm)
+                           /* Objective C method */
+                           {
+                             tok.named = TRUE;
+                           }
                          else
                            {
-                             while (token_name.size < toklen + 1)
-                               {
-                                 token_name.size *= 2;
-                                 token_name.buffer
-                                   = (char *) xrealloc (token_name.buffer,
-                                                        token_name.size);
-                               }
+                             GROW_LINEBUFFER (token_name, toklen+1);
                              strncpy (token_name.buffer,
                                       newlb.buffer+tokoff, toklen);
                              token_name.buffer[toklen] = '\0';
@@ -2179,7 +2307,8 @@ C_entries (c_ext, inf)
                          if (definedef == dnone
                              && (funcdef == ftagseen
                                  || structdef == stagseen
-                                 || typdef == tend))
+                                 || typdef == tend
+                                 || objdef != onone))
                            {
                              if (current_lb_is_new)
                                switch_line_buffers ();
@@ -2238,6 +2367,20 @@ C_entries (c_ext, inf)
        case ':':
          if (definedef != dnone)
            break;
+         switch (objdef)
+           {
+           case  otagseen:
+             objdef = oignore;
+             make_tag (TRUE);
+             break;
+           case omethodtag:
+           case omethodparm:
+             objdef = omethodcolon;
+             methodlen += 1;
+             GROW_LINEBUFFER (token_name, methodlen+1);
+             strcat (token_name.buffer, ":");
+             break;
+           }
          if (structdef == stagseen)
            structdef = scolonseen;
          else
@@ -2281,6 +2424,14 @@ C_entries (c_ext, inf)
        case ',':
          if (definedef != dnone)
            break;
+         switch (objdef)
+           {
+           case omethodtag:
+           case omethodparm:
+             make_tag (TRUE);
+             objdef = oinbody;
+             break;
+           }
          if (funcdef != finlist && funcdef != fignore)
            funcdef = fnone;
          if (structdef == stagseen)
@@ -2303,6 +2454,8 @@ C_entries (c_ext, inf)
        case '(':
          if (definedef != dnone)
            break;
+         if (objdef == otagseen && parlev == 0)
+           objdef = oparenseen;
          switch (funcdef)
            {
            case fnone:
@@ -2333,6 +2486,11 @@ C_entries (c_ext, inf)
        case ')':
          if (definedef != dnone)
            break;
+         if (objdef == ocatseen && parlev == 1)
+           {
+             make_tag (TRUE);
+             objdef = oignore;
+           }
          if (--parlev == 0)
            {
              switch (funcdef)
@@ -2377,9 +2535,22 @@ C_entries (c_ext, inf)
              funcdef = fnone;
              break;
            case fnone:
-             /* Neutralize `extern "C" {' grot and look inside structs. */
-             if (cblev == 0 && structdef == snone && typdef == tnone)
-               cblev = -1;
+             switch (objdef)
+               {
+               case otagseen:
+                 make_tag (TRUE);
+                 objdef = oignore;
+                 break;
+               case omethodtag:
+               case omethodparm:
+                 make_tag (TRUE);
+                 objdef = oinbody;
+                 break;
+               default:
+                 /* Neutralize `extern "C" {' grot and look inside structs. */
+                 if (cblev == 0 && structdef == snone && typdef == tnone)
+                   cblev = -1;
+               }
            }
          cblev++;
          break;
@@ -2415,8 +2586,15 @@ C_entries (c_ext, inf)
              structtag = "<error>";
            }
          break;
-       case '=':
-       case '#': case '+': case '-': case '~': case '&': case '%': case '/':
+       case '+':
+       case '-':
+         if (objdef == oinbody && cblev == 0)
+           {
+             objdef = omethodsign;
+             break;
+           }
+         /* FALLTHRU */
+       case '=': case '#': case '~': case '&': case '%': case '/':
        case '|': case '^': case '!': case '<': case '>': case '.': case '?':
          if (definedef != dnone)
            break;
@@ -2425,6 +2603,11 @@ C_entries (c_ext, inf)
            funcdef = fnone;
          break;
        case '\0':
+         if (objdef == otagseen)
+           {
+             make_tag (TRUE);
+             objdef = oignore;
+           }
          /* If a macro spans multiple lines don't reset its state. */
          if (quotednl)
            CNL_SAVE_DEFINEDEF;
@@ -2553,7 +2736,8 @@ getit (inf)
        && (isalpha (*cp) || isdigit (*cp) || (*cp == '_') || (*cp == '$')));
        cp++)
     continue;
-  pfnote (NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
+  pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE,
+         lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
 }
 
 void
@@ -2669,7 +2853,7 @@ Asm_labels (inf)
          if (*cp == ':' || isspace (*cp))
            {
              /* Found end of label, so copy it and add it to the table. */
-             pfnote (NULL, TRUE,
+             pfnote ((CTAGS) ? savenstr(lb.buffer, cp-lb.buffer) : NULL, TRUE,
                      lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
            }
        }
@@ -2702,7 +2886,7 @@ Perl_functions (inf)
            cp++;
          while (*cp && ! isspace(*cp) && *cp != '{')
            cp++;
-         pfnote (NULL, TRUE,
+         pfnote ((CTAGS) ? savenstr (lb.buffer, cp-lb.buffer) : NULL, TRUE,
                  lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
        }
     }
@@ -2731,7 +2915,7 @@ Pascal_functions (inf)
   struct linebuffer tline;     /* mostly copied from C_entries */
   long save_lcno;
   int save_lineno, save_len;
-  char c;
+  char c, *cp, *namebuf;
 
   logical                      /* each of these flags is TRUE iff: */
     incomment,                 /* point is inside a comment */
@@ -2845,32 +3029,27 @@ Pascal_functions (inf)
            {
              found_tag = FALSE;
              verify_tag = FALSE;
-             pfnote (NULL, TRUE,
+             pfnote (namebuf, TRUE,
                      tline.buffer, save_len, save_lineno, save_lcno);
              continue;
            }
        }
       if (get_tagname)         /* grab name of proc or fn */
        {
-         int size;
-
          if (*dbp == '\0')
            continue;
 
          /* save all values for later tagging */
-         size  = strlen (lb.buffer) + 1;
-         while (size > tline.size)
-           {
-             tline.size *= 2;
-             tline.buffer = (char *) xrealloc (tline.buffer, tline.size);
-           }
+         GROW_LINEBUFFER (tline, strlen (lb.buffer) + 1);
          strcpy (tline.buffer, lb.buffer);
          save_lineno = lineno;
          save_lcno = linecharno;
 
          /* grab block name */
-         for (dbp++; *dbp && (!endtoken (*dbp)); dbp++)
+         for (cp = dbp + 1; *cp && (!endtoken (*cp)); cp++)
            continue;
+         namebuf = (CTAGS) ? savenstr (dbp, cp-dbp) : NULL;
+         dbp = cp;             /* set dbp to e-o-token */
          save_len = dbp - lb.buffer + 1;
          get_tagname = FALSE;
          found_tag = TRUE;
@@ -2943,7 +3122,8 @@ L_getit ()
   if (cp == dbp)
     return;
 
-  pfnote (NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
+  pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE,
+         lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
 }
 
 void
@@ -3060,7 +3240,8 @@ get_scheme ()
        *cp && *cp != '(' && *cp != ')' && !isspace (*cp);
        cp++)
     continue;
-  pfnote (NULL, TRUE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
+  pfnote ((CTAGS) ? savenstr (dbp, cp-dbp) : NULL, TRUE,
+         lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
 }
 \f
 /* Find tags in TeX and LaTeX input files.  */
@@ -3319,7 +3500,8 @@ prolog_getit (s)
       else
        s++;
     }
-  pfnote (NULL, TRUE, save_s, s-save_s, lineno, linecharno);
+  pfnote ((CTAGS) ? savenstr (save_s, s-save_s) : NULL, TRUE,
+         save_s, s-save_s, lineno, linecharno);
 }
 
 /* It is assumed that prolog predicate starts from column 0. */
@@ -3604,10 +3786,10 @@ readline (linebuffer, stream)
      FILE *stream;
 {
   /* Read new line. */
-  int i;
   long result = readline_internal (linebuffer, stream);
-
 #ifdef ETAGS_REGEXPS
+  int i;
+
   /* Match against all listed patterns. */
   for (i = 0; i < num_patterns; ++i)
     {
@@ -3754,6 +3936,14 @@ pfatal (s1)
   exit (BAD);
 }
 
+void
+suggest_asking_for_help ()
+{
+  fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n",
+          progname);
+  exit (BAD);
+}
+
 /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
 void
 error (s1, s2)