]> code.delx.au - gnu-emacs/blobdiff - lib-src/etags.c
Merge from gnus--devo--0
[gnu-emacs] / lib-src / etags.c
index 50f7162ded0f3cb69a9e6f57bf04e499ed644cf5..280399868d18fa584db0585084f9abdf85ebc4b1 100644 (file)
@@ -1,30 +1,70 @@
 /* Tags file maker to go with GNU Emacs           -*- coding: latin-1 -*-
-   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.
+Copyright (C) 1984 The Regents of the University of California
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the
+   distribution.
+3. Neither the name of the University nor the names of its
+   contributors may be used to endorse or promote products derived
+   from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Copyright (C) 1984, 1987, 1988, 1989, 1993, 1994, 1995, 1998, 1999,
+  2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+  Free Software Foundation, Inc.
+
+This file is not considered part of GNU Emacs.
+
+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 3, or (at your option)
+any later version.
+
+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 this program; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+
+/* NB To comply with the above BSD license, copyright information is
+reproduced in etc/ETAGS.README.  That file should be updated when the
+above notices are.
+
+To the best of our knowledge, this code was originally based on the
+ctags.c distributed with BSD4.2, which was copyrighted by the
+University of California, as described above. */
 
- 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 2 of the License, or
- (at your option) any later version.
-
- 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 this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
 
 /*
  * Authors:
- *     Ctags originally by Ken Arnold.
- *     Fortran added by Jim Kleckner.
- *     Ed Pelegri-Llopart added C typedefs.
- *     Gnu Emacs TAGS format and modifications by RMS?
+ * 1983        Ctags originally by Ken Arnold.
+ * 1984        Fortran added by Jim Kleckner.
+ * 1984        Ed Pelegri-Llopart added C typedefs.
+ * 1985        Emacs TAGS format by Richard Stallman.
  * 1989        Sam Kendall added C++.
  * 1992 Joseph B. Wells improved C and C++ parsing.
  * 1993        Francesco Potortì reorganised C and C++.
@@ -41,7 +81,7 @@
  * configuration file containing regexp definitions for etags.
  */
 
-char pot_etags_version[] = "@(#) pot revision number is 17.20";
+char pot_etags_version[] = "@(#) pot revision number is 17.38";
 
 #define        TRUE    1
 #define        FALSE   0
@@ -120,7 +160,20 @@ char pot_etags_version[] = "@(#) pot revision number is 17.20";
 #  include <stdlib.h>
 #  include <string.h>
 # else /* no standard C headers */
-    extern char *getenv ();
+   extern char *getenv __P((const char *));
+   extern char *strcpy __P((char *, const char *));
+   extern char *strncpy __P((char *, const char *, unsigned long));
+   extern char *strcat __P((char *, const char *));
+   extern char *strncat __P((char *, const char *, unsigned long));
+   extern int strcmp __P((const char *, const char *));
+   extern int strncmp __P((const char *, const char *, unsigned long));
+   extern int system __P((const char *));
+   extern unsigned long strlen __P((const char *));
+   extern void *malloc __P((unsigned long));
+   extern void *realloc __P((void *, unsigned long));
+   extern void exit __P((int));
+   extern void free __P((void *));
+   extern void *memmove __P((void *, const void *, unsigned long));
 #  ifdef VMS
 #   define EXIT_SUCCESS        1
 #   define EXIT_FAILURE        0
@@ -444,7 +497,7 @@ static char
   *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
 
 static bool append_to_tagfile; /* -a: append to tags */
-/* The next four default to TRUE for etags, but to FALSE for ctags.  */
+/* The next five default to TRUE in C and derived languages.  */
 static bool typedefs;          /* -t: create tags for C and Ada typedefs */
 static bool typedefs_or_cplusplus; /* -T: create tags for C typedefs, level */
                                /* 0 struct/enum/union decls, and C++ */
@@ -453,12 +506,13 @@ static bool constantypedefs;      /* -d: create tags for C #define, enum */
                                /* constants and variables. */
                                /* -D: opposite of -d.  Default under ctags. */
 static bool globals;           /* create tags for global variables */
-static bool declarations;      /* --declarations: tag them and extern in C&Co*/
 static bool members;           /* create tags for C member variables */
+static bool declarations;      /* --declarations: tag them and extern in C&Co*/
 static bool no_line_directive; /* ignore #line directives (undocumented) */
+static bool no_duplicates;     /* no duplicate tags for ctags (undocumented) */
 static bool update;            /* -u: update tags */
 static bool vgrind_style;      /* -v: create vgrind style index output */
-static bool no_warnings;       /* -w: suppress warnings */
+static bool no_warnings;       /* -w: suppress warnings (undocumented) */
 static bool cxref_style;       /* -x: create cxref style output */
 static bool cplusplus;         /* .[hc] means C++, not C */
 static bool ignoreindent;      /* -I: ignore indentation in C */
@@ -477,39 +531,40 @@ static bool need_filebuf; /* some regexes are multi-line */
 
 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  },
-  { "no-line-directive",  no_argument,      &no_line_directive, TRUE  },
-  { "help",              no_argument,       NULL,               'h'   },
-  { "help",              no_argument,       NULL,               'H'   },
-  { "ignore-indentation", no_argument,      NULL,               'I'   },
-  { "language",           required_argument, NULL,                      'l'   },
-  { "members",           no_argument,       &members,           TRUE  },
-  { "no-members",        no_argument,       &members,           FALSE },
-  { "output",            required_argument, NULL,               'o'   },
-  { "regex",             required_argument, NULL,               'r'   },
-  { "no-regex",                  no_argument,       NULL,               'R'   },
-  { "ignore-case-regex",  required_argument, NULL,              'c'   },
+  { "append",             no_argument,       NULL,               'a'   },
+  { "packages-only",      no_argument,       &packages_only,     TRUE  },
+  { "c++",                no_argument,       NULL,               'C'   },
+  { "declarations",       no_argument,       &declarations,      TRUE  },
+  { "no-line-directive",  no_argument,       &no_line_directive, TRUE  },
+  { "no-duplicates",      no_argument,       &no_duplicates,     TRUE  },
+  { "help",               no_argument,       NULL,               'h'   },
+  { "help",               no_argument,       NULL,               'H'   },
+  { "ignore-indentation", no_argument,       NULL,               'I'   },
+  { "language",           required_argument, NULL,               'l'   },
+  { "members",            no_argument,       &members,           TRUE  },
+  { "no-members",         no_argument,       &members,           FALSE },
+  { "output",             required_argument, NULL,               'o'   },
+  { "regex",              required_argument, NULL,               'r'   },
+  { "no-regex",           no_argument,       NULL,               'R'   },
+  { "ignore-case-regex",  required_argument, NULL,               'c'   },
   { "parse-stdin",        required_argument, NULL,               STDIN },
-  { "version",           no_argument,       NULL,               'V'   },
+  { "version",            no_argument,       NULL,               'V'   },
 
 #if CTAGS /* Ctags options */
-  { "backward-search",   no_argument,       NULL,               'B'   },
-  { "cxref",             no_argument,       NULL,               'x'   },
-  { "defines",           no_argument,       NULL,               'd'   },
-  { "globals",           no_argument,       &globals,           TRUE  },
-  { "typedefs",                  no_argument,       NULL,               't'   },
-  { "typedefs-and-c++",          no_argument,       NULL,               'T'   },
-  { "update",            no_argument,       NULL,               'u'   },
-  { "vgrind",            no_argument,       NULL,               'v'   },
-  { "no-warn",           no_argument,       NULL,               'w'   },
+  { "backward-search",    no_argument,       NULL,               'B'   },
+  { "cxref",              no_argument,       NULL,               'x'   },
+  { "defines",            no_argument,       NULL,               'd'   },
+  { "globals",            no_argument,       &globals,           TRUE  },
+  { "typedefs",           no_argument,       NULL,               't'   },
+  { "typedefs-and-c++",   no_argument,       NULL,               'T'   },
+  { "update",             no_argument,       NULL,               'u'   },
+  { "vgrind",             no_argument,       NULL,               'v'   },
+  { "no-warn",            no_argument,       NULL,               'w'   },
 
 #else /* Etags options */
-  { "no-defines",        no_argument,       NULL,               'D'   },
-  { "no-globals",        no_argument,       &globals,           FALSE },
-  { "include",           required_argument, NULL,               'i'   },
+  { "no-defines",         no_argument,       NULL,               'D'   },
+  { "no-globals",         no_argument,       &globals,           FALSE },
+  { "include",            required_argument, NULL,               'i'   },
 #endif
   { NULL }
 };
@@ -575,10 +630,11 @@ static char default_C_help [] =
 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\
+`--no-globals' and so are struct members unless you specify\n\
+`--no-members'.  Use of `--no-globals', `--no-defines' and\n\
+`--no-members' 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'.";
+using `--declarations'.";
 
 static char *Cplusplus_suffixes [] =
   { "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",
@@ -588,8 +644,8 @@ static char *Cplusplus_suffixes [] =
 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\
+In addition to C tags, member functions are also recognized.  Member\n\
+variables are recognized unless you use the `--no-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+'.";
@@ -684,8 +740,8 @@ 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.";
+"In PHP code, tags are functions, classes and defines.  Unless you use\n\
+the `--no-members' option, vars are tags too.";
 
 static char *plain_C_suffixes [] =
   { "pc",                      /* Pro*C file */
@@ -833,18 +889,25 @@ etags --help --lang=ada.");
 # define EMACS_NAME "standalone"
 #endif
 #ifndef VERSION
-# define VERSION "version"
+# define VERSION "17.38"
 #endif
 static void
 print_version ()
 {
+  /* Makes it easier to update automatically. */
+  char emacs_copyright[] = "Copyright (C) 2007 Free Software Foundation, Inc.";
+
   printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);
-  puts ("Copyright (C) 2006 Free Software Foundation, Inc. and Ken Arnold");
-  puts ("This program is distributed under the same terms as Emacs");
+  puts (emacs_copyright);
+  puts ("This program is distributed under the terms in ETAGS.README");
 
   exit (EXIT_SUCCESS);
 }
 
+#ifndef PRINT_UNDOCUMENTED_OPTIONS_HELP
+# define PRINT_UNDOCUMENTED_OPTIONS_HELP FALSE
+#endif
+
 static void
 print_help (argbuffer)
      argument *argbuffer;
@@ -927,8 +990,18 @@ Relative ones are stored relative to the output file's directory.\n");
     puts ("--no-globals\n\
        Do not create tag entries for global variables in some\n\
        languages.  This makes the tags file smaller.");
-  puts ("--members\n\
+
+  if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
+    puts ("--no-line-directive\n\
+        Ignore #line preprocessor directives in C and derived languages.");
+
+  if (CTAGS)
+    puts ("--members\n\
        Create tag entries for members of structures in some languages.");
+  else
+    puts ("--no-members\n\
+       Do not create tag entries for members of structures\n\
+       in some languages.");
 
   puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\
         Make a tag for each line matching a regular expression pattern\n\
@@ -942,13 +1015,17 @@ Relative ones are stored relative to the output file's directory.\n");
        MODS are optional one-letter modifiers: `i' means to ignore case,\n\
        `m' means to allow multi-line matches, `s' implies `m' and\n\
        causes dot to match any character, including newline.");
+
   puts ("-R, --no-regex\n\
         Don't create tags from regexps for the following files.");
+
   puts ("-I, --ignore-indentation\n\
         In C and C++ do not assume that a closing brace in the first\n\
         column is the final brace of a function or structure definition.");
+
   puts ("-o FILE, --output=FILE\n\
         Write the tags to FILE.");
+
   puts ("--parse-stdin=NAME\n\
         Read from standard input and record tags as belonging to file NAME.");
 
@@ -976,9 +1053,16 @@ Relative ones are stored relative to the output file's directory.\n");
         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.");
+
+      if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
+       puts ("-w, --no-duplicates\n\
+        Do not create duplicate tag entries, for compatibility with\n\
+       traditional ctags.");
+
+      if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
+       puts ("-w, --no-warn\n\
+        Suppress warning messages about duplicate tag entries.");
+
       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\
@@ -1161,15 +1245,12 @@ main (argc, argv)
   argbuffer = xnew (argc, argument);
 
   /*
-   * If etags, always find typedefs and structure tags.  Why not?
-   * Also default to find macro constants, enum constants and
-   * global variables.
+   * Always find typedefs and structure tags.
+   * Also default to find macro constants, enum constants, struct
+   * members and global variables.  Do it for both etags and ctags.
    */
-  if (!CTAGS)
-    {
-      typedefs = typedefs_or_cplusplus = constantypedefs = TRUE;
-      globals = TRUE;
-    }
+  typedefs = typedefs_or_cplusplus = constantypedefs = TRUE;
+  globals = members = 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. */
@@ -1420,6 +1501,7 @@ main (argc, argv)
       exit (EXIT_SUCCESS);
     }
 
+  /* From here on, we are in (CTAGS && !cxref_style) */
   if (update)
     {
       char cmd[BUFSIZ];
@@ -1454,8 +1536,11 @@ main (argc, argv)
   if (CTAGS)
     if (append_to_tagfile || update)
       {
-       char cmd[2*BUFSIZ+10];
-       sprintf (cmd, "sort -o %.*s %.*s", BUFSIZ, tagfile, BUFSIZ, tagfile);
+       char cmd[2*BUFSIZ+20];
+       /* Maybe these should be used:
+          setenv ("LC_COLLATE", "C", 1);
+          setenv ("LC_ALL", "C", 1); */
+       sprintf (cmd, "sort -u -o %.*s %.*s", BUFSIZ, tagfile, BUFSIZ, tagfile);
        exit (system (cmd));
       }
   return EXIT_SUCCESS;
@@ -2168,7 +2253,7 @@ add_node (np, cur_node_p)
        * If this tag name matches an existing one, then
        * do not add the node, but maybe print a warning.
        */
-      if (!dif)
+      if (no_duplicates && !dif)
        {
          if (np->fdp == cur_node->fdp)
            {
@@ -2409,12 +2494,12 @@ __attribute__,  0,                      st_C_attribute
 @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
+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
+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
@@ -2525,19 +2610,19 @@ in_word_set (str, len)
       {"@end",         0,                      st_C_objend},
       {"union",                0,                      st_C_struct},
       {"define",               0,                      st_C_define},
-      {"import",               (C_JAVA & !C_PLPL),     st_C_ignore},
+      {"import",               (C_JAVA & ~C_PLPL),     st_C_ignore},
       {"template",     0,                      st_C_template},
       {"operator",     C_PLPL,                 st_C_operator},
       {"@interface",   0,                      st_C_objprot},
-      {"implements",   (C_JAVA & !C_PLPL),     st_C_javastruct},
+      {"implements",   (C_JAVA & ~C_PLPL),     st_C_javastruct},
       {"friend",               C_PLPL,                 st_C_ignore},
       {"typedef",      0,                      st_C_typedef},
       {"return",               0,                      st_C_ignore},
       {"@implementation",0,                    st_C_objimpl},
       {"@protocol",    0,                      st_C_objprot},
-      {"interface",    (C_JAVA & !C_PLPL),     st_C_struct},
+      {"interface",    (C_JAVA & ~C_PLPL),     st_C_struct},
       {"extern",               0,                      st_C_extern},
-      {"extends",      (C_JAVA & !C_PLPL),     st_C_javastruct},
+      {"extends",      (C_JAVA & ~C_PLPL),     st_C_javastruct},
       {"struct",               0,                      st_C_struct},
       {"domain",               C_STAR,                 st_C_struct},
       {"switch",               0,                      st_C_ignore},
@@ -2547,7 +2632,7 @@ in_word_set (str, len)
       {"class",                0,                      st_C_class},
       {"while",                0,                      st_C_ignore},
       {"undef",                0,                      st_C_define},
-      {"package",      (C_JAVA & !C_PLPL),     st_C_ignore},
+      {"package",      (C_JAVA & ~C_PLPL),     st_C_ignore},
       {"__attribute__",        0,                      st_C_attribute},
       {"SYSCALL",      0,                      st_C_gnumacro},
       {"ENTRY",                0,                      st_C_gnumacro},
@@ -2802,7 +2887,7 @@ static void make_C_tag __P((bool));
  *     function or variable, or corresponds to a typedef, or
  *     is a struct/union/enum tag, or #define, or an enum constant.
  *
- *     *IS_FUNC gets TRUE iff the token is a function or #define macro
+ *     *IS_FUNC gets TRUE if the token is a function or #define macro
  *     with args.  C_EXTP points to which language we are looking at.
  *
  * Globals
@@ -2925,11 +3010,6 @@ consider_token (str, len, c, c_extp, bracelev, parlev, is_func_or_var)
        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:
@@ -3163,18 +3243,18 @@ static void
 make_C_tag (isfun)
      bool isfun;
 {
-  /* This function should never be called when token.valid is FALSE, but
+  /* This function is never called when token.valid is FALSE, but
      we must protect against invalid input or internal errors. */
-  if (!DEBUG && !token.valid)
-    return;
-
   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);
+  else if (DEBUG)
+    {                            /* this branch 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);
+      error ("INVALID TOKEN", NULL);
+    }
 
   token.valid = FALSE;
 }
@@ -3347,17 +3427,15 @@ C_entries (c_ext, inf)
        case '/':
          if (*lp == '*')
            {
-             lp++;
              incomm = TRUE;
-             continue;
+             lp++;
+             c = ' ';
            }
          else if (/* cplpl && */ *lp == '/')
            {
              c = '\0';
-             break;
            }
-         else
-           break;
+         break;
        case '%':
          if ((c_ext & YACC) && *lp == '%')
            {
@@ -3493,7 +3571,6 @@ C_entries (c_ext, inf)
                                  off += 1;
                                  len -= 1;
                                }
-                             len = toklen;
                              linebuffer_setlen (&token_name, len);
                              strncpy (token_name.buffer,
                                       newlb.buffer + off, len);
@@ -3900,7 +3977,7 @@ C_entries (c_ext, inf)
              make_C_tag (FALSE);  /* a struct or enum */
              break;
            }
-         bracelev++;
+         bracelev += 1;
          break;
        case '*':
          if (definedef != dnone)
@@ -3914,17 +3991,21 @@ C_entries (c_ext, inf)
        case '}':
          if (definedef != dnone)
            break;
+         bracelev -= 1;
          if (!ignoreindent && lp == newlb.buffer + 1)
            {
              if (bracelev != 0)
-               token.valid = FALSE;
+               token.valid = FALSE; /* unexpected value, token unreliable */
              bracelev = 0;     /* reset brace level if first column */
              parlev = 0;       /* also reset paren level, just in case... */
            }
-         else if (bracelev > 0)
-           bracelev--;
-         else
-           token.valid = FALSE; /* something gone amiss, token unreliable */
+         else if (bracelev < 0)
+           {
+             token.valid = FALSE; /* something gone amiss, token unreliable */
+             bracelev = 0;
+           }
+         if (bracelev == 0 && fvdef == vignore)
+           fvdef = fvnone;             /* end of function */
          popclass_above (bracelev);
          structdef = snone;
          /* Only if typdef == tinbody is typdefbracelev significant. */
@@ -4687,8 +4768,16 @@ Makefile_targets (inf)
       while (*bp != '\0' && *bp != '=' && *bp != ':')
        bp++;
       if (*bp == ':' || (globals && *bp == '='))
-       make_tag (lb.buffer, bp - lb.buffer, TRUE,
-                 lb.buffer, bp - lb.buffer + 1, lineno, linecharno);
+       {
+         /* We should detect if there is more than one tag, but we do not.
+            We just skip initial and final spaces. */
+         char * namestart = skip_spaces (lb.buffer);
+         while (--bp > namestart)
+           if (!notinname (*bp))
+             break;
+         make_tag (namestart, bp - namestart + 1, TRUE,
+                   lb.buffer, bp - lb.buffer + 2, lineno, linecharno);
+       }
     }
 }
 
@@ -4711,7 +4800,7 @@ Pascal_functions (inf)
   int save_lineno, namelen, taglen;
   char c, *name;
 
-  bool                         /* each of these flags is TRUE iff: */
+  bool                         /* each of these flags is TRUE if: */
     incomment,                 /* point is inside a comment */
     inquote,                   /* point is inside '..' string */
     get_tagname,               /* point is after PROCEDURE/FUNCTION
@@ -4955,7 +5044,7 @@ Lua_functions (inf)
       if (bp[0] != 'f' && bp[0] != 'l')
        continue;
 
-      LOOKING_AT (bp, "local");        /* skip possible "local" */
+      (void)LOOKING_AT (bp, "local"); /* skip possible "local" */
 
       if (LOOKING_AT (bp, "function"))
        get_tag (bp, NULL);
@@ -5137,7 +5226,7 @@ TeX_commands (inf)
                if (!opgrp || *p == TEX_clgrp)
                  {
                    while (*p != '\0' && *p != TEX_opgrp && *p != TEX_clgrp)
-                     *p++;
+                     p++;
                    linelen = p - lb.buffer + 1;
                  }
                make_tag (cp, namelen, TRUE,
@@ -6256,14 +6345,14 @@ readline (lbp, stream)
       /* Check whether this is a #line directive. */
       if (result > 12 && strneq (lbp->buffer, "#line ", 6))
        {
-         int start, lno;
+         unsigned int lno;
+         int start = 0;
 
-         if (DEBUG) start = 0; /* shut up the compiler */
-         if (sscanf (lbp->buffer, "#line %d \"%n", &lno, &start) == 2)
+         if (sscanf (lbp->buffer, "#line %u \"%n", &lno, &start) >= 1
+             && start > 0)     /* double quote character found */
            {
              char *endp = lbp->buffer + start;
 
-             assert (start > 0);
              while ((endp = etags_strchr (endp, '"')) != NULL
                     && endp[-1] == '\\')
                endp++;
@@ -6278,7 +6367,7 @@ readline (lbp, stream)
                  name = lbp->buffer + start;
                  *endp = '\0';
                  canonicalize_filename (name); /* for DOS */
-                 taggedabsname = absolute_filename (name, curfdp->infabsdir);
+                 taggedabsname = absolute_filename (name, tagfiledir);
                  if (filename_is_absolute (name)
                      || filename_is_absolute (curfdp->infname))
                    taggedfname = savestr (taggedabsname);
@@ -6878,6 +6967,7 @@ xrealloc (ptr, size)
  * tab-width: 8
  * fill-column: 79
  * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node" "regexp")
+ * c-file-style: "gnu"
  * End:
  */