Commits

Anonymous committed b82b59f

Import from CVS: tag r19-15b3

  • Participants
  • Parent commits 30df880
  • Tags r19-15b3

Comments (0)

Files changed (301)

File CHANGES-beta

 							-*- indented-text -*-
+to 19.15 beta3
+
+-- EDT/TPU modes synched from GNU Emacs, should actually work for the first
+   first time.
+-- Lots of files synched with GNU Emacs 19.34.
+-- Apropos mode enhancements.
+-- locate-library is now silent when called non-interactively.
+-- Non aggressive keyboard focus throwing is supported.
+-- Various enhancements from Lars Magne Ingebrigtsen.
+-- smtpmail.el added from GNU Emacs 19.34.
+-- man.el & man-xref.el added from GNU Emacs 19.35.
+-- crisp/brief emulation courtesy of Gary D. Foster.
+-- id-select.el courtesy of Bob Weiner.
+-- m4-mode 1.8
+-- etags.c 11.78
+-- ilisp 5.8
+-- cperl-mode 1.28
+-- cc-mode 4.322
+-- elp 2.37
+-- python-mode 2.83
+-- load-warn-when-source-newer now defaults to t
+-- tm 7.95
 
 to 19.15 beta2
 

File etc/sgml/CATALOG

 PUBLIC "-//Microsoft//DTD Internet Explorer 2.0 Tables//EN"     ietables.dtd
 PUBLIC "-//W3C//DTD HTML 3.2//EN"                       html-3.2.dtd
 PUBLIC "-//W3C//DTD HTML Experimental 19960712//EN"	html-cougar.dtd
+DOCTYPE HTML						html-3.2.dtd
+DOCTYPE HTML-3						html-3.dtd

File lib-src/etags.c

 /* Tags file maker to go with GNU Emacs
    Copyright (C) 1984, 87, 88, 89, 93, 94, 95
    Free Software Foundation, Inc. and Ken Arnold
+
 This file is not considered part of GNU Emacs.
 
 This program is free software; you can redistribute it and/or modify
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
-/* Synched up with: FSF 19.30. */
+along with this program; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
 
 /*
  * Authors:
  *	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.
+ *	Francesco Potorti` (F.Potorti@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.78";
 
 #define	TRUE	1
 #define	FALSE	0
+
 #ifndef DEBUG
 # define DEBUG FALSE
 #endif
 
 #ifdef MSDOS
-#include <fcntl.h>
-#include <sys/param.h>
+# include <string.h>
+# include <fcntl.h>
+# include <sys/param.h>
 #endif /* MSDOS */
 
 #ifdef WINDOWSNT
+# include <stdlib.h>
+# include <fcntl.h>
+# include <string.h>
+# include <io.h>
+# define MAXPATHLEN _MAX_PATH
+#endif
+
+#if !defined (MSDOS) && !defined (WINDOWSNT) && defined (STDC_HEADERS)
 #include <stdlib.h>
-#include <fcntl.h>
 #include <string.h>
-#define MAXPATHLEN _MAX_PATH
 #endif
 
 #ifdef HAVE_CONFIG_H
-#include <../src/config.h>
-/* On some systems, Emacs defines static as nothing for the sake
-   of unexec.  We don't want that here since we don't use unexec. */
-#undef static
-#endif
-
-#if __STDC__ || defined(STDC_HEADERS)
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#else
-extern char *getenv ();
+# include <config.h>
+  /* On some systems, Emacs defines static as nothing for the sake
+     of unexec.  We don't want that here since we don't use unexec. */
+# undef static
 #endif
 
 #include <stdio.h>
 #include <getopt.h>
 
 #ifdef ETAGS_REGEXPS
-#include <regex.h>
+# include <regex.h>
 #endif /* ETAGS_REGEXPS */
 
 /* Define CTAGS to make the program "ctags" compatible with the usual one.
 
 /* Exit codes for success and failure.  */
 #ifdef VMS
-#define	GOOD	1
-#define BAD	0
+# define	GOOD	1
+# define	BAD	0
 #else
-#define	GOOD	0
-#define	BAD	1
+# define	GOOD	0
+# define	BAD	1
 #endif
 
 /* C extensions. */
 #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 lowcase(c)	tolower ((unsigned char)c)
-
-#define	iswhite(arg)	(_wht[(unsigned int) arg]) /* T if char is white */
-#define	begtoken(arg)	(_btk[(unsigned int) arg]) /* T if char can start token */
-#define	intoken(arg)	(_itk[(unsigned int) arg]) /* T if char can be in token */
-#define	endtoken(arg)	(_etk[(unsigned int) arg]) /* T if char ends tokens */
-
-/* typedefs from down below, moved up for prototypes */
+#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 ((char)c)
+
+#define	iswhite(arg)	(_wht[arg])	/* T if char is white		*/
+#define	begtoken(arg)	(_btk[arg])	/* T if char can start token	*/
+#define	intoken(arg)	(_itk[arg])	/* T if char can be in token	*/
+#define	endtoken(arg)	(_etk[arg])	/* T if char ends tokens	*/
+
+#ifdef DOS_NT
+# define absolutefn(fn) (fn[0] == '/' \
+			 || (fn[1] == ':' && fn[2] == '/'))
+#else
+# define absolutefn(fn) (fn[0] == '/')
+#endif
+
+
+/*
+ *	xnew -- allocate storage
+ *
+ * SYNOPSIS:	Type *xnew (int n, Type);
+ */
+#define xnew(n,Type)	((Type *) xmalloc ((n) * sizeof (Type)))
+
+typedef int logical;
+
+typedef struct nd_st
+{				/* sorting structure		*/
+  char *name;			/* function or type name	*/
+  char *file;			/* file name			*/
+  logical is_func;		/* use pattern or line no	*/
+  logical been_warned;		/* set if noticed dup		*/
+  int lno;			/* line number tag is on	*/
+  long cno;			/* character number line starts on */
+  char *pat;			/* search pattern		*/
+  struct nd_st *left, *right;	/* left and right sons		*/
+} NODE;
+
+extern char *getenv ();
+
+char *concat ();
+char *savenstr (), *savestr ();
+char *etags_strchr (), *etags_strrchr ();
+char *etags_getcwd ();
+char *relative_filename (), *absolute_filename (), *absolute_dirname ();
+void grow_linebuffer ();
+long *xmalloc (), *xrealloc ();
+
+typedef void Lang_function ();
+#if FALSE				/* many compilers barf on this */
+Lang_function Asm_labels;
+Lang_function default_C_entries;
+Lang_function C_entries;
+Lang_function Cplusplus_entries;
+Lang_function Cstar_entries;
+Lang_function Erlang_functions;
+Lang_function Fortran_functions;
+Lang_function Yacc_entries;
+Lang_function Lisp_functions;
+Lang_function Pascal_functions;
+Lang_function Perl_functions;
+Lang_function Prolog_functions;
+Lang_function Scheme_functions;
+Lang_function TeX_functions;
+Lang_function just_read_file;
+#else				/* so let's write it this way */
+void Asm_labels ();
+void C_entries ();
+void default_C_entries ();
+void plain_C_entries ();
+void Cplusplus_entries ();
+void Cstar_entries ();
+void Erlang_functions ();
+void Fortran_functions ();
+void Yacc_entries ();
+void Lisp_functions ();
+void Pascal_functions ();
+void Perl_functions ();
+void Prolog_functions ();
+void Scheme_functions ();
+void TeX_functions ();
+void just_read_file ();
+#endif
+
+Lang_function *get_language_from_name ();
+Lang_function *get_language_from_interpreter ();
+Lang_function *get_language_from_suffix ();
+int total_size_of_entries ();
+long readline ();
+long readline_internal ();
+#ifdef ETAGS_REGEXPS
+void add_regex ();
+#endif
+void add_node ();
+void error ();
+void suggest_asking_for_help ();
+void fatal (), pfatal ();
+void find_entries ();
+void free_tree ();
+void getit ();
+void init ();
+void initbuffer ();
+void pfnote ();
+void process_file ();
+void put_entries ();
+void takeprec ();
+
+
+char searchar = '/';		/* use /.../ searches */
+
+int lineno;			/* line number of current line */
+long charno;			/* current character number */
+long linecharno;		/* charno of start of line */
+
+char *curfile;			/* current input file name */
+char *tagfile;			/* output file */
+char *progname;			/* name this program was invoked with */
+char *cwd;			/* current working directory */
+char *tagfiledir;		/* directory of tagfile */
+
+FILE *tagf;			/* ioptr for tags file */
+NODE *head;			/* the head of the binary tree of tags */
 
 /*
  * A `struct linebuffer' is a structure which holds a line of text.
   char *buffer;
 };
 
-#ifdef DOS_NT
-# define absolutefn(fn) (fn[0] == '/' || (isalpha (fn[0]) && fn[1] == ':'))
-#else
-# define absolutefn(fn) (fn[0] == '/')
-#endif
-
-
-/*
- *	xnew -- allocate storage
- *
- * SYNOPSIS:	Type *xnew (int n, Type);
- */
-#define xnew(n,Type)	((Type *) xmalloc ((n) * sizeof (Type)))
-
-typedef int logical;
-
-typedef struct nd_st
-{				/* sorting structure			*/
-  char *name;			/* function or type name	*/
-  char *file;			/* file name			*/
-  logical is_func;		/* use pattern or line no	*/
-  logical been_warned;		/* set if noticed dup		*/
-  long lno;			/* line number tag is on	*/
-  long cno;			/* character number line starts on */
-  char *pat;			/* search pattern		*/
-  struct nd_st *left, *right;	/* left and right sons		*/
-} NODE;
-
-extern char *getenv ();
-
-char *concat (CONST char *s1, CONST char *s2, CONST char *s3);
-char *savenstr (CONST char *cp, int len);
-char *savestr (CONST char *cp);
-char *etags_strchr (CONST char *sp, char c);
-char *etags_strrchr (CONST char *sp, char c);
-char *etags_getcwd (void);
-char *relative_filename (CONST char *file, CONST char *dir);
-char *absolute_filename (CONST char *file, CONST char *cwd);
-char *absolute_dirname (char *file, CONST char *cwd);
-void *xmalloc (unsigned int size);
-void *xrealloc (void *ptr, unsigned int size);
-
-typedef void Lang_function ();
-#if FALSE				/* many compilers barf on this */
-Lang_function Asm_labels;
-Lang_function default_C_entries;
-Lang_function C_entries;
-Lang_function Cplusplus_entries;
-Lang_function Cstar_entries;
-Lang_function Fortran_functions;
-Lang_function Yacc_entries;
-Lang_function Lisp_functions;
-Lang_function Pascal_functions;
-Lang_function Perl_functions;
-Lang_function Postscript_functions;
-Lang_function Prolog_functions;
-Lang_function Scheme_functions;
-Lang_function TeX_functions;
-Lang_function just_read_file;
-#else				/* so let's write it this way */
-void Asm_labels (FILE *inf);
-void C_entries (int c_ext, FILE *inf);
-void default_C_entries (FILE *inf);
-void plain_C_entries (FILE *inf);
-void Cplusplus_entries (FILE *inf);
-void Cstar_entries (FILE *inf);
-void Fortran_functions (FILE *inf);
-void Yacc_entries (FILE *inf);
-void Lisp_functions (FILE *inf);
-void Pascal_functions (FILE *inf);
-void Perl_functions (FILE *inf);
-void Postscript_functions (FILE *inf);
-void Prolog_functions (FILE *inf);
-void Scheme_functions (FILE *inf);
-void TeX_functions (FILE *inf);
-void just_read_file (FILE *inf);
-#endif
-
-Lang_function *get_language_from_name (char *name);
-Lang_function *get_language_from_interpreter (char *interpreter);
-Lang_function *get_language_from_suffix (CONST char *suffix);
-int total_size_of_entries (NODE *node);
-long readline (struct linebuffer *linebuffer, FILE *stream);
-long readline_internal (struct linebuffer *linebuffer, FILE *stream);
-#ifdef ETAGS_REGEXPS
-void add_regex (char *regexp_pattern);
-#endif
-void add_node (NODE *node, NODE **cur_node_p);
-void error (CONST char *s1, CONST void *s2);
-void fatal (CONST char *s1, CONST char *s2);
-void pfatal (CONST char *s1);
-void find_entries (CONST char *file, FILE *inf);
-void free_tree (NODE *);
-void getit (FILE *inf);
-void init (void);
-void initbuffer (struct linebuffer *linebuffer);
-void pfnote (char *name, logical is_func, char *linestart,
-	     int linelen, int lno, long cno);
-void process_file (CONST char *file);
-void put_entries (NODE *node);
-void takeprec (void);
-
-
-char searchar = '/';		/* use /.../ searches */
-
-int lineno;			/* line number of current line */
-long charno;			/* current character number */
-
-long linecharno;		/* charno of start of line; not used by C,
-				   but by every other language. */
-
-char *curfile;			/* current input file name */
-char *tagfile;			/* output file */
-CONST char *progname;		/* name this program was invoked with */
-char *cwd;			/* current working directory */
-char *tagfiledir;		/* directory of tagfile */
-
-FILE *tagf;			/* ioptr for tags file */
-NODE *head;			/* the head of the binary tree of tags */
-
 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;
 
 /* boolean "functions" (see init)	*/
 logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
-CONST 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";
+char
+  /* 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.  */
 				/* 0 struct/enum/union decls, and C++ */
 				/* member functions. */
 logical constantypedefs;	/* -d: create tags for C #define and enum */
-				/* constants.  Enum consts not implemented. */
+				/* constants. */
 				/* -D: opposite of -d.  Default under ctags. */
 logical update;			/* -u: update tags */
 logical vgrind_style;		/* -v: create vgrind style index output */
 Lang_function *lang_func = NULL;
 
 /* Assembly code */
-CONST char *Asm_suffixes [] = { "a",	/* Unix assembler */
+char *Asm_suffixes [] = { "a",	/* Unix assembler */
 			  "asm", /* Microcontroller assembly */
 			  "def", /* BSO/Tasking definition includes  */
 			  "inc", /* Microcontroller include files */
 
 /* Note that .c and .h can be considered C++, if the --c++ flag was
    given.  That is why default_C_entries is called here. */
-CONST char *default_C_suffixes [] =
+char *default_C_suffixes [] =
   { "c", "h", NULL };
 
-/* C++ file */
-CONST char *Cplusplus_suffixes [] =
-  { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx",
-      /* XEmacs addition: Postscript with C syntax */
-      "pdb", NULL };
-
-/* C* file */
-CONST char *Cstar_suffixes [] =
+/* .M is for Objective C++ files. */
+char *Cplusplus_suffixes [] =
+  { "C", "H", "c++", "cc", "cpp", "cxx", "h++", "hh", "hpp", "hxx", "M", NULL};
+
+char *Cstar_suffixes [] =
   { "cs", "hs", NULL };
 
-/* Fortran */
-CONST char *Fortran_suffixes [] =
+char *Erlang_suffixes [] =
+  { "erl", "hrl", NULL };
+
+char *Fortran_suffixes [] =
   { "F", "f", "f90", "for", NULL };
 
-/* Lisp source code */
-CONST char *Lisp_suffixes [] =
+char *Lisp_suffixes [] =
   { "cl", "clisp", "el", "l", "lisp", "lsp", "ml", NULL };
 
-/* Pascal file */
-CONST char *Pascal_suffixes [] =
+char *Pascal_suffixes [] =
   { "p", "pas", NULL };
 
-/* Perl file */
-CONST char *Perl_suffixes [] =
+char *Perl_suffixes [] =
   { "pl", "pm", NULL };
-CONST char *Perl_interpreters [] =
-  { "perl", NULL };
-
-/* Pro*C file. */
-CONST char *plain_C_suffixes [] =
-  { "pc", NULL };
-
-/* XEmacs addition */
-/* Postscript source code */
-CONST char *Postscript_suffixes [] =
-  { "ps", NULL };
-
-/* Prolog source code */
-CONST char *Prolog_suffixes [] =
+char *Perl_interpreters [] =
+  { "perl", "@PERL@", NULL };
+
+char *plain_C_suffixes [] =
+  { "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 */
-CONST char *Scheme_suffixes [] =
+/* 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 */
-CONST char *TeX_suffixes [] =
-  { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };
-
-/* Yacc file */
-CONST char *Yacc_suffixes [] =
-  { "y", NULL };
+char *TeX_suffixes [] =
+  { "TeX", "bib", "clo", "cls", "ltx", "sty", "tex", NULL };
+
+char *Yacc_suffixes [] =
+  { "y", "ym", NULL };		/* .ym is Objective yacc file */
 
 /* Table of language names and corresponding functions, file suffixes
    and interpreter names.
    name.  I just didn't. */
 struct lang_entry
 {
-  CONST char *name;
+  char *name;
   Lang_function *function;
-  CONST char **suffixes;
-  CONST char **interpreters;
+  char **suffixes;
+  char **interpreters;
 };
 
-CONST struct lang_entry lang_names [] =
+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 },
-  { "postscript", Postscript_functions, Postscript_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              },
+  { "erlang",  Erlang_functions,    Erlang_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 */
 };
 
 
-static void
-print_language_names (void)
+void
+print_language_names ()
 {
-  CONST struct lang_entry *lang;
-  CONST char **ext;
+  struct lang_entry *lang;
+  char **ext;
 
   puts ("\nThese are the currently supported languages, along with the\n\
 default file name suffixes:");
 #ifndef VERSION
 # define VERSION "19"
 #endif
-static void
-print_version (void)
+void
+print_version ()
 {
-  printf ("%s for Emacs version %s\n", (CTAGS) ? "ctags" : "etags", VERSION);
+  printf ("%s (GNU Emacs %s)\n", (CTAGS) ? "ctags" : "etags", VERSION);
+  puts ("Copyright (C) 1996 Free Software Foundation, Inc. and Ken Arnold");
+  puts ("This program is distributed under the same terms as Emacs");
 
   exit (GOOD);
 }
 
-static void
-print_help (void)
+void
+print_help ()
 {
   printf ("These are the options accepted by %s.  You may use unambiguous\n\
 abbreviations for the long option names.  A - as file name means read\n\
-names from stdin.\n\n", progname);
+names from stdin.", progname);
+  if (!CTAGS)
+    printf ("  Absolute names are stored in the output file as they\n\
+are.  Relative ones are stored relative to the output file's directory.");
+  puts ("\n");
 
   puts ("-a, --append\n\
         Append tag entries to existing tags file.");
 
   if (CTAGS)
     puts ("-d, --defines\n\
-        Create tag entries for constant C #defines, too.");
+        Create tag entries for C #define constants and enum constants, too.");
   else
     puts ("-D, --no-defines\n\
-        Don't create tag entries for constant C #defines.  This makes\n\
-	the tags file smaller.");
+        Don't create tag entries for C #define constants and enum constants.\n\
+	This makes the tags file smaller.");
 
   if (!CTAGS)
     {
 
   print_language_names ();
 
+  puts ("");
+  puts ("Report bugs to bug-gnu-emacs@prep.ai.mit.edu");
+
   exit (GOOD);
 }
 
 
-#ifdef ETAGS_REGEXPS
 enum argument_type
 {
   at_language,
   at_regexp,
   at_filename
 };
-#else /* !ETAGS_REGEXPS */
-enum argument_type
-{
-  at_language,
-  at_filename
-};
-#endif /* !ETAGS_REGEXPS */
 
 /* This structure helps us allow mixing of --lang and filenames. */
 typedef struct
 #include	<descrip.h>
 #define		OUTSIZE	MAX_FILE_SPEC_LEN
 short
-fn_exp (vspec *out, char *in)
+fn_exp (out, in)
+     vspec *out;
+     char *in;
 {
   static long context = 0;
   static struct dsc$descriptor_s o;
   name of each file specified by the provided arg expanding wildcards.
 */
 char *
-gfnames (char *arg, logical *p_error)
+gfnames (arg, p_error)
+     char *arg;
+     logical *p_error;
 {
   static vspec filename = {MAX_FILE_SPEC_LEN, "\0"};
 
 }
 
 #ifndef OLD  /* Newer versions of VMS do provide `system'.  */
-void
-system (char *cmd)
+system (cmd)
+     char *cmd;
 {
   fprintf (stderr, "system() function not implemented under VMS\n");
 }
 #endif
 
 #define	VERSION_DELIM	';'
-char *
-massage_name (char *s)
+char *massage_name (s)
+     char *s;
 {
   char *start = s;
 
 #endif /* VMS */
 
 
-void
-main (int argc, char *argv[])
+int
+main (argc, argv)
+     int argc;
+     char *argv[];
 {
   int i;
   unsigned int nincluded_files = 0;
 
   /*
    * If etags, always find typedefs and structure tags.  Why not?
-   * Also default is to find macro constants.
+   * Also default is to find macro constants and enum constants.
    */
   if (!CTAGS)
     typedefs = typedefs_and_cplusplus = constantypedefs = TRUE;
 	    {
 	      fprintf (stderr, "%s: -%c option may only be given once.\n",
 		       progname, opt);
-	      goto usage;
+	      suggest_asking_for_help ();
 	    }
 	  tagfile = optarg;
 	  break;
 	  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;
 	  break;
 #endif /* CTAGS */
 	default:
-	  goto usage;
+	  suggest_asking_for_help ();
 	}
     }
 
   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)
-    {
-      tagfile = CTAGS ? (char *) "tags" : (char *) "TAGS";
-    }
+    tagfile = CTAGS ? "tags" : "TAGS";
   cwd = etags_getcwd ();	/* the current working directory */
-  strcat (cwd, "/");
+  if (cwd[strlen (cwd) - 1] != '/')
+    cwd = concat (cwd, "/", "");
   if (streq (tagfile, "-"))
-    {
-      tagfiledir = cwd;
-    }
+    tagfiledir = cwd;
   else
-    {
-      tagfiledir = absolute_dirname (tagfile, cwd);
-    }
+    tagfiledir = absolute_dirname (tagfile, cwd);
 
   init ();			/* set up boolean "functions" */
 
   if (!CTAGS)
     {
       if (streq (tagfile, "-"))
-	tagf = stdout;
+	{
+	  tagf = stdout;
+#ifdef DOS_NT
+	  /* Switch redirected `stdout' to binary mode (setting `_fmode'
+	     doesn't take effect until after `stdout' is already open). */
+	  if (!isatty (fileno (stdout)))
+	    setmode (fileno (stdout), O_BINARY);
+#endif /* DOS_NT */
+	}
       else
 	tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
       if (tagf == NULL)
      because we want them ordered.  Let's do it now. */
   if (cxref_style)
     {
-      tagf = fopen (tagfile, append_to_tagfile ? "a" : "w");
-      if (tagf == NULL)
-	pfatal (tagfile);
       put_entries (head);
       exit (GOOD);
     }
 		   "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
 		   tagfile, argbuffer[i].what, tagfile);
 	  if (system (cmd) != GOOD)
-	    fatal ("failed to execute shell command", 0);
+	    fatal ("failed to execute shell command", (char *)NULL);
 	}
       append_to_tagfile = TRUE;
     }
       sprintf (cmd, "sort %s -o %s", tagfile, tagfile);
       exit (system (cmd));
     }
-  exit (GOOD);
+  return GOOD;
 }
 
 
  * Return a Lang_function given the name.
  */
 Lang_function *
-get_language_from_name (char *name)
+get_language_from_name (name)
+     char *name;
 {
-  CONST 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;
+  struct lang_entry *lang;
+
+  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 */
 }
 
 
  * Return a Lang_function given the interpreter name.
  */
 Lang_function *
-get_language_from_interpreter (char *interpreter)
+get_language_from_interpreter (interpreter)
+     char *interpreter;
 {
-  CONST struct lang_entry *lang;
-  CONST char **iname;
+  struct lang_entry *lang;
+  char **iname;
 
   if (interpreter == NULL)
     return NULL;
  * Return a Lang_function given the file suffix.
  */
 Lang_function *
-get_language_from_suffix (CONST char *suffix)
+get_language_from_suffix (suffix)
+     char *suffix;
 {
-  CONST struct lang_entry *lang;
-  CONST char **ext;
+  struct lang_entry *lang;
+  char **ext;
 
   if (suffix == NULL)
     return NULL;
  * This routine is called on each file argument.
  */
 void
-process_file (CONST char *file)
+process_file (file)
+     char *file;
 {
   struct stat stat_buf;
   FILE *inf;
+#ifdef DOS_NT
+  char *p;
+
+  for (p = file; *p != '\0'; p++)
+    if (*p == '\\')
+      *p = '/';
+#endif
 
   if (stat (file, &stat_buf) == 0 && !S_ISREG (stat_buf.st_mode))
     {
  * of a char is TRUE if it is the string "white", else FALSE.
  */
 void
-init (void)
+init ()
 {
-  register CONST char *sp;
+  register char *sp;
   register int i;
 
   for (i = 0; i < 0177; i++)
     _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
   for (sp = white; *sp; sp++)
-    _wht[(unsigned int) *sp] = TRUE;
+    _wht[*sp] = TRUE;
   for (sp = endtk; *sp; sp++)
-    _etk[(unsigned int) *sp] = TRUE;
+    _etk[*sp] = TRUE;
   for (sp = intk; *sp; sp++)
-    _itk[(unsigned int) *sp] = TRUE;
+    _itk[*sp] = TRUE;
   for (sp = begtk; *sp; sp++)
-    _btk[(unsigned int) *sp] = TRUE;
+    _btk[*sp] = TRUE;
   _wht[0] = _wht['\n'];
   _etk[0] = _etk['\n'];
   _btk[0] = _btk['\n'];
  * which finds the function and type definitions.
  */
 void
-find_entries (CONST char *file, FILE *inf)
+find_entries (file, inf)
+     char *file;
+     FILE *inf;
 {
   char *cp;
   Lang_function *function;
   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. */
 	continue;
       *cp = '\0';
 
-      if (strlen (lp) > (size_t) 0)
+      if (strlen (lp) > 0)
 	{
 	  function = get_language_from_interpreter (lp);
 	  if (function != NULL)
 }
 
 /* Record a tag. */
-#if 0
-     char *name;		/* tag name, if different from definition */
+void
+pfnote (name, is_func, linestart, linelen, lno, cno)
+     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 */
-#endif
-void
-pfnote (char *name, logical is_func, char *linestart,
-	int linelen, int lno, long cno)
 {
-  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"))
   np->lno = lno;
   /* Our char numbers are 0-base, because of C language tradition?
      ctags compatibility?  old versions compatibility?   I don't know.
-     Anyway, since emacs's are 1-base we espect etags.el to take care
+     Anyway, since emacs's are 1-base we expect etags.el to take care
      of the difference.  If we wanted to have 1-based numbers, we would
      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);
 }
  *	recurse on left children, iterate on right children.
  */
 void
-free_tree (NODE *node)
+free_tree (node)
+     register NODE *node;
 {
   while (node)
     {
  */
 NODE *last_node = NULL;
 void
-add_node (NODE *node, NODE **cur_node_p)
+add_node (node, cur_node_p)
+     NODE *node, **cur_node_p;
 {
   register int dif;
   register NODE *cur_node = *cur_node_p;
     {
       /* Etags Mode */
       if (last_node == NULL)
-	fatal ("internal error in add_node", 0);
+	fatal ("internal error in add_node", (char *)NULL);
       last_node->right = node;
       last_node = node;
     }
 }
 
 void
-put_entries (NODE *node)
+put_entries (node)
+     register NODE *node;
 {
   register char *sp;
 
   if (!CTAGS)
     {
       if (node->name != NULL)
-	fprintf (tagf, "%s\177%s\001%ld,%ld\n",
+	fprintf (tagf, "%s\177%s\001%d,%d\n",
 		 node->pat, node->name, node->lno, node->cno);
       else
-	fprintf (tagf, "%s\177%ld,%ld\n",
+	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.", (char *)NULL);
+
+      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, "%ld", 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 %ld\n",
-	     node->name, node->file, (node->lno + 63) / 64);
-  else
-    fprintf (stdout, "%-16s %3ld %-16s %s\n",
-	     node->name, node->lno, node->file, node->pat);
 
   /* Output subentries that follow this one */
   put_entries (node->right);
 }
 
 /* Length of a number's decimal representation. */
-static int
-number_len (long num)
+int
+number_len (num)
+     long num;
 {
   int len = 0;
   if (!num)
  * backward compatibility.
  */
 int
-total_size_of_entries (NODE *node)
+total_size_of_entries (node)
+     register NODE *node;
 {
   register int total;
 
  */
 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:
-      gperf -c -k1,3 -o -p -r -t
+      gperf -c -k 1,3 -o -p -r -t
 %[
-struct C_stab_entry { CONST char *name; int c_ext; enum sym_type 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
+namespace,	C_PLPL,	st_C_struct
 domain, 	C_STAR,	st_C_struct
 union,  	0,	st_C_struct
 struct, 	0,	st_C_struct
 enum,    	0,	st_C_enum
 typedef, 	0,	st_C_typedef
 define,  	0,	st_C_define
+bool,		C_PLPL,	st_C_typespec
 long,    	0,	st_C_typespec
 short,   	0,	st_C_typespec
 int,     	0,	st_C_typespec
 static,  	0,	st_C_typespec
 const,   	0,	st_C_typespec
 volatile,	0,	st_C_typespec
+explicit,	C_PLPL,	st_C_typespec
+mutable,	C_PLPL,	st_C_typespec
+typename,	C_PLPL,	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. */
 /*%<*/
-/* C code produced by gperf version 1.8.1 (K&R C version) */
-/* Command-line: gperf -c -k1,3 -o -p -r -t  */
-
-
-struct C_stab_entry { CONST char *name; int c_ext; enum sym_type type; };
+/* C code produced by gperf version 2.1 (K&R C version) */
+/* Command-line: gperf -c -k 1,3 -o -p -r -t  */
+
+
+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 34
+#define MAX_HASH_VALUE 121
 /*
-   21 keywords
-   53 is the maximum key range
+   34 keywords
+   88 is the maximum key range
 */
 
 static int
-hash (CONST char *str, int len)
+hash (str, len)
+     register char *str;
+     register unsigned int  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,
+     121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+     121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+     121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+     121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+     121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+     121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+     121, 121, 121, 121,  45, 121, 121, 121,  16,  19,
+      61, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+      10, 121, 121,  20,  53, 121, 121, 121, 121, 121,
+     121, 121, 121, 121, 121, 121, 121,  41,  45,  22,
+      60,  47,  37,  28, 121,  55, 121, 121,  20,  14,
+      29,  30,   5, 121,  50,  59,  30,  54,   6, 121,
+     121, 121, 121, 121, 121, 121, 121, 121,
   };
-  return len + hash_table[(int) str[2]] + hash_table[(int) str[0]];
+  return len + hash_table[str[2]] + hash_table[str[0]];
 }
 
-static struct C_stab_entry *
-in_word_set  (CONST char *str, int len)
+struct C_stab_entry *
+in_word_set (str, len)
+     register char *str;
+     register unsigned int len;
 {
 
   static struct C_stab_entry  wordlist[] =
     {
-      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
-      {"",},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
       {"volatile", 	0,	st_C_typespec},
-      {"",},
+      {"PSEUDO", 		0,	st_C_gnumacro},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"typedef",  	0,	st_C_typedef},
+      {"typename", 	C_PLPL,	st_C_typespec},
+      {"",}, {"",}, {"",}, 
+      {"SYSCALL", 	0,	st_C_gnumacro},
+      {"",}, {"",}, {"",}, 
+      {"mutable", 	C_PLPL,	st_C_typespec},
+      {"namespace", 	C_PLPL,	st_C_struct},
       {"long",     	0,	st_C_typespec},
+      {"",}, {"",}, 
+      {"const",    	0,	st_C_typespec},
+      {"",}, {"",}, {"",}, 
+      {"explicit", 	C_PLPL,	st_C_typespec},
+      {"",}, {"",}, {"",}, {"",}, 
+      {"void",     	0,	st_C_typespec},
+      {"",}, 
       {"char",     	0,	st_C_typespec},
       {"class",   	C_PLPL,	st_C_struct},
-      {"",}, {"",}, {"",}, {"",},
-      {"const",    	0,	st_C_typespec},
-      {"",}, {"",}, {"",}, {"",},
+      {"",}, {"",}, {"",}, 
+      {"float",    	0,	st_C_typespec},
+      {"",}, 
+      {"@implementation", 0,	st_C_objimpl},
       {"auto",     	0,	st_C_typespec},
-      {"",}, {"",},
+      {"",}, 
+      {"ENTRY", 		0,	st_C_gnumacro},
+      {"@end", 		0,	st_C_objend},
+      {"bool", 		C_PLPL,	st_C_typespec},
+      {"domain",  	C_STAR,	st_C_struct},
+      {"",}, 
+      {"DEFUN", 		0,	st_C_gnumacro},
+      {"extern",   	0,	st_C_typespec},
+      {"@interface", 	0,	st_C_objprot},
+      {"",}, {"",}, {"",}, 
+      {"int",      	0,	st_C_typespec},
+      {"",}, {"",}, {"",}, {"",}, 
+      {"signed",   	0,	st_C_typespec},
+      {"short",    	0,	st_C_typespec},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
       {"define",   	0,	st_C_define},
-      {"",},
-      {"void",     	0,	st_C_typespec},
-      {"",}, {"",}, {"",},
-      {"extern",   	0,	st_C_typespec},
+      {"@protocol", 	0,	st_C_objprot},
+      {"enum",     	0,	st_C_enum},
       {"static",   	0,	st_C_typespec},
-      {"",},
-      {"domain",  	C_STAR,	st_C_struct},
-      {"",},
-      {"typedef",  	0,	st_C_typedef},
+      {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, 
+      {"union",   	0,	st_C_struct},
+      {"struct",  	0,	st_C_struct},
+      {"",}, {"",}, {"",}, {"",}, 
       {"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)
 
       if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
         {
-          register CONST char *s = wordlist[key].name;
-
-          if (*s == *str && strneq (str + 1, s + 1, len - 1))
+          register char *s = wordlist[key].name;
+
+          if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
             return &wordlist[key];
         }
     }
 }
 /*%>*/
 
-static enum sym_type
-C_symtype (char *str, int len, int c_ext)
+enum sym_type
+C_symtype (str, len, c_ext)
+     char *str;
+     int len;
+     int c_ext;
 {
-  register struct C_stab_entry *se = in_word_set(str, len);
+  register struct C_stab_entry *se = in_word_set (str, len);
 
   if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
     return st_none;
   * 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 */
   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.
+  * typdef 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;
 
 
  /*
   * 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
  * struct tag, and structtype is the type of the preceding struct-like
  * keyword.
  */
-CONST char *structtag = "<uninited>";
+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.
 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
- *	tag.
+ *	tag, or #define, or an enum constant.
  *
- *	*IS_FUNC gets TRUE iff the token is a function or macro with args.
- *	C_EXT is which language we are looking at.
+ *	*IS_FUNC gets TRUE iff the token is a function or #define macro
+ *	with args.  C_EXT is which language we are looking at.
  *
  *	In the future we will need some way to adjust where the end of
  *	the token is; for instance, implementing the C++ keyword
  *	structdef		IN OUT
  *	definedef		IN OUT
  *	typdef			IN OUT
+ *	objdef			IN OUT
  *	next_token_is_func	IN OUT
  */
 
-#if 0
+logical
+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 */
-#endif
-static logical
-consider_token (char *str, int len, char c, int c_ext, int cblev,
-		logical *is_func)
 {
   enum sym_type toktype = C_symtype (str, len, c_ext);
 
     case dignorerest:
       return FALSE;
     default:
-      error ("internal error: definedef value.", 0);
+      error ("internal error: definedef value.", (char *)NULL);
     }
 
   /*
 	case st_C_struct:
 	case st_C_enum:
 	  break;
-	default:
-	  break;
 	}
       /* Do not return here, so the structdef stuff has a chance. */
       break;
 	case st_C_struct:
 	case st_C_enum:
 	  return FALSE;
-	default:
-	  break;
 	}
       return TRUE;
-    default:
-      break;
     }
 
   /*
    * This structdef business is NOT invoked when we are ctags and the
    * file is plain C.  This is because a struct tag may have the same
    * name as another tag, and this loses with ctags.
-   *
-   * This if statement deals with the typdef state machine as
-   * follows: if typdef==ttypedseen and token is struct/union/class/enum,
-   * return FALSE.  All the other code here is for the structdef
-   * state machine.
    */
   switch (toktype)
     {
 	  structtype = toktype;
 	}
       return FALSE;
-    default:
-      break;
     }
+
   if (structdef == skeyseen)
     {
       /* Save the tag for struct/union/class, for functions that may be
       return FALSE;
     }
 
-  /* 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;
-      }
+  /* Detect GNU macros.
+
+     DEFUN note for writers of emacs C code:
+      The DEFUN macro, used in emacs C source code, has a first arg
+     that is a string (the lisp function name), and a second arg that
+     is a C function name.  Since etags skips strings, the second arg
+     is tagged.  This is unfortunate, as it would be better to tag the
+     first arg.  The simplest way to deal with this problem would be
+     to name the tag with a name built from the function name, by
+     removing the initial 'F' character and substituting '-' for '_'.
+     Anyway, this assumes that the conventions of naming lisp
+     functions will never change.  Currently, this method is not
+     implemented, so writers of emacs code are recommended to put the
+     first two args of a DEFUN on the same line. */
+  if (definedef == dnone && toktype == st_C_gnumacro)
+    {
+      next_token_is_func = TRUE;
+      return FALSE;
+    }
   if (next_token_is_func)
     {
       next_token_is_func = FALSE;
       return TRUE;
     }
 
-  /* A function? */
+  /* Detect 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 lengths of the
+	     class tags.
+	  free (objtag); */
+	  objdef = onone;
+	}
+      return FALSE;
+    }
+
+  /* A function or enum constant? */
   switch (toktype)
     {
     case st_C_typespec:
       if (funcdef != finlist && funcdef != fignore)
         funcdef = fnone;		/* should be useless */
       return FALSE;
-    default:
+    case st_none:
+      if (constantypedefs && structdef == sinbody && structtype == st_C_enum)
+	return TRUE;
       if (funcdef == fnone)
 	{
 	  funcdef = ftagseen;
 
 /*
  * C_entries ()
- *	This routine finds functions, typedefs, #define's and
- * 	struct/union/enum definitions in C syntax and adds them
- *	to the list.
+ *	This routine finds functions, typedefs, #define's, enum
+ * 	constants and struct/union/enum definitions in C syntax
+ *	and adds them to the list.
  */
 typedef struct
 {
 do {									\
   curlinepos = charno;							\
   lineno++;								\
+  linecharno = charno;							\
   charno += readline (&curlb, inf);					\
   lp = curlb.buffer;							\
   quotednl = FALSE;							\
   definedef = dnone;							\
 } while (0)
 
-#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 ();						\
+/* This macro should never be called when tok.valid is FALSE, but
+   we must protect about both invalid input and internal errors. */
+#define make_C_tag(isfun)  do \
+if (tok.valid) {							\
+  char *name = NULL;							\
+  if (CTAGS || tok.named)						\