changeset 13696:f89aa5a5c485

* etags.c (Cplusplus_suffixes): Add .M suffix for Objective C++. (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.
author Francesco Potortì <pot@gnu.org>
date Thu, 07 Dec 1995 09:10:54 +0000
parents 30147ba2d776
children 5a8356dc9ffc
files lib-src/etags.c
diffstat 1 files changed, 426 insertions(+), 236 deletions(-) [+]
line wrap: on
line diff
--- a/lib-src/etags.c	Thu Dec 07 08:41:11 1995 +0000
+++ b/lib-src/etags.c	Thu Dec 07 09:10:54 1995 +0000
@@ -25,17 +25,16 @@
  *	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 @@
 #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 @@
 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 @@
 #endif
 void add_node ();
 void error ();
+void suggest_asking_for_help ();
 void fatal (), pfatal ();
 void find_entries ();
 void free_tree ();
@@ -228,6 +228,9 @@
  * `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 lb;		/* the current line */
-struct linebuffer token_name;	/* used by C_entries as temporary area */
+struct linebuffer token_name;	/* used by C_entries as a temporary area */
 struct
 {
   long linepos;
@@ -245,12 +248,14 @@
 /* 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 *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* file */
+  { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx", "M", NULL};
+
 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 };
-
-/* Pro*C file. */
+  { "perl", "@PERL@", NULL };
+
 char *plain_C_suffixes [] =
-  { "pc", NULL };
-
-/* Prolog source code */
+  { "pc",			/* Pro*C file */
+    "m",			/* Objective C file */
+    "lm",			/* Objective lex file */
+     NULL };
+
 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 };
-
-/* Yacc file */
+  { "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL };
+
 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 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 */
 };
 
 
@@ -763,7 +761,7 @@
 	    {
 	      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 @@
 	  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 @@
 	  break;
 #endif /* CTAGS */
 	default:
-	  goto usage;
+	  suggest_asking_for_help ();
 	}
     }
 
@@ -846,11 +838,7 @@
   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 @@
 {
   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;
-    }
-
-  return NULL;
+  if (name != NULL)
+    for (lang = lang_names; lang->name != NULL; lang++)
+      {
+	if (streq (name, lang->name))
+	  return lang->function;
+      }
+
+  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 @@
   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 @@
 /* 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 @@
      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 @@
 	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);
-
-	  for (sp = node->pat; *sp; sp++)
-	    {
-	      if (*sp == '\\' || *sp == searchar)
-		putc ('\\', tagf);
-	      putc (*sp, tagf);
-	    }
-	  putc (searchar, tagf);
+      if (node->name == NULL)
+	error ("internal error: NULL name in ctags mode.", 0);
+
+      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 @@
  */
 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 @@
 %[
 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 @@
 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 @@
 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 @@
 {
   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 @@
 
   static struct C_stab_entry  wordlist[] =
     {
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
+      {"SYSCALL", 	0,	st_C_gnumacro},
+      {"",}, {"",}, {"",}, {"",}, {"",},
+      {"DEFUN", 		0,	st_C_gnumacro},
+      {"",}, {"",}, {"",},
+      {"domain",  	C_STAR,	st_C_struct},
+      {"",}, {"",}, {"",}, {"",}, {"",},
+      {"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},
+      {"",}, {"",},
+      {"@end", 		0,	st_C_objend},
+      {"@implementation", 0,	st_C_objimpl},
+      {"float",    	0,	st_C_typespec},
+      {"int",      	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},
+      {"",}, {"",}, {"",},
+      {"@protocol", 	0,	st_C_objprot},
+      {"",}, {"",},
+      {"auto",     	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},
-      {"",}, {"",}, {"",},
+      {"typedef",  	0,	st_C_typedef},
       {"extern",   	0,	st_C_typespec},
-      {"static",   	0,	st_C_typespec},
-      {"",},
-      {"domain",  	C_STAR,	st_C_struct},
-      {"",},
-      {"typedef",  	0,	st_C_typedef},
-      {"double",   	0,	st_C_typespec},
-      {"enum",     	0,	st_C_enum},
-      {"",}, {"",}, {"",}, {"",},
-      {"int",      	0,	st_C_typespec},
-      {"",},
-      {"float",    	0,	st_C_typespec},
-      {"",}, {"",}, {"",},
-      {"struct",  	0,	st_C_struct},
-      {"",}, {"",}, {"",}, {"",},
-      {"union",   	0,	st_C_struct},
-      {"",},
-      {"short",    	0,	st_C_typespec},
-      {"",}, {"",},
-      {"unsigned", 	0,	st_C_typespec},
-      {"signed",   	0,	st_C_typespec},
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -1580,7 +1615,7 @@
         {
           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 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 @@
   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 @@
   * 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
@@ -1656,16 +1688,39 @@
 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.
@@ -1679,6 +1734,11 @@
 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
  *	function, or corresponds to a typedef, or is a struct/union/enum
@@ -1697,16 +1757,18 @@
  *	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 @@
     }
 
   /* 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 @@
       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 @@
   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 @@
   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 @@
 		incomm = TRUE;
 		continue;
 	      }
-	    else if (cplpl && *lp == '/')
+	    else if (/* cplpl && */ *lp == '/')
 	      {
-		c = 0;
+		c = '\0';
 		break;
 	      }
 	    else
@@ -2114,7 +2236,7 @@
 	    {
 	      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 @@
 		      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 @@
 			  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 @@
 	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 @@
 	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 @@
 	case '(':
 	  if (definedef != dnone)
 	    break;
+	  if (objdef == otagseen && parlev == 0)
+	    objdef = oparenseen;
 	  switch (funcdef)
 	    {
 	    case fnone:
@@ -2333,6 +2486,11 @@
 	case ')':
 	  if (definedef != dnone)
 	    break;
+	  if (objdef == ocatseen && parlev == 1)
+	    {
+	      make_tag (TRUE);
+	      objdef = oignore;
+	    }
 	  if (--parlev == 0)
 	    {
 	      switch (funcdef)
@@ -2377,9 +2535,22 @@
 	      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 @@
 	      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 @@
 	    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 @@
 	&& (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 @@
  	  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 @@
 	    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 @@
   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 @@
 	    {
 	      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 @@
   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 @@
        *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);
 }
 
 /* Find tags in TeX and LaTeX input files.  */
@@ -3319,7 +3500,8 @@
       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 @@
      FILE *stream;
 {
   /* Read new line. */
+  long result = readline_internal (linebuffer, stream);
+#ifdef ETAGS_REGEXPS
   int i;
-  long result = readline_internal (linebuffer, stream);
-
-#ifdef ETAGS_REGEXPS
+
   /* Match against all listed patterns. */
   for (i = 0; i < num_patterns; ++i)
     {
@@ -3754,6 +3936,14 @@
   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)