(describe-current-display-table):
[bpt/emacs.git] / lib-src / etags.c
index 4921e31..3057800 100644 (file)
@@ -1,21 +1,21 @@
 /* Tags file maker to go with GNU Emacs
-   Copyright (C) 1984, 1987, 1988, 1989, 1992 Free Software Foundation, Inc. and Ken Arnold
+   Copyright (C) 1984, 1987, 1988, 1989, 1993 Free Software Foundation, Inc. and Ken Arnold
 
-This file is part of GNU Emacs.
+This file is not considered part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
-any later version.
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
 
-GNU Emacs is distributed in the hope that it will be useful,
+This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /*
  * Authors:
@@ -24,25 +24,25 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  *     Ed Pelegri-Llopart added C typedefs.
  *     Gnu Emacs TAGS format and modifications by RMS?
  *     Sam Kendall added C++.
+ *
+ *     Francesco Potorti` (pot@cnuce.cnr.it) is the current maintainer. 9.7
  */
 
+#ifdef HAVE_CONFIG_H
+#include <../src/config.h>
+#endif
+
 #include <stdio.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include "getopt.h"
-
-#ifdef __GNUC__
-#define        alloca  __builtin_alloca
-#else
-#ifdef sparc
-#include <alloca.h>
-#else
-extern char *alloca ();
-#endif
+#if !defined (S_ISREG) && defined (S_IFREG)
+# define S_ISREG(m)    (((m) & S_IFMT) == S_IFREG)
 #endif
 
+#include "getopt.h"
+
 extern char *malloc (), *realloc ();
 extern char *getenv ();
 extern char *strcpy (), *strncpy ();
@@ -86,8 +86,6 @@ char *savenstr ();
  *
  *     long GET_CHARNO (pos)
  *                             returns absolute char number.
- *     long GET_COOKIE (pos)
- *                             returns ftell () cookie.
  *     void SET_FILEPOS (pos, fp, charno)
  *         FILE *fp; long charno;
  *                             sets `pos' from the current file
@@ -105,44 +103,29 @@ char *savenstr ();
  *
  * Implementation notes: the `+ 0' is to enforce rvalue-ness.
  */
-#ifdef VMS
-typedef struct
-{
-  long cookie;
-  long charno;
-} FILEPOS;
 
-#define GET_CHARNO(pos)        ((pos).charno + 0)
-#define GET_COOKIE(pos)        ((pos).cookie + 0)
-#define SET_FILEPOS(pos, fp, cno) \
-    ((void) ((pos).cookie = ftell (fp), (pos).charno = (cno)))
-#else
 #ifndef DEBUG
- /* UNIX real implementation */
+ /* real implementation */
 typedef long FILEPOS;
 #define GET_CHARNO(pos)        ((pos) + 0)
-#define GET_COOKIE(pos)        GET_CHARNO (pos)
 #define SET_FILEPOS(pos, fp, cno)      ((void) ((pos) = (cno)))
 #else
- /* UNIX debugging implementation */
+ /* debugging implementation */
 typedef struct
 {
   long charno;
 } FILEPOS;
 
 #define GET_CHARNO(pos)        ((pos).charno + 0)
-#define GET_COOKIE(pos)        GET_CHARNO (pos)
 #define SET_FILEPOS(pos, fp, cno)                                      \
     ((void) ((pos).charno = (cno),                                     \
             (cno) != ftell (fp) ? (error ("SET_FILEPOS inconsistency"), 0) \
                                 : 0))
 #endif
-#endif
 
 #define streq(s, t)    (strcmp (s, t) == 0)
 #define strneq(s, t, n)        (strncmp (s, t, n) == 0)
-#define        reg     register
-#define        logical char
+#define        logical         int
 
 #define        TRUE    1
 #define        FALSE   0
@@ -151,7 +134,6 @@ typedef struct
 #define        begtoken(arg)   (_btk[arg])     /* T if char can start token    */
 #define        intoken(arg)    (_itk[arg])     /* T if char can be in token    */
 #define        endtoken(arg)   (_etk[arg])     /* T if char ends tokens        */
-#define        isgood(arg)     (_gd[arg])      /* T if char can be after ')'   */
 
 #define        max(I1,I2)      ((I1) > (I2) ? (I1) : (I2))
 
@@ -160,7 +142,7 @@ struct nd_st
   char *name;                  /* function or type name        */
   char *file;                  /* file name                    */
   logical is_func;             /* use pattern or line no       */
-  logical rewritten;           /* list name separately         */
+  logical named;               /* list name separately         */
   logical been_warned;         /* set if noticed dup           */
   int lno;                     /* line number tag is on        */
   long cno;                    /* character number line starts on */
@@ -171,10 +153,9 @@ struct nd_st
 long ftell ();
 typedef struct nd_st NODE;
 
-logical gotone,                        /* found a func already on line */
- /* boolean "func" (see init)  */
-  header_file,                 /* TRUE if .h file, FALSE o.w.  */
-  _wht[0177], _etk[0177], _itk[0177], _btk[0177], _gd[0177];
+logical header_file;           /* TRUE if .h file, FALSE o.w.  */
+/* boolean "functions" (see init)      */
+logical _wht[0177], _etk[0177], _itk[0177], _btk[0177];
 
 
 char *concat ();
@@ -182,7 +163,7 @@ char *savenstr ();
 char *savestr ();
 char *xmalloc ();
 char *xrealloc ();
-int L_isdef ();
+int L_isdef (), L_isquote ();
 int PF_funcs ();
 int total_size_of_entries ();
 logical consider_token ();
@@ -348,87 +329,20 @@ typedef struct
 {
   char *p;
   int len;
-  FILEPOS linestart;
   LINENO lineno;
-  logical rewritten;
+  logical named;
 } TOKEN;
-\f
-
- /* typedefs are recognized using a simple finite automaton.
-  * tydef is its state variable.
-  */
-typedef enum
-{
-  none, begin, middle, end
-} TYST;
-
-TYST tydef = none;
-
-
- /* struct tags for C++ are recognized using another simple
-  * finite automaton.  `structdef' is its state variable.
-  * This machinery is only invoked for C++; otherwise structdef
-  * should remain snone.  However, this machinery can easily be
-  * adapted to find structure tags in normal C code.
-  */
-typedef enum
-{
-  snone,                       /* nothing seen yet */
-  skeyseen,                    /* struct-like keyword seen */
-  stagseen,                    /* struct-like tag seen */
-  scolonseen,                  /* colon seen after struct-like tag */
-  sinbody                      /* in a class body: recognize member func defs */
-} STRUCTST;
-STRUCTST structdef = snone;
-/*
- * When structdef is stagseen, scolonseen, or sinbody, structtag is the
- * struct tag, and structkey is the preceding struct-like keyword.
- */
-char structtag[512];
-Stab_entry *structkey;
-
-/*
- * Yet another little state machine to deal with preprocessor lines.
- */
-typedef enum
-{
-  dnone,                       /* nothing seen */
-  dsharpseen,                  /* '#' seen as first char on line */
-  ddefineseen,                 /* '#' and 'define' seen */
-  dignorerest                  /* ignore rest of line */
-} DEFINEST;
-DEFINEST definedef;
-
-/*
- * LEVEL_OK_FOR_FUNCDEF allows C++ function definition within class body.
- * Currently tydef and structdef stuff (typedefs and struct definitions) are
- * only noticed when level==0, but that may change.
- *
- * Note that this macro may only be evaluated inside C_entries().  It is
- * for self-documentation only.
- */
-#define LEVEL_OK_FOR_FUNCDEF()                                 \
-       (level==0 || (c_ext && level==1 && structdef==sinbody))
-
-/*
- * next_token_is_func
- *     set this to TRUE, and the next token considered is called a function.
- */
-logical next_token_is_func;
 
-/* C extensions.  Currently all listed extensions are C++ dialects, so
- * `c_ext' is used as an abbreviation for `c_ext&C_PLPL'.  If a non-C++
- * dialect is added, this must change.
+/* C extensions.
  */
-#define C_PLPL 0x1             /* C++ */
-#define C_STAR 0x3             /* C* */
+#define C_PLPL 0x00001         /* C++ */
+#define C_STAR 0x00003         /* C* */
+#define YACC   0x10000         /* yacc file */
 
 char searchar = '/';           /* use /.../ searches           */
 
 LINENO lineno;                 /* line number of current line */
 long charno;                   /* current character number */
-FILEPOS linepos;               /* start of line (C only) */
-FILEPOS prev_linepos;          /* start of previous line (C only) */
 
 long linecharno;               /* charno of start of line; not used by C, but
                                 * by every other language.
@@ -437,10 +351,11 @@ long linecharno;          /* charno of start of line; not used by C, but
 char *curfile,                 /* current input file name              */
  *outfile,                     /* output file                          */
  *white = " \f\t\n",           /* white chars                          */
- *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars                   */
- *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",    /* token starting chars                 */
- *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789",   /* valid in-token chars                 */
- *notgd = ",;";                        /* non-valid after-function chars       */
+ *endtk = " \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?", /* token ending chars   */
+                               /* token starting chars                 */
+ *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$",
+                                 /* valid in-token chars               */
+ *intk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
 
 int append_to_tagfile;         /* -a: append to tags */
 int emacs_tags_format;         /* emacs style output (no -e option any more) */
@@ -502,10 +417,13 @@ struct linebuffer
 };
 
 struct linebuffer lb;          /* the current line */
-struct linebuffer lb1;         /* sometimes, a previous line in which a token lies */
 struct linebuffer filename_lb; /* used to read in filenames */
+struct
+{
+  FILEPOS linepos;
+  struct linebuffer lb;                /* used by C_entries instead of lb */
+} lbs[2];
 \f
-
 void
 print_version ()
 {
@@ -518,7 +436,7 @@ print_version ()
 #ifdef ETAGS
   printf ("ETAGS ");
 #endif
-  printf ("for Emacs version 19.0.\n");
+  printf ("for Emacs version 19.\n");
 
   exit (0);
 }
@@ -529,14 +447,13 @@ print_help ()
   printf ("These are the options accepted by %s.  You may use unambiguous\n\
 abbreviations for the long option names.\n\n", progname);
 
-  fputs ("\
--a, --append\n\
-        Append tag entries to existing tags file.\n\
--C, --c++\n\
+  puts ("-a, --append\n\
+        Append tag entries to existing tags file.");
+  puts ("-C, --c++\n\
         Treat files with `.c' and `.h' extensions as C++ code, not C\n\
         code.  Files with `.C', `.H', `.cxx', `.hxx', or `.cc'\n\
-        extensions are always assumed to be C++ code.\n\
--d, --defines\n\
+        extensions are always assumed to be C++ code.");
+  fputs ("-d, --defines\n\
         Create tag entries for #defines, too.", stdout);
 
 #ifdef ETAGS
@@ -560,11 +477,11 @@ abbreviations for the long option names.\n\n", progname);
         Don't rely on indentation quite as much as normal.  Currently,\n\
         this means not to assume that a closing brace in the first\n\
         column is the final brace of a function or structure\n\
-        definition.\n\
--t, --typedefs\n\
+        definition.");
+  puts ("-t, --typedefs\n\
         Generate tag entries for typedefs.  This is the default\n\
-        behavior.\n\
--T, --typedefs-and-c++\n\
+        behavior.");
+  puts ("-T, --typedefs-and-c++\n\
         Generate tag entries for typedefs, struct/enum/union tags, and\n\
         C++ member functions.");
 
@@ -578,27 +495,27 @@ abbreviations for the long option names.\n\n", progname);
 #ifdef CTAGS
   puts ("-B, --backward-search\n\
         Write the search commands for the tag entries using '?', the\n\
-        backward-search command.\n\
--F, --forward-search\n\
+        backward-search command.");
+  puts ("-F, --forward-search\n\
         Write the search commands for the tag entries using '/', the\n\
-        forward-search command.\n\
--u, --update\n\
+        forward-search command.");
+  puts ("-u, --update\n\
         Update the tag entries for the given files, leaving tag\n\
         entries for other files in place.  Currently, this is\n\
         implemented by deleting the existing entries for the given\n\
         files and then rewriting the new entries at the end of the\n\
         tags file.  It is often faster to simply rebuild the entire\n\
-        tag file than to use this.\n\
--v, --vgrind\n\
+        tag file than to use this.");
+  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.\n\
--x, --cxref\n\
+        gives the page number of each item.");
+  puts ("-x, --cxref\n\
         Like --vgrind, but in the style of cxref, rather than vgrind.\n\
         The output uses line numbers instead of page numbers, but\n\
         beyond that the differences are cosmetic; try both to see\n\
-        which you like.\n\
--w, --no-warn\n\
+        which you like.");
+  puts ("-w, --no-warn\n\
         Suppress warning messages about entries defined in multiple\n\
         files.");
 #endif
@@ -620,7 +537,7 @@ main (argc, argv)
   char cmd[100];
   int i;
   unsigned int nincluded_files = 0;
-  char **included_files = (char **) alloca (argc * sizeof (char *));
+  char **included_files = xnew (argc, char *);
   char *this_file;
 #ifdef VMS
   char got_err;
@@ -647,7 +564,7 @@ main (argc, argv)
   for (;;)
     {
       int opt;
-      opt = getopt_long (argc, argv, "aCdDo:StTi:BFuvxwVH", longopts, 0);
+      opt = getopt_long (argc, argv, "aCdDo:f:StTi:BFuvxwVH", longopts, 0);
 
       if (opt == EOF)
        break;
@@ -672,11 +589,12 @@ main (argc, argv)
        case 'D':
          constantypedefs = 0;
          break;
+       case 'f':
        case 'o':
          if (outfile)
            {
              fprintf (stderr,
-                      "%s: -o flag may only be given once\n", progname);
+                      "%s: -%c flag may only be given once\n", progname, opt);
              goto usage;
            }
          outfile = optarg;
@@ -740,12 +658,12 @@ main (argc, argv)
        }
     }
 
-  if (optind == argc)
+  if (optind == argc && nincluded_files == 0)
     {
       fprintf (stderr, "%s: No input files specified.\n", progname);
 
     usage:
-      fprintf (stderr, "%s: Try '%s --help' for a complete list of options.\n",
+      fprintf (stderr, "%s: Try `%s --help' for a complete list of options.\n",
               progname, progname);
       exit (BAD);
     }
@@ -758,7 +676,8 @@ main (argc, argv)
   init ();                     /* set up boolean "functions"           */
 
   initbuffer (&lb);
-  initbuffer (&lb1);
+  initbuffer (&lbs[0].lb);
+  initbuffer (&lbs[1].lb);
   initbuffer (&filename_lb);
   /*
    * loop through files finding functions
@@ -791,7 +710,7 @@ main (argc, argv)
          this_file = massage_name (this_file);
 #if 0
        }
-    }                          /* solely to balance out the ifdef'd parens above */
+    }                  /* solely to balance out the ifdef'd parens above */
 #endif
 #else
   for (; optind < argc; optind++)
@@ -869,12 +788,7 @@ process_file (file)
 {
   struct stat stat_buf;
 
-  stat (file, &stat_buf);
-  if (!(stat_buf.st_mode & S_IFREG)
-#ifdef S_IFLNK
-      || !(stat_buf.st_mode & S_IFLNK)
-#endif
-      )
+  if (stat (file, &stat_buf) || !S_ISREG (stat_buf.st_mode))
     {
       fprintf (stderr, "Skipping %s: it is not a regular file.\n", file);
       return;
@@ -885,19 +799,10 @@ process_file (file)
       fprintf (stderr, "Skipping inclusion of %s in self.\n", file);
       return;
     }
-  if (emacs_tags_format)
-    {
-      char *cp = etags_rindex (file, '/');
-      if (cp)
-       ++cp;
-      else
-       cp = file;
-    }
   find_entries (file);
   if (emacs_tags_format)
     {
-      fprintf (outf, "\f\n%s,%d\n",
-              file, total_size_of_entries (head));
+      fprintf (outf, "\f\n%s,%d\n", file, total_size_of_entries (head));
       put_entries (head);
       free_tree (head);
       head = NULL;
@@ -905,8 +810,8 @@ process_file (file)
 }
 
 /*
- * This routine sets up the boolean psuedo-functions which work
- * by seting boolean flags dependent upon the corresponding character
+ * This routine sets up the boolean pseudo-functions which work
+ * by setting boolean flags dependent upon the corresponding character
  * Every char which is NOT in that string is not a white char.  Therefore,
  * all of the array "_wht" is set to FALSE, and then the elements
  * subscripted by the chars in "white" are set to TRUE.  Thus "_wht"
@@ -915,14 +820,11 @@ process_file (file)
 void
 init ()
 {
-  reg char *sp;
-  reg int i;
+  register char *sp;
+  register int i;
 
   for (i = 0; i < 0177; i++)
-    {
-      _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
-      _gd[i] = TRUE;
-    }
+    _wht[i] = _etk[i] = _itk[i] = _btk[i] = FALSE;
   for (sp = white; *sp; sp++)
     _wht[*sp] = TRUE;
   for (sp = endtk; *sp; sp++)
@@ -931,13 +833,10 @@ init ()
     _itk[*sp] = TRUE;
   for (sp = begtk; *sp; sp++)
     _btk[*sp] = TRUE;
-  for (sp = notgd; *sp; sp++)
-    _gd[*sp] = FALSE;
   _wht[0] = _wht['\n'];
   _etk[0] = _etk['\n'];
   _btk[0] = _btk['\n'];
   _itk[0] = _itk['\n'];
-  _gd[0] = _gd['\n'];
 }
 
 /*
@@ -998,8 +897,11 @@ find_entries (file)
       fclose (inf);
       return;
     }
-  /* Assume that ".s" or ".a" is assembly code. -wolfgang.  */
-  if (cp && (cp[1] == 's' || cp[1] == 'a') && cp[2] == '\0')
+  /* Assume that ".s" or ".a" is assembly code. -wolfgang.
+     Or even ".sa". */
+  if (cp && (streq (cp + 1, "s")
+            || streq (cp + 1, "a")
+            || streq (cp + 1, "sa")))
     {
       Asm_funcs (inf);
       fclose (inf);
@@ -1016,13 +918,20 @@ find_entries (file)
       goto close_and_return;
     }
   /* .cs or .hs: a C* file */
-  if (cp && (cp[1] == 'c' || cp[1] == 'h') && cp[2] == 's' && cp[3] == '\0')
+  if (cp && (streq (cp + 1, "cs")
+            || streq (cp + 1, "hs")))
     {
       C_entries (C_STAR);
       goto close_and_return;
     }
+  /* .y: a yacc file */
+  if (cp && (streq (cp + 1, "y")))
+    {
+      C_entries (YACC);
+      goto close_and_return;
+    }
   /* .pl implies prolog source code */
-  if (cp && !strcmp (cp + 1, "pl"))
+  if (cp && streq (cp + 1, "pl"))
     {
       prolog_funcs (inf);
       goto close_and_return;
@@ -1034,11 +943,18 @@ find_entries (file)
       PAS_funcs (inf);
       goto close_and_return;
     }
+  /* If .f or .for, assume it is fortran or nothing.  */
+  if (cp && (streq (cp + 1, "f")
+            || streq (cp + 1, "for")))
+    {
+      PF_funcs (inf);
+      goto close_and_return;
+    }
   /* if not a .c or .h or .y file, try fortran */
-  else if (cp && ((cp[1] != 'c'
-                  && cp[1] != 'h'
-                  && cp[1] != 'y')
-                 || (cp[1] != 0 && cp[2] != 0)))
+  if (cp && ((cp[1] != 'c'
+             && cp[1] != 'h'
+             && cp[1] != 'y')
+            || (cp[1] != 0 && cp[2] != 0)))
     {
       if (PF_funcs (inf) != 0)
        goto close_and_return;
@@ -1066,12 +982,11 @@ string_numeric_p (str)
 \f
 /* Record a tag. */
 /* Should take a TOKEN* instead!! */
-
 void
-pfnote (name, is_func, rewritten, linestart, linelen, lno, cno)
+pfnote (name, is_func, named, linestart, linelen, lno, cno)
      char *name;               /* tag name */
      logical is_func;          /* function or type name? */
-     logical rewritten;                /* tag different from text of definition? */
+     logical named;            /* tag different from text of definition? */
      char *linestart;
      int linelen;
      int lno;
@@ -1106,12 +1021,12 @@ pfnote (name, is_func, rewritten, linestart, linelen, lno, cno)
       fp = etags_rindex (name, '.');
       if (fp && fp[1] != '\0' && fp[2] == '\0')
        *fp = 0;
-      rewritten = TRUE;
+      named = TRUE;
     }
   np->name = savestr (name);
   np->file = curfile;
   np->is_func = is_func;
-  np->rewritten = rewritten;
+  np->named = named;
   np->lno = lno;
   /* UNCOMMENT THE +1 HERE: */
   np->cno = cno /* + 1 */ ;    /* our char numbers are 0-base; emacs's are 1-base */
@@ -1163,13 +1078,16 @@ free_tree (node)
  *     add_node is the only function allowed to add nodes, so it can
  *     maintain state.
  */
+/* Must avoid static vars within functions since some systems
+   #define static as nothing.  */
+static NODE *last_node = NULL;
+
 void
 add_node (node, cur_node_p)
      NODE *node, **cur_node_p;
 {
   register int dif;
   register NODE *cur_node = *cur_node_p;
-  static NODE *last_node = NULL;/* careful */
 
   if (cur_node == NULL)
     {
@@ -1232,9 +1150,9 @@ add_node (node, cur_node_p)
 \f
 void
 put_entries (node)
-     reg NODE *node;
+     register NODE *node;
 {
-  reg char *sp;
+  register char *sp;
 
   if (node == NULL)
     return;
@@ -1246,15 +1164,17 @@ put_entries (node)
 
   if (emacs_tags_format)
     {
-      if (node->rewritten)
+      if (node->named)
        {
          fprintf (outf, "%s\177%s\001%d,%d\n",
-                  node->name, node->pat, node->lno, node->cno);
+                  node->pat, node->name,
+                  node->lno, node->cno);
        }
       else
        {
          fprintf (outf, "%s\177%d,%d\n",
-                  node->pat, node->lno, node->cno);
+                  node->pat,
+                  node->lno, node->cno);
        }
     }
   else if (!cxref_style)
@@ -1313,9 +1233,9 @@ number_len (num)
  */
 int
 total_size_of_entries (node)
-     reg NODE *node;
+     register NODE *node;
 {
-  reg int total;
+  register int total;
 
   if (node == NULL)
     return 0;
@@ -1329,7 +1249,7 @@ total_size_of_entries (node)
       /* Count this entry */
       total += strlen (node->pat) + 1;
       total += number_len ((long) node->lno) + 1 + number_len (node->cno) + 1;
-      if (node->rewritten)
+      if (node->named)
        total += 1 + strlen (node->name);       /* \001name */
     }
 
@@ -1346,8 +1266,8 @@ Stab *C_stab, *C_PLPL_stab, *C_STAR_stab;
  * SYNOPSIS
  *     Stab *get_C_stab (int c_ext);
  */
-#define get_C_stab(c_ext) ((c_ext&C_STAR) ? C_STAR_stab :              \
-                          c_ext ? C_PLPL_stab :                        \
+#define get_C_stab(c_ext) ((c_ext & C_STAR) ? C_STAR_stab :            \
+                          (c_ext & C_PLPL) ? C_PLPL_stab :             \
                           C_stab)
 
 void
@@ -1385,6 +1305,10 @@ C_create_stab (c_ext)
   add_keyword (stab, "double", st_C_typespec);
   add_keyword (stab, "signed", st_C_typespec);
   add_keyword (stab, "unsigned", st_C_typespec);
+  add_keyword (stab, "auto", st_C_typespec);
+  add_keyword (stab, "void", st_C_typespec);
+  add_keyword (stab, "extern", st_C_typespec);
+  add_keyword (stab, "static", st_C_typespec);
   add_keyword (stab, "const", st_C_typespec);
   add_keyword (stab, "volatile", st_C_typespec);
 
@@ -1399,49 +1323,140 @@ C_create_stabs ()
   C_STAR_stab = C_create_stab (C_STAR | C_PLPL);
 }
 \f
+ /*
+  * C functions are recognized using a simple finite automaton.
+  * funcdef is its state variable.
+  */
+typedef enum
+{
+  fnone,                       /* nothing seen */
+  ftagseen,                    /* function-like tag seen */
+  finlist,                     /* in parameter list */
+  flistseen,                   /* after parameter list */
+  fignore,                     /* before open brace */
+} FUNCST;
+FUNCST funcdef;
+
+
+ /* typedefs are recognized using a simple finite automaton.
+  * typeddef is its state variable.
+  */
+typedef enum
+{
+  tnone,                       /* nothing seen */
+  ttypedseen,                  /* typedef keyword seen */
+  tinbody,                     /* inside typedef body */
+  tend,                                /* just before typedef tag */
+} TYPEDST;
+TYPEDST typdef;
+
+
+ /* struct tags for C++ are recognized using another simple
+  * finite automaton.  `structdef' is its state variable.
+  * This machinery is only invoked for C++; otherwise structdef
+  * should remain snone.  However, this machinery can easily be
+  * adapted to find structure tags in normal C code.
+  */
+typedef enum
+{
+  snone,                       /* nothing seen yet */
+  skeyseen,                    /* struct-like keyword seen */
+  stagseen,                    /* struct-like tag seen */
+  scolonseen,                  /* colon seen after struct-like tag */
+  sinbody,                     /* in struct body: recognize member func defs*/
+} STRUCTST;
+STRUCTST structdef;
+/*
+ * When structdef is stagseen, scolonseen, or sinbody, structtag is the
+ * struct tag, and structkey is the preceding struct-like keyword.
+ */
+char structtag[BUFSIZ];
+Stab_entry *structkey;
+
+/*
+ * Yet another little state machine to deal with preprocessor lines.
+ */
+typedef enum
+{
+  dnone,                       /* nothing seen */
+  dsharpseen,                  /* '#' seen as first char on line */
+  ddefineseen,                 /* '#' and 'define' seen */
+  dignorerest,                 /* ignore rest of line */
+} DEFINEST;
+DEFINEST definedef;
+
+/*
+ * Set this to TRUE, and the next token considered is called a function.
+ * Used only for GNUmacs's function-defining macros.
+ */
+logical next_token_is_func;
+
+/*
+ * TRUE in the rules part of a yacc file, FALSE outside (parse as C).
+ */
+logical yacc_rules;
+
 /*
  * C_entries ()
- *     This routine finds functions and typedefs in C syntax and adds them
+ *     This routine finds functions, typedefs, #define's and
+ *     struct/union/enum definitions in C syntax and adds them
  *     to the list.
  */
 
+#define curlb (lbs[curndx].lb)
+#define othlb (lbs[1-curndx].lb)
+#define newlb (lbs[newndx].lb)
+#define curlinepos (lbs[curndx].linepos)
+#define othlinepos (lbs[1-curndx].linepos)
+#define newlinepos (lbs[newndx].linepos)
+
 #define CNL_SAVE_DEFINEDEF                                             \
-{                                                                      \
-  prev_linepos = linepos;                                              \
-  SET_FILEPOS (linepos, inf, charno);                                  \
+do {                                                                   \
+  SET_FILEPOS (curlinepos, inf, charno);                               \
   lineno++;                                                            \
-  charno += readline (&lb, inf);                                       \
-  lp = lb.buffer;                                                      \
-}
+  charno += readline (&curlb, inf);                                    \
+  lp = curlb.buffer;                                                   \
+  quotednl = FALSE;                                                    \
+  newndx = curndx;                                                     \
+} while (FALSE)
 
 #define CNL                                                            \
-{                                                                      \
+do {                                                                   \
   CNL_SAVE_DEFINEDEF;                                                  \
   definedef = dnone;                                                   \
-}
+} while (FALSE)
+
+#define MAKE_TAG_FROM_NEW_LB(isfun)  pfnote (nameb, isfun, tok.named,  \
+  newlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (newlinepos))
+#define MAKE_TAG_FROM_OTH_LB(isfun)  pfnote (nameb, isfun, tok.named,  \
+  othlb.buffer, tokoff + toklen + 1, tok.lineno, GET_CHARNO (othlinepos))
 
 void
 C_entries (c_ext)
      int c_ext;                        /* extension of C? */
 {
-  register int c;              /* latest char read; '\0' for end of line */
-  register int tokoff;         /* offset in line of beginning of latest token */
-  register int toklen;         /* length of latest token */
+  register char c;             /* latest char read; '\0' for end of line */
   register char *lp;           /* pointer one beyond the character `c' */
-  logical incomm, inquote, inchar, midtoken;
-  int level;                   /* current curly brace level */
-  char tokb[BUFSIZ];
+  int curndx, newndx;          /* indices for current and new lb */
+  TOKEN tok;                   /* latest token read for funcdef & structdef */
+  char nameb[BUFSIZ];          /* latest token name for funcdef & structdef */
+  register int tokoff;         /* offset in line of start of latest token */
+  register int toklen;         /* length of latest token */
+  int cblev;                   /* current curly brace level */
+  logical incomm, inquote, inchar, quotednl, midtoken;
+  logical cplpl;
 
+  curndx = newndx = 0;
   lineno = 0;
   charno = 0;
-  lp = lb.buffer;
+  lp = curlb.buffer;
   *lp = 0;
 
-  definedef = dnone;
-  gotone = midtoken = inquote = inchar = incomm = FALSE;
-  level = 0;
-  tydef = none;
-  next_token_is_func = 0;
+  definedef = dnone; funcdef = fnone; typdef= tnone; structdef= snone;
+  next_token_is_func = yacc_rules = FALSE;
+  midtoken = inquote = inchar = incomm = quotednl = FALSE;
+  cblev = 0;
+  cplpl = c_ext & C_PLPL;
 
   C_create_stabs ();
 
@@ -1453,25 +1468,48 @@ C_entries (c_ext)
          /* 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
             to read the next line.  */
-         if (*lp == 0)
-           continue;
+         if (*lp == '\0')
+           {
+             quotednl = TRUE;
+             continue;
+           }
          lp++;
          c = ' ';
        }
       else if (incomm)
        {
-         if (c == '*' && *lp == '/')
+         switch (c)
            {
-             c = *lp++;
-             incomm = FALSE;
+           case '*':
+             if (*lp == '/')
+               {
+                 c = *lp++;
+                 incomm = FALSE;
+               }
+             break;
+           case '\0':
+             /* Newlines inside comments do not end macro definitions in
+                traditional cpp. */
+             CNL_SAVE_DEFINEDEF;
+             break;
            }
+         continue;
        }
       else if (inquote)
        {
-         if (c == '"')
-           inquote = FALSE;
-         else if (c == '\\')
-           c = *lp++;
+         switch (c)
+           {
+           case '"':
+             inquote = FALSE;
+             break;
+           case '\0':
+             /* Newlines inside strings, do not end macro definitions
+                in traditional cpp, even though compilers don't
+                usually accept them. */
+             CNL_SAVE_DEFINEDEF;
+             break;
+           }
+         continue;
        }
       else if (inchar)
        {
@@ -1479,7 +1517,7 @@ C_entries (c_ext)
            inchar = FALSE;
          continue;
        }
-      else
+      else 
        switch (c)
          {
          case '"':
@@ -1493,76 +1531,45 @@ C_entries (c_ext)
              {
                lp++;
                incomm = TRUE;
+               continue;
              }
-           else if (c_ext && *lp == '/')
+           else if (cplpl && *lp == '/')
              {
                c = 0;
                break;
              }
            continue;
+         case '%':
+           if ((c_ext & YACC) && *lp == '%')
+             {
+               /* entering or exiting rules section in yacc file */
+               lp++;
+               definedef = dnone; funcdef = fnone;
+               typdef= tnone; structdef= snone;
+               next_token_is_func = FALSE;
+               midtoken = inquote = inchar = incomm = quotednl = FALSE;
+               cblev = 0;
+               yacc_rules = !yacc_rules;
+               continue;
+             }
          case '#':
-           if (lp == lb.buffer + 1 && definedef == dnone)
+           if (lp == newlb.buffer + 1 && definedef == dnone)
              definedef = dsharpseen;
            continue;
+         } /* switch (c) */
 
-           /*
-            * The next two are to help the strucdef state machine.
-            * They break when they are finished, so they don't interfere
-            * with anything else that is going on.
-            */
-         case ':':
-           if (structdef == stagseen)
-             structdef = scolonseen;
-           break;
-           /* Not a struct definition when semicolon seen in non-sinbody context. */
-         case ';':
-           if (structdef != snone && structdef != sinbody)
-             {
-               structdef = snone;
-               (void) strcpy (structtag, "<error 1>");
-             }
-           break;
 
-         case '{':
-           if (tydef == begin)
-             {
-               tydef = middle;
-             }
-           switch (structdef)
-             {
-             case skeyseen:    /* unnamed struct */
-               structtag[0] = '\0';
-               /* FALLTHRU */
-             case stagseen:
-             case scolonseen:  /* named struct */
-               structdef = sinbody;
-               break;
-             }
-           level++;
-           continue;
-         case '}':
-           if (!noindentypedefs && lp == lb.buffer + 1)
-             level = 0;        /* reset level if first column */
-           else if (level > 0)
-             level--;
-           if (level == 0 && tydef == middle)
-             {
-               tydef = end;
-             }
-           if (level == 0)
-             {
-               structdef = snone;
-               (void) strcpy (structtag, "<error 2>");
-             }
-           continue;
-         }
-      if (LEVEL_OK_FOR_FUNCDEF () && !inquote && !incomm && gotone == FALSE)
+      /* Consider token only if some complicated conditions are satisfied. */
+      if (((cblev == 0 && structdef != scolonseen)
+          || (cblev == 1 && cplpl && structdef == sinbody))
+         && definedef != dignorerest
+         && funcdef != finlist)
        {
          if (midtoken)
            {
              if (endtoken (c))
                {
-                 if (c_ext && c == ':' && *lp == ':' && intoken (*(lp + 1)))
+                 if (cplpl && c == ':' && *lp == ':' && intoken (*(lp + 1)))
                    {
                      /*
                       * This handles :: in the middle, but not at beginning
@@ -1573,114 +1580,190 @@ C_entries (c_ext)
                    }
                  else
                    {
-                     /* The following is no longer true,
-                        now that we advance to the next line
-                        at the end of processing the character.  */
-                     /*
-                      * We've just finished lexing an identifier.
-                      * Note that if `c' is '\0', `lb' is the NEXT
-                      * line, `lp' points to the beginning of it, and
-                      * old pointers into `lb.buffer' may no longer be
-                      * valid, since `lb.buffer' may have been
-                      * reallocated.  In this case (which corresponds
-                      * to an identifier followed immediately by a
-                      * newline), we re-read the line into lb1.
-                      *
-                      * This would be faster if the previous line's
-                      * buffer were always saved.
-                      */
-                     logical is_func;
-                     char *tok_linebuf;
-                     TOKEN tok;
-                     logical bingo, tok_at_end_of_line;
-                     char *lp_tmp;     /* addressable */
+                     logical is_func = FALSE;
 
-#if 0
-                     if (c == '\0')
-                       {
-                         getline (GET_COOKIE (prev_linepos));
-                         tok_linebuf = lb1.buffer;
-                         tok_at_end_of_line = TRUE;
-                         tok.linestart = prev_linepos;
-                         tok.lineno = lineno - 1;
-                       }
-                     else
-#endif
-                       {
-                         tok_linebuf = lb.buffer;
-                         tok_at_end_of_line = FALSE;
-                         tok.linestart = linepos;
-                         tok.lineno = lineno;
-                       }
-                     tok.p = tok_linebuf + tokoff;
+                     tok.lineno = lineno;
+                     tok.p = newlb.buffer + tokoff;
                      tok.len = toklen;
-                     tok.rewritten = FALSE;
-                     lp_tmp = lp;
-                     bingo = consider_token (c, &lp_tmp, &tok,
-                                             &is_func, c_ext, level);
-                     lp = lp_tmp;
-                     if (bingo)
+                     tok.named = FALSE;
+                     if (yacc_rules
+                         || consider_token (c, lp, &tok,
+                                            c_ext, cblev, &is_func))
                        {
-                         if (GET_CHARNO (tok.linestart) != GET_CHARNO (linepos)
-                             && !tok_at_end_of_line)
+                         if (structdef == sinbody
+                             && definedef == dnone
+                             && is_func)
+                           /* function defined in C++ class body */
                            {
-                             /*
-                              * Resynchronize tok.p to point into the right
-                              * linebuffer.
-                              */
-                             getline (GET_COOKIE (tok.linestart));
-                             if (!tok.rewritten)
-                               tok.p = lb1.buffer + (tok.p - tok_linebuf);
-                             tok_linebuf = lb1.buffer;
-                           }
-                         if (structdef == sinbody && definedef == dnone && is_func)
-                           {   /* function defined in C++ class body */
-                             sprintf (tokb, "%s::%.*s",
-                                      structtag[0] == '\0' ? "_anonymous_"
-                                      : structtag,
+                             tok.named = TRUE;
+                             sprintf (nameb, "%s::%.*s",
+                                      ((structtag[0] == '\0')
+                                       ? "_anonymous_" : structtag),
                                       tok.len, tok.p);
-                             tok.rewritten = TRUE;
                            }
                          else
                            {
-                             sprintf (tokb, "%.*s", tok.len, tok.p);
+                             sprintf (nameb, "%.*s", tok.len, tok.p);
                            }
-                         pfnote (tokb, is_func, tok.rewritten, tok_linebuf,
-                            tokoff + toklen + (tok_at_end_of_line ? 0 : 1),
-                                 tok.lineno, GET_CHARNO (tok.linestart));
-                         gotone = is_func;     /* function */
+
+                         if (structdef == stagseen
+                             || typdef == tend)
+                           tok.named = TRUE;
+
+                         if (funcdef == ftagseen
+                             || structdef == stagseen
+                             || typdef == tend)
+                           {
+                             if (newndx == curndx)
+                               curndx = 1 - curndx; /* switch line buffers */
+                           }
+                         else
+                           MAKE_TAG_FROM_NEW_LB (is_func);
                        }
                      midtoken = FALSE;
                    }
-               }
+               } /* if (endtoken (c)) */
              else if (intoken (c))
-               toklen++;
-           }
+               {
+                 toklen++;
+                 continue;
+               }
+           } /* if (midtoken) */
          else if (begtoken (c))
            {
-             tokoff = lp - 1 - lb.buffer;
-             toklen = 1;
-             midtoken = TRUE;
+             switch (funcdef)
+               {
+               case flistseen:
+                 MAKE_TAG_FROM_OTH_LB (TRUE);
+                 funcdef = fignore;
+                 break;
+               case ftagseen:
+                 funcdef = fnone;
+                 break;
+               }
+             if (structdef == stagseen)
+               structdef = snone;
+             if (!yacc_rules || lp == newlb.buffer + 1)
+               {
+                 tokoff = lp - 1 - newlb.buffer;
+                 toklen = 1;
+                 midtoken = TRUE;
+               }
+             continue;
            }
-       }
-      /* Detect end of line, after having handled the last token on the line.  */
-      if (c == 0)
+       } /* if must look at token */
+
+
+      /* Detect end of line, colon, comma, semicolon and various braces
+        after having handled the last token on the line.*/
+      switch (c)
        {
-         CNL;
-         gotone = FALSE;
-       }
-      if (c == ';' && tydef == end)    /* clean with typedefs */
-       tydef = none;
-    }
+       case ':':
+         if (structdef == stagseen)
+           structdef = scolonseen;
+         else if (yacc_rules && funcdef == ftagseen)
+           {
+             MAKE_TAG_FROM_OTH_LB (FALSE);
+             funcdef = fignore;
+           }
+         break;
+       case ';':
+         if (cblev == 0 && typdef == tend)
+           {
+             typdef = tnone;
+             MAKE_TAG_FROM_OTH_LB (FALSE);
+           }
+         if (funcdef != fignore)
+           funcdef = fnone;
+         /* FALLTHRU */
+       case ',':
+         /* FALLTHRU */
+       case '[':
+         if (funcdef != finlist && funcdef != fignore)
+           funcdef = fnone;
+         if (structdef == stagseen)
+           structdef = snone;
+         break;
+       case '(':
+         switch (funcdef)
+           {
+           case ftagseen:
+             funcdef = finlist;
+             break;
+           case finlist:
+           case flistseen:
+             funcdef = fnone;
+             break;
+           }
+         break;
+       case ')':
+         if (funcdef == finlist)
+           funcdef = flistseen;
+         break;
+       case '{':
+         if (typdef == ttypedseen)
+           typdef = tinbody;
+         switch (structdef)
+           {
+           case skeyseen:      /* unnamed struct */
+             structtag[0] = '\0';
+             structdef = sinbody;
+             break;
+           case stagseen:
+           case scolonseen:    /* named struct */
+             structdef = sinbody;
+             MAKE_TAG_FROM_OTH_LB (FALSE);
+             break;
+           }
+         switch (funcdef)
+           {
+           case flistseen:
+             MAKE_TAG_FROM_OTH_LB (TRUE);
+             /* FALLTHRU */
+           case fignore:
+             funcdef = fnone;
+           }
+         cblev++;
+         break;
+       case '*':
+         if (funcdef == flistseen)
+           {
+             MAKE_TAG_FROM_OTH_LB (TRUE);
+             funcdef = fignore;
+           }
+         break;
+       case '}':
+         if (!noindentypedefs && lp == newlb.buffer + 1)
+           cblev = 0;  /* reset curly brace level if first column */
+         else if (cblev > 0)
+           cblev--;
+         if (cblev == 0)
+           {
+             if (typdef == tinbody)
+               typdef = tend;
+             structdef = snone;
+             (void) strcpy (structtag, "<error 2>");
+           }
+         break;
+       case '\0':
+         /* If a macro spans multiple lines don't reset its state. */
+         if (quotednl)
+           CNL_SAVE_DEFINEDEF;
+         else
+           CNL;
+         break;
+       } /* switch (c) */
+
+    } /* while not eof */
 }
 
 /*
  * consider_token ()
  *     checks to see if the current token is at the start of a
- *     function, or corresponds to a typedef.  It updates the input
- *     line pointer *LPP so that the '(' will be in it when it returns.
+ *     function, or corresponds to a typedef, or is a struct/union/enum
+ *     tag.
  *
- *     *IS_FUNC gets TRUE iff the token is a function.
+ *     *IS_FUNC gets TRUE iff the token is a function or macro with args.
  *     C_EXT is which language we are looking at.
  *
  *     In the future we will need some way to adjust where the end of
@@ -1689,30 +1772,27 @@ C_entries (c_ext)
  *     whatever follows `operator'.
  *
  * Globals
- *     structdef       IN OUT
- *     definedef       IN OUT
- *     tydef           IN OUT
+ *     funcdef                 IN OUT
+ *     structdef               IN OUT
+ *     definedef               IN OUT
+ *     typdef                  IN OUT
+ *     next_token_is_func      IN OUT
  */
 
 logical
-consider_token (c, lpp, tokp, is_func, c_ext, level)
-     reg char c;               /* IN: first char after the token */
-     char **lpp;               /* IN OUT: *lpp points to 2nd char after the token */
-     reg TOKEN *tokp;          /* IN */
+consider_token (c, lp, tokp, c_ext, cblev, is_func)
+     register char c;          /* IN: first char after the token */
+     register char *lp;                /* IN: lp points to 2nd char after the token */
+     register TOKEN *tokp;     /* IN: token pointer */
+     int c_ext;                        /* IN: C extensions mask */
+     int cblev;                        /* IN: curly brace level */
      logical *is_func;         /* OUT */
-     int c_ext;                        /* IN */
-     int level;                        /* IN */
 {
-  reg char *lp = *lpp;
-  logical firsttok;            /* TRUE if have seen first token in ()'s */
   Stab_entry *tokse = stab_find (get_C_stab (c_ext), tokp->p, tokp->len);
   enum sym_type toktype = stab_type (tokse);
 
-  *is_func = TRUE;             /* a function */
-
   /*
-   * Advance the definedef state machine.  We set `gotone' for good measure;
-   * it's redundant.
+   * Advance the definedef state machine.
    */
   switch (definedef)
     {
@@ -1723,170 +1803,114 @@ consider_token (c, lpp, tokp, is_func, c_ext, level)
       if (toktype == st_C_define)
        {
          definedef = ddefineseen;
-         gotone = FALSE;
        }
       else
        {
          definedef = dignorerest;
-         gotone = TRUE;
        }
-      goto badone;
+      return (FALSE);
     case ddefineseen:
       /*
        * Make a tag for any macro.
-       * This will flub up if there is a newline immediately following
-       * the macro name.
        */
-      *is_func = (c == '(');
       definedef = dignorerest;
-      gotone = TRUE;
+      *is_func = (c == '(');
       if (!*is_func && !constantypedefs)
-       goto badone;
-      goto goodone;
+       return (FALSE);
+      else
+       return (TRUE);
     case dignorerest:
-      goto badone;
+      return (FALSE);
     default:
       error ("internal error: definedef value");
     }
 
   /*
-   * Skip whitespace and comments after the token.  This loop should
-   * also skip C++ comments.
+   * Now typedefs
    */
-  while (1)
+  switch (typdef)
     {
-      /* At whitespace => skip it.  */
-      if (iswhite (c))
+    case tnone:
+      if (toktype == st_C_typedef)
        {
-         c = *lp++;
+         if (typedefs)
+           typdef = ttypedseen;
+         return (FALSE);
        }
-      /* At a comment => skip to end of comment.  */
-      else if (c == '/' && *lp == '*')
-       {
-         /* If we find a comment, skip it.  */
-         while (!(c == '*' && *lp == '/'))
-           {
-             c = *lp++;
-             if (c == 0)
-               {
-                 lp--;
-                 break;
-               }
-           }
-         if (c == '*' && *lp == '/')
-           {
-             lp++;             /* lp now points past the '/' */
-             c = *lp++;        /* c is now the --whatever-- after the '/' */
-           }
-       }
-      else
-       break;
-
-      /* If we arrived at eof or eol, decide which one it is.
-        If it's eol, advance to the next line.  */
-
-      if (c == 0)
+      break;
+    case ttypedseen:
+      switch (toktype)
        {
-         lp--;
+       case st_none:
+       case st_C_typespec:
+         typdef = tend;
+         break;
+       case st_C_struct:
+       case st_C_enum:
          break;
        }
-    }
-
-  /*
-   * If you have custom token types, or when configuration files can
-   * define custom token types, this switch will be larger.
-   */
-  switch (toktype)
-    {
-    case st_C_typedef:
-      if (typedefs)
-       {
-         tydef = begin;
-         goto badone;
-       }
+      /* Do not return here, so the structdef stuff has a chance. */
       break;
-    case st_C_typespec:
-      if (tydef == begin || tydef == end)
+    case tend:
+      switch (toktype)
        {
-         tydef = end;
-         goto badone;
+       case st_C_typespec:
+       case st_C_struct:
+       case st_C_enum:
+         return (FALSE);
        }
-      break;
+      return (TRUE);
     }
 
   /*
-   * This structdef business is currently only invoked when level==0.
-   * It should be recursively invoked whatever the level, and a stack of
-   * states kept, to allow for definitions of structs within structs.
+   * This structdef business is currently only invoked when cblev==0.
+   * It should be recursively invoked whatever the curly brace level,
+   * and a stack of states kept, to allow for definitions of structs
+   * within structs.
    *
    * This structdef business is NOT invoked when we are ctags and the
    * file is plain C.  This is because a struct tag may have the same
    * name as another tag, and this loses with ctags.
    *
-   * This if statement deals with the tydef state machine as follows: if
-   * tydef==begin and token is struct/union/class/enum, goto badone.
-   * All the other code here is for the structdef state machine.
+   * This if statement deals with the typdef state machine as 
+   * follows: if typdef==ttypedseen and token is struct/union/class/enum,
+   * return (FALSE).  All the other code here is for the structdef 
+   * state machine.
    */
   switch (toktype)
     {
     case st_C_struct:
     case st_C_enum:
-      if (tydef == begin || (typedefs_and_cplusplus && level == 0 && structdef == snone))
+      if (typdef == ttypedseen
+         || (typedefs_and_cplusplus && cblev == 0 && structdef == snone))
        {
          structdef = skeyseen;
          structkey = tokse;
        }
-      goto badone;
+      return (FALSE);
     }
-
   if (structdef == skeyseen)
     {
-      /* If next char is '{' or (for C++) ':', found a structure tag. */
-      if (c == '{' || (c_ext && c == ':'))
+      if (stab_type (structkey) == st_C_struct)
        {
-         /*
-          * We should do this slightly differently for straight C:
-          * instead of defining `tag', as we now do, we should define
-          * `struct tag'.  (Do this only if the find-tag defaulting is
-          * done on a sophisticated per-mode basis, so that if the user
-          * says meta-. anywhere in `struct foo', the default comes out
-          * `struct foo', not `struct' or `foo'.)  This will require
-          * remembering which keyword (struct/union/class/enum) we saw, as a
-          * Stab_entry* -- this will also make it possible to merge the
-          * skeyseen and senumseen states, if we want.
-          */
-         if (stab_type (structkey) == st_C_struct)
-           {
-             (void) strncpy (structtag, tokp->p, tokp->len);
-             structtag[tokp->len] = '\0';      /* for struct/union/class */
-             structdef = stagseen;
-           }
-         else
-           {
-             structtag[0] = '\0';      /* for enum */
-           }
-         *is_func = FALSE;     /* not a function */
-         goto goodone;
+         (void) strncpy (structtag, tokp->p, tokp->len);
+         structtag[tokp->len] = '\0';  /* for struct/union/class */
        }
       else
        {
-         /* Not a definition: reset structdef */
-         structdef = snone;
-         (void) strcpy (structtag, "<error 3>");
+         structtag[0] = '\0';  /* for enum (why is it treated differently?) */
        }
-      /* Now what?  And how does/should this stuff interact with tydef?? */
-      /* Also maybe reset lp to *lpp for benefit of the function finding code. */
-    }
-  if (tydef == begin)
-    {
-      tydef = end;
-      goto badone;
+      structdef = stagseen;
+      return (TRUE);
     }
-  if (tydef == end)
+
+  /* Avoid entering funcdef stuff if typdef is going on. */
+  if (typdef != tnone)
     {
-      *is_func = 0;
-      goto goodone;
+      definedef = dnone;
+      return (FALSE);
     }
+
   /* Detect GNUmacs's function-defining macros. */
   if (definedef == dnone)
     {
@@ -1896,70 +1920,38 @@ consider_token (c, lpp, tokp, is_func, c_ext, level)
          || strneq (tokp->p, "PSEUDO", 6))
        {
          next_token_is_func = TRUE;
-         goto badone;
+         return (FALSE);
        }
-      else if (strneq (tokp->p, "EXFUN", 5))
+      if (strneq (tokp->p, "EXFUN", 5))
        {
          next_token_is_func = FALSE;
-         goto badone;
+         return (FALSE);
        }
     }
   if (next_token_is_func)
     {
       next_token_is_func = FALSE;
-      goto goodone;
-    }
-  if (c != '(')
-    goto badone;
-  firsttok = FALSE;
-  while ((c = *lp++) != ')')
-    {
-      if (c == 0)
-       {
-         lp--;
-         break;
-       }
-      /*
-       * This line used to confuse ctags:
-       *       int     (*oldhup)();
-       * This fixes it. A nonwhite char before the first
-       * token, other than a / (in case of a comment in there)
-       * makes this not a declaration.
-       */
-      if (begtoken (c) || c == '/')
-       firsttok++;
-      else if (!iswhite (c) && !firsttok)
-       goto badone;
+      funcdef = fnone;
+      *is_func = TRUE;         /* to force search string in ctags */
+      return (TRUE);
     }
-  while (iswhite (c = *lp++))
+
+  /* A function? */
+  switch (toktype)
     {
-      if (c == 0)
+    case st_C_typespec:
+      funcdef = fnone;         /* should be useless */
+      return (FALSE);
+    default:
+      if (funcdef == fnone)
        {
-         lp--;
-         break;
+         funcdef = ftagseen;
+         *is_func = TRUE;
+         return (TRUE);
        }
     }
-  if (!isgood (c))
-    goto badone;
-
-goodone:
-  *lpp = lp - 1;
-  return TRUE;
-
-badone:
-  *lpp = lp - 1;
-  return FALSE;
-}
 
-void
-getline (atcookie)
-     long atcookie;
-{
-  long saveftell = ftell (inf);
-
-  (void) fseek (inf, atcookie, 0);
-  (void) readline (&lb1, inf);
-  (void) fseek (inf, saveftell, 0);
+  return (FALSE);
 }
 \f
 /* Fortran parsing */
@@ -2368,15 +2360,17 @@ L_funcs (fi)
          else
            {
              /* Check for (foo::defmumble name-defined ... */
-             while (*dbp && *dbp != ':' && !isspace (*dbp)
-                    && *dbp != '(' && *dbp != ')')
+             do
                dbp++;
+             while (*dbp && !isspace (*dbp)
+                    && *dbp != ':' && *dbp != '(' && *dbp != ')');
              if (*dbp == ':')
                {
-                 while (*dbp == ':')
+                 do
                    dbp++;
+                 while (*dbp == ':');
 
-                 if (L_isdef (dbp))
+                 if (L_isdef (dbp - 1))
                    {
                      while (!isspace (*dbp))
                        dbp++;
@@ -2392,11 +2386,23 @@ L_funcs (fi)
 
 int
 L_isdef (dbp)
-     char *dbp;
+     register char *dbp;
 {
-  return ((dbp[1] == 'D' || dbp[1] == 'd') &&
-         (dbp[2] == 'E' || dbp[2] == 'e') &&
-         (dbp[3] == 'F' || dbp[3] == 'f'));
+  return ((dbp[1] == 'd' || dbp[1] == 'D')
+         && (dbp[2] == 'e' || dbp[2] == 'E')
+         && (dbp[3] == 'f' || dbp[3] == 'F'));
+}
+
+int
+L_isquote (dbp)
+     register char *dbp;
+{
+  return ((*(++dbp) == 'q' || *dbp == 'Q')
+         && (*(++dbp) == 'u' || *dbp == 'U')
+         && (*(++dbp) == 'o' || *dbp == 'O')
+         && (*(++dbp) == 't' || *dbp == 'T')
+         && (*(++dbp) == 'e' || *dbp == 'E')
+         && isspace(*(++dbp)));
 }
 
 void
@@ -2406,15 +2412,25 @@ L_getit ()
   char c;
   char nambuf[BUFSIZ];
 
-  if (*dbp == 0)
-    return;
-  for (cp = dbp + 1; *cp && *cp != '(' && *cp != ' '; cp++)
+  if (*dbp == '\'')            /* Skip prefix quote */
+    dbp++;
+  else if (*dbp == '(' && L_isquote (dbp)) /* Skip "(quote " */
+  {
+    dbp += 7;
+    while (isspace(*dbp))
+      dbp++;
+  }
+  for (cp = dbp /*+1*/; *cp && *cp != '(' && *cp != ' ' && *cp != ')'; cp++)
     continue;
+  if (cp == dbp)
+    return;
+  
   c = cp[0];
   cp[0] = 0;
   (void) strcpy (nambuf, dbp);
   cp[0] = c;
-  pfnote (nambuf, TRUE, FALSE, lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
+  pfnote (nambuf, TRUE, FALSE, lb.buffer,
+         cp - lb.buffer + 1, lineno, linecharno);
   pfcnt++;
 }
 \f
@@ -2546,13 +2562,13 @@ TEX_funcs (fi)
     TEX_toktab = TEX_decode_env ("TEXTAGS", TEX_defenv);
 
   while (!feof (fi))
-    {                  /* Scan each line in file */
+    {                          /* Scan each line in file */
       lineno++;
       linecharno = charno;
       charno += readline (&lb, fi);
       dbp = lb.buffer;
       lasthit = dbp;
-      while (dbp = etags_index (dbp, TEX_esc)) /* Look at each escape in line */
+      while (dbp = etags_index (dbp, TEX_esc)) /* Look at each escape in line */
        {
          register int i;
 
@@ -2564,7 +2580,7 @@ TEX_funcs (fi)
          if (0 <= i)
            {
              TEX_getit (lasthit, TEX_toktab[i].len);
-             break;    /* We only save a line once */
+             break;            /* We only save a line once */
            }
        }
     }
@@ -2759,7 +2775,7 @@ prolog_getit (s, lineno, linecharno)
   *s = '\0';
   strcpy (nambuf, save_s);
   *s = tmpc;
-  pfnote (nambuf, TRUE, save_s, strlen (nambuf), lineno, linecharno);
+  pfnote (nambuf, TRUE, FALSE, save_s, strlen (nambuf), lineno, linecharno);
 }
 
 /* It is assumed that prolog predicate starts from column 0. */
@@ -2857,7 +2873,7 @@ readline (linebuffer, stream)
   register char *pend;
   int newline;                 /* 1 if ended with newline, 0 if ended with EOF */
 
-  pend = p + linebuffer->size; /* Separate to avoind 386/IX compiler bug.  */
+  pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug.  */
 
   while (1)
     {