]> code.delx.au - gnu-emacs/blobdiff - lib-src/etags.c
Rename `Emacs and Microsoft Windows' into `Microsoft Windows'.
[gnu-emacs] / lib-src / etags.c
index 4293ebd6fc88a545bb2006056be7f28f63c473b5..e206443f39b82579c2a41bcc12b4f3db45fd6172 100644 (file)
@@ -1,6 +1,7 @@
 /* Tags file maker to go with GNU Emacs           -*- coding: latin-1 -*-
-   Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2001, 2002
-   Free Software Foundation, Inc. and Ken Arnold
+   Copyright (C) 1984, 1987, 1988, 1989, 1993, 1994, 1995,
+                 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+                 2005, 2006 Free Software Foundation, Inc. and Ken Arnold
 
  This file is not considered part of GNU Emacs.
 
@@ -16,7 +17,7 @@
 
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
 
 /*
  * Authors:
  * 2002 #line directives by Francesco Potortì.
  *
  * Francesco Potortì <pot@gnu.org> has maintained and improved it since 1993.
- *
  */
 
-char pot_etags_version[] = "@(#) pot revision number is 16.46";
+/*
+ * If you want to add support for a new language, start by looking at the LUA
+ * language, which is the simplest.  Alternatively, consider shipping a
+ * configuration file containing regexp definitions for etags.
+ */
+
+char pot_etags_version[] = "@(#) pot revision number is 17.17";
 
 #define        TRUE    1
 #define        FALSE   0
@@ -61,11 +67,11 @@ char pot_etags_version[] = "@(#) pot revision number is 16.46";
 # ifndef __P                   /* for Xemacs */
 #   define __P(args) args
 # endif
-#else
+#else  /* no config.h */
 # if defined(__STDC__) && (__STDC__ || defined(__SUNPRO_C))
 #   define __P(args) args      /* use prototypes */
 #   define PTR void *          /* for generic pointers */
-# else
+# else /* not standard C */
 #   define __P(args) ()                /* no prototypes */
 #   define const               /* remove const for old compilers' sake */
 #   define PTR long *          /* don't use void* */
@@ -76,6 +82,13 @@ char pot_etags_version[] = "@(#) pot revision number is 16.46";
 # define _GNU_SOURCE 1         /* enables some compiler checks on GNU */
 #endif
 
+#ifdef LONG_OPTIONS
+#  undef LONG_OPTIONS
+#  define LONG_OPTIONS TRUE
+#else
+#  define LONG_OPTIONS  FALSE
+#endif
+
 /* WIN32_NATIVE is for Xemacs.
    MSDOS, WINDOWSNT, DOS_NT are for Emacs. */
 #ifdef WIN32_NATIVE
@@ -111,12 +124,19 @@ char pot_etags_version[] = "@(#) pot revision number is 16.46";
 # ifndef HAVE_GETCWD
 #   define HAVE_GETCWD
 # endif /* undef HAVE_GETCWD */
-#else /* !WINDOWSNT */
+#else /* not WINDOWSNT */
 # ifdef STDC_HEADERS
 #  include <stdlib.h>
 #  include <string.h>
-# else
+# else /* no standard C headers */
     extern char *getenv ();
+#  ifdef VMS
+#   define EXIT_SUCCESS        1
+#   define EXIT_FAILURE        0
+#  else /* no VMS */
+#   define EXIT_SUCCESS        0
+#   define EXIT_FAILURE        1
+#  endif
 # endif
 #endif /* !WINDOWSNT */
 
@@ -147,7 +167,7 @@ char pot_etags_version[] = "@(#) pot revision number is 16.46";
 # define S_ISREG(m)    (((m) & S_IFMT) == S_IFREG)
 #endif
 
-#ifdef LONG_OPTIONS
+#if LONG_OPTIONS
 # include <getopt.h>
 #else
 # define getopt_long(argc,argv,optstr,lopts,lind) getopt (argc, argv, optstr)
@@ -177,15 +197,6 @@ If you want regular expression support, you should delete this notice and
 # define CTAGS FALSE
 #endif
 
-/* Exit codes for success and failure.  */
-#ifdef VMS
-# define       GOOD    1
-# define       BAD     0
-#else
-# define       GOOD    0
-# define       BAD     1
-#endif
-
 #define streq(s,t)     (assert((s)!=NULL || (t)!=NULL), !strcmp (s, t))
 #define strcaseeq(s,t) (assert((s)!=NULL && (t)!=NULL), !etags_strcasecmp (s, t))
 #define strneq(s,t,n)  (assert((s)!=NULL || (t)!=NULL), !strncmp (s, t, n))
@@ -239,11 +250,12 @@ typedef struct
 typedef struct
 {
   char *name;                  /* language name */
-  bool metasource;             /* source used to generate other sources */
+  char *help;                   /* detailed help for the language */
   Lang_function *function;     /* parse function */
-  char **filenames;            /* names of this language's files */
   char **suffixes;             /* name suffixes of this language's files */
+  char **filenames;            /* names of this language's files */
   char **interpreters;         /* interpreters for this language */
+  bool metasource;             /* source used to generate other sources */
 } language;
 
 typedef struct fdesc
@@ -293,7 +305,8 @@ typedef struct
     at_language,               /* a language specification */
     at_regexp,                 /* a regular expression */
     at_filename,               /* a file name */
-    at_stdin                   /* read from stdin here */
+    at_stdin,                  /* read from stdin here */
+    at_end                     /* stop parsing the list */
   } arg_type;                  /* argument type */
   language *lang;              /* language associated with the argument */
   char *what;                  /* the argument itself */
@@ -330,14 +343,16 @@ static void Cobol_paragraphs __P((FILE *));
 static void Cplusplus_entries __P((FILE *));
 static void Cstar_entries __P((FILE *));
 static void Erlang_functions __P((FILE *));
+static void Forth_words __P((FILE *));
 static void Fortran_functions __P((FILE *));
 static void HTML_labels __P((FILE *));
 static void Lisp_functions __P((FILE *));
+static void Lua_functions __P((FILE *));
 static void Makefile_targets __P((FILE *));
 static void Pascal_functions __P((FILE *));
 static void Perl_functions __P((FILE *));
 static void PHP_functions __P((FILE *));
-static void Postscript_functions __P((FILE *));
+static void PS_functions __P((FILE *));
 static void Prolog_functions __P((FILE *));
 static void Python_functions __P((FILE *));
 static void Scheme_functions __P((FILE *));
@@ -348,7 +363,7 @@ static void just_read_file __P((FILE *));
 
 static void print_language_names __P((void));
 static void print_version __P((void));
-static void print_help __P((void));
+static void print_help __P((argument *));
 int main __P((int, char **));
 
 static compressor *get_compressor_from_suffix __P((char *, char **));
@@ -462,6 +477,11 @@ static bool cplusplus;             /* .[hc] means C++, not C */
 static bool ignoreindent;      /* -I: ignore indentation in C */
 static bool packages_only;     /* --packages-only: in Ada, only tag packages*/
 
+/* STDIN is defined in LynxOS system headers */
+#ifdef STDIN
+# undef STDIN
+#endif
+
 #define STDIN 0x1001           /* returned by getopt_long on --parse-stdin */
 static bool parsing_stdin;     /* --parse-stdin used */
 
@@ -472,9 +492,10 @@ static bool need_filebuf;  /* some regexes are multi-line */
 # define need_filebuf FALSE
 #endif /* ETAGS_REGEXPS */
 
-#ifdef LONG_OPTIONS
+#if LONG_OPTIONS
 static struct option longopts[] =
 {
+  { "append",            no_argument,       NULL,               'a'   },
   { "packages-only",      no_argument,      &packages_only,     TRUE  },
   { "c++",               no_argument,       NULL,               'C'   },
   { "declarations",      no_argument,       &declarations,      TRUE  },
@@ -494,7 +515,7 @@ static struct option longopts[] =
   { "parse-stdin",        required_argument, NULL,               STDIN },
   { "version",           no_argument,       NULL,               'V'   },
 
-#if CTAGS /* Etags options */
+#if CTAGS /* Ctags options */
   { "backward-search",   no_argument,       NULL,               'B'   },
   { "cxref",             no_argument,       NULL,               'x'   },
   { "defines",           no_argument,       NULL,               'd'   },
@@ -505,8 +526,7 @@ static struct option longopts[] =
   { "vgrind",            no_argument,       NULL,               'v'   },
   { "no-warn",           no_argument,       NULL,               'w'   },
 
-#else /* Ctags options */
-  { "append",            no_argument,       NULL,               'a'   },
+#else /* Etags options */
   { "no-defines",        no_argument,       NULL,               'D'   },
   { "no-globals",        no_argument,       &globals,           FALSE },
   { "include",           required_argument, NULL,               'i'   },
@@ -532,6 +552,22 @@ static compressor compressors[] =
 /* Ada code */
 static char *Ada_suffixes [] =
   { "ads", "adb", "ada", NULL };
+static char Ada_help [] =
+"In Ada code, functions, procedures, packages, tasks and types are\n\
+tags.  Use the `--packages-only' option to create tags for\n\
+packages only.\n\
+Ada tag names have suffixes indicating the type of entity:\n\
+       Entity type:    Qualifier:\n\
+       ------------    ----------\n\
+       function        /f\n\
+       procedure       /p\n\
+       package spec    /s\n\
+       package body    /b\n\
+       type            /t\n\
+       task            /k\n\
+Thus, `M-x find-tag <RET> bidule/b <RET>' will go directly to the\n\
+body of the package `bidule', while `M-x find-tag <RET> bidule <RET>'\n\
+will just search for any tag `bidule'.";
 
 /* Assembly code */
 static char *Asm_suffixes [] =
@@ -545,82 +581,198 @@ static char *Asm_suffixes [] =
     "src", /* BSO/Tasking C compiler output */
     NULL
   };
+static char Asm_help [] =
+"In assembler code, labels appearing at the beginning of a line,\n\
+followed by a colon, are tags.";
+
 
 /* Note that .c and .h can be considered C++, if the --c++ flag was
-   given, or if the `class' keyowrd is met inside the file.
+   given, or if the `class' or `template' keyowrds are met inside the file.
    That is why default_C_entries is called for these. */
 static char *default_C_suffixes [] =
   { "c", "h", NULL };
+static char default_C_help [] =
+"In C code, any C function or typedef is a tag, and so are\n\
+definitions of `struct', `union' and `enum'.  `#define' macro\n\
+definitions and `enum' constants are tags unless you specify\n\
+`--no-defines'.  Global variables are tags unless you specify\n\
+`--no-globals'.  Use of `--no-globals' and `--no-defines'\n\
+can make the tags table file much smaller.\n\
+You can tag function declarations and external variables by\n\
+using `--declarations', and struct members by using `--members'.";
 
 static char *Cplusplus_suffixes [] =
   { "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",
     "M",                       /* Objective C++ */
     "pdb",                     /* Postscript with C syntax */
     NULL };
+static char Cplusplus_help [] =
+"In C++ code, all the tag constructs of C code are tagged.  (Use\n\
+--help --lang=c --lang=c++ for full help.)\n\
+In addition to C tags, member functions are also recognized, and\n\
+optionally member variables if you use the `--members' option.\n\
+Tags for variables and functions in classes are named `CLASS::VARIABLE'\n\
+and `CLASS::FUNCTION'.  `operator' definitions have tag names like\n\
+`operator+'.";
 
 static char *Cjava_suffixes [] =
   { "java", NULL };
+static char Cjava_help [] =
+"In Java code, all the tags constructs of C and C++ code are\n\
+tagged.  (Use --help --lang=c --lang=c++ --lang=java for full help.)";
+
 
 static char *Cobol_suffixes [] =
   { "COB", "cob", NULL };
+static char Cobol_help [] =
+"In Cobol code, tags are paragraph names; that is, any word\n\
+starting in column 8 and followed by a period.";
 
 static char *Cstar_suffixes [] =
   { "cs", "hs", NULL };
 
 static char *Erlang_suffixes [] =
   { "erl", "hrl", NULL };
+static char Erlang_help [] =
+"In Erlang code, the tags are the functions, records and macros\n\
+defined in the file.";
+
+char *Forth_suffixes [] =
+  { "fth", "tok", NULL };
+static char Forth_help [] =
+"In Forth code, tags are words defined by `:',\n\
+constant, code, create, defer, value, variable, buffer:, field.";
 
 static char *Fortran_suffixes [] =
   { "F", "f", "f90", "for", NULL };
+static char Fortran_help [] =
+"In Fortran code, functions, subroutines and block data are tags.";
 
 static char *HTML_suffixes [] =
   { "htm", "html", "shtml", NULL };
+static char HTML_help [] =
+"In HTML input files, the tags are the `title' and the `h1', `h2',\n\
+`h3' headers.  Also, tags are `name=' in anchors and all\n\
+occurrences of `id='.";
 
 static char *Lisp_suffixes [] =
   { "cl", "clisp", "el", "l", "lisp", "LSP", "lsp", "ml", NULL };
+static char Lisp_help [] =
+"In Lisp code, any function defined with `defun', any variable\n\
+defined with `defvar' or `defconst', and in general the first\n\
+argument of any expression that starts with `(def' in column zero\n\
+is a tag.";
+
+static char *Lua_suffixes [] =
+  { "lua", "LUA", NULL };
+static char Lua_help [] =
+"In Lua scripts, all functions are tags.";
 
 static char *Makefile_filenames [] =
   { "Makefile", "makefile", "GNUMakefile", "Makefile.in", "Makefile.am", NULL};
+static char Makefile_help [] =
+"In makefiles, targets are tags; additionally, variables are tags\n\
+unless you specify `--no-globals'.";
+
+static char *Objc_suffixes [] =
+  { "lm",                      /* Objective lex file */
+    "m",                       /* Objective C file */
+     NULL };
+static char Objc_help [] =
+"In Objective C code, tags include Objective C definitions for classes,\n\
+class categories, methods and protocols.  Tags for variables and\n\
+functions in classes are named `CLASS::VARIABLE' and `CLASS::FUNCTION'.";
 
 static char *Pascal_suffixes [] =
   { "p", "pas", NULL };
+static char Pascal_help [] =
+"In Pascal code, the tags are the functions and procedures defined\n\
+in the file.";
 
 static char *Perl_suffixes [] =
   { "pl", "pm", NULL };
-
 static char *Perl_interpreters [] =
   { "perl", "@PERL@", NULL };
+static char Perl_help [] =
+"In Perl code, the tags are the packages, subroutines and variables\n\
+defined by the `package', `sub', `my' and `local' keywords.  Use\n\
+`--globals' if you want to tag global variables.  Tags for\n\
+subroutines are named `PACKAGE::SUB'.  The name for subroutines\n\
+defined in the default package is `main::SUB'.";
 
 static char *PHP_suffixes [] =
   { "php", "php3", "php4", NULL };
+static char PHP_help [] =
+"In PHP code, tags are functions, classes and defines.  When using\n\
+the `--members' option, vars are tags too.";
 
 static char *plain_C_suffixes [] =
-  { "lm",                      /* Objective lex file */
-    "m",                       /* Objective C file */
-    "pc",                      /* Pro*C file */
+  { "pc",                      /* Pro*C file */
      NULL };
 
-static char *Postscript_suffixes [] =
+static char *PS_suffixes [] =
   { "ps", "psw", NULL };       /* .psw is for PSWrap */
+static char PS_help [] =
+"In PostScript code, the tags are the functions.";
 
 static char *Prolog_suffixes [] =
   { "prolog", NULL };
+static char Prolog_help [] =
+"In Prolog code, tags are predicates and rules at the beginning of\n\
+line.";
 
 static char *Python_suffixes [] =
   { "py", NULL };
+static char Python_help [] =
+"In Python code, `def' or `class' at the beginning of a line\n\
+generate a tag.";
 
 /* Can't do the `SCM' or `scm' prefix with a version number. */
 static char *Scheme_suffixes [] =
   { "oak", "sch", "scheme", "SCM", "scm", "SM", "sm", "ss", "t", NULL };
+static char Scheme_help [] =
+"In Scheme code, tags include anything defined with `def' or with a\n\
+construct whose name starts with `def'.  They also include\n\
+variables set with `set!' at top level in the file.";
 
 static char *TeX_suffixes [] =
   { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };
+static char TeX_help [] =
+"In LaTeX text, the argument of any of the commands `\\chapter',\n\
+`\\section', `\\subsection', `\\subsubsection', `\\eqno', `\\label',\n\
+`\\ref', `\\cite', `\\bibitem', `\\part', `\\appendix', `\\entry',\n\
+`\\index', `\\def', `\\newcommand', `\\renewcommand',\n\
+`\\newenvironment' or `\\renewenvironment' is a tag.\n\
+\n\
+Other commands can be specified by setting the environment variable\n\
+`TEXTAGS' to a colon-separated list like, for example,\n\
+     TEXTAGS=\"mycommand:myothercommand\".";
+
 
 static char *Texinfo_suffixes [] =
   { "texi", "texinfo", "txi", NULL };
+static char Texinfo_help [] =
+"for texinfo files, lines starting with @node are tagged.";
 
 static char *Yacc_suffixes [] =
   { "y", "y++", "ym", "yxx", "yy", NULL }; /* .ym is Objective yacc file */
+static char Yacc_help [] =
+"In Bison or Yacc input files, each rule defines as a tag the\n\
+nonterminal it constructs.  The portions of the file that contain\n\
+C code are parsed as C code (use --help --lang=c --lang=yacc\n\
+for full help).";
+
+static char auto_help [] =
+"`auto' is not a real language, it indicates to use\n\
+a default language for files base on file name suffix and file contents.";
+
+static char none_help [] =
+"`none' is not a real language, it indicates to only do\n\
+regexp processing on files.";
+
+static char no_lang_help [] =
+"No detailed help available for this language.";
+
 
 /*
  * Table of languages.
@@ -631,32 +783,35 @@ static char *Yacc_suffixes [] =
 
 static language lang_names [] =
 {
-  { "ada",      FALSE, Ada_funcs,            NULL, Ada_suffixes,        NULL },
-  { "asm",      FALSE, Asm_labels,           NULL, Asm_suffixes,        NULL },
-  { "c",        FALSE, default_C_entries,    NULL, default_C_suffixes,  NULL },
-  { "c++",      FALSE, Cplusplus_entries,    NULL, Cplusplus_suffixes,  NULL },
-  { "c*",       FALSE, Cstar_entries,        NULL, Cstar_suffixes,      NULL },
-  { "cobol",    FALSE, Cobol_paragraphs,     NULL, Cobol_suffixes,      NULL },
-  { "erlang",   FALSE, Erlang_functions,     NULL, Erlang_suffixes,     NULL },
-  { "fortran",  FALSE, Fortran_functions,    NULL, Fortran_suffixes,    NULL },
-  { "html",     FALSE, HTML_labels,          NULL, HTML_suffixes,       NULL },
-  { "java",     FALSE, Cjava_entries,        NULL, Cjava_suffixes,      NULL },
-  { "lisp",     FALSE, Lisp_functions,       NULL, Lisp_suffixes,       NULL },
-  { "makefile", FALSE, Makefile_targets,     Makefile_filenames, NULL,  NULL },
-  { "pascal",   FALSE, Pascal_functions,     NULL, Pascal_suffixes,     NULL },
-  { "perl",     FALSE, Perl_functions,NULL, Perl_suffixes, Perl_interpreters },
-  { "php",      FALSE, PHP_functions,        NULL, PHP_suffixes,        NULL },
-  { "postscript",FALSE, Postscript_functions,NULL, Postscript_suffixes, NULL },
-  { "proc",     FALSE, plain_C_entries,      NULL, plain_C_suffixes,    NULL },
-  { "prolog",   FALSE, Prolog_functions,     NULL, Prolog_suffixes,     NULL },
-  { "python",   FALSE, Python_functions,     NULL, Python_suffixes,     NULL },
-  { "scheme",   FALSE, Scheme_functions,     NULL, Scheme_suffixes,     NULL },
-  { "tex",      FALSE, TeX_commands,         NULL, TeX_suffixes,        NULL },
-  { "texinfo",  FALSE, Texinfo_nodes,        NULL, Texinfo_suffixes,    NULL },
-  { "yacc",      TRUE, Yacc_entries,         NULL, Yacc_suffixes,       NULL },
-  { "auto", FALSE, NULL },             /* default guessing scheme */
-  { "none", FALSE, just_read_file },   /* regexp matching only */
-  { NULL, FALSE, NULL }                /* end of list */
+  { "ada",       Ada_help,       Ada_funcs,         Ada_suffixes       },
+  { "asm",       Asm_help,       Asm_labels,        Asm_suffixes       },
+  { "c",         default_C_help, default_C_entries, default_C_suffixes },
+  { "c++",       Cplusplus_help, Cplusplus_entries, Cplusplus_suffixes },
+  { "c*",        no_lang_help,   Cstar_entries,     Cstar_suffixes     },
+  { "cobol",     Cobol_help,     Cobol_paragraphs,  Cobol_suffixes     },
+  { "erlang",    Erlang_help,    Erlang_functions,  Erlang_suffixes    },
+  { "forth",     Forth_help,     Forth_words,       Forth_suffixes     },
+  { "fortran",   Fortran_help,   Fortran_functions, Fortran_suffixes   },
+  { "html",      HTML_help,      HTML_labels,       HTML_suffixes      },
+  { "java",      Cjava_help,     Cjava_entries,     Cjava_suffixes     },
+  { "lisp",      Lisp_help,      Lisp_functions,    Lisp_suffixes      },
+  { "lua",       Lua_help,       Lua_functions,     Lua_suffixes       },
+  { "makefile",  Makefile_help,Makefile_targets,NULL,Makefile_filenames},
+  { "objc",      Objc_help,      plain_C_entries,   Objc_suffixes      },
+  { "pascal",    Pascal_help,    Pascal_functions,  Pascal_suffixes    },
+  { "perl",Perl_help,Perl_functions,Perl_suffixes,NULL,Perl_interpreters},
+  { "php",       PHP_help,       PHP_functions,     PHP_suffixes       },
+  { "postscript",PS_help,        PS_functions,      PS_suffixes        },
+  { "proc",      no_lang_help,   plain_C_entries,   plain_C_suffixes   },
+  { "prolog",    Prolog_help,    Prolog_functions,  Prolog_suffixes    },
+  { "python",    Python_help,    Python_functions,  Python_suffixes    },
+  { "scheme",    Scheme_help,    Scheme_functions,  Scheme_suffixes    },
+  { "tex",       TeX_help,       TeX_commands,      TeX_suffixes       },
+  { "texinfo",   Texinfo_help,   Texinfo_nodes,     Texinfo_suffixes   },
+  { "yacc",      Yacc_help,Yacc_entries,Yacc_suffixes,NULL,NULL,TRUE},
+  { "auto",      auto_help },                      /* default guessing scheme */
+  { "none",      none_help,      just_read_file }, /* regexp matching only */
+  { NULL }                /* end of list */
 };
 
 \f
@@ -679,14 +834,18 @@ default file names and dot suffixes:");
          printf (" .%s", *ext);
       puts ("");
     }
-  puts ("Where `auto' means use default language for files based on file\n\
+  puts ("where `auto' means use default language for files based on file\n\
 name suffix, and `none' means only do regexp processing on files.\n\
 If no language is specified and no matching suffix is found,\n\
 the first line of the file is read for a sharp-bang (#!) sequence\n\
 followed by the name of an interpreter.  If no such sequence is found,\n\
 Fortran is tried first; if no tags are found, C is tried next.\n\
-When parsing any C file, a \"class\" keyword switches to C++.\n\
-Compressed files are supported using gzip and bzip2.");
+When parsing any C file, a \"class\" or \"template\" keyword\n\
+switches to C++.");
+  puts ("Compressed files are supported using gzip and bzip2.\n\
+\n\
+For detailed help on a given language use, for example,\n\
+etags --help --lang=ada.");
 }
 
 #ifndef EMACS_NAME
@@ -699,30 +858,43 @@ static void
 print_version ()
 {
   printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);
-  puts ("Copyright (C) 2002 Free Software Foundation, Inc. and Ken Arnold");
+  puts ("Copyright (C) 2006 Free Software Foundation, Inc. and Ken Arnold");
   puts ("This program is distributed under the same terms as Emacs");
 
-  exit (GOOD);
+  exit (EXIT_SUCCESS);
 }
 
 static void
-print_help ()
+print_help (argbuffer)
+     argument *argbuffer;
 {
+  bool help_for_lang = FALSE;
+
+  for (; argbuffer->arg_type != at_end; argbuffer++)
+    if (argbuffer->arg_type == at_language)
+      {
+       if (help_for_lang)
+         puts ("");
+       puts (argbuffer->lang->help);
+       help_for_lang = TRUE;
+      }
+
+  if (help_for_lang)
+    exit (EXIT_SUCCESS);
+
   printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
 \n\
 These are the options accepted by %s.\n", progname, progname);
-#ifdef LONG_OPTIONS
-  puts ("You may use unambiguous abbreviations for the long option names.");
-#else
-  puts ("Long option names do not work with this executable, as it is not\n\
+  if (LONG_OPTIONS)
+    puts ("You may use unambiguous abbreviations for the long option names.");
+  else
+    puts ("Long option names do not work with this executable, as it is not\n\
 linked with GNU getopt.");
-#endif /* LONG_OPTIONS */
   puts ("  A - as file name means read names from stdin (one per line).\n\
 Absolute names are stored in the output file as they are.\n\
 Relative ones are stored relative to the output file's directory.\n");
 
-  if (!CTAGS)
-    puts ("-a, --append\n\
+  puts ("-a, --append\n\
         Append tag entries to existing tags file.");
 
   puts ("--packages-only\n\
@@ -736,7 +908,7 @@ Relative ones are stored relative to the output file's directory.\n");
   /* This option is mostly obsolete, because etags can now automatically
      detect C++.  Retained for backward compatibility and for debugging and
      experimentation.  In principle, we could want to tag as C++ even
-     before any "class" keyword.
+     before any "class" or "template" keyword.
   puts ("-C, --c++\n\
         Treat files whose name suffix defaults to C language as C++ files.");
   */
@@ -775,7 +947,7 @@ Relative ones are stored relative to the output file's directory.\n");
        Do not create tag entries for global variables in some\n\
        languages.  This makes the tags file smaller.");
   puts ("--members\n\
-       Create tag entries for member variables in some languages.");
+       Create tag entries for members of structures in some languages.");
 
 #ifdef ETAGS_REGEXPS
   puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\
@@ -822,9 +994,9 @@ Relative ones are stored relative to the output file's directory.\n");
   if (CTAGS)
     {
       puts ("-v, --vgrind\n\
-        Generates an index of items intended for human consumption,\n\
-        similar to the output of vgrind.  The index is sorted, and\n\
-        gives the page number of each item.");
+        Print on the standard output an index of items intended for\n\
+        human consumption, similar to the output of vgrind.  The index\n\
+        is sorted, and gives the page number of each item.");
       puts ("-w, --no-warn\n\
         Suppress warning messages about entries defined in multiple\n\
         files.");
@@ -838,14 +1010,16 @@ Relative ones are stored relative to the output file's directory.\n");
   puts ("-V, --version\n\
         Print the version of the program.\n\
 -h, --help\n\
-        Print this help message.");
+        Print this help message.\n\
+        Followed by one or more `--language' options prints detailed\n\
+        help about tag generation for the specified languages.");
 
   print_language_names ();
 
   puts ("");
   puts ("Report bugs to bug-gnu-emacs@gnu.org");
 
-  exit (GOOD);
+  exit (EXIT_SUCCESS);
 }
 
 \f
@@ -985,6 +1159,7 @@ main (argc, argv)
   argument *argbuffer;
   int current_arg, file_count;
   linebuffer filename_lb;
+  bool help_asked = FALSE;
 #ifdef VMS
   bool got_err;
 #endif
@@ -1017,18 +1192,19 @@ main (argc, argv)
       globals = TRUE;
     }
 
+  /* When the optstring begins with a '-' getopt_long does not rearrange the
+     non-options arguments to be at the end, but leaves them alone. */
   optstring = "-";
 #ifdef ETAGS_REGEXPS
   optstring = "-r:Rc:";
 #endif /* ETAGS_REGEXPS */
-#ifndef LONG_OPTIONS
-  optstring = optstring + 1;
-#endif /* LONG_OPTIONS */
+  if (!LONG_OPTIONS)
+    optstring += 1;            /* remove the initial '-' */
   optstring = concat (optstring,
-                     "Cf:Il:o:SVhH",
-                     (CTAGS) ? "BxdtTuvw" : "aDi:");
+                     "aCf:Il:o:SVhH",
+                     (CTAGS) ? "BxdtTuvw" : "Di:");
 
-  while ((opt = getopt_long (argc, argv, optstring, longopts, 0)) != EOF)
+  while ((opt = getopt_long (argc, argv, optstring, longopts, NULL)) != EOF)
     switch (opt)
       {
       case 0:
@@ -1056,6 +1232,7 @@ main (argc, argv)
        break;
 
        /* Common options. */
+      case 'a': append_to_tagfile = TRUE;      break;
       case 'C': cplusplus = TRUE;              break;
       case 'f':                /* for compatibility with old makefiles */
       case 'o':
@@ -1063,6 +1240,7 @@ main (argc, argv)
          {
            error ("-o option may only be given once.", (char *)NULL);
            suggest_asking_for_help ();
+           /* NOTREACHED */
          }
        tagfile = optarg;
        break;
@@ -1100,11 +1278,10 @@ main (argc, argv)
        break;
       case 'h':
       case 'H':
-       print_help ();
+       help_asked = TRUE;
        break;
 
        /* Etags options */
-      case 'a': append_to_tagfile = TRUE;                      break;
       case 'D': constantypedefs = FALSE;                       break;
       case 'i': included_files[nincluded_files++] = optarg;    break;
 
@@ -1119,9 +1296,11 @@ main (argc, argv)
       case 'w': no_warnings = TRUE;                            break;
       default:
        suggest_asking_for_help ();
+       /* NOTREACHED */
       }
 
-  for (; optind < argc; ++optind)
+  /* No more options.  Store the rest of arguments. */
+  for (; optind < argc; optind++)
     {
       argbuffer[current_arg].arg_type = at_filename;
       argbuffer[current_arg].what = argv[optind];
@@ -1129,10 +1308,17 @@ main (argc, argv)
       ++file_count;
     }
 
+  argbuffer[current_arg].arg_type = at_end;
+
+  if (help_asked)
+    print_help (argbuffer);
+    /* NOTREACHED */
+
   if (nincluded_files == 0 && file_count == 0)
     {
       error ("no input files specified.", (char *)NULL);
       suggest_asking_for_help ();
+      /* NOTREACHED */
     }
 
   if (tagfile == NULL)
@@ -1144,7 +1330,9 @@ main (argc, argv)
       cwd = concat (oldcwd, "/", "");
       free (oldcwd);
     }
-  if (streq (tagfile, "-"))
+  /* Relative file names are made relative to the current directory. */
+  if (streq (tagfile, "-")
+      || strneq (tagfile, "/dev/", 5))
     tagfiledir = cwd;
   else
     tagfiledir = absolute_dirname (tagfile, cwd);
@@ -1177,7 +1365,7 @@ main (argc, argv)
   /*
    * Loop through files finding functions.
    */
-  for (i = 0; i < current_arg; ++i)
+  for (i = 0; i < current_arg; i++)
     {
       static language *lang;   /* non-NULL if language is forced */
       char *this_file;
@@ -1240,7 +1428,8 @@ main (argc, argv)
 
   if (!CTAGS || cxref_style)
     {
-      put_entries (nodehead);  /* write the remainig tags (ETAGS) */
+      /* Write the remaining tags to tagf (ETAGS) or stdout (CXREF). */
+      put_entries (nodehead);
       free_tree (nodehead);
       nodehead = NULL;
       if (!CTAGS)
@@ -1254,11 +1443,12 @@ main (argc, argv)
 
          while (nincluded_files-- > 0)
            fprintf (tagf, "\f\n%s,include\n", *included_files++);
+
+         if (fclose (tagf) == EOF)
+           pfatal (tagfile);
        }
 
-      if (fclose (tagf) == EOF)
-       pfatal (tagfile);
-      exit (GOOD);
+      exit (EXIT_SUCCESS);
     }
 
   if (update)
@@ -1277,7 +1467,7 @@ main (argc, argv)
          sprintf (cmd,
                   "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
                   tagfile, argbuffer[i].what, tagfile);
-         if (system (cmd) != GOOD)
+         if (system (cmd) != EXIT_SUCCESS)
            fatal ("failed to execute shell command", (char *)NULL);
        }
       append_to_tagfile = TRUE;
@@ -1292,13 +1482,14 @@ main (argc, argv)
   if (fclose (tagf) == EOF)
     pfatal (tagfile);
 
-  if (update)
-    {
-      char cmd[2*BUFSIZ+10];
-      sprintf (cmd, "sort -o %.*s %.*s", BUFSIZ, tagfile, BUFSIZ, tagfile);
-      exit (system (cmd));
-    }
-  return GOOD;
+  if (CTAGS)
+    if (append_to_tagfile || update)
+      {
+       char cmd[2*BUFSIZ+10];
+       sprintf (cmd, "sort -o %.*s %.*s", BUFSIZ, tagfile, BUFSIZ, tagfile);
+       exit (system (cmd));
+      }
+  return EXIT_SUCCESS;
 }
 
 
@@ -1765,12 +1956,8 @@ find_entries (inf)
          {
            fdesc *badfdp = *fdpp;
 
-           if (DEBUG)
-             fprintf (stderr,
-                      "Removing references to \"%s\" obtained from \"%s\"\n",
-                      badfdp->taggedfname, badfdp->infname);
-
-           /* Delete the tags referring to badfdp. */
+           /* Delete the tags referring to badfdp->taggedfname
+              that were obtained from badfdp->infname. */
            invalidate_nodes (badfdp, &nodehead);
 
            *fdpp = badfdp->next; /* remove the bad description from the list */
@@ -1875,6 +2062,7 @@ pfnote (name, is_func, linestart, linelen, lno, cno)
 {
   register node *np;
 
+  assert (name == NULL || name[0] != '\0');
   if (CTAGS && name == NULL)
     return;
 
@@ -2225,11 +2413,11 @@ enum sym_type
   st_none,
   st_C_objprot, st_C_objimpl, st_C_objend,
   st_C_gnumacro,
-  st_C_ignore,
+  st_C_ignore, st_C_attribute,
   st_C_javastruct,
   st_C_operator,
   st_C_class, st_C_template,
-  st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef, st_C_typespec
+  st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef
 };
 
 static unsigned int hash __P((const char *, unsigned int));
@@ -2237,79 +2425,67 @@ static struct C_stab_entry * in_word_set __P((const char *, unsigned int));
 static enum sym_type C_symtype __P((char *, int, int));
 
 /* Feed stuff between (but not including) %[ and %] lines to:
-      gperf -c -k 1,3 -o -p -r -t
+     gperf -m 5
 %[
+%compare-strncmp
+%enum
+%struct-type
 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
 %%
-if,            0,      st_C_ignore
-for,           0,      st_C_ignore
-while,         0,      st_C_ignore
-switch,                0,      st_C_ignore
-return,                0,      st_C_ignore
-@interface,    0,      st_C_objprot
-@protocol,     0,      st_C_objprot
-@implementation,0,     st_C_objimpl
-@end,          0,      st_C_objend
-import,                C_JAVA, st_C_ignore
-package,       C_JAVA, st_C_ignore
-friend,                C_PLPL, st_C_ignore
-extends,       C_JAVA, st_C_javastruct
-implements,    C_JAVA, st_C_javastruct
-interface,     C_JAVA, st_C_struct
-class,         0,      st_C_class
-namespace,     C_PLPL, st_C_struct
-domain,        C_STAR, st_C_struct
-union,         0,      st_C_struct
-struct,        0,      st_C_struct
-extern,        0,      st_C_extern
-enum,          0,      st_C_enum
-typedef,       0,      st_C_typedef
-define,        0,      st_C_define
-operator,      C_PLPL, st_C_operator
-template,      0,      st_C_template
-bool,          C_PLPL, st_C_typespec
-long,          0,      st_C_typespec
-short,         0,      st_C_typespec
-int,           0,      st_C_typespec
-char,          0,      st_C_typespec
-float,         0,      st_C_typespec
-double,        0,      st_C_typespec
-signed,        0,      st_C_typespec
-unsigned,      0,      st_C_typespec
-auto,          0,      st_C_typespec
-void,          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
+if,            0,                      st_C_ignore
+for,           0,                      st_C_ignore
+while,         0,                      st_C_ignore
+switch,                0,                      st_C_ignore
+return,                0,                      st_C_ignore
+__attribute__, 0,                      st_C_attribute
+@interface,    0,                      st_C_objprot
+@protocol,     0,                      st_C_objprot
+@implementation,0,                     st_C_objimpl
+@end,          0,                      st_C_objend
+import,                (C_JAVA & !C_PLPL),     st_C_ignore
+package,       (C_JAVA & !C_PLPL),     st_C_ignore
+friend,                C_PLPL,                 st_C_ignore
+extends,       (C_JAVA & !C_PLPL),     st_C_javastruct
+implements,    (C_JAVA & !C_PLPL),     st_C_javastruct
+interface,     (C_JAVA & !C_PLPL),     st_C_struct
+class,         0,                      st_C_class
+namespace,     C_PLPL,                 st_C_struct
+domain,                C_STAR,                 st_C_struct
+union,         0,                      st_C_struct
+struct,                0,                      st_C_struct
+extern,                0,                      st_C_extern
+enum,          0,                      st_C_enum
+typedef,       0,                      st_C_typedef
+define,                0,                      st_C_define
+operator,      C_PLPL,                 st_C_operator
+template,      0,                      st_C_template
 # 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
+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
+#EXFUN,                0,                      st_C_gnumacro
+#DEFVAR_,      0,                      st_C_gnumacro
 %]
-and replace lines between %< and %> with its output,
-then make in_word_set and C_stab_entry static. */
+and replace lines between %< and %> with its output, then:
+ - remove the #if characterset check
+ - make in_word_set static and not inline. */
 /*%<*/
-/* C code produced by gperf version 2.7.1 (19981006 egcs) */
-/* Command-line: gperf -c -k 1,3 -o -p -r -t  */
-struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
+/* C code produced by gperf version 3.0.1 */
+/* Command-line: gperf -m 5  */
+/* Computed positions: -k'1-2' */
 
-#define TOTAL_KEYWORDS 47
-#define MIN_WORD_LENGTH 2
-#define MAX_WORD_LENGTH 15
-#define MIN_HASH_VALUE 18
-#define MAX_HASH_VALUE 138
-/* maximum key range = 121, duplicates = 0 */
+struct C_stab_entry { char *name; int c_ext; enum sym_type type; };
+/* maximum key range = 31, duplicates = 0 */
 
 #ifdef __GNUC__
 __inline
+#else
+#ifdef __cplusplus
+inline
+#endif
 #endif
 static unsigned int
 hash (str, len)
@@ -2318,132 +2494,84 @@ hash (str, len)
 {
   static unsigned char asso_values[] =
     {
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139,  63, 139, 139, 139,  33,  44,
-       62, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-       42, 139, 139,  12,  32, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139,  34,  59,  37,
-       24,  58,  33,   3, 139,  16, 139, 139,  42,  60,
-       18,  11,  39, 139,  23,  57,   4,  63,   6,  20,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
-      139, 139, 139, 139, 139, 139
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34,  1, 34, 34, 34, 14, 14,
+      34, 34, 34, 34, 34, 34, 34, 34, 13, 34,
+      13, 34, 34, 12, 34, 34, 34, 34, 34, 11,
+      34, 34, 34, 34, 34,  8, 34, 11, 34, 12,
+      11,  0,  1, 34,  7,  0, 34, 34, 11,  9,
+       0,  4,  0, 34,  7,  4, 14, 21, 34, 15,
+       0,  2, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+      34, 34, 34, 34, 34, 34
     };
-  register int hval = len;
-
-  switch (hval)
-    {
-      default:
-      case 3:
-        hval += asso_values[(unsigned char)str[2]];
-      case 2:
-      case 1:
-        hval += asso_values[(unsigned char)str[0]];
-        break;
-    }
-  return hval;
+  return len + asso_values[(unsigned char)str[1]] + asso_values[(unsigned char)str[0]];
 }
 
-#ifdef __GNUC__
-__inline
-#endif
 static struct C_stab_entry *
 in_word_set (str, len)
      register const char *str;
      register unsigned int len;
 {
+  enum
+    {
+      TOTAL_KEYWORDS = 31,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 15,
+      MIN_HASH_VALUE = 3,
+      MAX_HASH_VALUE = 33
+    };
+
   static struct C_stab_entry wordlist[] =
     {
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {"if",           0,      st_C_ignore},
-      {""}, {""}, {""}, {""},
-      {"int",          0,      st_C_typespec},
-      {""}, {""},
-      {"void",         0,      st_C_typespec},
-      {""}, {""},
-      {"interface",    C_JAVA, st_C_struct},
-      {""},
-      {"SYSCALL",      0,      st_C_gnumacro},
-      {""},
-      {"return",               0,      st_C_ignore},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {"while",                0,      st_C_ignore},
-      {"auto",         0,      st_C_typespec},
-      {""}, {""}, {""}, {""}, {""}, {""},
-      {"float",        0,      st_C_typespec},
-      {"typedef",      0,      st_C_typedef},
-      {"typename",     C_PLPL, st_C_typespec},
       {""}, {""}, {""},
-      {"friend",               C_PLPL, st_C_ignore},
-      {"volatile",     0,      st_C_typespec},
-      {""}, {""},
-      {"for",          0,      st_C_ignore},
-      {"const",        0,      st_C_typespec},
-      {"import",               C_JAVA, st_C_ignore},
-      {""},
-      {"define",       0,      st_C_define},
-      {"long",         0,      st_C_typespec},
-      {"implements",   C_JAVA, st_C_javastruct},
-      {"signed",       0,      st_C_typespec},
-      {""},
-      {"extern",       0,      st_C_extern},
-      {"extends",      C_JAVA, st_C_javastruct},
-      {""},
-      {"mutable",      C_PLPL, st_C_typespec},
-      {"template",     0,      st_C_template},
-      {"short",        0,      st_C_typespec},
-      {"bool",         C_PLPL, st_C_typespec},
-      {"char",         0,      st_C_typespec},
-      {"class",        0,      st_C_class},
-      {"operator",     C_PLPL, st_C_operator},
-      {""},
-      {"switch",               0,      st_C_ignore},
-      {""},
-      {"ENTRY",                0,      st_C_gnumacro},
-      {""},
-      {"package",      C_JAVA, st_C_ignore},
-      {"union",        0,      st_C_struct},
-      {"@end",         0,      st_C_objend},
-      {"struct",       0,      st_C_struct},
-      {"namespace",    C_PLPL, st_C_struct},
-      {""}, {""},
-      {"domain",       C_STAR, st_C_struct},
-      {"@interface",   0,      st_C_objprot},
-      {"PSEUDO",               0,      st_C_gnumacro},
-      {"double",       0,      st_C_typespec},
-      {""},
-      {"@protocol",    0,      st_C_objprot},
-      {""},
-      {"static",       0,      st_C_typespec},
-      {""}, {""},
-      {"DEFUN",                0,      st_C_gnumacro},
-      {""}, {""}, {""}, {""},
-      {"explicit",     C_PLPL, st_C_typespec},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {""},
-      {"enum",         0,      st_C_enum},
-      {""}, {""},
-      {"unsigned",     0,      st_C_typespec},
-      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
-      {"@implementation",0,    st_C_objimpl}
+      {"if",           0,                      st_C_ignore},
+      {"enum",         0,                      st_C_enum},
+      {"@end",         0,                      st_C_objend},
+      {"extern",               0,                      st_C_extern},
+      {"extends",      (C_JAVA & !C_PLPL),     st_C_javastruct},
+      {"for",          0,                      st_C_ignore},
+      {"interface",    (C_JAVA & !C_PLPL),     st_C_struct},
+      {"@protocol",    0,                      st_C_objprot},
+      {"@interface",   0,                      st_C_objprot},
+      {"operator",     C_PLPL,                 st_C_operator},
+      {"return",               0,                      st_C_ignore},
+      {"friend",               C_PLPL,                 st_C_ignore},
+      {"import",               (C_JAVA & !C_PLPL),     st_C_ignore},
+      {"@implementation",0,                    st_C_objimpl},
+      {"define",               0,                      st_C_define},
+      {"package",      (C_JAVA & !C_PLPL),     st_C_ignore},
+      {"implements",   (C_JAVA & !C_PLPL),     st_C_javastruct},
+      {"namespace",    C_PLPL,                 st_C_struct},
+      {"domain",               C_STAR,                 st_C_struct},
+      {"template",     0,                      st_C_template},
+      {"typedef",      0,                      st_C_typedef},
+      {"struct",               0,                      st_C_struct},
+      {"switch",               0,                      st_C_ignore},
+      {"union",                0,                      st_C_struct},
+      {"while",                0,                      st_C_ignore},
+      {"class",                0,                      st_C_class},
+      {"__attribute__",        0,                      st_C_attribute},
+      {"SYSCALL",      0,                      st_C_gnumacro},
+      {"PSEUDO",               0,                      st_C_gnumacro},
+      {"ENTRY",                0,                      st_C_gnumacro},
+      {"DEFUN",                0,                      st_C_gnumacro}
     };
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -2454,7 +2582,7 @@ in_word_set (str, len)
         {
           register const char *s = wordlist[key].name;
 
-          if (*str == *s && !strncmp (str + 1, s + 1, len - 1))
+          if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
             return &wordlist[key];
         }
     }
@@ -2476,6 +2604,11 @@ C_symtype (str, len, c_ext)
 }
 
 \f
+/*
+ * Ignoring __attribute__ ((list))
+ */
+static bool inattribute;       /* looking at an __attribute__ construct */
+
 /*
  * C functions and variables are recognized using a simple
  * finite automaton.  fvdef is its state variable.
@@ -2518,10 +2651,9 @@ static enum
 static enum
 {
   snone,                       /* nothing seen yet,
-                                  or in struct body if cblev > 0 */
+                                  or in struct body if bracelev > 0 */
   skeyseen,                    /* struct-like keyword seen */
   stagseen,                    /* struct-like tag seen */
-  sintemplate,                 /* inside template (ignore) */
   scolonseen                   /* colon seen after struct-like tag */
 } structdef;
 
@@ -2568,13 +2700,21 @@ static enum
  */
 static struct tok
 {
-  bool valid;
-  bool named;
-  int offset;
-  int length;
-  int lineno;
-  long linepos;
-  char *line;
+  char *line;                  /* string containing the token */
+  int offset;                  /* where the token starts in LINE */
+  int length;                  /* token length */
+  /*
+    The previous members can be used to pass strings around for generic
+    purposes.  The following ones specifically refer to creating tags.  In this
+    case the token contained here is the pattern that will be used to create a
+    tag.
+  */
+  bool valid;                  /* do not create a tag; the token should be
+                                  invalidated whenever a state machine is
+                                  reset prematurely */
+  bool named;                  /* create a named tag */
+  int lineno;                  /* source line number of tag */
+  long linepos;                        /* source char number of tag */
 } token;                       /* latest token read */
 
 /*
@@ -2587,7 +2727,7 @@ static void write_classname __P((linebuffer *, char *qualifier));
 
 static struct {
   char **cname;                        /* nested class names */
-  int *cblev;                  /* nested class curly brace level */
+  int *bracelev;               /* nested class brace level */
   int nl;                      /* class nesting level (elements used) */
   int size;                    /* length of the array */
 } cstack;                      /* stack for nested declaration tags */
@@ -2595,38 +2735,38 @@ static struct {
 #define nestlev                (cstack.nl)
 /* After struct keyword or in struct body, not inside a nested function. */
 #define instruct       (structdef == snone && nestlev > 0                      \
-                        && cblev == cstack.cblev[nestlev-1] + 1)
+                        && bracelev == cstack.bracelev[nestlev-1] + 1)
 
 static void
-pushclass_above (cblev, str, len)
-     int cblev;
+pushclass_above (bracelev, str, len)
+     int bracelev;
      char *str;
      int len;
 {
   int nl;
 
-  popclass_above (cblev);
+  popclass_above (bracelev);
   nl = cstack.nl;
   if (nl >= cstack.size)
     {
       int size = cstack.size *= 2;
       xrnew (cstack.cname, size, char *);
-      xrnew (cstack.cblev, size, int);
+      xrnew (cstack.bracelev, size, int);
     }
-  assert (nl == 0 || cstack.cblev[nl-1] < cblev);
+  assert (nl == 0 || cstack.bracelev[nl-1] < bracelev);
   cstack.cname[nl] = (str == NULL) ? NULL : savenstr (str, len);
-  cstack.cblev[nl] = cblev;
+  cstack.bracelev[nl] = bracelev;
   cstack.nl = nl + 1;
 }
 
 static void
-popclass_above (cblev)
-     int cblev;
+popclass_above (bracelev)
+     int bracelev;
 {
   int nl;
 
   for (nl = cstack.nl - 1;
-       nl >= 0 && cstack.cblev[nl] >= cblev;
+       nl >= 0 && cstack.bracelev[nl] >= bracelev;
        nl--)
     {
       if (cstack.cname[nl] != NULL)
@@ -2693,268 +2833,295 @@ static void make_C_tag __P((bool));
  */
 
 static bool
-consider_token (str, len, c, c_extp, cblev, parlev, is_func_or_var)
+consider_token (str, len, c, c_extp, bracelev, parlev, is_func_or_var)
      register char *str;       /* IN: token pointer */
      register int len;         /* IN: token length */
      register int c;           /* IN: first char after the token */
      int *c_extp;              /* IN, OUT: C extensions mask */
-     int cblev;                        /* IN: curly brace level */
+     int bracelev;             /* IN: brace level */
      int parlev;               /* IN: parenthesis level */
      bool *is_func_or_var;     /* OUT: function or variable found */
 {
-  /* When structdef is stagseen, scolonseen, or snone with cblev > 0,
+  /* When structdef is stagseen, scolonseen, or snone with bracelev > 0,
      structtype is the type of the preceding struct-like keyword, and
-     structcblev is the curly brace level where it has been seen. */
+     structbracelev is the brace level where it has been seen. */
   static enum sym_type structtype;
-  static int structcblev;
+  static int structbracelev;
   static enum sym_type toktype;
 
 
   toktype = C_symtype (str, len, *c_extp);
 
   /*
-   * Advance the definedef state machine.
-   */
-  switch (definedef)
-    {
-    case dnone:
-      /* We're not on a preprocessor line. */
-      if (toktype == st_C_gnumacro)
-       {
-         fvdef = fdefunkey;
-         return FALSE;
-       }
-      break;
-    case dsharpseen:
-      if (toktype == st_C_define)
-       {
-         definedef = ddefineseen;
-       }
-      else
-       {
-         definedef = dignorerest;
-       }
-      return FALSE;
-    case ddefineseen:
-      /*
-       * Make a tag for any macro, unless it is a constant
-       * and constantypedefs is FALSE.
-       */
-      definedef = dignorerest;
-      *is_func_or_var = (c == '(');
-      if (!*is_func_or_var && !constantypedefs)
-       return FALSE;
-      else
-       return TRUE;
-    case dignorerest:
-      return FALSE;
-    default:
-      error ("internal error: definedef value.", (char *)NULL);
-    }
-
-  /*
-   * Now typedefs
-   */
-  switch (typdef)
-    {
-    case tnone:
-      if (toktype == st_C_typedef)
-       {
-         if (typedefs)
-           typdef = tkeyseen;
-         fvextern = FALSE;
-         fvdef = fvnone;
-         return FALSE;
-       }
-      break;
-    case tkeyseen:
-      switch (toktype)
-       {
-       case st_none:
-       case st_C_typespec:
-       case st_C_class:
-       case st_C_struct:
-       case st_C_enum:
-         typdef = ttypeseen;
-         break;
-       }
-      break;
-    case ttypeseen:
-      if (structdef == snone && fvdef == fvnone)
-       {
-         fvdef = fvnameseen;
-         return TRUE;
-       }
-      break;
-    case tend:
-      switch (toktype)
-       {
-       case st_C_typespec:
-       case st_C_class:
-       case st_C_struct:
-       case st_C_enum:
-         return FALSE;
-       }
-      return TRUE;
-    }
-
-  /*
-   * 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.
+   * Skip __attribute__
    */
-  switch (toktype)
-    {
-    case st_C_javastruct:
-      if (structdef == stagseen)
-        structdef = scolonseen;
-      return FALSE;
-    case st_C_template:
-    case st_C_class:
-      if (cblev == 0
-         && (*c_extp & C_AUTO) /* automatic detection of C++ language */
-         && definedef == dnone && structdef == snone
-         && typdef == tnone && fvdef == fvnone)
-       *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
-      if (toktype == st_C_template)
-       break;
-      /* FALLTHRU */
-    case st_C_struct:
-    case st_C_enum:
-      if (parlev == 0
-         && fvdef != vignore
-         && (typdef == tkeyseen
-             || (typedefs_or_cplusplus && structdef == snone)))
-       {
-         structdef = skeyseen;
-         structtype = toktype;
-         structcblev = cblev;
-       }
-      return FALSE;
-    }
-
-  if (structdef == skeyseen)
-    {
-      structdef = stagseen;
-      return TRUE;
-    }
-
-  if (typdef != tnone)
-    definedef = dnone;
-
-  /* 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 or variables 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_or_var = TRUE;
-      return TRUE;
-    case oparenseen:
-      objdef = ocatseen;
-      *is_func_or_var = TRUE;
-      return TRUE;
-    case oinbody:
-      break;
-    case omethodsign:
-      if (parlev == 0)
-       {
-         objdef = omethodtag;
-         linebuffer_setlen (&token_name, len);
-         strncpy (token_name.buffer, str, len);
-         token_name.buffer[len] = '\0';
-         return TRUE;
-       }
-      return FALSE;
-    case omethodcolon:
-      if (parlev == 0)
-       objdef = omethodparm;
-      return FALSE;
-    case omethodparm:
-      if (parlev == 0)
-       {
-         objdef = omethodtag;
-         linebuffer_setlen (&token_name, token_name.len + len);
-         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, variable or enum constant? */
-  switch (toktype)
+  if (toktype == st_C_attribute)
     {
-    case st_C_extern:
-      fvextern = TRUE;
-      /* FALLTHRU */
-    case st_C_typespec:
-      if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
-       fvdef = fvnone;         /* should be useless */
+      inattribute = TRUE;
       return FALSE;
-    case st_C_ignore:
-      fvextern = FALSE;
-      fvdef = vignore;
-      return FALSE;
-    case st_C_operator:
-      fvdef = foperator;
-      *is_func_or_var = TRUE;
-      return TRUE;
-    case st_none:
-      if (constantypedefs
-         && structdef == snone
-         && structtype == st_C_enum && cblev > structcblev)
-       return TRUE;            /* enum constant */
-      switch (fvdef)
-       {
-       case fdefunkey:
-         if (cblev > 0)
-           break;
-         fvdef = fdefunname;   /* GNU macro */
-         *is_func_or_var = TRUE;
-         return TRUE;
-       case fvnone:
-         if ((strneq (str, "asm", 3) && endtoken (str[3]))
-             || (strneq (str, "__asm__", 7) && endtoken (str[7])))
-           {
-             fvdef = vignore;
-             return FALSE;
-           }
-         if ((*c_extp & C_PLPL) && strneq (str+len-10, "::operator", 10))
+     }
+
+   /*
+    * Advance the definedef state machine.
+    */
+   switch (definedef)
+     {
+     case dnone:
+       /* We're not on a preprocessor line. */
+       if (toktype == st_C_gnumacro)
+        {
+          fvdef = fdefunkey;
+          return FALSE;
+        }
+       break;
+     case dsharpseen:
+       if (toktype == st_C_define)
+        {
+          definedef = ddefineseen;
+        }
+       else
+        {
+          definedef = dignorerest;
+        }
+       return FALSE;
+     case ddefineseen:
+       /*
+       * Make a tag for any macro, unless it is a constant
+       * and constantypedefs is FALSE.
+       */
+       definedef = dignorerest;
+       *is_func_or_var = (c == '(');
+       if (!*is_func_or_var && !constantypedefs)
+        return FALSE;
+       else
+        return TRUE;
+     case dignorerest:
+       return FALSE;
+     default:
+       error ("internal error: definedef value.", (char *)NULL);
+     }
+
+   /*
+    * Now typedefs
+    */
+   switch (typdef)
+     {
+     case tnone:
+       if (toktype == st_C_typedef)
+        {
+          if (typedefs)
+            typdef = tkeyseen;
+          fvextern = FALSE;
+          fvdef = fvnone;
+          return FALSE;
+        }
+       break;
+     case tkeyseen:
+       switch (toktype)
+        {
+        case st_none:
+        case st_C_class:
+        case st_C_struct:
+        case st_C_enum:
+          typdef = ttypeseen;
+        }
+       break;
+     case ttypeseen:
+       if (structdef == snone && fvdef == fvnone)
+        {
+          fvdef = fvnameseen;
+          return TRUE;
+        }
+       break;
+     case tend:
+       switch (toktype)
+        {
+        case st_C_class:
+        case st_C_struct:
+        case st_C_enum:
+          return FALSE;
+        }
+       return TRUE;
+     }
+
+   /*
+    * 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.
+    */
+   switch (toktype)
+     {
+     case st_C_javastruct:
+       if (structdef == stagseen)
+        structdef = scolonseen;
+       return FALSE;
+     case st_C_template:
+     case st_C_class:
+       if ((*c_extp & C_AUTO)  /* automatic detection of C++ language */
+          && bracelev == 0
+          && definedef == dnone && structdef == snone
+          && typdef == tnone && fvdef == fvnone)
+        *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
+       if (toktype == st_C_template)
+        break;
+       /* FALLTHRU */
+     case st_C_struct:
+     case st_C_enum:
+       if (parlev == 0
+          && fvdef != vignore
+          && (typdef == tkeyseen
+              || (typedefs_or_cplusplus && structdef == snone)))
+        {
+          structdef = skeyseen;
+          structtype = toktype;
+          structbracelev = bracelev;
+          if (fvdef == fvnameseen)
+            fvdef = fvnone;
+        }
+       return FALSE;
+     }
+
+   if (structdef == skeyseen)
+     {
+       structdef = stagseen;
+       return TRUE;
+     }
+
+   if (typdef != tnone)
+     definedef = dnone;
+
+   /* 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 or variables 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_or_var = TRUE;
+       return TRUE;
+     case oparenseen:
+       objdef = ocatseen;
+       *is_func_or_var = TRUE;
+       return TRUE;
+     case oinbody:
+       break;
+     case omethodsign:
+       if (parlev == 0)
+        {
+          fvdef = fvnone;
+          objdef = omethodtag;
+          linebuffer_setlen (&token_name, len);
+          strncpy (token_name.buffer, str, len);
+          token_name.buffer[len] = '\0';
+          return TRUE;
+        }
+       return FALSE;
+     case omethodcolon:
+       if (parlev == 0)
+        objdef = omethodparm;
+       return FALSE;
+     case omethodparm:
+       if (parlev == 0)
+        {
+          fvdef = fvnone;
+          objdef = omethodtag;
+          linebuffer_setlen (&token_name, token_name.len + len);
+          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, variable or enum constant? */
+   switch (toktype)
+     {
+     case st_C_extern:
+       fvextern = TRUE;
+       switch  (fvdef)
+        {
+        case finlist:
+        case flistseen:
+        case fignore:
+        case vignore:
+          break;
+        default:
+          fvdef = fvnone;
+        }
+       return FALSE;
+     case st_C_ignore:
+       fvextern = FALSE;
+       fvdef = vignore;
+       return FALSE;
+     case st_C_operator:
+       fvdef = foperator;
+       *is_func_or_var = TRUE;
+       return TRUE;
+     case st_none:
+       if (constantypedefs
+          && structdef == snone
+          && structtype == st_C_enum && bracelev > structbracelev)
+        return TRUE;           /* enum constant */
+       switch (fvdef)
+        {
+        case fdefunkey:
+          if (bracelev > 0)
+            break;
+          fvdef = fdefunname;  /* GNU macro */
+          *is_func_or_var = TRUE;
+          return TRUE;
+        case fvnone:
+          switch (typdef)
+            {
+            case ttypeseen:
+              return FALSE;
+            case tnone:
+              if ((strneq (str, "asm", 3) && endtoken (str[3]))
+                  || (strneq (str, "__asm__", 7) && endtoken (str[7])))
+                {
+                  fvdef = vignore;
+                  return FALSE;
+                }
+              break;
+            }
+         /* FALLTHRU */
+         case fvnameseen:
+         if (len >= 10 && strneq (str+len-10, "::operator", 10))
            {
+             if (*c_extp & C_AUTO) /* automatic detection of C++ */
+               *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
              fvdef = foperator;
              *is_func_or_var = TRUE;
              return TRUE;
            }
-         if (cblev > 0 && !instruct)
+         if (bracelev > 0 && !instruct)
            break;
          fvdef = fvnameseen;   /* function or variable */
          *is_func_or_var = TRUE;
@@ -2986,7 +3153,8 @@ static struct
 #define curlinepos (lbs[curndx].linepos)
 #define newlinepos (lbs[newndx].linepos)
 
-#define cplpl ((c_ext & C_PLPL) == C_PLPL)
+#define plainc ((c_ext & C_EXT) == C_PLAIN)
+#define cplpl (c_ext & C_PLPL)
 #define cjava ((c_ext & C_JAVA) == C_JAVA)
 
 #define CNL_SAVE_DEFINEDEF()                                           \
@@ -3019,13 +3187,13 @@ make_C_tag (isfun)
   if (!DEBUG && !token.valid)
     return;
 
-  if (!token.valid)            /* this case is optimised away if !DEBUG */
-    make_tag (concat (token_name.buffer, "##invalid token##", ""),
-             token_name.len + 17, isfun, token.line,
-             token.offset+token.length+1, token.lineno, token.linepos);
-  else
+  if (token.valid)
     make_tag (token_name.buffer, token_name.len, isfun, token.line,
              token.offset+token.length+1, token.lineno, token.linepos);
+  else                         /* this case is optimised away if !DEBUG */
+    make_tag (concat ("INVALID TOKEN:-->", token_name.buffer, ""),
+             token_name.len + 17, isfun, token.line,
+             token.offset+token.length+1, token.lineno, token.linepos);
 
   token.valid = FALSE;
 }
@@ -3049,9 +3217,12 @@ C_entries (c_ext, inf)
   register int toklen;         /* length of current token */
   char *qualifier;             /* string used to qualify names */
   int qlen;                    /* length of qualifier */
-  int cblev;                   /* current curly brace level */
+  int bracelev;                        /* current brace level */
+  int bracketlev;              /* current bracket level */
   int parlev;                  /* current parenthesis level */
-  int typdefcblev;             /* cblev where a typedef struct body begun */
+  int attrparlev;              /* __attribute__ parenthesis level */
+  int templatelev;             /* current template level */
+  int typdefbracelev;          /* bracelev where a typedef struct body begun */
   bool incomm, inquote, inchar, quotednl, midtoken;
   bool yacc_rules;             /* in the rules part of a yacc file */
   struct tok savetoken;                /* token saved during preprocessor handling */
@@ -3064,10 +3235,10 @@ C_entries (c_ext, inf)
       cstack.size = (DEBUG) ? 1 : 4;
       cstack.nl = 0;
       cstack.cname = xnew (cstack.size, char *);
-      cstack.cblev = xnew (cstack.size, int);
+      cstack.bracelev = xnew (cstack.size, int);
     }
 
-  tokoff = toklen = typdefcblev = 0; /* keep compiler quiet */
+  tokoff = toklen = typdefbracelev = 0; /* keep compiler quiet */
   curndx = newndx = 0;
   lp = curlb.buffer;
   *lp = 0;
@@ -3077,8 +3248,7 @@ C_entries (c_ext, inf)
   yacc_rules = FALSE;
   midtoken = inquote = inchar = incomm = quotednl = FALSE;
   token.valid = savetoken.valid = FALSE;
-  cblev = 0;
-  parlev = 0;
+  bracelev = bracketlev = parlev = attrparlev = templatelev = 0;
   if (cjava)
     { qualifier = "."; qlen = 1; }
   else
@@ -3090,8 +3260,8 @@ C_entries (c_ext, inf)
       c = *lp++;
       if (c == '\\')
        {
-         /* If we're at the end of the line, the next character is a
-            '\0'; don't skip it, because it's the thing that tells us
+         /* If we are at the end of the line, the next character is a
+            '\0'; do not skip it, because it is what tells us
             to read the next line.  */
          if (*lp == '\0')
            {
@@ -3150,107 +3320,127 @@ C_entries (c_ext, inf)
            }
          continue;
        }
-      else
-       switch (c)
-         {
-         case '"':
-           inquote = TRUE;
-           switch (fvdef)
-             {
-             case fdefunkey:
-             case fstartlist:
-             case finlist:
-             case fignore:
-             case vignore:
-               break;
-             default:
-               fvextern = FALSE;
-               fvdef = fvnone;
-             }
-           continue;
-         case '\'':
-           inchar = TRUE;
-           if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
-             {
-               fvextern = FALSE;
-               fvdef = fvnone;
-             }
-           continue;
-         case '/':
-           if (*lp == '*')
-             {
-               lp++;
-               incomm = TRUE;
+      else if (bracketlev > 0)
+       {
+         switch (c)
+           {
+           case ']':
+             if (--bracketlev > 0)
                continue;
-             }
-           else if (/* cplpl && */ *lp == '/')
-             {
-               c = '\0';
-               break;
-             }
-           else
              break;
-         case '%':
-           if ((c_ext & YACC) && *lp == '%')
-             {
-               /* Entering or exiting rules section in yacc file. */
-               lp++;
-               definedef = dnone; fvdef = fvnone; fvextern = FALSE;
-               typdef = tnone; structdef = snone;
-               midtoken = inquote = inchar = incomm = quotednl = FALSE;
-               cblev = 0;
-               yacc_rules = !yacc_rules;
-               continue;
-             }
-           else
+           case '\0':
+             CNL_SAVE_DEFINEDEF ();
              break;
-         case '#':
-           if (definedef == dnone)
-             {
-               char *cp;
-               bool cpptoken = TRUE;
-
-               /* Look back on this line.  If all blanks, or nonblanks
-                  followed by an end of comment, this is a preprocessor
-                  token. */
-               for (cp = newlb.buffer; cp < lp-1; cp++)
-                 if (!iswhite (*cp))
-                   {
-                     if (*cp == '*' && *(cp+1) == '/')
-                       {
-                         cp++;
-                         cpptoken = TRUE;
-                       }
-                     else
-                       cpptoken = FALSE;
-                   }
-               if (cpptoken)
-                 definedef = dsharpseen;
-             } /* if (definedef == dnone) */
-
+           }
+         continue;
+       }
+      else switch (c)
+       {
+       case '"':
+         inquote = TRUE;
+         if (inattribute)
+           break;
+         switch (fvdef)
+           {
+           case fdefunkey:
+           case fstartlist:
+           case finlist:
+           case fignore:
+           case vignore:
+             break;
+           default:
+             fvextern = FALSE;
+             fvdef = fvnone;
+           }
+         continue;
+       case '\'':
+         inchar = TRUE;
+         if (inattribute)
+           break;
+         if (fvdef != finlist && fvdef != fignore && fvdef !=vignore)
+           {
+             fvextern = FALSE;
+             fvdef = fvnone;
+           }
+         continue;
+       case '/':
+         if (*lp == '*')
+           {
+             lp++;
+             incomm = TRUE;
+             continue;
+           }
+         else if (/* cplpl && */ *lp == '/')
+           {
+             c = '\0';
+             break;
+           }
+         else
+           break;
+       case '%':
+         if ((c_ext & YACC) && *lp == '%')
+           {
+             /* Entering or exiting rules section in yacc file. */
+             lp++;
+             definedef = dnone; fvdef = fvnone; fvextern = FALSE;
+             typdef = tnone; structdef = snone;
+             midtoken = inquote = inchar = incomm = quotednl = FALSE;
+             bracelev = 0;
+             yacc_rules = !yacc_rules;
+             continue;
+           }
+         else
+           break;
+       case '#':
+         if (definedef == dnone)
+           {
+             char *cp;
+             bool cpptoken = TRUE;
+
+             /* Look back on this line.  If all blanks, or nonblanks
+                followed by an end of comment, this is a preprocessor
+                token. */
+             for (cp = newlb.buffer; cp < lp-1; cp++)
+               if (!iswhite (*cp))
+                 {
+                   if (*cp == '*' && *(cp+1) == '/')
+                     {
+                       cp++;
+                       cpptoken = TRUE;
+                     }
+                   else
+                     cpptoken = FALSE;
+                 }
+             if (cpptoken)
+               definedef = dsharpseen;
+           } /* if (definedef == dnone) */
+         continue;
+       case '[':
+         bracketlev++;
            continue;
-         } /* switch (c) */
+       } /* switch (c) */
 
 
       /* Consider token only if some involved conditions are satisfied. */
       if (typdef != tignore
          && definedef != dignorerest
          && fvdef != finlist
-         && structdef != sintemplate
+         && templatelev == 0
          && (definedef != dnone
-             || structdef != scolonseen))
+             || structdef != scolonseen)
+         && !inattribute)
        {
          if (midtoken)
            {
              if (endtoken (c))
                {
-                 if (c == ':' && cplpl && *lp == ':' && begtoken (lp[1]))
+                 if (c == ':' && *lp == ':' && begtoken (lp[1]))
+                   /* This handles :: in the middle,
+                      but not at the beginning of an identifier.
+                      Also, space-separated :: is not recognised. */
                    {
-                     /*
-                      * This handles :: in the middle, but not at the
-                      * beginning of an identifier.  Also, space-separated
-                      * :: is not recognised.
-                      */
+                     if (c_ext & C_AUTO) /* automatic detection of C++ */
+                       c_ext = (c_ext | C_PLPL) & ~C_AUTO;
                      lp += 2;
                      toklen += 2;
                      c = lp[-1];
@@ -3262,7 +3452,8 @@ C_entries (c_ext, inf)
 
                      if (yacc_rules
                          || consider_token (newlb.buffer + tokoff, toklen, c,
-                                            &c_ext, cblev, parlev, &funorvar))
+                                            &c_ext, bracelev, parlev,
+                                            &funorvar))
                        {
                          if (fvdef == foperator)
                            {
@@ -3277,7 +3468,7 @@ C_entries (c_ext, inf)
                              toklen += lp - oldlp;
                            }
                          token.named = FALSE;
-                         if ((c_ext & C_EXT)   /* not pure C */
+                         if (!plainc
                              && nestlev > 0 && definedef == dnone)
                            /* in struct body */
                            {
@@ -3347,7 +3538,7 @@ C_entries (c_ext, inf)
                                             || (funorvar
                                                 && definedef == dnone
                                                 && structdef == snone
-                                                && cblev > 0));
+                                                && bracelev > 0));
                            }
                          token.lineno = lineno;
                          token.offset = tokoff;
@@ -3372,6 +3563,16 @@ C_entries (c_ext, inf)
                                   || instruct)
                            make_C_tag (funorvar);
                        }
+                     else /* not yacc and consider_token failed */
+                       {
+                         if (inattribute && fvdef == fignore)
+                           {
+                             /* We have just met __attribute__ after a
+                                function parameter list: do not tag the
+                                function again. */
+                             fvdef = fvnone;
+                           }
+                       }
                      midtoken = FALSE;
                    }
                } /* if (endtoken (c)) */
@@ -3390,22 +3591,22 @@ C_entries (c_ext, inf)
                  switch (fvdef)
                    {
                    case fstartlist:
+                     /* This prevents tagging fb in
+                        void (__attribute__((noreturn)) *fb) (void);
+                        Fixing this is not easy and not very important. */
                      fvdef = finlist;
                      continue;
                    case flistseen:
-#if 0
-                     if (!instruct || members)
-#endif
-                       make_C_tag (TRUE); /* a function */
-                     fvdef = fignore;
-                     break;
-                   case fvnameseen:
-                     fvdef = fvnone;
+                     if (plainc || declarations)
+                       {
+                         make_C_tag (TRUE); /* a function */
+                         fvdef = fignore;
+                       }
                      break;
                    }
                  if (structdef == stagseen && !cjava)
                    {
-                     popclass_above (cblev);
+                     popclass_above (bracelev);
                      structdef = snone;
                    }
                  break;
@@ -3429,6 +3630,8 @@ C_entries (c_ext, inf)
       switch (c)
        {
        case ':':
+         if (inattribute)
+           break;
          if (yacc_rules && token.offset == 0 && token.valid)
            {
              make_C_tag (FALSE); /* a yacc function */
@@ -3454,17 +3657,16 @@ C_entries (c_ext, inf)
              structdef = scolonseen;
              break;
            }
-#if 0
+         /* Should be useless, but may be work as a safety net. */
          if (cplpl && fvdef == flistseen)
            {
              make_C_tag (TRUE); /* a function */
              fvdef = fignore;
              break;
            }
-#endif
          break;
        case ';':
-         if (definedef != dnone)
+         if (definedef != dnone || inattribute)
            break;
          switch (typdef)
            {
@@ -3484,7 +3686,7 @@ C_entries (c_ext, inf)
                    fvdef = fvnone;
                  break;
                case fvnameseen:
-                 if ((globals && cblev == 0 && (!fvextern || declarations))
+                 if ((globals && bracelev == 0 && (!fvextern || declarations))
                      || (members && instruct))
                    make_C_tag (FALSE); /* a variable */
                  fvextern = FALSE;
@@ -3492,20 +3694,20 @@ C_entries (c_ext, inf)
                  token.valid = FALSE;
                  break;
                case flistseen:
-                 if ((declarations && typdef == tnone && !instruct)
-                     || (members && typdef != tignore && instruct))
-                   make_C_tag (TRUE);  /* a function declaration */
+                 if ((declarations
+                      && (cplpl || !instruct)
+                      && (typdef == tnone || (typdef != tignore && instruct)))
+                     || (members
+                         && plainc && instruct))
+                   make_C_tag (TRUE);  /* a function */
                  /* FALLTHRU */
                default:
                  fvextern = FALSE;
                  fvdef = fvnone;
                  if (declarations
-                     && structdef == stagseen && (c_ext & C_PLPL))
+                      && cplpl && structdef == stagseen)
                    make_C_tag (FALSE); /* forward declaration */
                  else
-                   /* The following instruction invalidates the token.
-                      Probably the token should be invalidated in all other
-                      cases where some state machine is reset prematurely. */
                    token.valid = FALSE;
                } /* switch (fvdef) */
              /* FALLTHRU */
@@ -3517,7 +3719,7 @@ C_entries (c_ext, inf)
            structdef = snone;
          break;
        case ',':
-         if (definedef != dnone)
+         if (definedef != dnone || inattribute)
            break;
          switch (objdef)
            {
@@ -3539,16 +3741,20 @@ C_entries (c_ext, inf)
            case fdefunname:
              fvdef = fignore;
              break;
-           case fvnameseen:    /* a variable */
-             if ((globals && cblev == 0 && (!fvextern || declarations))
-                 || (members && instruct))
-               make_C_tag (FALSE);
+           case fvnameseen:
+             if (parlev == 0
+                 && ((globals
+                      && bracelev == 0
+                      && templatelev == 0
+                      && (!fvextern || declarations))
+                     || (members && instruct)))
+                 make_C_tag (FALSE); /* a variable */
              break;
-           case flistseen:     /* a function */
+           case flistseen:
              if ((declarations && typdef == tnone && !instruct)
                  || (members && typdef != tignore && instruct))
                {
-                 make_C_tag (TRUE); /* a function declaration */
+                 make_C_tag (TRUE); /* a function */
                  fvdef = fvnameseen;
                }
              else if (!declarations)
@@ -3561,8 +3767,8 @@ C_entries (c_ext, inf)
          if (structdef == stagseen)
            structdef = snone;
          break;
-       case '[':
-         if (definedef != dnone)
+       case ']':
+         if (definedef != dnone || inattribute)
            break;
          if (structdef == stagseen)
            structdef = snone;
@@ -3583,8 +3789,8 @@ C_entries (c_ext, inf)
                case vignore:
                  break;
                case fvnameseen:
-                 if ((members && cblev == 1)
-                     || (globals && cblev == 0
+                 if ((members && bracelev == 1)
+                     || (globals && bracelev == 0
                          && (!fvextern || declarations)))
                    make_C_tag (FALSE); /* a variable */
                  /* FALLTHRU */
@@ -3595,6 +3801,11 @@ C_entries (c_ext, inf)
            }
          break;
        case '(':
+         if (inattribute)
+           {
+             attrparlev++;
+             break;
+           }
          if (definedef != dnone)
            break;
          if (objdef == otagseen && parlev == 0)
@@ -3624,6 +3835,12 @@ C_entries (c_ext, inf)
          parlev++;
          break;
        case ')':
+         if (inattribute)
+           {
+             if (--attrparlev == 0)
+               inattribute = FALSE;
+             break;
+           }
          if (definedef != dnone)
            break;
          if (objdef == ocatseen && parlev == 1)
@@ -3657,9 +3874,9 @@ C_entries (c_ext, inf)
          if (typdef == ttypeseen)
            {
              /* Whenever typdef is set to tinbody (currently only
-                here), typdefcblev should be set to cblev. */
+                here), typdefbracelev should be set to bracelev. */
              typdef = tinbody;
-             typdefcblev = cblev;
+             typdefbracelev = bracelev;
            }
          switch (fvdef)
            {
@@ -3683,49 +3900,56 @@ C_entries (c_ext, inf)
                  break;
                default:
                  /* Neutralize `extern "C" {' grot. */
-                 if (cblev == 0 && structdef == snone && nestlev == 0
+                 if (bracelev == 0 && structdef == snone && nestlev == 0
                      && typdef == tnone)
-                   cblev = -1;
+                   bracelev = -1;
                }
              break;
            }
          switch (structdef)
            {
            case skeyseen:         /* unnamed struct */
-             pushclass_above (cblev, NULL, 0);
+             pushclass_above (bracelev, NULL, 0);
              structdef = snone;
              break;
            case stagseen:         /* named struct or enum */
            case scolonseen:       /* a class */
-             pushclass_above (cblev, token.line+token.offset, token.length);
+             pushclass_above (bracelev,token.line+token.offset, token.length);
              structdef = snone;
              make_C_tag (FALSE);  /* a struct or enum */
              break;
            }
-         cblev++;
+         bracelev++;
          break;
        case '*':
          if (definedef != dnone)
            break;
          if (fvdef == fstartlist)
-           fvdef = fvnone;     /* avoid tagging `foo' in `foo (*bar()) ()' */
+           {
+             fvdef = fvnone;   /* avoid tagging `foo' in `foo (*bar()) ()' */
+             token.valid = FALSE;
+           }
          break;
        case '}':
          if (definedef != dnone)
            break;
          if (!ignoreindent && lp == newlb.buffer + 1)
            {
-             cblev = 0;        /* reset curly brace level if first column */
+             if (bracelev != 0)
+               token.valid = FALSE;
+             bracelev = 0;     /* reset brace level if first column */
              parlev = 0;       /* also reset paren level, just in case... */
            }
-         else if (cblev > 0)
-           cblev--;
-         popclass_above (cblev);
+         else if (bracelev > 0)
+           bracelev--;
+         else
+           token.valid = FALSE; /* something gone amiss, token unreliable */
+         popclass_above (bracelev);
          structdef = snone;
-         /* Only if typdef == tinbody is typdefcblev significant. */
-         if (typdef == tinbody && cblev <= typdefcblev)
+         /* Only if typdef == tinbody is typdefbracelev significant. */
+         if (typdef == tinbody && bracelev <= typdefbracelev)
            {
-             assert (cblev == typdefcblev);
+             assert (bracelev == typdefbracelev);
              typdef = tend;
            }
          break;
@@ -3740,8 +3964,8 @@ C_entries (c_ext, inf)
            case vignore:
              break;
            case fvnameseen:
-             if ((members && cblev == 1)
-                 || (globals && cblev == 0 && (!fvextern || declarations)))
+             if ((members && bracelev == 1)
+                 || (globals && bracelev == 0 && (!fvextern || declarations)))
                make_C_tag (FALSE); /* a variable */
              /* FALLTHRU */
            default:
@@ -3749,30 +3973,31 @@ C_entries (c_ext, inf)
            }
          break;
        case '<':
-         if (cplpl && structdef == stagseen)
+         if (cplpl
+             && (structdef == stagseen || fvdef == fvnameseen))
            {
-             structdef = sintemplate;
+             templatelev++;
              break;
            }
          goto resetfvdef;
        case '>':
-         if (structdef == sintemplate)
+         if (templatelev > 0)
            {
-             structdef = stagseen;
+             templatelev--;
              break;
            }
          goto resetfvdef;
        case '+':
        case '-':
-         if (objdef == oinbody && cblev == 0)
+         if (objdef == oinbody && bracelev == 0)
            {
              objdef = omethodsign;
              break;
            }
          /* FALLTHRU */
        resetfvdef:
-       case '#': case '~': case '&': case '%': case '/': case '|':
-       case '^': case '!': case '.': case '?': case ']':
+       case '#': case '~': case '&': case '%': case '/':
+       case '|': case '^': case '!': case '.': case '?':
          if (definedef != dnone)
            break;
          /* These surely cannot follow a function tag in C. */
@@ -3868,10 +4093,18 @@ Yacc_entries (inf)
            char_pointer = line_buffer.buffer,                          \
           TRUE);                                                       \
       )
-#define LOOKING_AT(cp, keyword)        /* keyword is a constant string */      \
-  (strneq ((cp), keyword, sizeof(keyword)-1) /* cp points at keyword */        \
-   && notinname ((cp)[sizeof(keyword)-1])      /* end of keyword */    \
-   && ((cp) = skip_spaces((cp)+sizeof(keyword)-1))) /* skip spaces */
+
+#define LOOKING_AT(cp, kw)  /* kw is the keyword, a literal string */  \
+  ((assert("" kw), TRUE)   /* syntax error if not a literal string */  \
+   && strneq ((cp), kw, sizeof(kw)-1)          /* cp points at kw */   \
+   && notinname ((cp)[sizeof(kw)-1])           /* end of kw */         \
+   && ((cp) = skip_spaces((cp)+sizeof(kw)-1))) /* skip spaces */
+
+/* Similar to LOOKING_AT but does not use notinname, does not skip */
+#define LOOKING_AT_NOCASE(cp, kw) /* the keyword is a literal string */        \
+  ((assert("" kw), TRUE)     /* syntax error if not a literal string */        \
+   && strncaseeq ((cp), kw, sizeof(kw)-1)      /* cp points at kw */   \
+   && ((cp) += sizeof(kw)-1))                  /* skip spaces */
 
 /*
  * Read a file, but do no processing.  This is used to do regexp
@@ -4018,7 +4251,7 @@ Fortran_functions (inf)
 /*
  * Ada parsing
  * Original code by
- * Philippe Waroquiers <philippe.waroquiers@eurocontrol.int> (1998)
+ * Philippe Waroquiers (1998)
  */
 
 static void Ada_getit __P((FILE *, char *));
@@ -4310,6 +4543,7 @@ Perl_functions (inf)
                    lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
        }
     }
+  free (package);
 }
 
 
@@ -4724,7 +4958,32 @@ Lisp_functions (inf)
 
 \f
 /*
- * Postscript tag functions
+ * Lua script language parsing
+ * Original code by David A. Capello <dacap@users.sourceforge.net> (2004)
+ *
+ *  "function" and "local function" are tags if they start at column 1.
+ */
+static void
+Lua_functions (inf)
+     FILE *inf;
+{
+  register char *bp;
+
+  LOOP_ON_INPUT_LINES (inf, lb, bp)
+    {
+      if (bp[0] != 'f' && bp[0] != 'l')
+       continue;
+
+      LOOKING_AT (bp, "local");        /* skip possible "local" */
+
+      if (LOOKING_AT (bp, "function"))
+       get_tag (bp, NULL);
+    }
+}
+
+\f
+/*
+ * Postscript tags
  * Just look for lines where the first character is '/'
  * Also look at "defineps" for PSWrap
  * Ideas by:
@@ -4732,7 +4991,7 @@ Lisp_functions (inf)
  *   Masatake Yamato <masata-y@is.aist-nara.ac.jp> (1999)
  */
 static void
-Postscript_functions (inf)
+PS_functions (inf)
      FILE *inf;
 {
   register char *bp, *ep;
@@ -4753,6 +5012,43 @@ Postscript_functions (inf)
     }
 }
 
+\f
+/*
+ * Forth tags
+ * Ignore anything after \ followed by space or in ( )
+ * Look for words defined by :
+ * Look for constant, code, create, defer, value, and variable
+ * OBP extensions:  Look for buffer:, field,
+ * Ideas by Eduardo Horvath <eeh@netbsd.org> (2004)
+ */
+static void
+Forth_words (inf)
+     FILE *inf;
+{
+  register char *bp;
+
+  LOOP_ON_INPUT_LINES (inf, lb, bp)
+    while ((bp = skip_spaces (bp))[0] != '\0')
+      if (bp[0] == '\\' && iswhite(bp[1]))
+       break;                  /* read next line */
+      else if (bp[0] == '(' && iswhite(bp[1]))
+       do                      /* skip to ) or eol */
+         bp++;
+       while (*bp != ')' && *bp != '\0');
+      else if ((bp[0] == ':' && iswhite(bp[1]) && bp++)
+              || LOOKING_AT_NOCASE (bp, "constant")
+              || LOOKING_AT_NOCASE (bp, "code")
+              || LOOKING_AT_NOCASE (bp, "create")
+              || LOOKING_AT_NOCASE (bp, "defer")
+              || LOOKING_AT_NOCASE (bp, "value")
+              || LOOKING_AT_NOCASE (bp, "variable")
+              || LOOKING_AT_NOCASE (bp, "buffer:")
+              || LOOKING_AT_NOCASE (bp, "field"))
+       get_tag (skip_spaces (bp), NULL); /* Yay!  A definition! */
+      else
+       bp = skip_non_spaces (bp);
+}
+
 \f
 /*
  * Scheme tag functions
@@ -4762,7 +5058,6 @@ Postscript_functions (inf)
  *          (set! xyzzy
  * Original code by Ken Haase (1985?)
  */
-
 static void
 Scheme_functions (inf)
      FILE *inf;
@@ -4981,11 +5276,6 @@ Texinfo_nodes (inf)
 }
 
 \f
-/* Similar to LOOKING_AT but does not use notinname, does not skip */
-#define LOOKING_AT_NOCASE(cp, kw)      /* kw is a constant string */   \
-  (strncaseeq ((cp), kw, sizeof(kw)-1) /* cp points at kw */           \
-   && ((cp) += sizeof(kw)-1))          /* skip spaces */
-
 /*
  * HTML support.
  * Contents of <title>, <h1>, <h2>, <h3> are tags.
@@ -5152,6 +5442,8 @@ Prolog_functions (inf)
          last[len] = '\0';
        }
     }
+  if (last != NULL)
+    free (last);
 }
 
 
@@ -5202,7 +5494,7 @@ prolog_pr (s, last)
        || (s[pos] == '(' && (pos += 1))
        || (s[pos] == ':' && s[pos + 1] == '-' && (pos += 2)))
       && (last == NULL         /* save only the first clause */
-         || len != strlen (last)
+         || len != (int)strlen (last)
          || !strneq (s, last, len)))
        {
          make_tag (s, len, TRUE, s, pos, lineno, linecharno);
@@ -5308,7 +5600,11 @@ Erlang_functions (inf)
       else if (cp[0] == '-')   /* attribute, e.g. "-define" */
        {
          erlang_attribute (cp);
-         last = NULL;
+         if (last != NULL)
+           {
+             free (last);
+             last = NULL;
+           }
        }
       else if ((len = erlang_func (cp, last)) > 0)
        {
@@ -5325,6 +5621,8 @@ Erlang_functions (inf)
          last[len] = '\0';
        }
     }
+  if (last != NULL)
+    free (last);
 }
 
 
@@ -5709,6 +6007,7 @@ substitute (in, out, regs)
       size -= 1;
 
   /* Allocate space and do the substitutions. */
+  assert (size >= 0);
   result = xnew (size + 1, char);
 
   for (t = result; *out != '\0'; out++)
@@ -5723,7 +6022,8 @@ substitute (in, out, regs)
       *t++ = *out;
   *t = '\0';
 
-  assert (t <= result + size && t - result == (int)strlen (result));
+  assert (t <= result + size);
+  assert (t - result == (int)strlen (result));
 
   return result;
 }
@@ -5810,8 +6110,9 @@ regex_tag_multiline ()
                if (buffer[charno++] == '\n')
                  lineno++, linecharno = charno;
              name = rp->name;
-             if (name[0] != '\0')
-               /* Make a named tag. */
+             if (name[0] == '\0')
+               name = NULL;
+             else /* make a named tag */
                name = substitute (buffer, rp->name, &rp->regs);
              if (rp->force_explicit_name)
                /* Force explicit tag name, if a name is there. */
@@ -6133,8 +6434,9 @@ readline (lbp, stream)
            default:
              /* Match occurred.  Construct a tag. */
              name = rp->name;
-             if (name[0] != '\0')
-               /* Make a named tag. */
+             if (name[0] == '\0')
+               name = NULL;
+             else /* make a named tag */
                name = substitute (lbp->buffer, rp->name, &rp->regs);
              if (rp->force_explicit_name)
                /* Force explicit tag name, if a name is there. */
@@ -6266,7 +6568,7 @@ etags_strncasecmp (s1, s2, n)
            : *s1 - *s2);
 }
 
-/* Skip spaces, return new pointer. */
+/* Skip spaces (end of string is not space), return new pointer. */
 static char *
 skip_spaces (cp)
      char *cp;
@@ -6276,7 +6578,7 @@ skip_spaces (cp)
   return cp;
 }
 
-/* Skip non spaces, return new pointer. */
+/* Skip non spaces, except end of string, return new pointer. */
 static char *
 skip_non_spaces (cp)
      char *cp;
@@ -6292,7 +6594,7 @@ fatal (s1, s2)
      char *s1, *s2;
 {
   error (s1, s2);
-  exit (BAD);
+  exit (EXIT_FAILURE);
 }
 
 static void
@@ -6300,21 +6602,15 @@ pfatal (s1)
      char *s1;
 {
   perror (s1);
-  exit (BAD);
+  exit (EXIT_FAILURE);
 }
 
 static void
 suggest_asking_for_help ()
 {
   fprintf (stderr, "\tTry `%s %s' for a complete list of options.\n",
-          progname,
-#ifdef LONG_OPTIONS
-          "--help"
-#else
-          "-h"
-#endif
-          );
-  exit (BAD);
+          progname, LONG_OPTIONS ? "--help" : "-h");
+  exit (EXIT_FAILURE);
 }
 
 /* Print error message.  `s1' is printf control string, `s2' is arg for it. */
@@ -6600,10 +6896,14 @@ xrealloc (ptr, size)
 
 /*
  * Local Variables:
- * c-indentation-style: gnu
  * indent-tabs-mode: t
  * tab-width: 8
  * fill-column: 79
  * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node" "regexp")
  * End:
  */
+
+/* arch-tag: 8a9b748d-390c-4922-99db-2eeefa921051
+   (do not change this comment) */
+
+/* etags.c ends here */