root/test/manual/etags/c-src/etags.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_language_names
  2. print_version
  3. print_help
  4. main
  5. get_compressor_from_suffix
  6. get_language_from_langname
  7. get_language_from_interpreter
  8. get_language_from_filename
  9. process_file_name
  10. process_file
  11. init
  12. find_entries
  13. make_tag
  14. pfnote
  15. free_tree
  16. free_fdesc
  17. add_node
  18. invalidate_nodes
  19. number_len
  20. total_size_of_entries
  21. put_entries
  22. hash
  23. in_word_set
  24. C_symtype
  25. pushclass_above
  26. popclass_above
  27. write_classname
  28. consider_token
  29. make_C_tag
  30. C_entries
  31. default_C_entries
  32. plain_C_entries
  33. Cplusplus_entries
  34. Cjava_entries
  35. Cstar_entries
  36. Yacc_entries
  37. just_read_file
  38. F_takeprec
  39. F_getit
  40. Fortran_functions
  41. Ada_getit
  42. Ada_funcs
  43. Asm_labels
  44. Perl_functions
  45. Python_functions
  46. PHP_functions
  47. Cobol_paragraphs
  48. Makefile_targets
  49. Pascal_functions
  50. L_getit
  51. Lisp_functions
  52. Lua_functions
  53. PS_functions
  54. Forth_words
  55. Scheme_functions
  56. TeX_commands
  57. TEX_mode
  58. TEX_decode_env
  59. Texinfo_nodes
  60. HTML_labels
  61. Prolog_functions
  62. prolog_skip_comment
  63. prolog_pr
  64. prolog_atom
  65. Erlang_functions
  66. erlang_func
  67. erlang_attribute
  68. erlang_atom
  69. scan_separators
  70. analyze_regex
  71. add_regex
  72. substitute
  73. free_regexps
  74. regex_tag_multiline
  75. nocase_tail
  76. get_tag
  77. readline_internal
  78. readline
  79. savestr
  80. savenstr
  81. skip_spaces
  82. skip_non_spaces
  83. skip_name
  84. fatal
  85. pfatal
  86. suggest_asking_for_help
  87. error
  88. concat
  89. etags_getcwd
  90. relative_filename
  91. absolute_filename
  92. absolute_dirname
  93. filename_is_absolute
  94. canonicalize_filename
  95. linebuffer_init
  96. linebuffer_setlen
  97. xmalloc
  98. xrealloc

     1 /* Tags file maker to go with GNU Emacs           -*- coding: utf-8 -*-
     2 
     3 Copyright (C) 1984 The Regents of the University of California
     4 
     5 Redistribution and use in source and binary forms, with or without
     6 modification, are permitted provided that the following conditions are
     7 met:
     8 1. Redistributions of source code must retain the above copyright
     9    notice, this list of conditions and the following disclaimer.
    10 2. Redistributions in binary form must reproduce the above copyright
    11    notice, this list of conditions and the following disclaimer in the
    12    documentation and/or other materials provided with the
    13    distribution.
    14 3. Neither the name of the University nor the names of its
    15    contributors may be used to endorse or promote products derived
    16    from this software without specific prior written permission.
    17 
    18 THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
    19 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    20 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    21 PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
    22 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    23 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    24 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    25 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    26 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
    27 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
    28 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    29 
    30 
    31 Copyright (C) 1984, 1987-1989, 1993-1995, 1998-2023 Free Software
    32 Foundation, Inc.
    33 
    34 This file is not considered part of GNU Emacs.
    35 
    36 This program is free software: you can redistribute it and/or modify
    37 it under the terms of the GNU General Public License as published by
    38 the Free Software Foundation, either version 3 of the License, or (at
    39 your option) any later version.
    40 
    41 This program is distributed in the hope that it will be useful,
    42 but WITHOUT ANY WARRANTY; without even the implied warranty of
    43 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    44 GNU General Public License for more details.
    45 
    46 You should have received a copy of the GNU General Public License
    47 along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
    48 
    49 
    50 /* NB To comply with the above BSD license, copyright information is
    51 reproduced in etc/ETAGS.README.  That file should be updated when the
    52 above notices are.
    53 
    54 To the best of our knowledge, this code was originally based on the
    55 ctags.c distributed with BSD4.2, which was copyrighted by the
    56 University of California, as described above. */
    57 
    58 
    59 /*
    60  * Authors:
    61  * 1983 Ctags originally by Ken Arnold.
    62  * 1984 Fortran added by Jim Kleckner.
    63  * 1984 Ed Pelegri-Llopart added C typedefs.
    64  * 1985 Emacs TAGS format by Richard Stallman.
    65  * 1989 Sam Kendall added C++.
    66  * 1992 Joseph B. Wells improved C and C++ parsing.
    67  * 1993 Francesco Potortì reorganized C and C++.
    68  * 1994 Line-by-line regexp tags by Tom Tromey.
    69  * 2001 Nested classes by Francesco Potortì (concept by Mykola Dzyuba).
    70  * 2002 #line directives by Francesco Potortì.
    71  *
    72  * Francesco Potortì <pot@gnu.org> has maintained and improved it since 1993.
    73  */
    74 
    75 /*
    76  * If you want to add support for a new language, start by looking at the LUA
    77  * language, which is the simplest.  Alternatively, consider distributing etags
    78  * together with a configuration file containing regexp definitions for etags.
    79  */
    80 
    81 char pot_etags_version[] = "@(#) pot revision number is 17.38.1.4";
    82 
    83 #ifdef DEBUG
    84 #  undef DEBUG
    85 #  define DEBUG true
    86 #else
    87 #  define DEBUG  false
    88 #  define NDEBUG                /* disable assert */
    89 #endif
    90 
    91 #include <config.h>
    92 
    93 #ifndef _GNU_SOURCE
    94 # define _GNU_SOURCE 1          /* enables some compiler checks on GNU */
    95 #endif
    96 
    97 /* WIN32_NATIVE is for XEmacs.
    98    MSDOS, WINDOWSNT, DOS_NT are for Emacs. */
    99 #ifdef WIN32_NATIVE
   100 # undef MSDOS
   101 # undef  WINDOWSNT
   102 # define WINDOWSNT
   103 #endif /* WIN32_NATIVE */
   104 
   105 #ifdef MSDOS
   106 # undef MSDOS
   107 # define MSDOS true
   108 # include <sys/param.h>
   109 #else
   110 # define MSDOS false
   111 #endif /* MSDOS */
   112 
   113 #ifdef WINDOWSNT
   114 # include <direct.h>
   115 # define MAXPATHLEN _MAX_PATH
   116 # undef HAVE_NTGUI
   117 # undef  DOS_NT
   118 # define DOS_NT
   119 #endif /* WINDOWSNT */
   120 
   121 #include <unistd.h>
   122 #include <stdarg.h>
   123 #include <stdlib.h>
   124 #include <string.h>
   125 #include <sysstdio.h>
   126 #include <ctype.h>
   127 #include <errno.h>
   128 #include <sys/types.h>
   129 #include <sys/stat.h>
   130 #include <binary-io.h>
   131 #include <c-strcase.h>
   132 
   133 #include <assert.h>
   134 #ifdef NDEBUG
   135 # undef  assert                 /* some systems have a buggy assert.h */
   136 # define assert(x) ((void) 0)
   137 #endif
   138 
   139 #include <getopt.h>
   140 #include <regex.h>
   141 
   142 /* Define CTAGS to make the program "ctags" compatible with the usual one.
   143  Leave it undefined to make the program "etags", which makes emacs-style
   144  tag tables and tags typedefs, #defines and struct/union/enum by default. */
   145 #ifdef CTAGS
   146 # undef  CTAGS
   147 # define CTAGS true
   148 #else
   149 # define CTAGS false
   150 #endif
   151 
   152 #define streq(s,t)      (assert ((s)!=NULL || (t)!=NULL), !strcmp (s, t))
   153 #define strcaseeq(s,t)  (assert ((s)!=NULL && (t)!=NULL), !c_strcasecmp (s, t))
   154 #define strneq(s,t,n)   (assert ((s)!=NULL || (t)!=NULL), !strncmp (s, t, n))
   155 #define strncaseeq(s,t,n) (assert ((s)!=NULL && (t)!=NULL), !c_strncasecmp (s, t, n))
   156 
   157 #define CHARS 256               /* 2^sizeof(char) */
   158 #define CHAR(x)         ((unsigned int)(x) & (CHARS - 1))
   159 #define iswhite(c)      (_wht[CHAR (c)]) /* c is white (see white) */
   160 #define notinname(c)    (_nin[CHAR (c)]) /* c is not in a name (see nonam) */
   161 #define begtoken(c)     (_btk[CHAR (c)]) /* c can start token (see begtk) */
   162 #define intoken(c)      (_itk[CHAR (c)]) /* c can be in token (see midtk) */
   163 #define endtoken(c)     (_etk[CHAR (c)]) /* c ends tokens (see endtk) */
   164 
   165 #define ISALNUM(c)      isalnum (CHAR (c))
   166 #define ISALPHA(c)      isalpha (CHAR (c))
   167 #define ISDIGIT(c)      isdigit (CHAR (c))
   168 #define ISLOWER(c)      islower (CHAR (c))
   169 
   170 #define lowcase(c)      tolower (CHAR (c))
   171 
   172 
   173 /*
   174  *      xnew, xrnew -- allocate, reallocate storage
   175  *
   176  * SYNOPSIS:    Type *xnew (int n, Type);
   177  *              void xrnew (OldPointer, int n, Type);
   178  */
   179 #define xnew(n, Type)      ((Type *) xmalloc ((n) * sizeof (Type)))
   180 #define xrnew(op, n, Type) ((op) = (Type *) xrealloc (op, (n) * sizeof (Type)))
   181 
   182 typedef void Lang_function (FILE *);
   183 
   184 typedef struct
   185 {
   186   const char *suffix;           /* file name suffix for this compressor */
   187   const char *command;          /* takes one arg and decompresses to stdout */
   188 } compressor;
   189 
   190 typedef struct
   191 {
   192   const char *name;             /* language name */
   193   const char *help;             /* detailed help for the language */
   194   Lang_function *function;      /* parse function */
   195   const char **suffixes;        /* name suffixes of this language's files */
   196   const char **filenames;       /* names of this language's files */
   197   const char **interpreters;    /* interpreters for this language */
   198   bool metasource;              /* source used to generate other sources */
   199 } language;
   200 
   201 typedef struct fdesc
   202 {
   203   struct fdesc *next;           /* for the linked list */
   204   char *infname;                /* uncompressed input file name */
   205   char *infabsname;             /* absolute uncompressed input file name */
   206   char *infabsdir;              /* absolute dir of input file */
   207   char *taggedfname;            /* file name to write in tagfile */
   208   language *lang;               /* language of file */
   209   char *prop;                   /* file properties to write in tagfile */
   210   bool usecharno;               /* etags tags shall contain char number */
   211   bool written;                 /* entry written in the tags file */
   212 } fdesc;
   213 
   214 typedef struct node_st
   215 {                               /* sorting structure */
   216   struct node_st *left, *right; /* left and right sons */
   217   fdesc *fdp;                   /* description of file to whom tag belongs */
   218   char *name;                   /* tag name */
   219   char *regex;                  /* search regexp */
   220   bool valid;                   /* write this tag on the tag file */
   221   bool is_func;                 /* function tag: use regexp in CTAGS mode */
   222   bool been_warned;             /* warning already given for duplicated tag */
   223   int lno;                      /* line number tag is on */
   224   long cno;                     /* character number line starts on */
   225 } node;
   226 
   227 /*
   228  * A `linebuffer' is a structure which holds a line of text.
   229  * `readline_internal' reads a line from a stream into a linebuffer
   230  * and works regardless of the length of the line.
   231  * SIZE is the size of BUFFER, LEN is the length of the string in
   232  * BUFFER after readline reads it.
   233  */
   234 typedef struct
   235 {
   236   long size;
   237   int len;
   238   char *buffer;
   239 } linebuffer;
   240 
   241 /* Used to support mixing of --lang and file names. */
   242 typedef struct
   243 {
   244   enum {
   245     at_language,                /* a language specification */
   246     at_regexp,                  /* a regular expression */
   247     at_filename,                /* a file name */
   248     at_stdin,                   /* read from stdin here */
   249     at_end                      /* stop parsing the list */
   250   } arg_type;                   /* argument type */
   251   language *lang;               /* language associated with the argument */
   252   char *what;                   /* the argument itself */
   253 } argument;
   254 
   255 /* Structure defining a regular expression. */
   256 typedef struct regexp
   257 {
   258   struct regexp *p_next;        /* pointer to next in list */
   259   language *lang;               /* if set, use only for this language */
   260   char *pattern;                /* the regexp pattern */
   261   char *name;                   /* tag name */
   262   struct re_pattern_buffer *pat; /* the compiled pattern */
   263   struct re_registers regs;     /* re registers */
   264   bool error_signaled;          /* already signaled for this regexp */
   265   bool force_explicit_name;     /* do not allow implicit tag name */
   266   bool ignore_case;             /* ignore case when matching */
   267   bool multi_line;              /* do a multi-line match on the whole file */
   268 } regexp;
   269 
   270 
   271 /* Many compilers barf on this:
   272         Lang_function Ada_funcs;
   273    so let's write it this way */
   274 static void Ada_funcs (FILE *);
   275 static void Asm_labels (FILE *);
   276 static void C_entries (int c_ext, FILE *);
   277 static void default_C_entries (FILE *);
   278 static void plain_C_entries (FILE *);
   279 static void Cjava_entries (FILE *);
   280 static void Cobol_paragraphs (FILE *);
   281 static void Cplusplus_entries (FILE *);
   282 static void Cstar_entries (FILE *);
   283 static void Erlang_functions (FILE *);
   284 static void Forth_words (FILE *);
   285 static void Fortran_functions (FILE *);
   286 static void HTML_labels (FILE *);
   287 static void Lisp_functions (FILE *);
   288 static void Lua_functions (FILE *);
   289 static void Makefile_targets (FILE *);
   290 static void Pascal_functions (FILE *);
   291 static void Perl_functions (FILE *);
   292 static void PHP_functions (FILE *);
   293 static void PS_functions (FILE *);
   294 static void Prolog_functions (FILE *);
   295 static void Python_functions (FILE *);
   296 static void Scheme_functions (FILE *);
   297 static void TeX_commands (FILE *);
   298 static void Texinfo_nodes (FILE *);
   299 static void Yacc_entries (FILE *);
   300 static void just_read_file (FILE *);
   301 
   302 static language *get_language_from_langname (const char *);
   303 static void readline (linebuffer *, FILE *);
   304 static long readline_internal (linebuffer *, FILE *);
   305 static bool nocase_tail (const char *);
   306 static void get_tag (char *, char **);
   307 
   308 static void analyze_regex (char *);
   309 static void free_regexps (void);
   310 static void regex_tag_multiline (void);
   311 static void error (const char *, ...) ATTRIBUTE_FORMAT_PRINTF (1, 2);
   312 static _Noreturn void suggest_asking_for_help (void);
   313 _Noreturn void fatal (const char *, const char *);
   314 static _Noreturn void pfatal (const char *);
   315 static void add_node (node *, node **);
   316 
   317 static void init (void);
   318 static void process_file_name (char *, language *);
   319 static void process_file (FILE *, char *, language *);
   320 static void find_entries (FILE *);
   321 static void free_tree (node *);
   322 static void free_fdesc (fdesc *);
   323 static void pfnote (char *, bool, char *, int, int, long);
   324 static void invalidate_nodes (fdesc *, node **);
   325 static void put_entries (node *);
   326 
   327 static char *concat (const char *, const char *, const char *);
   328 static char *skip_spaces (char *);
   329 static char *skip_non_spaces (char *);
   330 static char *skip_name (char *);
   331 static char *savenstr (const char *, int);
   332 static char *savestr (const char *);
   333 static char *etags_getcwd (void);
   334 static char *relative_filename (char *, char *);
   335 static char *absolute_filename (char *, char *);
   336 static char *absolute_dirname (char *, char *);
   337 static bool filename_is_absolute (char *f);
   338 static void canonicalize_filename (char *);
   339 static void linebuffer_init (linebuffer *);
   340 static void linebuffer_setlen (linebuffer *, int);
   341 static void *xmalloc (size_t);
   342 static void *xrealloc (void *, size_t);
   343 
   344 
   345 static char searchar = '/';     /* use /.../ searches */
   346 
   347 static char *tagfile;           /* output file */
   348 static char *progname;          /* name this program was invoked with */
   349 static char *cwd;               /* current working directory */
   350 static char *tagfiledir;        /* directory of tagfile */
   351 static FILE *tagf;              /* ioptr for tags file */
   352 static ptrdiff_t whatlen_max;   /* maximum length of any 'what' member */
   353 
   354 static fdesc *fdhead;           /* head of file description list */
   355 static fdesc *curfdp;           /* current file description */
   356 static int lineno;              /* line number of current line */
   357 static long charno;             /* current character number */
   358 static long linecharno;         /* charno of start of current line */
   359 static char *dbp;               /* pointer to start of current tag */
   360 
   361 static const int invalidcharno = -1;
   362 
   363 static node *nodehead;          /* the head of the binary tree of tags */
   364 static node *last_node;         /* the last node created */
   365 
   366 static linebuffer lb;           /* the current line */
   367 static linebuffer filebuf;      /* a buffer containing the whole file */
   368 static linebuffer token_name;   /* a buffer containing a tag name */
   369 
   370 /* boolean "functions" (see init)       */
   371 static bool _wht[CHARS], _nin[CHARS], _itk[CHARS], _btk[CHARS], _etk[CHARS];
   372 static const char
   373   /* white chars */
   374   *white = " \f\t\n\r\v",
   375   /* not in a name */
   376   *nonam = " \f\t\n\r()=,;",    /* look at make_tag before modifying! */
   377   /* token ending chars */
   378   *endtk = " \t\n\r\"'#()[]{}=-+%*/&|^~!<>;,.:?",
   379   /* token starting chars */
   380   *begtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$~@",
   381   /* valid in-token chars */
   382   *midtk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz$0123456789";
   383 
   384 static bool append_to_tagfile;  /* -a: append to tags */
   385 /* The next five default to true in C and derived languages.  */
   386 static bool typedefs;           /* -t: create tags for C and Ada typedefs */
   387 static bool typedefs_or_cplusplus; /* -T: create tags for C typedefs, level */
   388                                 /* 0 struct/enum/union decls, and C++ */
   389                                 /* member functions. */
   390 static bool constantypedefs;    /* -d: create tags for C #define, enum */
   391                                 /* constants and variables. */
   392                                 /* -D: opposite of -d.  Default under ctags. */
   393 static int globals;             /* create tags for global variables */
   394 static int members;             /* create tags for C member variables */
   395 static int declarations;        /* --declarations: tag them and extern in C&Co*/
   396 static int no_line_directive;   /* ignore #line directives (undocumented) */
   397 static int no_duplicates;       /* no duplicate tags for ctags (undocumented) */
   398 static bool update;             /* -u: update tags */
   399 static bool vgrind_style;       /* -v: create vgrind style index output */
   400 static bool no_warnings;        /* -w: suppress warnings (undocumented) */
   401 static bool cxref_style;        /* -x: create cxref style output */
   402 static bool cplusplus;          /* .[hc] means C++, not C (undocumented) */
   403 static bool ignoreindent;       /* -I: ignore indentation in C */
   404 static int packages_only;       /* --packages-only: in Ada, only tag packages*/
   405 
   406 /* STDIN is defined in LynxOS system headers */
   407 #ifdef STDIN
   408 # undef STDIN
   409 #endif
   410 
   411 #define STDIN 0x1001            /* returned by getopt_long on --parse-stdin */
   412 static bool parsing_stdin;      /* --parse-stdin used */
   413 
   414 static regexp *p_head;          /* list of all regexps */
   415 static bool need_filebuf;       /* some regexes are multi-line */
   416 
   417 static struct option longopts[] =
   418 {
   419   { "append",             no_argument,       NULL,               'a'   },
   420   { "packages-only",      no_argument,       &packages_only,     1     },
   421   { "c++",                no_argument,       NULL,               'C'   },
   422   { "declarations",       no_argument,       &declarations,      1     },
   423   { "no-line-directive",  no_argument,       &no_line_directive, 1     },
   424   { "no-duplicates",      no_argument,       &no_duplicates,     1     },
   425   { "help",               no_argument,       NULL,               'h'   },
   426   { "help",               no_argument,       NULL,               'H'   },
   427   { "ignore-indentation", no_argument,       NULL,               'I'   },
   428   { "language",           required_argument, NULL,               'l'   },
   429   { "members",            no_argument,       &members,           1     },
   430   { "no-members",         no_argument,       &members,           0     },
   431   { "output",             required_argument, NULL,               'o'   },
   432   { "regex",              required_argument, NULL,               'r'   },
   433   { "no-regex",           no_argument,       NULL,               'R'   },
   434   { "ignore-case-regex",  required_argument, NULL,               'c'   },
   435   { "parse-stdin",        required_argument, NULL,               STDIN },
   436   { "version",            no_argument,       NULL,               'V'   },
   437 
   438 #if CTAGS /* Ctags options */
   439   { "backward-search",    no_argument,       NULL,               'B'   },
   440   { "cxref",              no_argument,       NULL,               'x'   },
   441   { "defines",            no_argument,       NULL,               'd'   },
   442   { "globals",            no_argument,       &globals,           1     },
   443   { "typedefs",           no_argument,       NULL,               't'   },
   444   { "typedefs-and-c++",   no_argument,       NULL,               'T'   },
   445   { "update",             no_argument,       NULL,               'u'   },
   446   { "vgrind",             no_argument,       NULL,               'v'   },
   447   { "no-warn",            no_argument,       NULL,               'w'   },
   448 
   449 #else /* Etags options */
   450   { "no-defines",         no_argument,       NULL,               'D'   },
   451   { "no-globals",         no_argument,       &globals,           0     },
   452   { "include",            required_argument, NULL,               'i'   },
   453 #endif
   454   { NULL }
   455 };
   456 
   457 static compressor compressors[] =
   458 {
   459   { "z", "gzip -d -c"},
   460   { "Z", "gzip -d -c"},
   461   { "gz", "gzip -d -c"},
   462   { "GZ", "gzip -d -c"},
   463   { "bz2", "bzip2 -d -c" },
   464   { "xz", "xz -d -c" },
   465   { NULL }
   466 };
   467 
   468 /*
   469  * Language stuff.
   470  */
   471 
   472 /* Ada code */
   473 static const char *Ada_suffixes [] =
   474   { "ads", "adb", "ada", NULL };
   475 static const char Ada_help [] =
   476 "In Ada code, functions, procedures, packages, tasks and types are\n\
   477 tags.  Use the `--packages-only' option to create tags for\n\
   478 packages only.\n\
   479 Ada tag names have suffixes indicating the type of entity:\n\
   480         Entity type:    Qualifier:\n\
   481         ------------    ----------\n\
   482         function        /f\n\
   483         procedure       /p\n\
   484         package spec    /s\n\
   485         package body    /b\n\
   486         type            /t\n\
   487         task            /k\n\
   488 Thus, `M-x find-tag <RET> bidule/b <RET>' will go directly to the\n\
   489 body of the package `bidule', while `M-x find-tag <RET> bidule <RET>'\n\
   490 will just search for any tag `bidule'.";
   491 
   492 /* Assembly code */
   493 static const char *Asm_suffixes [] =
   494   { "a",        /* Unix assembler */
   495     "asm", /* Microcontroller assembly */
   496     "def", /* BSO/Tasking definition includes  */
   497     "inc", /* Microcontroller include files */
   498     "ins", /* Microcontroller include files */
   499     "s", "sa", /* Unix assembler */
   500     "S",   /* cpp-processed Unix assembler */
   501     "src", /* BSO/Tasking C compiler output */
   502     NULL
   503   };
   504 static const char Asm_help [] =
   505 "In assembler code, labels appearing at the beginning of a line,\n\
   506 followed by a colon, are tags.";
   507 
   508 
   509 /* Note that .c and .h can be considered C++, if the --c++ flag was
   510    given, or if the `class' or `template' keywords are met inside the file.
   511    That is why default_C_entries is called for these. */
   512 static const char *default_C_suffixes [] =
   513   { "c", "h", NULL };
   514 #if CTAGS                               /* C help for Ctags */
   515 static const char default_C_help [] =
   516 "In C code, any C function is a tag.  Use -t to tag typedefs.\n\
   517 Use -T to tag definitions of `struct', `union' and `enum'.\n\
   518 Use -d to tag `#define' macro definitions and `enum' constants.\n\
   519 Use --globals to tag global variables.\n\
   520 You can tag function declarations and external variables by\n\
   521 using `--declarations', and struct members by using `--members'.";
   522 #else                                   /* C help for Etags */
   523 static const char default_C_help [] =
   524 "In C code, any C function or typedef is a tag, and so are\n\
   525 definitions of `struct', `union' and `enum'.  `#define' macro\n\
   526 definitions and `enum' constants are tags unless you specify\n\
   527 `--no-defines'.  Global variables are tags unless you specify\n\
   528 `--no-globals' and so are struct members unless you specify\n\
   529 `--no-members'.  Use of `--no-globals', `--no-defines' and\n\
   530 `--no-members' can make the tags table file much smaller.\n\
   531 You can tag function declarations and external variables by\n\
   532 using `--declarations'.";
   533 #endif  /* C help for Ctags and Etags */
   534 
   535 static const char *Cplusplus_suffixes [] =
   536   { "C", "c++", "cc", "cpp", "cxx", "H", "h++", "hh", "hpp", "hxx",
   537     "M",                        /* Objective C++ */
   538     "pdb",                      /* PostScript with C syntax */
   539     NULL };
   540 static const char Cplusplus_help [] =
   541 "In C++ code, all the tag constructs of C code are tagged.  (Use\n\
   542 --help --lang=c --lang=c++ for full help.)\n\
   543 In addition to C tags, member functions are also recognized.  Member\n\
   544 variables are recognized unless you use the `--no-members' option.\n\
   545 Tags for variables and functions in classes are named `CLASS::VARIABLE'\n\
   546 and `CLASS::FUNCTION'.  `operator' definitions have tag names like\n\
   547 `operator+'.";
   548 
   549 static const char *Cjava_suffixes [] =
   550   { "java", NULL };
   551 static char Cjava_help [] =
   552 "In Java code, all the tags constructs of C and C++ code are\n\
   553 tagged.  (Use --help --lang=c --lang=c++ --lang=java for full help.)";
   554 
   555 
   556 static const char *Cobol_suffixes [] =
   557   { "COB", "cob", NULL };
   558 static char Cobol_help [] =
   559 "In Cobol code, tags are paragraph names; that is, any word\n\
   560 starting in column 8 and followed by a period.";
   561 
   562 static const char *Cstar_suffixes [] =
   563   { "cs", "hs", NULL };
   564 
   565 static const char *Erlang_suffixes [] =
   566   { "erl", "hrl", NULL };
   567 static const char Erlang_help [] =
   568 "In Erlang code, the tags are the functions, records and macros\n\
   569 defined in the file.";
   570 
   571 const char *Forth_suffixes [] =
   572   { "fth", "tok", NULL };
   573 static const char Forth_help [] =
   574 "In Forth code, tags are words defined by `:',\n\
   575 constant, code, create, defer, value, variable, buffer:, field.";
   576 
   577 static const char *Fortran_suffixes [] =
   578   { "F", "f", "f90", "for", NULL };
   579 static const char Fortran_help [] =
   580 "In Fortran code, functions, subroutines and block data are tags.";
   581 
   582 static const char *HTML_suffixes [] =
   583   { "htm", "html", "shtml", NULL };
   584 static const char HTML_help [] =
   585 "In HTML input files, the tags are the `title' and the `h1', `h2',\n\
   586 `h3' headers.  Also, tags are `name=' in anchors and all\n\
   587 occurrences of `id='.";
   588 
   589 static const char *Lisp_suffixes [] =
   590   { "cl", "clisp", "el", "l", "lisp", "LSP", "lsp", "ml", NULL };
   591 static const char Lisp_help [] =
   592 "In Lisp code, any function defined with `defun', any variable\n\
   593 defined with `defvar' or `defconst', and in general the first\n\
   594 argument of any expression that starts with `(def' in column zero\n\
   595 is a tag.\n\
   596 The `--declarations' option tags \"(defvar foo)\" constructs too.";
   597 
   598 static const char *Lua_suffixes [] =
   599   { "lua", "LUA", NULL };
   600 static const char Lua_help [] =
   601 "In Lua scripts, all functions are tags.";
   602 
   603 static const char *Makefile_filenames [] =
   604   { "Makefile", "makefile", "GNUMakefile", "Makefile.in", "Makefile.am", NULL};
   605 static const char Makefile_help [] =
   606 "In makefiles, targets are tags; additionally, variables are tags\n\
   607 unless you specify `--no-globals'.";
   608 
   609 static const char *Objc_suffixes [] =
   610   { "lm",                       /* Objective lex file */
   611     "m",                        /* Objective C file */
   612      NULL };
   613 static const char Objc_help [] =
   614 "In Objective C code, tags include Objective C definitions for classes,\n\
   615 class categories, methods and protocols.  Tags for variables and\n\
   616 functions in classes are named `CLASS::VARIABLE' and `CLASS::FUNCTION'.\
   617 \n(Use --help --lang=c --lang=objc --lang=java for full help.)";
   618 
   619 static const char *Pascal_suffixes [] =
   620   { "p", "pas", NULL };
   621 static const char Pascal_help [] =
   622 "In Pascal code, the tags are the functions and procedures defined\n\
   623 in the file.";
   624 /* " // this is for working around an Emacs highlighting bug... */
   625 
   626 static const char *Perl_suffixes [] =
   627   { "pl", "pm", NULL };
   628 static const char *Perl_interpreters [] =
   629   { "perl", "@PERL@", NULL };
   630 static const char Perl_help [] =
   631 "In Perl code, the tags are the packages, subroutines and variables\n\
   632 defined by the `package', `sub', `my' and `local' keywords.  Use\n\
   633 `--globals' if you want to tag global variables.  Tags for\n\
   634 subroutines are named `PACKAGE::SUB'.  The name for subroutines\n\
   635 defined in the default package is `main::SUB'.";
   636 
   637 static const char *PHP_suffixes [] =
   638   { "php", "php3", "php4", NULL };
   639 static const char PHP_help [] =
   640 "In PHP code, tags are functions, classes and defines.  Unless you use\n\
   641 the `--no-members' option, vars are tags too.";
   642 
   643 static const char *plain_C_suffixes [] =
   644   { "pc",                       /* Pro*C file */
   645      NULL };
   646 
   647 static const char *PS_suffixes [] =
   648   { "ps", "psw", NULL };        /* .psw is for PSWrap */
   649 static const char PS_help [] =
   650 "In PostScript code, the tags are the functions.";
   651 
   652 static const char *Prolog_suffixes [] =
   653   { "prolog", NULL };
   654 static const char Prolog_help [] =
   655 "In Prolog code, tags are predicates and rules at the beginning of\n\
   656 line.";
   657 
   658 static const char *Python_suffixes [] =
   659   { "py", NULL };
   660 static const char Python_help [] =
   661 "In Python code, `def' or `class' at the beginning of a line\n\
   662 generate a tag.";
   663 
   664 /* Can't do the `SCM' or `scm' prefix with a version number. */
   665 static const char *Scheme_suffixes [] =
   666   { "oak", "sch", "scheme", "SCM", "scm", "SM", "sm", "ss", "t", NULL };
   667 static const char Scheme_help [] =
   668 "In Scheme code, tags include anything defined with `def' or with a\n\
   669 construct whose name starts with `def'.  They also include\n\
   670 variables set with `set!' at top level in the file.";
   671 
   672 static const char *TeX_suffixes [] =
   673   { "bib", "clo", "cls", "ltx", "sty", "TeX", "tex", NULL };
   674 static const char TeX_help [] =
   675 "In LaTeX text, the argument of any of the commands `\\chapter',\n\
   676 `\\section', `\\subsection', `\\subsubsection', `\\eqno', `\\label',\n\
   677 `\\ref', `\\cite', `\\bibitem', `\\part', `\\appendix', `\\entry',\n\
   678 `\\index', `\\def', `\\newcommand', `\\renewcommand',\n\
   679 `\\newenvironment' or `\\renewenvironment' is a tag.\n\
   680 \n\
   681 Other commands can be specified by setting the environment variable\n\
   682 `TEXTAGS' to a colon-separated list like, for example,\n\
   683      TEXTAGS=\"mycommand:myothercommand\".";
   684 
   685 
   686 static const char *Texinfo_suffixes [] =
   687   { "texi", "texinfo", "txi", NULL };
   688 static const char Texinfo_help [] =
   689 "for texinfo files, lines starting with @node are tagged.";
   690 
   691 static const char *Yacc_suffixes [] =
   692   { "y", "y++", "ym", "yxx", "yy", NULL }; /* .ym is Objective yacc file */
   693 static const char Yacc_help [] =
   694 "In Bison or Yacc input files, each rule defines as a tag the\n\
   695 nonterminal it constructs.  The portions of the file that contain\n\
   696 C code are parsed as C code (use --help --lang=c --lang=yacc\n\
   697 for full help).";
   698 
   699 static const char auto_help [] =
   700 "`auto' is not a real language, it indicates to use\n\
   701 a default language for files base on file name suffix and file contents.";
   702 
   703 static const char none_help [] =
   704 "`none' is not a real language, it indicates to only do\n\
   705 regexp processing on files.";
   706 
   707 static const char no_lang_help [] =
   708 "No detailed help available for this language.";
   709 
   710 
   711 /*
   712  * Table of languages.
   713  *
   714  * It is ok for a given function to be listed under more than one
   715  * name.  I just didn't.
   716  */
   717 
   718 static language lang_names [] =
   719 {
   720   { "ada",       Ada_help,       Ada_funcs,         Ada_suffixes       },
   721   { "asm",       Asm_help,       Asm_labels,        Asm_suffixes       },
   722   { "c",         default_C_help, default_C_entries, default_C_suffixes },
   723   { "c++",       Cplusplus_help, Cplusplus_entries, Cplusplus_suffixes },
   724   { "c*",        no_lang_help,   Cstar_entries,     Cstar_suffixes     },
   725   { "cobol",     Cobol_help,     Cobol_paragraphs,  Cobol_suffixes     },
   726   { "erlang",    Erlang_help,    Erlang_functions,  Erlang_suffixes    },
   727   { "forth",     Forth_help,     Forth_words,       Forth_suffixes     },
   728   { "fortran",   Fortran_help,   Fortran_functions, Fortran_suffixes   },
   729   { "html",      HTML_help,      HTML_labels,       HTML_suffixes      },
   730   { "java",      Cjava_help,     Cjava_entries,     Cjava_suffixes     },
   731   { "lisp",      Lisp_help,      Lisp_functions,    Lisp_suffixes      },
   732   { "lua",       Lua_help,       Lua_functions,     Lua_suffixes       },
   733   { "makefile",  Makefile_help,Makefile_targets,NULL,Makefile_filenames},
   734   { "objc",      Objc_help,      plain_C_entries,   Objc_suffixes      },
   735   { "pascal",    Pascal_help,    Pascal_functions,  Pascal_suffixes    },
   736   { "perl",Perl_help,Perl_functions,Perl_suffixes,NULL,Perl_interpreters},
   737   { "php",       PHP_help,       PHP_functions,     PHP_suffixes       },
   738   { "postscript",PS_help,        PS_functions,      PS_suffixes        },
   739   { "proc",      no_lang_help,   plain_C_entries,   plain_C_suffixes   },
   740   { "prolog",    Prolog_help,    Prolog_functions,  Prolog_suffixes    },
   741   { "python",    Python_help,    Python_functions,  Python_suffixes    },
   742   { "scheme",    Scheme_help,    Scheme_functions,  Scheme_suffixes    },
   743   { "tex",       TeX_help,       TeX_commands,      TeX_suffixes       },
   744   { "texinfo",   Texinfo_help,   Texinfo_nodes,     Texinfo_suffixes   },
   745   { "yacc",      Yacc_help,Yacc_entries,Yacc_suffixes,NULL,NULL,true},
   746   { "auto",      auto_help },                      /* default guessing scheme */
   747   { "none",      none_help,      just_read_file }, /* regexp matching only */
   748   { NULL }                /* end of list */
   749 };
   750 
   751 
   752 static void
   753 print_language_names (void)
   754 {
   755   language *lang;
   756   const char **name, **ext;
   757 
   758   puts ("\nThese are the currently supported languages, along with the\n\
   759 default file names and dot suffixes:");
   760   for (lang = lang_names; lang->name != NULL; lang++)
   761     {
   762       printf ("  %-*s", 10, lang->name);
   763       if (lang->filenames != NULL)
   764         for (name = lang->filenames; *name != NULL; name++)
   765           printf (" %s", *name);
   766       if (lang->suffixes != NULL)
   767         for (ext = lang->suffixes; *ext != NULL; ext++)
   768           printf (" .%s", *ext);
   769       puts ("");
   770     }
   771   puts ("where `auto' means use default language for files based on file\n\
   772 name suffix, and `none' means only do regexp processing on files.\n\
   773 If no language is specified and no matching suffix is found,\n\
   774 the first line of the file is read for a sharp-bang (#!) sequence\n\
   775 followed by the name of an interpreter.  If no such sequence is found,\n\
   776 Fortran is tried first; if no tags are found, C is tried next.\n\
   777 When parsing any C file, a \"class\" or \"template\" keyword\n\
   778 switches to C++.");
   779   puts ("Compressed files are supported using gzip, bzip2, and xz.\n\
   780 \n\
   781 For detailed help on a given language use, for example,\n\
   782 etags --help --lang=ada.");
   783 }
   784 
   785 #ifndef EMACS_NAME
   786 # define EMACS_NAME "standalone"
   787 #endif
   788 #ifndef VERSION
   789 # define VERSION "17.38.1.4"
   790 #endif
   791 static _Noreturn void
   792 print_version (void)
   793 {
   794   char emacs_copyright[] = COPYRIGHT;
   795 
   796   printf ("%s (%s %s)\n", (CTAGS) ? "ctags" : "etags", EMACS_NAME, VERSION);
   797   puts (emacs_copyright);
   798   puts ("This program is distributed under the terms in ETAGS.README");
   799 
   800   exit (EXIT_SUCCESS);
   801 }
   802 
   803 #ifndef PRINT_UNDOCUMENTED_OPTIONS_HELP
   804 # define PRINT_UNDOCUMENTED_OPTIONS_HELP false
   805 #endif
   806 
   807 static _Noreturn void
   808 print_help (argument *argbuffer)
   809 {
   810   bool help_for_lang = false;
   811 
   812   for (; argbuffer->arg_type != at_end; argbuffer++)
   813     if (argbuffer->arg_type == at_language)
   814       {
   815         if (help_for_lang)
   816           puts ("");
   817         puts (argbuffer->lang->help);
   818         help_for_lang = true;
   819       }
   820 
   821   if (help_for_lang)
   822     exit (EXIT_SUCCESS);
   823 
   824   printf ("Usage: %s [options] [[regex-option ...] file-name] ...\n\
   825 \n\
   826 These are the options accepted by %s.\n", progname, progname);
   827   puts ("You may use unambiguous abbreviations for the long option names.");
   828   puts ("  A - as file name means read names from stdin (one per line).\n\
   829 Absolute names are stored in the output file as they are.\n\
   830 Relative ones are stored relative to the output file's directory.\n");
   831 
   832   puts ("-a, --append\n\
   833         Append tag entries to existing tags file.");
   834 
   835   puts ("--packages-only\n\
   836         For Ada files, only generate tags for packages.");
   837 
   838   if (CTAGS)
   839     puts ("-B, --backward-search\n\
   840         Write the search commands for the tag entries using '?', the\n\
   841         backward-search command instead of '/', the forward-search command.");
   842 
   843   /* This option is mostly obsolete, because etags can now automatically
   844      detect C++.  Retained for backward compatibility and for debugging and
   845      experimentation.  In principle, we could want to tag as C++ even
   846      before any "class" or "template" keyword.
   847   puts ("-C, --c++\n\
   848         Treat files whose name suffix defaults to C language as C++ files.");
   849   */
   850 
   851   puts ("--declarations\n\
   852         In C and derived languages, create tags for function declarations,");
   853   if (CTAGS)
   854     puts ("\tand create tags for extern variables if --globals is used.");
   855   else
   856     puts
   857       ("\tand create tags for extern variables unless --no-globals is used.");
   858 
   859   if (CTAGS)
   860     puts ("-d, --defines\n\
   861         Create tag entries for C #define constants and enum constants, too.");
   862   else
   863     puts ("-D, --no-defines\n\
   864         Don't create tag entries for C #define constants and enum constants.\n\
   865         This makes the tags file smaller.");
   866 
   867   if (!CTAGS)
   868     puts ("-i FILE, --include=FILE\n\
   869         Include a note in tag file indicating that, when searching for\n\
   870         a tag, one should also consult the tags file FILE after\n\
   871         checking the current file.");
   872 
   873   puts ("-l LANG, --language=LANG\n\
   874         Force the following files to be considered as written in the\n\
   875         named language up to the next --language=LANG option.");
   876 
   877   if (CTAGS)
   878     puts ("--globals\n\
   879         Create tag entries for global variables in some languages.");
   880   else
   881     puts ("--no-globals\n\
   882         Do not create tag entries for global variables in some\n\
   883         languages.  This makes the tags file smaller.");
   884 
   885   if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
   886     puts ("--no-line-directive\n\
   887         Ignore #line preprocessor directives in C and derived languages.");
   888 
   889   if (CTAGS)
   890     puts ("--members\n\
   891         Create tag entries for members of structures in some languages.");
   892   else
   893     puts ("--no-members\n\
   894         Do not create tag entries for members of structures\n\
   895         in some languages.");
   896 
   897   puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\
   898         Make a tag for each line matching a regular expression pattern\n\
   899         in the following files.  {LANGUAGE}REGEXP uses REGEXP for LANGUAGE\n\
   900         files only.  REGEXFILE is a file containing one REGEXP per line.\n\
   901         REGEXP takes the form /TAGREGEXP/TAGNAME/MODS, where TAGNAME/ is\n\
   902         optional.  The TAGREGEXP pattern is anchored (as if preceded by ^).");
   903   puts ("       If TAGNAME/ is present, the tags created are named.\n\
   904         For example Tcl named tags can be created with:\n\
   905           --regex=\"/proc[ \\t]+\\([^ \\t]+\\)/\\1/.\".\n\
   906         MODS are optional one-letter modifiers: `i' means to ignore case,\n\
   907         `m' means to allow multi-line matches, `s' implies `m' and\n\
   908         causes dot to match any character, including newline.");
   909 
   910   puts ("-R, --no-regex\n\
   911         Don't create tags from regexps for the following files.");
   912 
   913   puts ("-I, --ignore-indentation\n\
   914         In C and C++ do not assume that a closing brace in the first\n\
   915         column is the final brace of a function or structure definition.");
   916 
   917   puts ("-o FILE, --output=FILE\n\
   918         Write the tags to FILE.");
   919 
   920   puts ("--parse-stdin=NAME\n\
   921         Read from standard input and record tags as belonging to file NAME.");
   922 
   923   if (CTAGS)
   924     {
   925       puts ("-t, --typedefs\n\
   926         Generate tag entries for C and Ada typedefs.");
   927       puts ("-T, --typedefs-and-c++\n\
   928         Generate tag entries for C typedefs, C struct/enum/union tags,\n\
   929         and C++ member functions.");
   930     }
   931 
   932   if (CTAGS)
   933     puts ("-u, --update\n\
   934         Update the tag entries for the given files, leaving tag\n\
   935         entries for other files in place.  Currently, this is\n\
   936         implemented by deleting the existing entries for the given\n\
   937         files and then rewriting the new entries at the end of the\n\
   938         tags file.  It is often faster to simply rebuild the entire\n\
   939         tag file than to use this.");
   940 
   941   if (CTAGS)
   942     {
   943       puts ("-v, --vgrind\n\
   944         Print on the standard output an index of items intended for\n\
   945         human consumption, similar to the output of vgrind.  The index\n\
   946         is sorted, and gives the page number of each item.");
   947 
   948       if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
   949         puts ("-w, --no-duplicates\n\
   950         Do not create duplicate tag entries, for compatibility with\n\
   951         traditional ctags.");
   952 
   953       if (PRINT_UNDOCUMENTED_OPTIONS_HELP)
   954         puts ("-w, --no-warn\n\
   955         Suppress warning messages about duplicate tag entries.");
   956 
   957       puts ("-x, --cxref\n\
   958         Like --vgrind, but in the style of cxref, rather than vgrind.\n\
   959         The output uses line numbers instead of page numbers, but\n\
   960         beyond that the differences are cosmetic; try both to see\n\
   961         which you like.");
   962     }
   963 
   964   puts ("-V, --version\n\
   965         Print the version of the program.\n\
   966 -h, --help\n\
   967         Print this help message.\n\
   968         Followed by one or more `--language' options prints detailed\n\
   969         help about tag generation for the specified languages.");
   970 
   971   print_language_names ();
   972 
   973   puts ("");
   974   puts ("Report bugs to bug-gnu-emacs@gnu.org");
   975 
   976   exit (EXIT_SUCCESS);
   977 }
   978 
   979 
   980 int
   981 main (int argc, char **argv)
   982 {
   983   int i;
   984   unsigned int nincluded_files;
   985   char **included_files;
   986   argument *argbuffer;
   987   int current_arg, file_count;
   988   linebuffer filename_lb;
   989   bool help_asked = false;
   990   ptrdiff_t len;
   991   char *optstring;
   992   int opt;
   993 
   994   progname = argv[0];
   995   nincluded_files = 0;
   996   included_files = xnew (argc, char *);
   997   current_arg = 0;
   998   file_count = 0;
   999 
  1000   /* Allocate enough no matter what happens.  Overkill, but each one
  1001      is small. */
  1002   argbuffer = xnew (argc, argument);
  1003 
  1004   /*
  1005    * Always find typedefs and structure tags.
  1006    * Also default to find macro constants, enum constants, struct
  1007    * members and global variables.  Do it for both etags and ctags.
  1008    */
  1009   typedefs = typedefs_or_cplusplus = constantypedefs = true;
  1010   globals = members = true;
  1011 
  1012   /* When the optstring begins with a '-' getopt_long does not rearrange the
  1013      non-options arguments to be at the end, but leaves them alone. */
  1014   optstring = concat ("-ac:Cf:Il:o:r:RSVhH",
  1015                       (CTAGS) ? "BxdtTuvw" : "Di:",
  1016                       "");
  1017 
  1018   while ((opt = getopt_long (argc, argv, optstring, longopts, NULL)) != EOF)
  1019     switch (opt)
  1020       {
  1021       case 0:
  1022         /* If getopt returns 0, then it has already processed a
  1023            long-named option.  We should do nothing.  */
  1024         break;
  1025 
  1026       case 1:
  1027         /* This means that a file name has been seen.  Record it. */
  1028         argbuffer[current_arg].arg_type = at_filename;
  1029         argbuffer[current_arg].what     = optarg;
  1030         len = strlen (optarg);
  1031         if (whatlen_max < len)
  1032           whatlen_max = len;
  1033         ++current_arg;
  1034         ++file_count;
  1035         break;
  1036 
  1037       case STDIN:
  1038         /* Parse standard input.  Idea by Vivek <vivek@etla.org>. */
  1039         argbuffer[current_arg].arg_type = at_stdin;
  1040         argbuffer[current_arg].what     = optarg;
  1041         len = strlen (optarg);
  1042         if (whatlen_max < len)
  1043           whatlen_max = len;
  1044         ++current_arg;
  1045         ++file_count;
  1046         if (parsing_stdin)
  1047           fatal ("cannot parse standard input more than once", (char *)NULL);
  1048         parsing_stdin = true;
  1049         break;
  1050 
  1051         /* Common options. */
  1052       case 'a': append_to_tagfile = true;       break;
  1053       case 'C': cplusplus = true;               break;
  1054       case 'f':         /* for compatibility with old makefiles */
  1055       case 'o':
  1056         if (tagfile)
  1057           {
  1058             error ("-o option may only be given once.");
  1059             suggest_asking_for_help ();
  1060             /* NOTREACHED */
  1061           }
  1062         tagfile = optarg;
  1063         break;
  1064       case 'I':
  1065       case 'S':         /* for backward compatibility */
  1066         ignoreindent = true;
  1067         break;
  1068       case 'l':
  1069         {
  1070           language *lang = get_language_from_langname (optarg);
  1071           if (lang != NULL)
  1072             {
  1073               argbuffer[current_arg].lang = lang;
  1074               argbuffer[current_arg].arg_type = at_language;
  1075               ++current_arg;
  1076             }
  1077         }
  1078         break;
  1079       case 'c':
  1080         /* Backward compatibility: support obsolete --ignore-case-regexp. */
  1081         optarg = concat (optarg, "i", ""); /* memory leak here */
  1082         /* FALLTHRU */
  1083       case 'r':
  1084         argbuffer[current_arg].arg_type = at_regexp;
  1085         argbuffer[current_arg].what = optarg;
  1086         len = strlen (optarg);
  1087         if (whatlen_max < len)
  1088           whatlen_max = len;
  1089         ++current_arg;
  1090         break;
  1091       case 'R':
  1092         argbuffer[current_arg].arg_type = at_regexp;
  1093         argbuffer[current_arg].what = NULL;
  1094         ++current_arg;
  1095         break;
  1096       case 'V':
  1097         print_version ();
  1098         break;
  1099       case 'h':
  1100       case 'H':
  1101         help_asked = true;
  1102         break;
  1103 
  1104         /* Etags options */
  1105       case 'D': constantypedefs = false;                        break;
  1106       case 'i': included_files[nincluded_files++] = optarg;     break;
  1107 
  1108         /* Ctags options. */
  1109       case 'B': searchar = '?';                                 break;
  1110       case 'd': constantypedefs = true;                         break;
  1111       case 't': typedefs = true;                                break;
  1112       case 'T': typedefs = typedefs_or_cplusplus = true;        break;
  1113       case 'u': update = true;                                  break;
  1114       case 'v': vgrind_style = true;                      /*FALLTHRU*/
  1115       case 'x': cxref_style = true;                             break;
  1116       case 'w': no_warnings = true;                             break;
  1117       default:
  1118         suggest_asking_for_help ();
  1119         /* NOTREACHED */
  1120       }
  1121 
  1122   /* No more options.  Store the rest of arguments. */
  1123   for (; optind < argc; optind++)
  1124     {
  1125       argbuffer[current_arg].arg_type = at_filename;
  1126       argbuffer[current_arg].what = argv[optind];
  1127       len = strlen (argv[optind]);
  1128       if (whatlen_max < len)
  1129         whatlen_max = len;
  1130       ++current_arg;
  1131       ++file_count;
  1132     }
  1133 
  1134   argbuffer[current_arg].arg_type = at_end;
  1135 
  1136   if (help_asked)
  1137     print_help (argbuffer);
  1138     /* NOTREACHED */
  1139 
  1140   if (nincluded_files == 0 && file_count == 0)
  1141     {
  1142       error ("no input files specified.");
  1143       suggest_asking_for_help ();
  1144       /* NOTREACHED */
  1145     }
  1146 
  1147   if (tagfile == NULL)
  1148     tagfile = savestr (CTAGS ? "tags" : "TAGS");
  1149   cwd = etags_getcwd ();        /* the current working directory */
  1150   if (cwd[strlen (cwd) - 1] != '/')
  1151     {
  1152       char *oldcwd = cwd;
  1153       cwd = concat (oldcwd, "/", "");
  1154       free (oldcwd);
  1155     }
  1156 
  1157   /* Compute base directory for relative file names. */
  1158   if (streq (tagfile, "-")
  1159       || strneq (tagfile, "/dev/", 5))
  1160     tagfiledir = cwd;            /* relative file names are relative to cwd */
  1161   else
  1162     {
  1163       canonicalize_filename (tagfile);
  1164       tagfiledir = absolute_dirname (tagfile, cwd);
  1165     }
  1166 
  1167   init ();                      /* set up boolean "functions" */
  1168 
  1169   linebuffer_init (&lb);
  1170   linebuffer_init (&filename_lb);
  1171   linebuffer_init (&filebuf);
  1172   linebuffer_init (&token_name);
  1173 
  1174   if (!CTAGS)
  1175     {
  1176       if (streq (tagfile, "-"))
  1177         {
  1178           tagf = stdout;
  1179           SET_BINARY (fileno (stdout));
  1180         }
  1181       else
  1182         tagf = fopen (tagfile, append_to_tagfile ? "ab" : "wb");
  1183       if (tagf == NULL)
  1184         pfatal (tagfile);
  1185     }
  1186 
  1187   /*
  1188    * Loop through files finding functions.
  1189    */
  1190   for (i = 0; i < current_arg; i++)
  1191     {
  1192       static language *lang;    /* non-NULL if language is forced */
  1193       char *this_file;
  1194 
  1195       switch (argbuffer[i].arg_type)
  1196         {
  1197         case at_language:
  1198           lang = argbuffer[i].lang;
  1199           break;
  1200         case at_regexp:
  1201           analyze_regex (argbuffer[i].what);
  1202           break;
  1203         case at_filename:
  1204               this_file = argbuffer[i].what;
  1205               /* Input file named "-" means read file names from stdin
  1206                  (one per line) and use them. */
  1207               if (streq (this_file, "-"))
  1208                 {
  1209                   if (parsing_stdin)
  1210                     fatal ("cannot parse standard input AND read file names from it",
  1211                            (char *)NULL);
  1212                   while (readline_internal (&filename_lb, stdin) > 0)
  1213                     process_file_name (filename_lb.buffer, lang);
  1214                 }
  1215               else
  1216                 process_file_name (this_file, lang);
  1217           break;
  1218         case at_stdin:
  1219           this_file = argbuffer[i].what;
  1220           process_file (stdin, this_file, lang);
  1221           break;
  1222         }
  1223     }
  1224 
  1225   free_regexps ();
  1226   free (lb.buffer);
  1227   free (filebuf.buffer);
  1228   free (token_name.buffer);
  1229 
  1230   if (!CTAGS || cxref_style)
  1231     {
  1232       /* Write the remaining tags to tagf (ETAGS) or stdout (CXREF). */
  1233       put_entries (nodehead);
  1234       free_tree (nodehead);
  1235       nodehead = NULL;
  1236       if (!CTAGS)
  1237         {
  1238           fdesc *fdp;
  1239 
  1240           /* Output file entries that have no tags. */
  1241           for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
  1242             if (!fdp->written)
  1243               fprintf (tagf, "\f\n%s,0\n", fdp->taggedfname);
  1244 
  1245           while (nincluded_files-- > 0)
  1246             fprintf (tagf, "\f\n%s,include\n", *included_files++);
  1247 
  1248           if (fclose (tagf) == EOF)
  1249             pfatal (tagfile);
  1250         }
  1251 
  1252       exit (EXIT_SUCCESS);
  1253     }
  1254 
  1255   /* From here on, we are in (CTAGS && !cxref_style) */
  1256   if (update)
  1257     {
  1258       char *cmd =
  1259         xmalloc (strlen (tagfile) + whatlen_max +
  1260                  sizeof "mv..OTAGS;fgrep -v '\t\t' OTAGS >;rm OTAGS");
  1261       for (i = 0; i < current_arg; ++i)
  1262         {
  1263           switch (argbuffer[i].arg_type)
  1264             {
  1265             case at_filename:
  1266             case at_stdin:
  1267               break;
  1268             default:
  1269               continue;         /* the for loop */
  1270             }
  1271           char *z = stpcpy (cmd, "mv ");
  1272           z = stpcpy (z, tagfile);
  1273           z = stpcpy (z, " OTAGS;fgrep -v '\t");
  1274           z = stpcpy (z, argbuffer[i].what);
  1275           z = stpcpy (z, "\t' OTAGS >");
  1276           z = stpcpy (z, tagfile);
  1277           strcpy (z, ";rm OTAGS");
  1278           if (system (cmd) != EXIT_SUCCESS)
  1279             fatal ("failed to execute shell command", (char *)NULL);
  1280         }
  1281       free (cmd);
  1282       append_to_tagfile = true;
  1283     }
  1284 
  1285   tagf = fopen (tagfile, append_to_tagfile ? "ab" : "wb");
  1286   if (tagf == NULL)
  1287     pfatal (tagfile);
  1288   put_entries (nodehead);       /* write all the tags (CTAGS) */
  1289   free_tree (nodehead);
  1290   nodehead = NULL;
  1291   if (fclose (tagf) == EOF)
  1292     pfatal (tagfile);
  1293 
  1294   if (CTAGS)
  1295     if (append_to_tagfile || update)
  1296       {
  1297         char *cmd = xmalloc (2 * strlen (tagfile) + sizeof "sort -u -o..");
  1298         /* Maybe these should be used:
  1299            setenv ("LC_COLLATE", "C", 1);
  1300            setenv ("LC_ALL", "C", 1); */
  1301         char *z = stpcpy (cmd, "sort -u -o ");
  1302         z = stpcpy (z, tagfile);
  1303         *z++ = ' ';
  1304         strcpy (z, tagfile);
  1305         exit (system (cmd));
  1306       }
  1307   return EXIT_SUCCESS;
  1308 }
  1309 
  1310 
  1311 /*
  1312  * Return a compressor given the file name.  If EXTPTR is non-zero,
  1313  * return a pointer into FILE where the compressor-specific
  1314  * extension begins.  If no compressor is found, NULL is returned
  1315  * and EXTPTR is not significant.
  1316  * Idea by Vladimir Alexiev <vladimir@cs.ualberta.ca> (1998)
  1317  */
  1318 static compressor *
  1319 get_compressor_from_suffix (char *file, char **extptr)
  1320 {
  1321   compressor *compr;
  1322   char *slash, *suffix;
  1323 
  1324   /* File has been processed by canonicalize_filename,
  1325      so we don't need to consider backslashes on DOS_NT.  */
  1326   slash = strrchr (file, '/');
  1327   suffix = strrchr (file, '.');
  1328   if (suffix == NULL || suffix < slash)
  1329     return NULL;
  1330   if (extptr != NULL)
  1331     *extptr = suffix;
  1332   suffix += 1;
  1333   /* Let those poor souls who live with DOS 8+3 file name limits get
  1334      some solace by treating foo.cgz as if it were foo.c.gz, etc.
  1335      Only the first do loop is run if not MSDOS */
  1336   do
  1337     {
  1338       for (compr = compressors; compr->suffix != NULL; compr++)
  1339         if (streq (compr->suffix, suffix))
  1340           return compr;
  1341       if (!MSDOS)
  1342         break;                  /* do it only once: not really a loop */
  1343       if (extptr != NULL)
  1344         *extptr = ++suffix;
  1345     } while (*suffix != '\0');
  1346   return NULL;
  1347 }
  1348 
  1349 
  1350 
  1351 /*
  1352  * Return a language given the name.
  1353  */
  1354 static language *
  1355 get_language_from_langname (const char *name)
  1356 {
  1357   language *lang;
  1358 
  1359   if (name == NULL)
  1360     error ("empty language name");
  1361   else
  1362     {
  1363       for (lang = lang_names; lang->name != NULL; lang++)
  1364         if (streq (name, lang->name))
  1365           return lang;
  1366       error ("unknown language \"%s\"", name);
  1367     }
  1368 
  1369   return NULL;
  1370 }
  1371 
  1372 
  1373 /*
  1374  * Return a language given the interpreter name.
  1375  */
  1376 static language *
  1377 get_language_from_interpreter (char *interpreter)
  1378 {
  1379   language *lang;
  1380   const char **iname;
  1381 
  1382   if (interpreter == NULL)
  1383     return NULL;
  1384   for (lang = lang_names; lang->name != NULL; lang++)
  1385     if (lang->interpreters != NULL)
  1386       for (iname = lang->interpreters; *iname != NULL; iname++)
  1387         if (streq (*iname, interpreter))
  1388             return lang;
  1389 
  1390   return NULL;
  1391 }
  1392 
  1393 
  1394 
  1395 /*
  1396  * Return a language given the file name.
  1397  */
  1398 static language *
  1399 get_language_from_filename (char *file, int case_sensitive)
  1400 {
  1401   language *lang;
  1402   const char **name, **ext, *suffix;
  1403 
  1404   /* Try whole file name first. */
  1405   for (lang = lang_names; lang->name != NULL; lang++)
  1406     if (lang->filenames != NULL)
  1407       for (name = lang->filenames; *name != NULL; name++)
  1408         if ((case_sensitive)
  1409             ? streq (*name, file)
  1410             : strcaseeq (*name, file))
  1411           return lang;
  1412 
  1413   /* If not found, try suffix after last dot. */
  1414   suffix = strrchr (file, '.');
  1415   if (suffix == NULL)
  1416     return NULL;
  1417   suffix += 1;
  1418   for (lang = lang_names; lang->name != NULL; lang++)
  1419     if (lang->suffixes != NULL)
  1420       for (ext = lang->suffixes; *ext != NULL; ext++)
  1421         if ((case_sensitive)
  1422             ? streq (*ext, suffix)
  1423             : strcaseeq (*ext, suffix))
  1424           return lang;
  1425   return NULL;
  1426 }
  1427 
  1428 
  1429 /*
  1430  * This routine is called on each file argument.
  1431  */
  1432 static void
  1433 process_file_name (char *file, language *lang)
  1434 {
  1435   struct stat stat_buf;
  1436   FILE *inf;
  1437   fdesc *fdp;
  1438   compressor *compr;
  1439   char *compressed_name, *uncompressed_name;
  1440   char *ext, *real_name;
  1441   int retval;
  1442 
  1443   canonicalize_filename (file);
  1444   if (streq (file, tagfile) && !streq (tagfile, "-"))
  1445     {
  1446       error ("skipping inclusion of %s in self.", file);
  1447       return;
  1448     }
  1449   if ((compr = get_compressor_from_suffix (file, &ext)) == NULL)
  1450     {
  1451       compressed_name = NULL;
  1452       real_name = uncompressed_name = savestr (file);
  1453     }
  1454   else
  1455     {
  1456       real_name = compressed_name = savestr (file);
  1457       uncompressed_name = savenstr (file, ext - file);
  1458     }
  1459 
  1460   /* If the canonicalized uncompressed name
  1461      has already been dealt with, skip it silently. */
  1462   for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
  1463     {
  1464       assert (fdp->infname != NULL);
  1465       if (streq (uncompressed_name, fdp->infname))
  1466         goto cleanup;
  1467     }
  1468 
  1469   if (stat (real_name, &stat_buf) != 0)
  1470     {
  1471       /* Reset real_name and try with a different name. */
  1472       real_name = NULL;
  1473       if (compressed_name != NULL) /* try with the given suffix */
  1474         {
  1475           if (stat (uncompressed_name, &stat_buf) == 0)
  1476             real_name = uncompressed_name;
  1477         }
  1478       else                      /* try all possible suffixes */
  1479         {
  1480           for (compr = compressors; compr->suffix != NULL; compr++)
  1481             {
  1482               compressed_name = concat (file, ".", compr->suffix);
  1483               if (stat (compressed_name, &stat_buf) != 0)
  1484                 {
  1485                   if (MSDOS)
  1486                     {
  1487                       char *suf = compressed_name + strlen (file);
  1488                       size_t suflen = strlen (compr->suffix) + 1;
  1489                       for ( ; suf[1]; suf++, suflen--)
  1490                         {
  1491                           memmove (suf, suf + 1, suflen);
  1492                           if (stat (compressed_name, &stat_buf) == 0)
  1493                             {
  1494                               real_name = compressed_name;
  1495                               break;
  1496                             }
  1497                         }
  1498                       if (real_name != NULL)
  1499                         break;
  1500                     } /* MSDOS */
  1501                   free (compressed_name);
  1502                   compressed_name = NULL;
  1503                 }
  1504               else
  1505                 {
  1506                   real_name = compressed_name;
  1507                   break;
  1508                 }
  1509             }
  1510         }
  1511       if (real_name == NULL)
  1512         {
  1513           perror (file);
  1514           goto cleanup;
  1515         }
  1516     } /* try with a different name */
  1517 
  1518   if (!S_ISREG (stat_buf.st_mode))
  1519     {
  1520       error ("skipping %s: it is not a regular file.", real_name);
  1521       goto cleanup;
  1522     }
  1523   if (real_name == compressed_name)
  1524     {
  1525       char *cmd = concat (compr->command, " ", real_name);
  1526       inf = popen (cmd, "r" FOPEN_BINARY);
  1527       free (cmd);
  1528     }
  1529   else
  1530     inf = fopen (real_name, "r" FOPEN_BINARY);
  1531   if (inf == NULL)
  1532     {
  1533       perror (real_name);
  1534       goto cleanup;
  1535     }
  1536 
  1537   process_file (inf, uncompressed_name, lang);
  1538 
  1539   if (real_name == compressed_name)
  1540     retval = pclose (inf);
  1541   else
  1542     retval = fclose (inf);
  1543   if (retval < 0)
  1544     pfatal (file);
  1545 
  1546  cleanup:
  1547   free (compressed_name);
  1548   free (uncompressed_name);
  1549   last_node = NULL;
  1550   curfdp = NULL;
  1551   return;
  1552 }
  1553 
  1554 static void
  1555 process_file (FILE *fh, char *fn, language *lang)
  1556 {
  1557   static const fdesc emptyfdesc;
  1558   fdesc *fdp;
  1559 
  1560   /* Create a new input file description entry. */
  1561   fdp = xnew (1, fdesc);
  1562   *fdp = emptyfdesc;
  1563   fdp->next = fdhead;
  1564   fdp->infname = savestr (fn);
  1565   fdp->lang = lang;
  1566   fdp->infabsname = absolute_filename (fn, cwd);
  1567   fdp->infabsdir = absolute_dirname (fn, cwd);
  1568   if (filename_is_absolute (fn))
  1569     {
  1570       /* An absolute file name.  Canonicalize it. */
  1571       fdp->taggedfname = absolute_filename (fn, NULL);
  1572     }
  1573   else
  1574     {
  1575       /* A file name relative to cwd.  Make it relative
  1576          to the directory of the tags file. */
  1577       fdp->taggedfname = relative_filename (fn, tagfiledir);
  1578     }
  1579   fdp->usecharno = true;        /* use char position when making tags */
  1580   fdp->prop = NULL;
  1581   fdp->written = false;         /* not written on tags file yet */
  1582 
  1583   fdhead = fdp;
  1584   curfdp = fdhead;              /* the current file description */
  1585 
  1586   find_entries (fh);
  1587 
  1588   /* If not Ctags, and if this is not metasource and if it contained no #line
  1589      directives, we can write the tags and free all nodes pointing to
  1590      curfdp. */
  1591   if (!CTAGS
  1592       && curfdp->usecharno      /* no #line directives in this file */
  1593       && !curfdp->lang->metasource)
  1594     {
  1595       node *np, *prev;
  1596 
  1597       /* Look for the head of the sublist relative to this file.  See add_node
  1598          for the structure of the node tree. */
  1599       prev = NULL;
  1600       for (np = nodehead; np != NULL; prev = np, np = np->left)
  1601         if (np->fdp == curfdp)
  1602           break;
  1603 
  1604       /* If we generated tags for this file, write and delete them. */
  1605       if (np != NULL)
  1606         {
  1607           /* This is the head of the last sublist, if any.  The following
  1608              instructions depend on this being true. */
  1609           assert (np->left == NULL);
  1610 
  1611           assert (fdhead == curfdp);
  1612           assert (last_node->fdp == curfdp);
  1613           put_entries (np);     /* write tags for file curfdp->taggedfname */
  1614           free_tree (np);       /* remove the written nodes */
  1615           if (prev == NULL)
  1616             nodehead = NULL;    /* no nodes left */
  1617           else
  1618             prev->left = NULL;  /* delete the pointer to the sublist */
  1619         }
  1620     }
  1621 }
  1622 
  1623 /*
  1624  * This routine sets up the boolean pseudo-functions which work
  1625  * by setting boolean flags dependent upon the corresponding character.
  1626  * Every char which is NOT in that string is not a white char.  Therefore,
  1627  * all of the array "_wht" is set to false, and then the elements
  1628  * subscripted by the chars in "white" are set to true.  Thus "_wht"
  1629  * of a char is true if it is the string "white", else false.
  1630  */
  1631 static void
  1632 init (void)
  1633 {
  1634   const char *sp;
  1635   int i;
  1636 
  1637   for (i = 0; i < CHARS; i++)
  1638     iswhite (i) = notinname (i) = begtoken (i) = intoken (i) = endtoken (i)
  1639       = false;
  1640   for (sp = white; *sp != '\0'; sp++) iswhite (*sp) = true;
  1641   for (sp = nonam; *sp != '\0'; sp++) notinname (*sp) = true;
  1642   notinname ('\0') = notinname ('\n');
  1643   for (sp = begtk; *sp != '\0'; sp++) begtoken (*sp) = true;
  1644   begtoken ('\0') = begtoken ('\n');
  1645   for (sp = midtk; *sp != '\0'; sp++) intoken (*sp) = true;
  1646   intoken ('\0') = intoken ('\n');
  1647   for (sp = endtk; *sp != '\0'; sp++) endtoken (*sp) = true;
  1648   endtoken ('\0') = endtoken ('\n');
  1649 }
  1650 
  1651 /*
  1652  * This routine opens the specified file and calls the function
  1653  * which finds the function and type definitions.
  1654  */
  1655 static void
  1656 find_entries (FILE *inf)
  1657 {
  1658   char *cp;
  1659   language *lang = curfdp->lang;
  1660   Lang_function *parser = NULL;
  1661 
  1662   /* If user specified a language, use it. */
  1663   if (lang != NULL && lang->function != NULL)
  1664     {
  1665       parser = lang->function;
  1666     }
  1667 
  1668   /* Else try to guess the language given the file name. */
  1669   if (parser == NULL)
  1670     {
  1671       lang = get_language_from_filename (curfdp->infname, true);
  1672       if (lang != NULL && lang->function != NULL)
  1673         {
  1674           curfdp->lang = lang;
  1675           parser = lang->function;
  1676         }
  1677     }
  1678 
  1679   /* Else look for sharp-bang as the first two characters. */
  1680   if (parser == NULL
  1681       && readline_internal (&lb, inf) > 0
  1682       && lb.len >= 2
  1683       && lb.buffer[0] == '#'
  1684       && lb.buffer[1] == '!')
  1685     {
  1686       char *lp;
  1687 
  1688       /* Set lp to point at the first char after the last slash in the
  1689          line or, if no slashes, at the first nonblank.  Then set cp to
  1690          the first successive blank and terminate the string. */
  1691       lp = strrchr (lb.buffer+2, '/');
  1692       if (lp != NULL)
  1693         lp += 1;
  1694       else
  1695         lp = skip_spaces (lb.buffer + 2);
  1696       cp = skip_non_spaces (lp);
  1697       *cp = '\0';
  1698 
  1699       if (strlen (lp) > 0)
  1700         {
  1701           lang = get_language_from_interpreter (lp);
  1702           if (lang != NULL && lang->function != NULL)
  1703             {
  1704               curfdp->lang = lang;
  1705               parser = lang->function;
  1706             }
  1707         }
  1708     }
  1709 
  1710   /* We rewind here, even if inf may be a pipe.  We fail if the
  1711      length of the first line is longer than the pipe block size,
  1712      which is unlikely. */
  1713   rewind (inf);
  1714 
  1715   /* Else try to guess the language given the case insensitive file name. */
  1716   if (parser == NULL)
  1717     {
  1718       lang = get_language_from_filename (curfdp->infname, false);
  1719       if (lang != NULL && lang->function != NULL)
  1720         {
  1721           curfdp->lang = lang;
  1722           parser = lang->function;
  1723         }
  1724     }
  1725 
  1726   /* Else try Fortran or C. */
  1727   if (parser == NULL)
  1728     {
  1729       node *old_last_node = last_node;
  1730 
  1731       curfdp->lang = get_language_from_langname ("fortran");
  1732       find_entries (inf);
  1733 
  1734       if (old_last_node == last_node)
  1735         /* No Fortran entries found.  Try C. */
  1736         {
  1737           /* We do not tag if rewind fails.
  1738              Only the file name will be recorded in the tags file. */
  1739           rewind (inf);
  1740           curfdp->lang = get_language_from_langname (cplusplus ? "c++" : "c");
  1741           find_entries (inf);
  1742         }
  1743       return;
  1744     }
  1745 
  1746   if (!no_line_directive
  1747       && curfdp->lang != NULL && curfdp->lang->metasource)
  1748     /* It may be that this is a bingo.y file, and we already parsed a bingo.c
  1749        file, or anyway we parsed a file that is automatically generated from
  1750        this one.  If this is the case, the bingo.c file contained #line
  1751        directives that generated tags pointing to this file.  Let's delete
  1752        them all before parsing this file, which is the real source. */
  1753     {
  1754       fdesc **fdpp = &fdhead;
  1755       while (*fdpp != NULL)
  1756         if (*fdpp != curfdp
  1757             && streq ((*fdpp)->taggedfname, curfdp->taggedfname))
  1758           /* We found one of those!  We must delete both the file description
  1759              and all tags referring to it. */
  1760           {
  1761             fdesc *badfdp = *fdpp;
  1762 
  1763             /* Delete the tags referring to badfdp->taggedfname
  1764                that were obtained from badfdp->infname. */
  1765             invalidate_nodes (badfdp, &nodehead);
  1766 
  1767             *fdpp = badfdp->next; /* remove the bad description from the list */
  1768             free_fdesc (badfdp);
  1769           }
  1770         else
  1771           fdpp = &(*fdpp)->next; /* advance the list pointer */
  1772     }
  1773 
  1774   assert (parser != NULL);
  1775 
  1776   /* Generic initializations before reading from file. */
  1777   linebuffer_setlen (&filebuf, 0); /* reset the file buffer */
  1778 
  1779   /* Generic initializations before parsing file with readline. */
  1780   lineno = 0;                  /* reset global line number */
  1781   charno = 0;                  /* reset global char number */
  1782   linecharno = 0;              /* reset global char number of line start */
  1783 
  1784   parser (inf);
  1785 
  1786   regex_tag_multiline ();
  1787 }
  1788 
  1789 
  1790 /*
  1791  * Check whether an implicitly named tag should be created,
  1792  * then call `pfnote'.
  1793  * NAME is a string that is internally copied by this function.
  1794  *
  1795  * TAGS format specification
  1796  * Idea by Sam Kendall <kendall@mv.mv.com> (1997)
  1797  * The following is explained in some more detail in etc/ETAGS.EBNF.
  1798  *
  1799  * make_tag creates tags with "implicit tag names" (unnamed tags)
  1800  * if the following are all true, assuming NONAM=" \f\t\n\r()=,;":
  1801  *  1. NAME does not contain any of the characters in NONAM;
  1802  *  2. LINESTART contains name as either a rightmost, or rightmost but
  1803  *     one character, substring;
  1804  *  3. the character, if any, immediately before NAME in LINESTART must
  1805  *     be a character in NONAM;
  1806  *  4. the character, if any, immediately after NAME in LINESTART must
  1807  *     also be a character in NONAM.
  1808  *
  1809  * The implementation uses the notinname() macro, which recognizes the
  1810  * characters stored in the string `nonam'.
  1811  * etags.el needs to use the same characters that are in NONAM.
  1812  */
  1813 static void
  1814 make_tag (const char *name,     /* tag name, or NULL if unnamed */
  1815           int namelen,          /* tag length */
  1816           bool is_func,         /* tag is a function */
  1817           char *linestart,      /* start of the line where tag is */
  1818           int linelen,          /* length of the line where tag is */
  1819           int lno,              /* line number */
  1820           long int cno)         /* character number */
  1821 {
  1822   bool named = (name != NULL && namelen > 0);
  1823   char *nname = NULL;
  1824 
  1825   if (!CTAGS && named)          /* maybe set named to false */
  1826     /* Let's try to make an implicit tag name, that is, create an unnamed tag
  1827        such that etags.el can guess a name from it. */
  1828     {
  1829       int i;
  1830       register const char *cp = name;
  1831 
  1832       for (i = 0; i < namelen; i++)
  1833         if (notinname (*cp++))
  1834           break;
  1835       if (i == namelen)                         /* rule #1 */
  1836         {
  1837           cp = linestart + linelen - namelen;
  1838           if (notinname (linestart[linelen-1]))
  1839             cp -= 1;                            /* rule #4 */
  1840           if (cp >= linestart                   /* rule #2 */
  1841               && (cp == linestart
  1842                   || notinname (cp[-1]))        /* rule #3 */
  1843               && strneq (name, cp, namelen))    /* rule #2 */
  1844             named = false;      /* use implicit tag name */
  1845         }
  1846     }
  1847 
  1848   if (named)
  1849     nname = savenstr (name, namelen);
  1850 
  1851   pfnote (nname, is_func, linestart, linelen, lno, cno);
  1852 }
  1853 
  1854 /* Record a tag. */
  1855 static void
  1856 pfnote (char *name, bool is_func, char *linestart, int linelen, int lno,
  1857         long int cno)
  1858                                 /* tag name, or NULL if unnamed */
  1859                                 /* tag is a function */
  1860                                 /* start of the line where tag is */
  1861                                 /* length of the line where tag is */
  1862                                 /* line number */
  1863                                 /* character number */
  1864 {
  1865   register node *np;
  1866 
  1867   assert (name == NULL || name[0] != '\0');
  1868   if (CTAGS && name == NULL)
  1869     return;
  1870 
  1871   np = xnew (1, node);
  1872 
  1873   /* If ctags mode, change name "main" to M<thisfilename>. */
  1874   if (CTAGS && !cxref_style && streq (name, "main"))
  1875     {
  1876       char *fp = strrchr (curfdp->taggedfname, '/');
  1877       np->name = concat ("M", fp == NULL ? curfdp->taggedfname : fp + 1, "");
  1878       fp = strrchr (np->name, '.');
  1879       if (fp != NULL && fp[1] != '\0' && fp[2] == '\0')
  1880         fp[0] = '\0';
  1881     }
  1882   else
  1883     np->name = name;
  1884   np->valid = true;
  1885   np->been_warned = false;
  1886   np->fdp = curfdp;
  1887   np->is_func = is_func;
  1888   np->lno = lno;
  1889   if (np->fdp->usecharno)
  1890     /* Our char numbers are 0-base, because of C language tradition?
  1891        ctags compatibility?  old versions compatibility?   I don't know.
  1892        Anyway, since emacs's are 1-base we expect etags.el to take care
  1893        of the difference.  If we wanted to have 1-based numbers, we would
  1894        uncomment the +1 below. */
  1895     np->cno = cno /* + 1 */ ;
  1896   else
  1897     np->cno = invalidcharno;
  1898   np->left = np->right = NULL;
  1899   if (CTAGS && !cxref_style)
  1900     {
  1901       if (strlen (linestart) < 50)
  1902         np->regex = concat (linestart, "$", "");
  1903       else
  1904         np->regex = savenstr (linestart, 50);
  1905     }
  1906   else
  1907     np->regex = savenstr (linestart, linelen);
  1908 
  1909   add_node (np, &nodehead);
  1910 }
  1911 
  1912 /*
  1913  * free_tree ()
  1914  *      recurse on left children, iterate on right children.
  1915  */
  1916 static void
  1917 free_tree (register node *np)
  1918 {
  1919   while (np)
  1920     {
  1921       register node *node_right = np->right;
  1922       free_tree (np->left);
  1923       free (np->name);
  1924       free (np->regex);
  1925       free (np);
  1926       np = node_right;
  1927     }
  1928 }
  1929 
  1930 /*
  1931  * free_fdesc ()
  1932  *      delete a file description
  1933  */
  1934 static void
  1935 free_fdesc (register fdesc *fdp)
  1936 {
  1937   free (fdp->infname);
  1938   free (fdp->infabsname);
  1939   free (fdp->infabsdir);
  1940   free (fdp->taggedfname);
  1941   free (fdp->prop);
  1942   free (fdp);
  1943 }
  1944 
  1945 /*
  1946  * add_node ()
  1947  *      Adds a node to the tree of nodes.  In etags mode, sort by file
  1948  *      name.  In ctags mode, sort by tag name.  Make no attempt at
  1949  *      balancing.
  1950  *
  1951  *      add_node is the only function allowed to add nodes, so it can
  1952  *      maintain state.
  1953  */
  1954 static void
  1955 add_node (node *np, node **cur_node_p)
  1956 {
  1957   register int dif;
  1958   register node *cur_node = *cur_node_p;
  1959 
  1960   if (cur_node == NULL)
  1961     {
  1962       *cur_node_p = np;
  1963       last_node = np;
  1964       return;
  1965     }
  1966 
  1967   if (!CTAGS)
  1968     /* Etags Mode */
  1969     {
  1970       /* For each file name, tags are in a linked sublist on the right
  1971          pointer.  The first tags of different files are a linked list
  1972          on the left pointer.  last_node points to the end of the last
  1973          used sublist. */
  1974       if (last_node != NULL && last_node->fdp == np->fdp)
  1975         {
  1976           /* Let's use the same sublist as the last added node. */
  1977           assert (last_node->right == NULL);
  1978           last_node->right = np;
  1979           last_node = np;
  1980         }
  1981       else if (cur_node->fdp == np->fdp)
  1982         {
  1983           /* Scanning the list we found the head of a sublist which is
  1984              good for us.  Let's scan this sublist. */
  1985           add_node (np, &cur_node->right);
  1986         }
  1987       else
  1988         /* The head of this sublist is not good for us.  Let's try the
  1989            next one. */
  1990         add_node (np, &cur_node->left);
  1991     } /* if ETAGS mode */
  1992 
  1993   else
  1994     {
  1995       /* Ctags Mode */
  1996       dif = strcmp (np->name, cur_node->name);
  1997 
  1998       /*
  1999        * If this tag name matches an existing one, then
  2000        * do not add the node, but maybe print a warning.
  2001        */
  2002       if (no_duplicates && !dif)
  2003         {
  2004           if (np->fdp == cur_node->fdp)
  2005             {
  2006               if (!no_warnings)
  2007                 {
  2008                   fprintf (stderr, "Duplicate entry in file %s, line %d: %s\n",
  2009                            np->fdp->infname, lineno, np->name);
  2010                   fprintf (stderr, "Second entry ignored\n");
  2011                 }
  2012             }
  2013           else if (!cur_node->been_warned && !no_warnings)
  2014             {
  2015               fprintf
  2016                 (stderr,
  2017                  "Duplicate entry in files %s and %s: %s (Warning only)\n",
  2018                  np->fdp->infname, cur_node->fdp->infname, np->name);
  2019               cur_node->been_warned = true;
  2020             }
  2021           return;
  2022         }
  2023 
  2024       /* Actually add the node */
  2025       add_node (np, dif < 0 ? &cur_node->left : &cur_node->right);
  2026     } /* if CTAGS mode */
  2027 }
  2028 
  2029 /*
  2030  * invalidate_nodes ()
  2031  *      Scan the node tree and invalidate all nodes pointing to the
  2032  *      given file description (CTAGS case) or free them (ETAGS case).
  2033  */
  2034 static void
  2035 invalidate_nodes (fdesc *badfdp, node **npp)
  2036 {
  2037   node *np = *npp;
  2038 
  2039   if (np == NULL)
  2040     return;
  2041 
  2042   if (CTAGS)
  2043     {
  2044       if (np->left != NULL)
  2045         invalidate_nodes (badfdp, &np->left);
  2046       if (np->fdp == badfdp)
  2047         np->valid = false;
  2048       if (np->right != NULL)
  2049         invalidate_nodes (badfdp, &np->right);
  2050     }
  2051   else
  2052     {
  2053       assert (np->fdp != NULL);
  2054       if (np->fdp == badfdp)
  2055         {
  2056           *npp = np->left;      /* detach the sublist from the list */
  2057           np->left = NULL;      /* isolate it */
  2058           free_tree (np);       /* free it */
  2059           invalidate_nodes (badfdp, npp);
  2060         }
  2061       else
  2062         invalidate_nodes (badfdp, &np->left);
  2063     }
  2064 }
  2065 
  2066 
  2067 static int total_size_of_entries (node *);
  2068 static int number_len (long) ATTRIBUTE_CONST;
  2069 
  2070 /* Length of a non-negative number's decimal representation. */
  2071 static int
  2072 number_len (long int num)
  2073 {
  2074   int len = 1;
  2075   while ((num /= 10) > 0)
  2076     len += 1;
  2077   return len;
  2078 }
  2079 
  2080 /*
  2081  * Return total number of characters that put_entries will output for
  2082  * the nodes in the linked list at the right of the specified node.
  2083  * This count is irrelevant with etags.el since emacs 19.34 at least,
  2084  * but is still supplied for backward compatibility.
  2085  */
  2086 static int
  2087 total_size_of_entries (register node *np)
  2088 {
  2089   register int total = 0;
  2090 
  2091   for (; np != NULL; np = np->right)
  2092     if (np->valid)
  2093       {
  2094         total += strlen (np->regex) + 1;                /* pat\177 */
  2095         if (np->name != NULL)
  2096           total += strlen (np->name) + 1;               /* name\001 */
  2097         total += number_len ((long) np->lno) + 1;       /* lno, */
  2098         if (np->cno != invalidcharno)                   /* cno */
  2099           total += number_len (np->cno);
  2100         total += 1;                                     /* newline */
  2101       }
  2102 
  2103   return total;
  2104 }
  2105 
  2106 static void
  2107 put_entries (register node *np)
  2108 {
  2109   register char *sp;
  2110   static fdesc *fdp = NULL;
  2111 
  2112   if (np == NULL)
  2113     return;
  2114 
  2115   /* Output subentries that precede this one */
  2116   if (CTAGS)
  2117     put_entries (np->left);
  2118 
  2119   /* Output this entry */
  2120   if (np->valid)
  2121     {
  2122       if (!CTAGS)
  2123         {
  2124           /* Etags mode */
  2125           if (fdp != np->fdp)
  2126             {
  2127               fdp = np->fdp;
  2128               fprintf (tagf, "\f\n%s,%d\n",
  2129                        fdp->taggedfname, total_size_of_entries (np));
  2130               fdp->written = true;
  2131             }
  2132           fputs (np->regex, tagf);
  2133           fputc ('\177', tagf);
  2134           if (np->name != NULL)
  2135             {
  2136               fputs (np->name, tagf);
  2137               fputc ('\001', tagf);
  2138             }
  2139           fprintf (tagf, "%d,", np->lno);
  2140           if (np->cno != invalidcharno)
  2141             fprintf (tagf, "%ld", np->cno);
  2142           fputs ("\n", tagf);
  2143         }
  2144       else
  2145         {
  2146           /* Ctags mode */
  2147           if (np->name == NULL)
  2148             error ("internal error: NULL name in ctags mode.");
  2149 
  2150           if (cxref_style)
  2151             {
  2152               if (vgrind_style)
  2153                 fprintf (stdout, "%s %s %d\n",
  2154                          np->name, np->fdp->taggedfname, (np->lno + 63) / 64);
  2155               else
  2156                 fprintf (stdout, "%-16s %3d %-16s %s\n",
  2157                          np->name, np->lno, np->fdp->taggedfname, np->regex);
  2158             }
  2159           else
  2160             {
  2161               fprintf (tagf, "%s\t%s\t", np->name, np->fdp->taggedfname);
  2162 
  2163               if (np->is_func)
  2164                 {               /* function or #define macro with args */
  2165                   putc (searchar, tagf);
  2166                   putc ('^', tagf);
  2167 
  2168                   for (sp = np->regex; *sp; sp++)
  2169                     {
  2170                       if (*sp == '\\' || *sp == searchar)
  2171                         putc ('\\', tagf);
  2172                       putc (*sp, tagf);
  2173                     }
  2174                   putc (searchar, tagf);
  2175                 }
  2176               else
  2177                 {               /* anything else; text pattern inadequate */
  2178                   fprintf (tagf, "%d", np->lno);
  2179                 }
  2180               putc ('\n', tagf);
  2181             }
  2182         }
  2183     } /* if this node contains a valid tag */
  2184 
  2185   /* Output subentries that follow this one */
  2186   put_entries (np->right);
  2187   if (!CTAGS)
  2188     put_entries (np->left);
  2189 }
  2190 
  2191 
  2192 /* C extensions. */
  2193 #define C_EXT   0x00fff         /* C extensions */
  2194 #define C_PLAIN 0x00000         /* C */
  2195 #define C_PLPL  0x00001         /* C++ */
  2196 #define C_STAR  0x00003         /* C* */
  2197 #define C_JAVA  0x00005         /* JAVA */
  2198 #define C_AUTO  0x01000         /* C, but switch to C++ if `class' is met */
  2199 #define YACC    0x10000         /* yacc file */
  2200 
  2201 /*
  2202  * The C symbol tables.
  2203  */
  2204 enum sym_type
  2205 {
  2206   st_none,
  2207   st_C_objprot, st_C_objimpl, st_C_objend,
  2208   st_C_gnumacro,
  2209   st_C_ignore, st_C_attribute,
  2210   st_C_javastruct,
  2211   st_C_operator,
  2212   st_C_class, st_C_template,
  2213   st_C_struct, st_C_extern, st_C_enum, st_C_define, st_C_typedef
  2214 };
  2215 
  2216 /* Feed stuff between (but not including) %[ and %] lines to:
  2217      gperf -m 5
  2218 %[
  2219 %compare-strncmp
  2220 %enum
  2221 %struct-type
  2222 struct C_stab_entry { char *name; int c_ext; enum sym_type type; }
  2223 %%
  2224 if,             0,                      st_C_ignore
  2225 for,            0,                      st_C_ignore
  2226 while,          0,                      st_C_ignore
  2227 switch,         0,                      st_C_ignore
  2228 return,         0,                      st_C_ignore
  2229 __attribute__,  0,                      st_C_attribute
  2230 GTY,            0,                      st_C_attribute
  2231 @interface,     0,                      st_C_objprot
  2232 @protocol,      0,                      st_C_objprot
  2233 @implementation,0,                      st_C_objimpl
  2234 @end,           0,                      st_C_objend
  2235 import,         (C_JAVA & ~C_PLPL),     st_C_ignore
  2236 package,        (C_JAVA & ~C_PLPL),     st_C_ignore
  2237 friend,         C_PLPL,                 st_C_ignore
  2238 extends,        (C_JAVA & ~C_PLPL),     st_C_javastruct
  2239 implements,     (C_JAVA & ~C_PLPL),     st_C_javastruct
  2240 interface,      (C_JAVA & ~C_PLPL),     st_C_struct
  2241 class,          0,                      st_C_class
  2242 namespace,      C_PLPL,                 st_C_struct
  2243 domain,         C_STAR,                 st_C_struct
  2244 union,          0,                      st_C_struct
  2245 struct,         0,                      st_C_struct
  2246 extern,         0,                      st_C_extern
  2247 enum,           0,                      st_C_enum
  2248 typedef,        0,                      st_C_typedef
  2249 define,         0,                      st_C_define
  2250 undef,          0,                      st_C_define
  2251 operator,       C_PLPL,                 st_C_operator
  2252 template,       0,                      st_C_template
  2253 # DEFUN used in emacs, the next three used in glibc (SYSCALL only for mach).
  2254 DEFUN,          0,                      st_C_gnumacro
  2255 SYSCALL,        0,                      st_C_gnumacro
  2256 ENTRY,          0,                      st_C_gnumacro
  2257 PSEUDO,         0,                      st_C_gnumacro
  2258 # These are defined inside C functions, so currently they are not met.
  2259 # EXFUN used in glibc, DEFVAR_* in emacs.
  2260 #EXFUN,         0,                      st_C_gnumacro
  2261 #DEFVAR_,       0,                      st_C_gnumacro
  2262 %]
  2263 and replace lines between %< and %> with its output, then:
  2264  - remove the #if characterset check
  2265  - make in_word_set static and not inline. */
  2266 /*%<*/
  2267 /* C code produced by gperf version 3.0.1 */
  2268 /* Command-line: gperf -m 5  */
  2269 /* Computed positions: -k'2-3' */
  2270 
  2271 struct C_stab_entry { const char *name; int c_ext; enum sym_type type; };
  2272 /* maximum key range = 33, duplicates = 0 */
  2273 
  2274 static int
  2275 hash (const char *str, int len)
  2276 {
  2277   static char const asso_values[] =
  2278     {
  2279       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2280       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2281       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2282       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2283       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2284       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2285       35, 35, 35, 35, 35, 35, 35, 35, 35,  3,
  2286       26, 35, 35, 35, 35, 35, 35, 35, 27, 35,
  2287       35, 35, 35, 24,  0, 35, 35, 35, 35,  0,
  2288       35, 35, 35, 35, 35,  1, 35, 16, 35,  6,
  2289       23,  0,  0, 35, 22,  0, 35, 35,  5,  0,
  2290        0, 15,  1, 35,  6, 35,  8, 19, 35, 16,
  2291        4,  5, 35, 35, 35, 35, 35, 35, 35, 35,
  2292       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2293       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2294       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2295       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2296       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2297       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2298       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2299       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2300       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2301       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2302       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2303       35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
  2304       35, 35, 35, 35, 35, 35
  2305     };
  2306   int hval = len;
  2307 
  2308   switch (hval)
  2309     {
  2310       default:
  2311         hval += asso_values[(unsigned char) str[2]];
  2312       /*FALLTHROUGH*/
  2313       case 2:
  2314         hval += asso_values[(unsigned char) str[1]];
  2315         break;
  2316     }
  2317   return hval;
  2318 }
  2319 
  2320 static struct C_stab_entry *
  2321 in_word_set (register const char *str, register unsigned int len)
  2322 {
  2323   enum
  2324     {
  2325       TOTAL_KEYWORDS = 33,
  2326       MIN_WORD_LENGTH = 2,
  2327       MAX_WORD_LENGTH = 15,
  2328       MIN_HASH_VALUE = 2,
  2329       MAX_HASH_VALUE = 34
  2330     };
  2331 
  2332   static struct C_stab_entry wordlist[] =
  2333     {
  2334       {""}, {""},
  2335       {"if",            0,                      st_C_ignore},
  2336       {"GTY",           0,                      st_C_attribute},
  2337       {"@end",          0,                      st_C_objend},
  2338       {"union",         0,                      st_C_struct},
  2339       {"define",                0,                      st_C_define},
  2340       {"import",                (C_JAVA & ~C_PLPL),     st_C_ignore},
  2341       {"template",      0,                      st_C_template},
  2342       {"operator",      C_PLPL,                 st_C_operator},
  2343       {"@interface",    0,                      st_C_objprot},
  2344       {"implements",    (C_JAVA & ~C_PLPL),     st_C_javastruct},
  2345       {"friend",                C_PLPL,                 st_C_ignore},
  2346       {"typedef",       0,                      st_C_typedef},
  2347       {"return",                0,                      st_C_ignore},
  2348       {"@implementation",0,                     st_C_objimpl},
  2349       {"@protocol",     0,                      st_C_objprot},
  2350       {"interface",     (C_JAVA & ~C_PLPL),     st_C_struct},
  2351       {"extern",                0,                      st_C_extern},
  2352       {"extends",       (C_JAVA & ~C_PLPL),     st_C_javastruct},
  2353       {"struct",                0,                      st_C_struct},
  2354       {"domain",                C_STAR,                 st_C_struct},
  2355       {"switch",                0,                      st_C_ignore},
  2356       {"enum",          0,                      st_C_enum},
  2357       {"for",           0,                      st_C_ignore},
  2358       {"namespace",     C_PLPL,                 st_C_struct},
  2359       {"class",         0,                      st_C_class},
  2360       {"while",         0,                      st_C_ignore},
  2361       {"undef",         0,                      st_C_define},
  2362       {"package",       (C_JAVA & ~C_PLPL),     st_C_ignore},
  2363       {"__attribute__", 0,                      st_C_attribute},
  2364       {"SYSCALL",       0,                      st_C_gnumacro},
  2365       {"ENTRY",         0,                      st_C_gnumacro},
  2366       {"PSEUDO",                0,                      st_C_gnumacro},
  2367       {"DEFUN",         0,                      st_C_gnumacro}
  2368     };
  2369 
  2370   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
  2371     {
  2372       int key = hash (str, len);
  2373 
  2374       if (key <= MAX_HASH_VALUE && key >= 0)
  2375         {
  2376           const char *s = wordlist[key].name;
  2377 
  2378           if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
  2379             return &wordlist[key];
  2380         }
  2381     }
  2382   return 0;
  2383 }
  2384 /*%>*/
  2385 
  2386 static enum sym_type
  2387 C_symtype (char *str, int len, int c_ext)
  2388 {
  2389   register struct C_stab_entry *se = in_word_set (str, len);
  2390 
  2391   if (se == NULL || (se->c_ext && !(c_ext & se->c_ext)))
  2392     return st_none;
  2393   return se->type;
  2394 }
  2395 
  2396 
  2397 /*
  2398  * Ignoring __attribute__ ((list))
  2399  */
  2400 static bool inattribute;        /* looking at an __attribute__ construct */
  2401 
  2402 /*
  2403  * C functions and variables are recognized using a simple
  2404  * finite automaton.  fvdef is its state variable.
  2405  */
  2406 static enum
  2407 {
  2408   fvnone,                       /* nothing seen */
  2409   fdefunkey,                    /* Emacs DEFUN keyword seen */
  2410   fdefunname,                   /* Emacs DEFUN name seen */
  2411   foperator,                    /* func: operator keyword seen (cplpl) */
  2412   fvnameseen,                   /* function or variable name seen */
  2413   fstartlist,                   /* func: just after open parenthesis */
  2414   finlist,                      /* func: in parameter list */
  2415   flistseen,                    /* func: after parameter list */
  2416   fignore,                      /* func: before open brace */
  2417   vignore                       /* var-like: ignore until ';' */
  2418 } fvdef;
  2419 
  2420 static bool fvextern;           /* func or var: extern keyword seen; */
  2421 
  2422 /*
  2423  * typedefs are recognized using a simple finite automaton.
  2424  * typdef is its state variable.
  2425  */
  2426 static enum
  2427 {
  2428   tnone,                        /* nothing seen */
  2429   tkeyseen,                     /* typedef keyword seen */
  2430   ttypeseen,                    /* defined type seen */
  2431   tinbody,                      /* inside typedef body */
  2432   tend,                         /* just before typedef tag */
  2433   tignore                       /* junk after typedef tag */
  2434 } typdef;
  2435 
  2436 /*
  2437  * struct-like structures (enum, struct and union) are recognized
  2438  * using another simple finite automaton.  `structdef' is its state
  2439  * variable.
  2440  */
  2441 static enum
  2442 {
  2443   snone,                        /* nothing seen yet,
  2444                                    or in struct body if bracelev > 0 */
  2445   skeyseen,                     /* struct-like keyword seen */
  2446   stagseen,                     /* struct-like tag seen */
  2447   scolonseen                    /* colon seen after struct-like tag */
  2448 } structdef;
  2449 
  2450 /*
  2451  * When objdef is different from onone, objtag is the name of the class.
  2452  */
  2453 static const char *objtag = "<uninited>";
  2454 
  2455 /*
  2456  * Yet another little state machine to deal with preprocessor lines.
  2457  */
  2458 static enum
  2459 {
  2460   dnone,                        /* nothing seen */
  2461   dsharpseen,                   /* '#' seen as first char on line */
  2462   ddefineseen,                  /* '#' and 'define' seen */
  2463   dignorerest                   /* ignore rest of line */
  2464 } definedef;
  2465 
  2466 /*
  2467  * State machine for Objective C protocols and implementations.
  2468  * Idea by Tom R.Hageman <tom@basil.icce.rug.nl> (1995)
  2469  */
  2470 static enum
  2471 {
  2472   onone,                        /* nothing seen */
  2473   oprotocol,                    /* @interface or @protocol seen */
  2474   oimplementation,              /* @implementations seen */
  2475   otagseen,                     /* class name seen */
  2476   oparenseen,                   /* parenthesis before category seen */
  2477   ocatseen,                     /* category name seen */
  2478   oinbody,                      /* in @implementation body */
  2479   omethodsign,                  /* in @implementation body, after +/- */
  2480   omethodtag,                   /* after method name */
  2481   omethodcolon,                 /* after method colon */
  2482   omethodparm,                  /* after method parameter */
  2483   oignore                       /* wait for @end */
  2484 } objdef;
  2485 
  2486 
  2487 /*
  2488  * Use this structure to keep info about the token read, and how it
  2489  * should be tagged.  Used by the make_C_tag function to build a tag.
  2490  */
  2491 static struct tok
  2492 {
  2493   char *line;                   /* string containing the token */
  2494   int offset;                   /* where the token starts in LINE */
  2495   int length;                   /* token length */
  2496   /*
  2497     The previous members can be used to pass strings around for generic
  2498     purposes.  The following ones specifically refer to creating tags.  In this
  2499     case the token contained here is the pattern that will be used to create a
  2500     tag.
  2501   */
  2502   bool valid;                   /* do not create a tag; the token should be
  2503                                    invalidated whenever a state machine is
  2504                                    reset prematurely */
  2505   bool named;                   /* create a named tag */
  2506   int lineno;                   /* source line number of tag */
  2507   long linepos;                 /* source char number of tag */
  2508 } token;                        /* latest token read */
  2509 
  2510 /*
  2511  * Variables and functions for dealing with nested structures.
  2512  * Idea by Mykola Dzyuba <mdzyuba@yahoo.com> (2001)
  2513  */
  2514 static void pushclass_above (int, char *, int);
  2515 static void popclass_above (int);
  2516 static void write_classname (linebuffer *, const char *qualifier);
  2517 
  2518 static struct {
  2519   char **cname;                 /* nested class names */
  2520   int *bracelev;                /* nested class brace level */
  2521   int nl;                       /* class nesting level (elements used) */
  2522   int size;                     /* length of the array */
  2523 } cstack;                       /* stack for nested declaration tags */
  2524 /* Current struct nesting depth (namespace, class, struct, union, enum). */
  2525 #define nestlev         (cstack.nl)
  2526 /* After struct keyword or in struct body, not inside a nested function. */
  2527 #define instruct        (structdef == snone && nestlev > 0                      \
  2528                          && bracelev == cstack.bracelev[nestlev-1] + 1)
  2529 
  2530 static void
  2531 pushclass_above (int bracelev, char *str, int len)
  2532 {
  2533   int nl;
  2534 
  2535   popclass_above (bracelev);
  2536   nl = cstack.nl;
  2537   if (nl >= cstack.size)
  2538     {
  2539       int size = cstack.size *= 2;
  2540       xrnew (cstack.cname, size, char *);
  2541       xrnew (cstack.bracelev, size, int);
  2542     }
  2543   assert (nl == 0 || cstack.bracelev[nl-1] < bracelev);
  2544   cstack.cname[nl] = (str == NULL) ? NULL : savenstr (str, len);
  2545   cstack.bracelev[nl] = bracelev;
  2546   cstack.nl = nl + 1;
  2547 }
  2548 
  2549 static void
  2550 popclass_above (int bracelev)
  2551 {
  2552   int nl;
  2553 
  2554   for (nl = cstack.nl - 1;
  2555        nl >= 0 && cstack.bracelev[nl] >= bracelev;
  2556        nl--)
  2557     {
  2558       free (cstack.cname[nl]);
  2559       cstack.nl = nl;
  2560     }
  2561 }
  2562 
  2563 static void
  2564 write_classname (linebuffer *cn, const char *qualifier)
  2565 {
  2566   int i, len;
  2567   int qlen = strlen (qualifier);
  2568 
  2569   if (cstack.nl == 0 || cstack.cname[0] == NULL)
  2570     {
  2571       len = 0;
  2572       cn->len = 0;
  2573       cn->buffer[0] = '\0';
  2574     }
  2575   else
  2576     {
  2577       len = strlen (cstack.cname[0]);
  2578       linebuffer_setlen (cn, len);
  2579       strcpy (cn->buffer, cstack.cname[0]);
  2580     }
  2581   for (i = 1; i < cstack.nl; i++)
  2582     {
  2583       char *s = cstack.cname[i];
  2584       if (s == NULL)
  2585         continue;
  2586       linebuffer_setlen (cn, len + qlen + strlen (s));
  2587       len += sprintf (cn->buffer + len, "%s%s", qualifier, s);
  2588     }
  2589 }
  2590 
  2591 
  2592 static bool consider_token (char *, int, int, int *, int, int, bool *);
  2593 static void make_C_tag (bool);
  2594 
  2595 /*
  2596  * consider_token ()
  2597  *      checks to see if the current token is at the start of a
  2598  *      function or variable, or corresponds to a typedef, or
  2599  *      is a struct/union/enum tag, or #define, or an enum constant.
  2600  *
  2601  *      *IS_FUNC_OR_VAR gets true if the token is a function or #define macro
  2602  *      with args.  C_EXTP points to which language we are looking at.
  2603  *
  2604  * Globals
  2605  *      fvdef                   IN OUT
  2606  *      structdef               IN OUT
  2607  *      definedef               IN OUT
  2608  *      typdef                  IN OUT
  2609  *      objdef                  IN OUT
  2610  */
  2611 
  2612 static bool
  2613 consider_token (char *str, int len, int c, int *c_extp,
  2614                 int bracelev, int parlev, bool *is_func_or_var)
  2615                                 /* IN: token pointer */
  2616                                 /* IN: token length */
  2617                                 /* IN: first char after the token */
  2618                                 /* IN, OUT: C extensions mask */
  2619                                 /* IN: brace level */
  2620                                 /* IN: parenthesis level */
  2621                                 /* OUT: function or variable found */
  2622 {
  2623   /* When structdef is stagseen, scolonseen, or snone with bracelev > 0,
  2624      structtype is the type of the preceding struct-like keyword, and
  2625      structbracelev is the brace level where it has been seen. */
  2626   static enum sym_type structtype;
  2627   static int structbracelev;
  2628   static enum sym_type toktype;
  2629 
  2630 
  2631   toktype = C_symtype (str, len, *c_extp);
  2632 
  2633   /*
  2634    * Skip __attribute__
  2635    */
  2636   if (toktype == st_C_attribute)
  2637     {
  2638       inattribute = true;
  2639       return false;
  2640      }
  2641 
  2642    /*
  2643     * Advance the definedef state machine.
  2644     */
  2645    switch (definedef)
  2646      {
  2647      case dnone:
  2648        /* We're not on a preprocessor line. */
  2649        if (toktype == st_C_gnumacro)
  2650          {
  2651            fvdef = fdefunkey;
  2652            return false;
  2653          }
  2654        break;
  2655      case dsharpseen:
  2656        if (toktype == st_C_define)
  2657          {
  2658            definedef = ddefineseen;
  2659          }
  2660        else
  2661          {
  2662            definedef = dignorerest;
  2663          }
  2664        return false;
  2665      case ddefineseen:
  2666        /*
  2667         * Make a tag for any macro, unless it is a constant
  2668         * and constantypedefs is false.
  2669         */
  2670        definedef = dignorerest;
  2671        *is_func_or_var = (c == '(');
  2672        if (!*is_func_or_var && !constantypedefs)
  2673          return false;
  2674        else
  2675          return true;
  2676      case dignorerest:
  2677        return false;
  2678      default:
  2679        error ("internal error: definedef value.");
  2680      }
  2681 
  2682    /*
  2683     * Now typedefs
  2684     */
  2685    switch (typdef)
  2686      {
  2687      case tnone:
  2688        if (toktype == st_C_typedef)
  2689          {
  2690            if (typedefs)
  2691              typdef = tkeyseen;
  2692            fvextern = false;
  2693            fvdef = fvnone;
  2694            return false;
  2695          }
  2696        break;
  2697      case tkeyseen:
  2698        switch (toktype)
  2699          {
  2700          case st_none:
  2701          case st_C_class:
  2702          case st_C_struct:
  2703          case st_C_enum:
  2704            typdef = ttypeseen;
  2705          }
  2706        break;
  2707      case ttypeseen:
  2708        if (structdef == snone && fvdef == fvnone)
  2709          {
  2710            fvdef = fvnameseen;
  2711            return true;
  2712          }
  2713        break;
  2714      case tend:
  2715        switch (toktype)
  2716          {
  2717          case st_C_class:
  2718          case st_C_struct:
  2719          case st_C_enum:
  2720            return false;
  2721          }
  2722        return true;
  2723      }
  2724 
  2725    switch (toktype)
  2726      {
  2727      case st_C_javastruct:
  2728        if (structdef == stagseen)
  2729          structdef = scolonseen;
  2730        return false;
  2731      case st_C_template:
  2732      case st_C_class:
  2733        if ((*c_extp & C_AUTO)   /* automatic detection of C++ language */
  2734            && bracelev == 0
  2735            && definedef == dnone && structdef == snone
  2736            && typdef == tnone && fvdef == fvnone)
  2737          *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
  2738        if (toktype == st_C_template)
  2739          break;
  2740        /* FALLTHRU */
  2741      case st_C_struct:
  2742      case st_C_enum:
  2743        if (parlev == 0
  2744            && fvdef != vignore
  2745            && (typdef == tkeyseen
  2746                || (typedefs_or_cplusplus && structdef == snone)))
  2747          {
  2748            structdef = skeyseen;
  2749            structtype = toktype;
  2750            structbracelev = bracelev;
  2751            if (fvdef == fvnameseen)
  2752              fvdef = fvnone;
  2753          }
  2754        return false;
  2755      }
  2756 
  2757    if (structdef == skeyseen)
  2758      {
  2759        structdef = stagseen;
  2760        return true;
  2761      }
  2762 
  2763    if (typdef != tnone)
  2764      definedef = dnone;
  2765 
  2766    /* Detect Objective C constructs. */
  2767    switch (objdef)
  2768      {
  2769      case onone:
  2770        switch (toktype)
  2771          {
  2772          case st_C_objprot:
  2773            objdef = oprotocol;
  2774            return false;
  2775          case st_C_objimpl:
  2776            objdef = oimplementation;
  2777            return false;
  2778          }
  2779        break;
  2780      case oimplementation:
  2781        /* Save the class tag for functions or variables defined inside. */
  2782        objtag = savenstr (str, len);
  2783        objdef = oinbody;
  2784        return false;
  2785      case oprotocol:
  2786        /* Save the class tag for categories. */
  2787        objtag = savenstr (str, len);
  2788        objdef = otagseen;
  2789        *is_func_or_var = true;
  2790        return true;
  2791      case oparenseen:
  2792        objdef = ocatseen;
  2793        *is_func_or_var = true;
  2794        return true;
  2795      case oinbody:
  2796        break;
  2797      case omethodsign:
  2798        if (parlev == 0)
  2799          {
  2800            fvdef = fvnone;
  2801            objdef = omethodtag;
  2802            linebuffer_setlen (&token_name, len);
  2803            memcpy (token_name.buffer, str, len);
  2804            token_name.buffer[len] = '\0';
  2805            return true;
  2806          }
  2807        return false;
  2808      case omethodcolon:
  2809        if (parlev == 0)
  2810          objdef = omethodparm;
  2811        return false;
  2812      case omethodparm:
  2813        if (parlev == 0)
  2814          {
  2815            int oldlen = token_name.len;
  2816            fvdef = fvnone;
  2817            objdef = omethodtag;
  2818            linebuffer_setlen (&token_name, oldlen + len);
  2819            memcpy (token_name.buffer + oldlen, str, len);
  2820            token_name.buffer[oldlen + len] = '\0';
  2821            return true;
  2822          }
  2823        return false;
  2824      case oignore:
  2825        if (toktype == st_C_objend)
  2826          {
  2827            /* Memory leakage here: the string pointed by objtag is
  2828               never released, because many tests would be needed to
  2829               avoid breaking on incorrect input code.  The amount of
  2830               memory leaked here is the sum of the lengths of the
  2831               class tags.
  2832            free (objtag); */
  2833            objdef = onone;
  2834          }
  2835        return false;
  2836      }
  2837 
  2838    /* A function, variable or enum constant? */
  2839    switch (toktype)
  2840      {
  2841      case st_C_extern:
  2842        fvextern = true;
  2843        switch  (fvdef)
  2844          {
  2845          case finlist:
  2846          case flistseen:
  2847          case fignore:
  2848          case vignore:
  2849            break;
  2850          default:
  2851            fvdef = fvnone;
  2852          }
  2853        return false;
  2854      case st_C_ignore:
  2855        fvextern = false;
  2856        fvdef = vignore;
  2857        return false;
  2858      case st_C_operator:
  2859        fvdef = foperator;
  2860        *is_func_or_var = true;
  2861        return true;
  2862      case st_none:
  2863        if (constantypedefs
  2864            && structdef == snone
  2865            && structtype == st_C_enum && bracelev > structbracelev
  2866            /* Don't tag tokens in expressions that assign values to enum
  2867               constants.  */
  2868            && fvdef != vignore)
  2869          return true;           /* enum constant */
  2870        switch (fvdef)
  2871          {
  2872          case fdefunkey:
  2873            if (bracelev > 0)
  2874              break;
  2875            fvdef = fdefunname;  /* GNU macro */
  2876            *is_func_or_var = true;
  2877            return true;
  2878          case fvnone:
  2879            switch (typdef)
  2880              {
  2881              case ttypeseen:
  2882                return false;
  2883              case tnone:
  2884                if ((strneq (str, "asm", 3) && endtoken (str[3]))
  2885                    || (strneq (str, "__asm__", 7) && endtoken (str[7])))
  2886                  {
  2887                    fvdef = vignore;
  2888                    return false;
  2889                  }
  2890                break;
  2891              }
  2892           /* FALLTHRU */
  2893           case fvnameseen:
  2894           if (len >= 10 && strneq (str+len-10, "::operator", 10))
  2895             {
  2896               if (*c_extp & C_AUTO) /* automatic detection of C++ */
  2897                 *c_extp = (*c_extp | C_PLPL) & ~C_AUTO;
  2898               fvdef = foperator;
  2899               *is_func_or_var = true;
  2900               return true;
  2901             }
  2902           if (bracelev > 0 && !instruct)
  2903             break;
  2904           fvdef = fvnameseen;   /* function or variable */
  2905           *is_func_or_var = true;
  2906           return true;
  2907         }
  2908       break;
  2909     }
  2910 
  2911   return false;
  2912 }
  2913 
  2914 
  2915 /*
  2916  * C_entries often keeps pointers to tokens or lines which are older than
  2917  * the line currently read.  By keeping two line buffers, and switching
  2918  * them at end of line, it is possible to use those pointers.
  2919  */
  2920 static struct
  2921 {
  2922   long linepos;
  2923   linebuffer lb;
  2924 } lbs[2];
  2925 
  2926 #define current_lb_is_new (newndx == curndx)
  2927 #define switch_line_buffers() (curndx = 1 - curndx)
  2928 
  2929 #define curlb (lbs[curndx].lb)
  2930 #define newlb (lbs[newndx].lb)
  2931 #define curlinepos (lbs[curndx].linepos)
  2932 #define newlinepos (lbs[newndx].linepos)
  2933 
  2934 #define plainc ((c_ext & C_EXT) == C_PLAIN)
  2935 #define cplpl (c_ext & C_PLPL)
  2936 #define cjava ((c_ext & C_JAVA) == C_JAVA)
  2937 
  2938 #define CNL_SAVE_DEFINEDEF()                                            \
  2939 do {                                                                    \
  2940   curlinepos = charno;                                                  \
  2941   readline (&curlb, inf);                                               \
  2942   lp = curlb.buffer;                                                    \
  2943   quotednl = false;                                                     \
  2944   newndx = curndx;                                                      \
  2945 } while (0)
  2946 
  2947 #define CNL()                                                           \
  2948 do {                                                                    \
  2949   CNL_SAVE_DEFINEDEF();                                                 \
  2950   if (savetoken.valid)                                                  \
  2951     {                                                                   \
  2952       token = savetoken;                                                \
  2953       savetoken.valid = false;                                          \
  2954     }                                                                   \
  2955   definedef = dnone;                                                    \
  2956 } while (0)
  2957 
  2958 
  2959 static void
  2960 make_C_tag (bool isfun)
  2961 {
  2962   /* This function is never called when token.valid is false, but
  2963      we must protect against invalid input or internal errors. */
  2964   if (token.valid)
  2965     make_tag (token_name.buffer, token_name.len, isfun, token.line,
  2966               token.offset+token.length+1, token.lineno, token.linepos);
  2967   else if (DEBUG)
  2968     {                             /* this branch is optimized away if !DEBUG */
  2969       make_tag (concat ("INVALID TOKEN:-->", token_name.buffer, ""),
  2970                 token_name.len + 17, isfun, token.line,
  2971                 token.offset+token.length+1, token.lineno, token.linepos);
  2972       error ("INVALID TOKEN");
  2973     }
  2974 
  2975   token.valid = false;
  2976 }
  2977 
  2978 
  2979 /*
  2980  * C_entries ()
  2981  *      This routine finds functions, variables, typedefs,
  2982  *      #define's, enum constants and struct/union/enum definitions in
  2983  *      C syntax and adds them to the list.
  2984  */
  2985 static void
  2986 C_entries (int c_ext, FILE *inf)
  2987                                 /* extension of C */
  2988                                 /* input file */
  2989 {
  2990   register char c;              /* latest char read; '\0' for end of line */
  2991   register char *lp;            /* pointer one beyond the character `c' */
  2992   int curndx, newndx;           /* indices for current and new lb */
  2993   register int tokoff;          /* offset in line of start of current token */
  2994   register int toklen;          /* length of current token */
  2995   const char *qualifier;        /* string used to qualify names */
  2996   int qlen;                     /* length of qualifier */
  2997   int bracelev;                 /* current brace level */
  2998   int bracketlev;               /* current bracket level */
  2999   int parlev;                   /* current parenthesis level */
  3000   int attrparlev;               /* __attribute__ parenthesis level */
  3001   int templatelev;              /* current template level */
  3002   int typdefbracelev;           /* bracelev where a typedef struct body begun */
  3003   bool incomm, inquote, inchar, quotednl, midtoken;
  3004   bool yacc_rules;              /* in the rules part of a yacc file */
  3005   struct tok savetoken = {0};   /* token saved during preprocessor handling */
  3006 
  3007 
  3008   linebuffer_init (&lbs[0].lb);
  3009   linebuffer_init (&lbs[1].lb);
  3010   if (cstack.size == 0)
  3011     {
  3012       cstack.size = (DEBUG) ? 1 : 4;
  3013       cstack.nl = 0;
  3014       cstack.cname = xnew (cstack.size, char *);
  3015       cstack.bracelev = xnew (cstack.size, int);
  3016     }
  3017 
  3018   tokoff = toklen = typdefbracelev = 0; /* keep compiler quiet */
  3019   curndx = newndx = 0;
  3020   lp = curlb.buffer;
  3021   *lp = 0;
  3022 
  3023   fvdef = fvnone; fvextern = false; typdef = tnone;
  3024   structdef = snone; definedef = dnone; objdef = onone;
  3025   yacc_rules = false;
  3026   midtoken = inquote = inchar = incomm = quotednl = false;
  3027   token.valid = savetoken.valid = false;
  3028   bracelev = bracketlev = parlev = attrparlev = templatelev = 0;
  3029   if (cjava)
  3030     { qualifier = "."; qlen = 1; }
  3031   else
  3032     { qualifier = "::"; qlen = 2; }
  3033 
  3034 
  3035   while (!feof (inf))
  3036     {
  3037       c = *lp++;
  3038       if (c == '\\')
  3039         {
  3040           /* If we are at the end of the line, the next character is a
  3041              '\0'; do not skip it, because it is what tells us
  3042              to read the next line.  */
  3043           if (*lp == '\0')
  3044             {
  3045               quotednl = true;
  3046               continue;
  3047             }
  3048           lp++;
  3049           c = ' ';
  3050         }
  3051       else if (incomm)
  3052         {
  3053           switch (c)
  3054             {
  3055             case '*':
  3056               if (*lp == '/')
  3057                 {
  3058                   c = *lp++;
  3059                   incomm = false;
  3060                 }
  3061               break;
  3062             case '\0':
  3063               /* Newlines inside comments do not end macro definitions in
  3064                  traditional cpp. */
  3065               CNL_SAVE_DEFINEDEF ();
  3066               break;
  3067             }
  3068           continue;
  3069         }
  3070       else if (inquote)
  3071         {
  3072           switch (c)
  3073             {
  3074             case '"':
  3075               inquote = false;
  3076               break;
  3077             case '\0':
  3078               /* Newlines inside strings do not end macro definitions
  3079                  in traditional cpp, even though compilers don't
  3080                  usually accept them. */
  3081               CNL_SAVE_DEFINEDEF ();
  3082               break;
  3083             }
  3084           continue;
  3085         }
  3086       else if (inchar)
  3087         {
  3088           switch (c)
  3089             {
  3090             case '\0':
  3091               /* Hmmm, something went wrong. */
  3092               CNL ();
  3093               /* FALLTHRU */
  3094             case '\'':
  3095               inchar = false;
  3096               break;
  3097             }
  3098           continue;
  3099         }
  3100       else switch (c)
  3101         {
  3102         case '"':
  3103           inquote = true;
  3104           if (bracketlev > 0)
  3105             continue;
  3106           if (inattribute)
  3107             break;
  3108           switch (fvdef)
  3109             {
  3110             case fdefunkey:
  3111             case fstartlist:
  3112             case finlist:
  3113             case fignore:
  3114             case vignore:
  3115               break;
  3116             default:
  3117               fvextern = false;
  3118               fvdef = fvnone;
  3119             }
  3120           continue;
  3121         case '\'':
  3122           inchar = true;
  3123           if (bracketlev > 0)
  3124             continue;
  3125           if (inattribute)
  3126             break;
  3127           if (fvdef != finlist && fvdef != fignore && fvdef != vignore)
  3128             {
  3129               fvextern = false;
  3130               fvdef = fvnone;
  3131             }
  3132           continue;
  3133         case '/':
  3134           if (*lp == '*')
  3135             {
  3136               incomm = true;
  3137               lp++;
  3138               c = ' ';
  3139               if (bracketlev > 0)
  3140                 continue;
  3141             }
  3142           else if (/* cplpl && */ *lp == '/')
  3143             {
  3144               c = '\0';
  3145             }
  3146           break;
  3147         case '%':
  3148           if ((c_ext & YACC) && *lp == '%')
  3149             {
  3150               /* Entering or exiting rules section in yacc file. */
  3151               lp++;
  3152               definedef = dnone; fvdef = fvnone; fvextern = false;
  3153               typdef = tnone; structdef = snone;
  3154               midtoken = inquote = inchar = incomm = quotednl = false;
  3155               bracelev = 0;
  3156               yacc_rules = !yacc_rules;
  3157               continue;
  3158             }
  3159           else
  3160             break;
  3161         case '#':
  3162           if (definedef == dnone)
  3163             {
  3164               char *cp;
  3165               bool cpptoken = true;
  3166 
  3167               /* Look back on this line.  If all blanks, or nonblanks
  3168                  followed by an end of comment, this is a preprocessor
  3169                  token. */
  3170               for (cp = newlb.buffer; cp < lp-1; cp++)
  3171                 if (!iswhite (*cp))
  3172                   {
  3173                     if (*cp == '*' && cp[1] == '/')
  3174                       {
  3175                         cp++;
  3176                         cpptoken = true;
  3177                       }
  3178                     else
  3179                       cpptoken = false;
  3180                   }
  3181               if (cpptoken)
  3182                 {
  3183                   definedef = dsharpseen;
  3184                   /* This is needed for tagging enum values: when there are
  3185                      preprocessor conditionals inside the enum, we need to
  3186                      reset the value of fvdef so that the next enum value is
  3187                      tagged even though the one before it did not end in a
  3188                      comma.  */
  3189                   if (fvdef == vignore && instruct && parlev == 0)
  3190                     {
  3191                       if (strneq (cp, "#if", 3) || strneq (cp, "#el", 3))
  3192                         fvdef = fvnone;
  3193                     }
  3194                 }
  3195             } /* if (definedef == dnone) */
  3196           continue;
  3197         case '[':
  3198           bracketlev++;
  3199           continue;
  3200         default:
  3201           if (bracketlev > 0)
  3202             {
  3203               if (c == ']')
  3204                 --bracketlev;
  3205               else if (c == '\0')
  3206                 CNL_SAVE_DEFINEDEF ();
  3207               continue;
  3208             }
  3209           break;
  3210         } /* switch (c) */
  3211 
  3212 
  3213       /* Consider token only if some involved conditions are satisfied. */
  3214       if (typdef != tignore
  3215           && definedef != dignorerest
  3216           && fvdef != finlist
  3217           && templatelev == 0
  3218           && (definedef != dnone
  3219               || structdef != scolonseen)
  3220           && !inattribute)
  3221         {
  3222           if (midtoken)
  3223             {
  3224               if (endtoken (c))
  3225                 {
  3226                   if (c == ':' && *lp == ':' && begtoken (lp[1]))
  3227                     /* This handles :: in the middle,
  3228                        but not at the beginning of an identifier.
  3229                        Also, space-separated :: is not recognized. */
  3230                     {
  3231                       if (c_ext & C_AUTO) /* automatic detection of C++ */
  3232                         c_ext = (c_ext | C_PLPL) & ~C_AUTO;
  3233                       lp += 2;
  3234                       toklen += 2;
  3235                       c = lp[-1];
  3236                       goto still_in_token;
  3237                     }
  3238                   else
  3239                     {
  3240                       bool funorvar = false;
  3241 
  3242                       if (yacc_rules
  3243                           || consider_token (newlb.buffer + tokoff, toklen, c,
  3244                                              &c_ext, bracelev, parlev,
  3245                                              &funorvar))
  3246                         {
  3247                           if (fvdef == foperator)
  3248                             {
  3249                               char *oldlp = lp;
  3250                               lp = skip_spaces (lp-1);
  3251                               if (*lp != '\0')
  3252                                 lp += 1;
  3253                               while (*lp != '\0'
  3254                                      && !iswhite (*lp) && *lp != '(')
  3255                                 lp += 1;
  3256                               c = *lp++;
  3257                               toklen += lp - oldlp;
  3258                             }
  3259                           token.named = false;
  3260                           if (!plainc
  3261                               && nestlev > 0 && definedef == dnone)
  3262                             /* in struct body */
  3263                             {
  3264                               int len;
  3265                               write_classname (&token_name, qualifier);
  3266                               len = token_name.len;
  3267                               linebuffer_setlen (&token_name, len+qlen+toklen);
  3268                               sprintf (token_name.buffer + len, "%s%.*s",
  3269                                        qualifier, toklen, newlb.buffer + tokoff);
  3270                               token.named = true;
  3271                             }
  3272                           else if (objdef == ocatseen)
  3273                             /* Objective C category */
  3274                             {
  3275                               int len = strlen (objtag) + 2 + toklen;
  3276                               linebuffer_setlen (&token_name, len);
  3277                               sprintf (token_name.buffer, "%s(%.*s)",
  3278                                        objtag, toklen, newlb.buffer + tokoff);
  3279                               token.named = true;
  3280                             }
  3281                           else if (objdef == omethodtag
  3282                                    || objdef == omethodparm)
  3283                             /* Objective C method */
  3284                             {
  3285                               token.named = true;
  3286                             }
  3287                           else if (fvdef == fdefunname)
  3288                             /* GNU DEFUN and similar macros */
  3289                             {
  3290                               bool defun = (newlb.buffer[tokoff] == 'F');
  3291                               int off = tokoff;
  3292                               int len = toklen;
  3293 
  3294                               /* Rewrite the tag so that emacs lisp DEFUNs
  3295                                  can be found by their elisp name */
  3296                               if (defun)
  3297                                 {
  3298                                   off += 1;
  3299                                   len -= 1;
  3300                                 }
  3301                               linebuffer_setlen (&token_name, len);
  3302                               memcpy (token_name.buffer,
  3303                                       newlb.buffer + off, len);
  3304                               token_name.buffer[len] = '\0';
  3305                               if (defun)
  3306                                 while (--len >= 0)
  3307                                   if (token_name.buffer[len] == '_')
  3308                                     token_name.buffer[len] = '-';
  3309                               token.named = defun;
  3310                             }
  3311                           else
  3312                             {
  3313                               linebuffer_setlen (&token_name, toklen);
  3314                               memcpy (token_name.buffer,
  3315                                       newlb.buffer + tokoff, toklen);
  3316                               token_name.buffer[toklen] = '\0';
  3317                               /* Name macros and members. */
  3318                               token.named = (structdef == stagseen
  3319                                              || typdef == ttypeseen
  3320                                              || typdef == tend
  3321                                              || (funorvar
  3322                                                  && definedef == dignorerest)
  3323                                              || (funorvar
  3324                                                  && definedef == dnone
  3325                                                  && structdef == snone
  3326                                                  && bracelev > 0));
  3327                             }
  3328                           token.lineno = lineno;
  3329                           token.offset = tokoff;
  3330                           token.length = toklen;
  3331                           token.line = newlb.buffer;
  3332                           token.linepos = newlinepos;
  3333                           token.valid = true;
  3334 
  3335                           if (definedef == dnone
  3336                               && (fvdef == fvnameseen
  3337                                   || fvdef == foperator
  3338                                   || structdef == stagseen
  3339                                   || typdef == tend
  3340                                   || typdef == ttypeseen
  3341                                   || objdef != onone))
  3342                             {
  3343                               if (current_lb_is_new)
  3344                                 switch_line_buffers ();
  3345                             }
  3346                           else if (definedef != dnone
  3347                                    || fvdef == fdefunname
  3348                                    || instruct)
  3349                             make_C_tag (funorvar);
  3350                         }
  3351                       else /* not yacc and consider_token failed */
  3352                         {
  3353                           if (inattribute && fvdef == fignore)
  3354                             {
  3355                               /* We have just met __attribute__ after a
  3356                                  function parameter list: do not tag the
  3357                                  function again. */
  3358                               fvdef = fvnone;
  3359                             }
  3360                         }
  3361                       midtoken = false;
  3362                     }
  3363                 } /* if (endtoken (c)) */
  3364               else if (intoken (c))
  3365                 still_in_token:
  3366                 {
  3367                   toklen++;
  3368                   continue;
  3369                 }
  3370             } /* if (midtoken) */
  3371           else if (begtoken (c))
  3372             {
  3373               switch (definedef)
  3374                 {
  3375                 case dnone:
  3376                   switch (fvdef)
  3377                     {
  3378                     case fstartlist:
  3379                       /* This prevents tagging fb in
  3380                          void (__attribute__((noreturn)) *fb) (void);
  3381                          Fixing this is not easy and not very important. */
  3382                       fvdef = finlist;
  3383                       continue;
  3384                     case flistseen:
  3385                       if (plainc || declarations)
  3386                         {
  3387                           make_C_tag (true); /* a function */
  3388                           fvdef = fignore;
  3389                         }
  3390                       break;
  3391                     }
  3392                   if (structdef == stagseen && !cjava)
  3393                     {
  3394                       popclass_above (bracelev);
  3395                       structdef = snone;
  3396                     }
  3397                   break;
  3398                 case dsharpseen:
  3399                   savetoken = token;
  3400                   break;
  3401                 }
  3402               if (!yacc_rules || lp == newlb.buffer + 1)
  3403                 {
  3404                   tokoff = lp - 1 - newlb.buffer;
  3405                   toklen = 1;
  3406                   midtoken = true;
  3407                 }
  3408               continue;
  3409             } /* if (begtoken) */
  3410         } /* if must look at token */
  3411 
  3412 
  3413       /* Detect end of line, colon, comma, semicolon and various braces
  3414          after having handled a token.*/
  3415       switch (c)
  3416         {
  3417         case ':':
  3418           if (inattribute)
  3419             break;
  3420           if (yacc_rules && token.offset == 0 && token.valid)
  3421             {
  3422               make_C_tag (false); /* a yacc function */
  3423               break;
  3424             }
  3425           if (definedef != dnone)
  3426             break;
  3427           switch (objdef)
  3428             {
  3429             case  otagseen:
  3430               objdef = oignore;
  3431               make_C_tag (true); /* an Objective C class */
  3432               break;
  3433             case omethodtag:
  3434             case omethodparm:
  3435               objdef = omethodcolon;
  3436               int toklen = token_name.len;
  3437               linebuffer_setlen (&token_name, toklen + 1);
  3438               strcpy (token_name.buffer + toklen, ":");
  3439               break;
  3440             }
  3441           if (structdef == stagseen)
  3442             {
  3443               structdef = scolonseen;
  3444               break;
  3445             }
  3446           /* Should be useless, but may be work as a safety net. */
  3447           if (cplpl && fvdef == flistseen)
  3448             {
  3449               make_C_tag (true); /* a function */
  3450               fvdef = fignore;
  3451               break;
  3452             }
  3453           break;
  3454         case ';':
  3455           if (definedef != dnone || inattribute)
  3456             break;
  3457           switch (typdef)
  3458             {
  3459             case tend:
  3460             case ttypeseen:
  3461               make_C_tag (false); /* a typedef */
  3462               typdef = tnone;
  3463               fvdef = fvnone;
  3464               break;
  3465             case tnone:
  3466             case tinbody:
  3467             case tignore:
  3468               switch (fvdef)
  3469                 {
  3470                 case fignore:
  3471                   if (typdef == tignore || cplpl)
  3472                     fvdef = fvnone;
  3473                   break;
  3474                 case fvnameseen:
  3475                   if ((globals && bracelev == 0 && (!fvextern || declarations))
  3476                       || (members && instruct))
  3477                     make_C_tag (false); /* a variable */
  3478                   fvextern = false;
  3479                   fvdef = fvnone;
  3480                   token.valid = false;
  3481                   break;
  3482                 case flistseen:
  3483                   if ((declarations
  3484                        && (cplpl || !instruct)
  3485                        && (typdef == tnone || (typdef != tignore && instruct)))
  3486                       || (members
  3487                           && plainc && instruct))
  3488                     make_C_tag (true);  /* a function */
  3489                   /* FALLTHRU */
  3490                 default:
  3491                   fvextern = false;
  3492                   fvdef = fvnone;
  3493                   if (declarations
  3494                        && cplpl && structdef == stagseen)
  3495                     make_C_tag (false); /* forward declaration */
  3496                   else
  3497                     token.valid = false;
  3498                 } /* switch (fvdef) */
  3499               /* FALLTHRU */
  3500             default:
  3501               if (!instruct)
  3502                 typdef = tnone;
  3503             }
  3504           if (structdef == stagseen)
  3505             structdef = snone;
  3506           break;
  3507         case ',':
  3508           if (definedef != dnone || inattribute)
  3509             break;
  3510           switch (objdef)
  3511             {
  3512             case omethodtag:
  3513             case omethodparm:
  3514               make_C_tag (true); /* an Objective C method */
  3515               objdef = oinbody;
  3516               break;
  3517             }
  3518           switch (fvdef)
  3519             {
  3520             case fdefunkey:
  3521             case foperator:
  3522             case fstartlist:
  3523             case finlist:
  3524             case fignore:
  3525               break;
  3526             case vignore:
  3527               if (instruct && parlev == 0)
  3528                 fvdef = fvnone;
  3529               break;
  3530             case fdefunname:
  3531               fvdef = fignore;
  3532               break;
  3533             case fvnameseen:
  3534               if (parlev == 0
  3535                   && ((globals
  3536                        && bracelev == 0
  3537                        && templatelev == 0
  3538                        && (!fvextern || declarations))
  3539                       || (members && instruct)))
  3540                   make_C_tag (false); /* a variable */
  3541               break;
  3542             case flistseen:
  3543               if ((declarations && typdef == tnone && !instruct)
  3544                   || (members && typdef != tignore && instruct))
  3545                 {
  3546                   make_C_tag (true); /* a function */
  3547                   fvdef = fvnameseen;
  3548                 }
  3549               else if (!declarations)
  3550                 fvdef = fvnone;
  3551               token.valid = false;
  3552               break;
  3553             default:
  3554               fvdef = fvnone;
  3555             }
  3556           if (structdef == stagseen)
  3557             structdef = snone;
  3558           break;
  3559         case ']':
  3560           if (definedef != dnone || inattribute)
  3561             break;
  3562           if (structdef == stagseen)
  3563             structdef = snone;
  3564           switch (typdef)
  3565             {
  3566             case ttypeseen:
  3567             case tend:
  3568               typdef = tignore;
  3569               make_C_tag (false);       /* a typedef */
  3570               break;
  3571             case tnone:
  3572             case tinbody:
  3573               switch (fvdef)
  3574                 {
  3575                 case foperator:
  3576                 case finlist:
  3577                 case fignore:
  3578                 case vignore:
  3579                   break;
  3580                 case fvnameseen:
  3581                   if ((members && bracelev == 1)
  3582                       || (globals && bracelev == 0
  3583                           && (!fvextern || declarations)))
  3584                     make_C_tag (false); /* a variable */
  3585                   /* FALLTHRU */
  3586                 default:
  3587                   fvdef = fvnone;
  3588                 }
  3589               break;
  3590             }
  3591           break;
  3592         case '(':
  3593           if (inattribute)
  3594             {
  3595               attrparlev++;
  3596               break;
  3597             }
  3598           if (definedef != dnone)
  3599             break;
  3600           if (objdef == otagseen && parlev == 0)
  3601             objdef = oparenseen;
  3602           switch (fvdef)
  3603             {
  3604             case fvnameseen:
  3605               if (typdef == ttypeseen
  3606                   && *lp != '*'
  3607                   && !instruct)
  3608                 {
  3609                   /* This handles constructs like:
  3610                      typedef void OperatorFun (int fun); */
  3611                   make_C_tag (false);
  3612                   typdef = tignore;
  3613                   fvdef = fignore;
  3614                   break;
  3615                 }
  3616               /* FALLTHRU */
  3617             case foperator:
  3618               fvdef = fstartlist;
  3619               break;
  3620             case flistseen:
  3621               fvdef = finlist;
  3622               break;
  3623             }
  3624           parlev++;
  3625           break;
  3626         case ')':
  3627           if (inattribute)
  3628             {
  3629               if (--attrparlev == 0)
  3630                 inattribute = false;
  3631               break;
  3632             }
  3633           if (definedef != dnone)
  3634             break;
  3635           if (objdef == ocatseen && parlev == 1)
  3636             {
  3637               make_C_tag (true); /* an Objective C category */
  3638               objdef = oignore;
  3639             }
  3640           if (--parlev == 0)
  3641             {
  3642               switch (fvdef)
  3643                 {
  3644                 case fstartlist:
  3645                 case finlist:
  3646                   fvdef = flistseen;
  3647                   break;
  3648                 }
  3649               if (!instruct
  3650                   && (typdef == tend
  3651                       || typdef == ttypeseen))
  3652                 {
  3653                   typdef = tignore;
  3654                   make_C_tag (false); /* a typedef */
  3655                 }
  3656             }
  3657           else if (parlev < 0)  /* can happen due to ill-conceived #if's. */
  3658             parlev = 0;
  3659           break;
  3660         case '{':
  3661           if (definedef != dnone)
  3662             break;
  3663           if (typdef == ttypeseen)
  3664             {
  3665               /* Whenever typdef is set to tinbody (currently only
  3666                  here), typdefbracelev should be set to bracelev. */
  3667               typdef = tinbody;
  3668               typdefbracelev = bracelev;
  3669             }
  3670           switch (fvdef)
  3671             {
  3672             case flistseen:
  3673               make_C_tag (true);    /* a function */
  3674               /* FALLTHRU */
  3675             case fignore:
  3676               fvdef = fvnone;
  3677               break;
  3678             case fvnone:
  3679               switch (objdef)
  3680                 {
  3681                 case otagseen:
  3682                   make_C_tag (true); /* an Objective C class */
  3683                   objdef = oignore;
  3684                   break;
  3685                 case omethodtag:
  3686                 case omethodparm:
  3687                   make_C_tag (true); /* an Objective C method */
  3688                   objdef = oinbody;
  3689                   break;
  3690                 default:
  3691                   /* Neutralize `extern "C" {' grot. */
  3692                   if (bracelev == 0 && structdef == snone && nestlev == 0
  3693                       && typdef == tnone)
  3694                     bracelev = -1;
  3695                 }
  3696               break;
  3697             }
  3698           switch (structdef)
  3699             {
  3700             case skeyseen:         /* unnamed struct */
  3701               pushclass_above (bracelev, NULL, 0);
  3702               structdef = snone;
  3703               break;
  3704             case stagseen:         /* named struct or enum */
  3705             case scolonseen:       /* a class */
  3706               pushclass_above (bracelev,token.line+token.offset, token.length);
  3707               structdef = snone;
  3708               make_C_tag (false);  /* a struct or enum */
  3709               break;
  3710             }
  3711           bracelev += 1;
  3712           break;
  3713         case '*':
  3714           if (definedef != dnone)
  3715             break;
  3716           if (fvdef == fstartlist)
  3717             {
  3718               fvdef = fvnone;   /* avoid tagging `foo' in `foo (*bar()) ()' */
  3719               token.valid = false;
  3720             }
  3721           break;
  3722         case '}':
  3723           if (definedef != dnone)
  3724             break;
  3725           bracelev -= 1;
  3726           if (!ignoreindent && lp == newlb.buffer + 1)
  3727             {
  3728               if (bracelev != 0)
  3729                 token.valid = false; /* unexpected value, token unreliable */
  3730               bracelev = 0;     /* reset brace level if first column */
  3731               parlev = 0;       /* also reset paren level, just in case... */
  3732             }
  3733           else if (bracelev < 0)
  3734             {
  3735               token.valid = false; /* something gone amiss, token unreliable */
  3736               bracelev = 0;
  3737             }
  3738           if (bracelev == 0 && fvdef == vignore)
  3739             fvdef = fvnone;             /* end of function */
  3740           popclass_above (bracelev);
  3741           structdef = snone;
  3742           /* Only if typdef == tinbody is typdefbracelev significant. */
  3743           if (typdef == tinbody && bracelev <= typdefbracelev)
  3744             {
  3745               assert (bracelev == typdefbracelev);
  3746               typdef = tend;
  3747             }
  3748           break;
  3749         case '=':
  3750           if (definedef != dnone)
  3751             break;
  3752           switch (fvdef)
  3753             {
  3754             case foperator:
  3755             case finlist:
  3756             case fignore:
  3757             case vignore:
  3758               break;
  3759             case fvnameseen:
  3760               if ((members && bracelev == 1)
  3761                   || (globals && bracelev == 0 && (!fvextern || declarations)))
  3762                 make_C_tag (false); /* a variable */
  3763               /* FALLTHRU */
  3764             default:
  3765               fvdef = vignore;
  3766             }
  3767           break;
  3768         case '<':
  3769           if (cplpl
  3770               && (structdef == stagseen || fvdef == fvnameseen))
  3771             {
  3772               templatelev++;
  3773               break;
  3774             }
  3775           goto resetfvdef;
  3776         case '>':
  3777           if (templatelev > 0)
  3778             {
  3779               templatelev--;
  3780               break;
  3781             }
  3782           goto resetfvdef;
  3783         case '+':
  3784         case '-':
  3785           if (objdef == oinbody && bracelev == 0)
  3786             {
  3787               objdef = omethodsign;
  3788               break;
  3789             }
  3790           /* FALLTHRU */
  3791         resetfvdef:
  3792         case '#': case '~': case '&': case '%': case '/':
  3793         case '|': case '^': case '!': case '.': case '?':
  3794           if (definedef != dnone)
  3795             break;
  3796           /* These surely cannot follow a function tag in C. */
  3797           switch (fvdef)
  3798             {
  3799             case foperator:
  3800             case finlist:
  3801             case fignore:
  3802             case vignore:
  3803               break;
  3804             default:
  3805               fvdef = fvnone;
  3806             }
  3807           break;
  3808         case '\0':
  3809           if (objdef == otagseen)
  3810             {
  3811               make_C_tag (true); /* an Objective C class */
  3812               objdef = oignore;
  3813             }
  3814           /* If a macro spans multiple lines don't reset its state. */
  3815           if (quotednl)
  3816             CNL_SAVE_DEFINEDEF ();
  3817           else
  3818             CNL ();
  3819           break;
  3820         } /* switch (c) */
  3821 
  3822     } /* while not eof */
  3823 
  3824   free (lbs[0].lb.buffer);
  3825   free (lbs[1].lb.buffer);
  3826 }
  3827 
  3828 /*
  3829  * Process either a C++ file or a C file depending on the setting
  3830  * of a global flag.
  3831  */
  3832 static void
  3833 default_C_entries (FILE *inf)
  3834 {
  3835   C_entries (cplusplus ? C_PLPL : C_AUTO, inf);
  3836 }
  3837 
  3838 /* Always do plain C. */
  3839 static void
  3840 plain_C_entries (FILE *inf)
  3841 {
  3842   C_entries (0, inf);
  3843 }
  3844 
  3845 /* Always do C++. */
  3846 static void
  3847 Cplusplus_entries (FILE *inf)
  3848 {
  3849   C_entries (C_PLPL, inf);
  3850 }
  3851 
  3852 /* Always do Java. */
  3853 static void
  3854 Cjava_entries (FILE *inf)
  3855 {
  3856   C_entries (C_JAVA, inf);
  3857 }
  3858 
  3859 /* Always do C*. */
  3860 static void
  3861 Cstar_entries (FILE *inf)
  3862 {
  3863   C_entries (C_STAR, inf);
  3864 }
  3865 
  3866 /* Always do Yacc. */
  3867 static void
  3868 Yacc_entries (FILE *inf)
  3869 {
  3870   C_entries (YACC, inf);
  3871 }
  3872 
  3873 
  3874 /* Useful macros. */
  3875 #define LOOP_ON_INPUT_LINES(file_pointer, line_buffer, char_pointer)    \
  3876   for (;                        /* loop initialization */               \
  3877        !feof (file_pointer)     /* loop test */                         \
  3878        &&                       /* instructions at start of loop */     \
  3879           (readline (&line_buffer, file_pointer),                       \
  3880            char_pointer = line_buffer.buffer,                           \
  3881            true);                                                       \
  3882       )
  3883 
  3884 #define LOOKING_AT(cp, kw)  /* kw is the keyword, a literal string */   \
  3885   ((assert ("" kw), true)   /* syntax error if not a literal string */  \
  3886    && strneq ((cp), kw, sizeof (kw)-1)          /* cp points at kw */   \
  3887    && notinname ((cp)[sizeof (kw)-1])           /* end of kw */         \
  3888    && ((cp) = skip_spaces ((cp)+sizeof (kw)-1))) /* skip spaces */
  3889 
  3890 /* Similar to LOOKING_AT but does not use notinname, does not skip */
  3891 #define LOOKING_AT_NOCASE(cp, kw) /* the keyword is a literal string */ \
  3892   ((assert ("" kw), true) /* syntax error if not a literal string */    \
  3893    && strncaseeq ((cp), kw, sizeof (kw)-1)      /* cp points at kw */   \
  3894    && ((cp) += sizeof (kw)-1))                  /* skip spaces */
  3895 
  3896 /*
  3897  * Read a file, but do no processing.  This is used to do regexp
  3898  * matching on files that have no language defined.
  3899  */
  3900 static void
  3901 just_read_file (FILE *inf)
  3902 {
  3903   while (!feof (inf))
  3904     readline (&lb, inf);
  3905 }
  3906 
  3907 
  3908 /* Fortran parsing */
  3909 
  3910 static void F_takeprec (void);
  3911 static void F_getit (FILE *);
  3912 
  3913 static void
  3914 F_takeprec (void)
  3915 {
  3916   dbp = skip_spaces (dbp);
  3917   if (*dbp != '*')
  3918     return;
  3919   dbp++;
  3920   dbp = skip_spaces (dbp);
  3921   if (strneq (dbp, "(*)", 3))
  3922     {
  3923       dbp += 3;
  3924       return;
  3925     }
  3926   if (!ISDIGIT (*dbp))
  3927     {
  3928       --dbp;                    /* force failure */
  3929       return;
  3930     }
  3931   do
  3932     dbp++;
  3933   while (ISDIGIT (*dbp));
  3934 }
  3935 
  3936 static void
  3937 F_getit (FILE *inf)
  3938 {
  3939   register char *cp;
  3940 
  3941   dbp = skip_spaces (dbp);
  3942   if (*dbp == '\0')
  3943     {
  3944       readline (&lb, inf);
  3945       dbp = lb.buffer;
  3946       if (dbp[5] != '&')
  3947         return;
  3948       dbp += 6;
  3949       dbp = skip_spaces (dbp);
  3950     }
  3951   if (!ISALPHA (*dbp) && *dbp != '_' && *dbp != '$')
  3952     return;
  3953   for (cp = dbp + 1; *cp != '\0' && intoken (*cp); cp++)
  3954     continue;
  3955   make_tag (dbp, cp-dbp, true,
  3956             lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  3957 }
  3958 
  3959 
  3960 static void
  3961 Fortran_functions (FILE *inf)
  3962 {
  3963   LOOP_ON_INPUT_LINES (inf, lb, dbp)
  3964     {
  3965       if (*dbp == '%')
  3966         dbp++;                  /* Ratfor escape to fortran */
  3967       dbp = skip_spaces (dbp);
  3968       if (*dbp == '\0')
  3969         continue;
  3970 
  3971       if (LOOKING_AT_NOCASE (dbp, "recursive"))
  3972         dbp = skip_spaces (dbp);
  3973 
  3974       if (LOOKING_AT_NOCASE (dbp, "pure"))
  3975         dbp = skip_spaces (dbp);
  3976 
  3977       if (LOOKING_AT_NOCASE (dbp, "elemental"))
  3978         dbp = skip_spaces (dbp);
  3979 
  3980       switch (lowcase (*dbp))
  3981         {
  3982         case 'i':
  3983           if (nocase_tail ("integer"))
  3984             F_takeprec ();
  3985           break;
  3986         case 'r':
  3987           if (nocase_tail ("real"))
  3988             F_takeprec ();
  3989           break;
  3990         case 'l':
  3991           if (nocase_tail ("logical"))
  3992             F_takeprec ();
  3993           break;
  3994         case 'c':
  3995           if (nocase_tail ("complex") || nocase_tail ("character"))
  3996             F_takeprec ();
  3997           break;
  3998         case 'd':
  3999           if (nocase_tail ("double"))
  4000             {
  4001               dbp = skip_spaces (dbp);
  4002               if (*dbp == '\0')
  4003                 continue;
  4004               if (nocase_tail ("precision"))
  4005                 break;
  4006               continue;
  4007             }
  4008           break;
  4009         }
  4010       dbp = skip_spaces (dbp);
  4011       if (*dbp == '\0')
  4012         continue;
  4013       switch (lowcase (*dbp))
  4014         {
  4015         case 'f':
  4016           if (nocase_tail ("function"))
  4017             F_getit (inf);
  4018           continue;
  4019         case 's':
  4020           if (nocase_tail ("subroutine"))
  4021             F_getit (inf);
  4022           continue;
  4023         case 'e':
  4024           if (nocase_tail ("entry"))
  4025             F_getit (inf);
  4026           continue;
  4027         case 'b':
  4028           if (nocase_tail ("blockdata") || nocase_tail ("block data"))
  4029             {
  4030               dbp = skip_spaces (dbp);
  4031               if (*dbp == '\0') /* assume un-named */
  4032                 make_tag ("blockdata", 9, true,
  4033                           lb.buffer, dbp - lb.buffer, lineno, linecharno);
  4034               else
  4035                 F_getit (inf);  /* look for name */
  4036             }
  4037           continue;
  4038         }
  4039     }
  4040 }
  4041 
  4042 
  4043 /*
  4044  * Ada parsing
  4045  * Original code by
  4046  * Philippe Waroquiers (1998)
  4047  */
  4048 
  4049 /* Once we are positioned after an "interesting" keyword, let's get
  4050    the real tag value necessary. */
  4051 static void
  4052 Ada_getit (FILE *inf, const char *name_qualifier)
  4053 {
  4054   register char *cp;
  4055   char *name;
  4056   char c;
  4057 
  4058   while (!feof (inf))
  4059     {
  4060       dbp = skip_spaces (dbp);
  4061       if (*dbp == '\0'
  4062           || (dbp[0] == '-' && dbp[1] == '-'))
  4063         {
  4064           readline (&lb, inf);
  4065           dbp = lb.buffer;
  4066         }
  4067       switch (lowcase (*dbp))
  4068         {
  4069         case 'b':
  4070           if (nocase_tail ("body"))
  4071             {
  4072               /* Skipping body of   procedure body   or   package body or ....
  4073                  resetting qualifier to body instead of spec. */
  4074               name_qualifier = "/b";
  4075               continue;
  4076             }
  4077           break;
  4078         case 't':
  4079           /* Skipping type of   task type   or   protected type ... */
  4080           if (nocase_tail ("type"))
  4081             continue;
  4082           break;
  4083         }
  4084       if (*dbp == '"')
  4085         {
  4086           dbp += 1;
  4087           for (cp = dbp; *cp != '\0' && *cp != '"'; cp++)
  4088             continue;
  4089         }
  4090       else
  4091         {
  4092           dbp = skip_spaces (dbp);
  4093           for (cp = dbp;
  4094                (*cp != '\0'
  4095                 && (ISALPHA (*cp) || ISDIGIT (*cp) || *cp == '_' || *cp == '.'));
  4096                cp++)
  4097             continue;
  4098           if (cp == dbp)
  4099             return;
  4100         }
  4101       c = *cp;
  4102       *cp = '\0';
  4103       name = concat (dbp, name_qualifier, "");
  4104       *cp = c;
  4105       make_tag (name, strlen (name), true,
  4106                 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4107       free (name);
  4108       if (c == '"')
  4109         dbp = cp + 1;
  4110       return;
  4111     }
  4112 }
  4113 
  4114 static void
  4115 Ada_funcs (FILE *inf)
  4116 {
  4117   bool inquote = false;
  4118   bool skip_till_semicolumn = false;
  4119 
  4120   LOOP_ON_INPUT_LINES (inf, lb, dbp)
  4121     {
  4122       while (*dbp != '\0')
  4123         {
  4124           /* Skip a string i.e. "abcd". */
  4125           if (inquote || (*dbp == '"'))
  4126             {
  4127               dbp = strchr (dbp + !inquote, '"');
  4128               if (dbp != NULL)
  4129                 {
  4130                   inquote = false;
  4131                   dbp += 1;
  4132                   continue;     /* advance char */
  4133                 }
  4134               else
  4135                 {
  4136                   inquote = true;
  4137                   break;        /* advance line */
  4138                 }
  4139             }
  4140 
  4141           /* Skip comments. */
  4142           if (dbp[0] == '-' && dbp[1] == '-')
  4143             break;              /* advance line */
  4144 
  4145           /* Skip character enclosed in single quote i.e. 'a'
  4146              and skip single quote starting an attribute i.e. 'Image. */
  4147           if (*dbp == '\'')
  4148             {
  4149               dbp++ ;
  4150               if (*dbp != '\0')
  4151                 dbp++;
  4152               continue;
  4153             }
  4154 
  4155           if (skip_till_semicolumn)
  4156             {
  4157               if (*dbp == ';')
  4158                 skip_till_semicolumn = false;
  4159               dbp++;
  4160               continue;         /* advance char */
  4161             }
  4162 
  4163           /* Search for beginning of a token.  */
  4164           if (!begtoken (*dbp))
  4165             {
  4166               dbp++;
  4167               continue;         /* advance char */
  4168             }
  4169 
  4170           /* We are at the beginning of a token. */
  4171           switch (lowcase (*dbp))
  4172             {
  4173             case 'f':
  4174               if (!packages_only && nocase_tail ("function"))
  4175                 Ada_getit (inf, "/f");
  4176               else
  4177                 break;          /* from switch */
  4178               continue;         /* advance char */
  4179             case 'p':
  4180               if (!packages_only && nocase_tail ("procedure"))
  4181                 Ada_getit (inf, "/p");
  4182               else if (nocase_tail ("package"))
  4183                 Ada_getit (inf, "/s");
  4184               else if (nocase_tail ("protected")) /* protected type */
  4185                 Ada_getit (inf, "/t");
  4186               else
  4187                 break;          /* from switch */
  4188               continue;         /* advance char */
  4189 
  4190             case 'u':
  4191               if (typedefs && !packages_only && nocase_tail ("use"))
  4192                 {
  4193                   /* when tagging types, avoid tagging  use type Pack.Typename;
  4194                      for this, we will skip everything till a ; */
  4195                   skip_till_semicolumn = true;
  4196                   continue;     /* advance char */
  4197                 }
  4198 
  4199             case 't':
  4200               if (!packages_only && nocase_tail ("task"))
  4201                 Ada_getit (inf, "/k");
  4202               else if (typedefs && !packages_only && nocase_tail ("type"))
  4203                 {
  4204                   Ada_getit (inf, "/t");
  4205                   while (*dbp != '\0')
  4206                     dbp += 1;
  4207                 }
  4208               else
  4209                 break;          /* from switch */
  4210               continue;         /* advance char */
  4211             }
  4212 
  4213           /* Look for the end of the token. */
  4214           while (!endtoken (*dbp))
  4215             dbp++;
  4216 
  4217         } /* advance char */
  4218     } /* advance line */
  4219 }
  4220 
  4221 
  4222 /*
  4223  * Unix and microcontroller assembly tag handling
  4224  * Labels:  /^[a-zA-Z_.$][a-zA_Z0-9_.$]*[: ^I^J]/
  4225  * Idea by Bob Weiner, Motorola Inc. (1994)
  4226  */
  4227 static void
  4228 Asm_labels (FILE *inf)
  4229 {
  4230   register char *cp;
  4231 
  4232   LOOP_ON_INPUT_LINES (inf, lb, cp)
  4233     {
  4234       /* If first char is alphabetic or one of [_.$], test for colon
  4235          following identifier. */
  4236       if (ISALPHA (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
  4237         {
  4238           /* Read past label. */
  4239           cp++;
  4240           while (ISALNUM (*cp) || *cp == '_' || *cp == '.' || *cp == '$')
  4241             cp++;
  4242           if (*cp == ':' || iswhite (*cp))
  4243             /* Found end of label, so copy it and add it to the table. */
  4244             make_tag (lb.buffer, cp - lb.buffer, true,
  4245                       lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4246         }
  4247     }
  4248 }
  4249 
  4250 
  4251 /*
  4252  * Perl support
  4253  * Perl sub names: /^sub[ \t\n]+[^ \t\n{]+/
  4254  *                 /^use constant[ \t\n]+[^ \t\n{=,;]+/
  4255  * Perl variable names: /^(my|local).../
  4256  * Original code by Bart Robinson <lomew@cs.utah.edu> (1995)
  4257  * Additions by Michael Ernst <mernst@alum.mit.edu> (1997)
  4258  * Ideas by Kai Großjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE> (2001)
  4259  */
  4260 static void
  4261 Perl_functions (FILE *inf)
  4262 {
  4263   char *package = savestr ("main"); /* current package name */
  4264   register char *cp;
  4265 
  4266   LOOP_ON_INPUT_LINES (inf, lb, cp)
  4267     {
  4268       cp = skip_spaces (cp);
  4269 
  4270       if (LOOKING_AT (cp, "package"))
  4271         {
  4272           free (package);
  4273           get_tag (cp, &package);
  4274         }
  4275       else if (LOOKING_AT (cp, "sub"))
  4276         {
  4277           char *pos, *sp;
  4278 
  4279         subr:
  4280           sp = cp;
  4281           while (!notinname (*cp))
  4282             cp++;
  4283           if (cp == sp)
  4284             continue;           /* nothing found */
  4285           if ((pos = strchr (sp, ':')) != NULL
  4286               && pos < cp && pos[1] == ':')
  4287             /* The name is already qualified. */
  4288             make_tag (sp, cp - sp, true,
  4289                       lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4290           else
  4291             /* Qualify it. */
  4292             {
  4293               char savechar, *name;
  4294 
  4295               savechar = *cp;
  4296               *cp = '\0';
  4297               name = concat (package, "::", sp);
  4298               *cp = savechar;
  4299               make_tag (name, strlen (name), true,
  4300                         lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4301               free (name);
  4302             }
  4303         }
  4304       else if (LOOKING_AT (cp, "use constant")
  4305                || LOOKING_AT (cp, "use constant::defer"))
  4306         {
  4307           /* For hash style multi-constant like
  4308                 use constant { FOO => 123,
  4309                                BAR => 456 };
  4310              only the first FOO is picked up.  Parsing across the value
  4311              expressions would be difficult in general, due to possible nested
  4312              hashes, here-documents, etc.  */
  4313           if (*cp == '{')
  4314             cp = skip_spaces (cp+1);
  4315           goto subr;
  4316         }
  4317       else if (globals) /* only if we are tagging global vars */
  4318         {
  4319           /* Skip a qualifier, if any. */
  4320           bool qual = LOOKING_AT (cp, "my") || LOOKING_AT (cp, "local");
  4321           /* After "my" or "local", but before any following paren or space. */
  4322           char *varstart = cp;
  4323 
  4324           if (qual              /* should this be removed?  If yes, how? */
  4325               && (*cp == '$' || *cp == '@' || *cp == '%'))
  4326             {
  4327               varstart += 1;
  4328               do
  4329                 cp++;
  4330               while (ISALNUM (*cp) || *cp == '_');
  4331             }
  4332           else if (qual)
  4333             {
  4334               /* Should be examining a variable list at this point;
  4335                  could insist on seeing an open parenthesis. */
  4336               while (*cp != '\0' && *cp != ';' && *cp != '=' &&  *cp != ')')
  4337                 cp++;
  4338             }
  4339           else
  4340             continue;
  4341 
  4342           make_tag (varstart, cp - varstart, false,
  4343                     lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4344         }
  4345     }
  4346   free (package);
  4347 }
  4348 
  4349 
  4350 /*
  4351  * Python support
  4352  * Look for /^[\t]*def[ \t\n]+[^ \t\n(:]+/ or /^class[ \t\n]+[^ \t\n(:]+/
  4353  * Idea by Eric S. Raymond <esr@thyrsus.com> (1997)
  4354  * More ideas by seb bacon <seb@jamkit.com> (2002)
  4355  */
  4356 static void
  4357 Python_functions (FILE *inf)
  4358 {
  4359   register char *cp;
  4360 
  4361   LOOP_ON_INPUT_LINES (inf, lb, cp)
  4362     {
  4363       cp = skip_spaces (cp);
  4364       if (LOOKING_AT (cp, "def") || LOOKING_AT (cp, "class"))
  4365         {
  4366           char *name = cp;
  4367           while (!notinname (*cp) && *cp != ':')
  4368             cp++;
  4369           make_tag (name, cp - name, true,
  4370                     lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4371         }
  4372     }
  4373 }
  4374 
  4375 
  4376 /*
  4377  * PHP support
  4378  * Look for:
  4379  *  - /^[ \t]*function[ \t\n]+[^ \t\n(]+/
  4380  *  - /^[ \t]*class[ \t\n]+[^ \t\n]+/
  4381  *  - /^[ \t]*define\(\"[^\"]+/
  4382  * Only with --members:
  4383  *  - /^[ \t]*var[ \t\n]+\$[^ \t\n=;]/
  4384  * Idea by Diez B. Roggisch (2001)
  4385  */
  4386 static void
  4387 PHP_functions (FILE *inf)
  4388 {
  4389   char *cp, *name;
  4390   bool search_identifier = false;
  4391 
  4392   LOOP_ON_INPUT_LINES (inf, lb, cp)
  4393     {
  4394       cp = skip_spaces (cp);
  4395       name = cp;
  4396       if (search_identifier
  4397           && *cp != '\0')
  4398         {
  4399           while (!notinname (*cp))
  4400             cp++;
  4401           make_tag (name, cp - name, true,
  4402                     lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4403           search_identifier = false;
  4404         }
  4405       else if (LOOKING_AT (cp, "function"))
  4406         {
  4407           if (*cp == '&')
  4408             cp = skip_spaces (cp+1);
  4409           if (*cp != '\0')
  4410             {
  4411               name = cp;
  4412               while (!notinname (*cp))
  4413                 cp++;
  4414               make_tag (name, cp - name, true,
  4415                         lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4416             }
  4417           else
  4418             search_identifier = true;
  4419         }
  4420       else if (LOOKING_AT (cp, "class"))
  4421         {
  4422           if (*cp != '\0')
  4423             {
  4424               name = cp;
  4425               while (*cp != '\0' && !iswhite (*cp))
  4426                 cp++;
  4427               make_tag (name, cp - name, false,
  4428                         lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4429             }
  4430           else
  4431             search_identifier = true;
  4432         }
  4433       else if (strneq (cp, "define", 6)
  4434                && (cp = skip_spaces (cp+6))
  4435                && *cp++ == '('
  4436                && (*cp == '"' || *cp == '\''))
  4437         {
  4438           char quote = *cp++;
  4439           name = cp;
  4440           while (*cp != quote && *cp != '\0')
  4441             cp++;
  4442           make_tag (name, cp - name, false,
  4443                     lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4444         }
  4445       else if (members
  4446                && LOOKING_AT (cp, "var")
  4447                && *cp == '$')
  4448         {
  4449           name = cp;
  4450           while (!notinname (*cp))
  4451             cp++;
  4452           make_tag (name, cp - name, false,
  4453                     lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  4454         }
  4455     }
  4456 }
  4457 
  4458 
  4459 /*
  4460  * Cobol tag functions
  4461  * We could look for anything that could be a paragraph name.
  4462  * i.e. anything that starts in column 8 is one word and ends in a full stop.
  4463  * Idea by Corny de Souza (1993)
  4464  */
  4465 static void
  4466 Cobol_paragraphs (FILE *inf)
  4467 {
  4468   register char *bp, *ep;
  4469 
  4470   LOOP_ON_INPUT_LINES (inf, lb, bp)
  4471     {
  4472       if (lb.len < 9)
  4473         continue;
  4474       bp += 8;
  4475 
  4476       /* If eoln, compiler option or comment ignore whole line. */
  4477       if (bp[-1] != ' ' || !ISALNUM (bp[0]))
  4478         continue;
  4479 
  4480       for (ep = bp; ISALNUM (*ep) || *ep == '-'; ep++)
  4481         continue;
  4482       if (*ep++ == '.')
  4483         make_tag (bp, ep - bp, true,
  4484                   lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
  4485     }
  4486 }
  4487 
  4488 
  4489 /*
  4490  * Makefile support
  4491  * Ideas by Assar Westerlund <assar@sics.se> (2001)
  4492  */
  4493 static void
  4494 Makefile_targets (FILE *inf)
  4495 {
  4496   register char *bp;
  4497 
  4498   LOOP_ON_INPUT_LINES (inf, lb, bp)
  4499     {
  4500       if (*bp == '\t' || *bp == '#')
  4501         continue;
  4502       while (*bp != '\0' && *bp != '=' && *bp != ':')
  4503         bp++;
  4504       if (*bp == ':' || (globals && *bp == '='))
  4505         {
  4506           /* We should detect if there is more than one tag, but we do not.
  4507              We just skip initial and final spaces. */
  4508           char * namestart = skip_spaces (lb.buffer);
  4509           while (--bp > namestart)
  4510             if (!notinname (*bp))
  4511               break;
  4512           make_tag (namestart, bp - namestart + 1, true,
  4513                     lb.buffer, bp - lb.buffer + 2, lineno, linecharno);
  4514         }
  4515     }
  4516 }
  4517 
  4518 
  4519 /*
  4520  * Pascal parsing
  4521  * Original code by Mosur K. Mohan (1989)
  4522  *
  4523  *  Locates tags for procedures & functions.  Doesn't do any type- or
  4524  *  var-definitions.  It does look for the keyword "extern" or
  4525  *  "forward" immediately following the procedure statement; if found,
  4526  *  the tag is skipped.
  4527  */
  4528 static void
  4529 Pascal_functions (FILE *inf)
  4530 {
  4531   linebuffer tline;             /* mostly copied from C_entries */
  4532   long save_lcno;
  4533   int save_lineno, namelen, taglen;
  4534   char c, *name;
  4535 
  4536   bool                          /* each of these flags is true if: */
  4537     incomment,                  /* point is inside a comment */
  4538     inquote,                    /* point is inside '..' string */
  4539     get_tagname,                /* point is after PROCEDURE/FUNCTION
  4540                                    keyword, so next item = potential tag */
  4541     found_tag,                  /* point is after a potential tag */
  4542     inparms,                    /* point is within parameter-list */
  4543     verify_tag;                 /* point has passed the parm-list, so the
  4544                                    next token will determine whether this
  4545                                    is a FORWARD/EXTERN to be ignored, or
  4546                                    whether it is a real tag */
  4547 
  4548   save_lcno = save_lineno = namelen = taglen = 0; /* keep compiler quiet */
  4549   name = NULL;                  /* keep compiler quiet */
  4550   dbp = lb.buffer;
  4551   *dbp = '\0';
  4552   linebuffer_init (&tline);
  4553 
  4554   incomment = inquote = false;
  4555   found_tag = false;            /* have a proc name; check if extern */
  4556   get_tagname = false;          /* found "procedure" keyword         */
  4557   inparms = false;              /* found '(' after "proc"            */
  4558   verify_tag = false;           /* check if "extern" is ahead        */
  4559 
  4560 
  4561   while (!feof (inf))           /* long main loop to get next char */
  4562     {
  4563       c = *dbp++;
  4564       if (c == '\0')            /* if end of line */
  4565         {
  4566           readline (&lb, inf);
  4567           dbp = lb.buffer;
  4568           if (*dbp == '\0')
  4569             continue;
  4570           if (!((found_tag && verify_tag)
  4571                 || get_tagname))
  4572             c = *dbp++;         /* only if don't need *dbp pointing
  4573                                    to the beginning of the name of
  4574                                    the procedure or function */
  4575         }
  4576       if (incomment)
  4577         {
  4578           if (c == '}')         /* within { } comments */
  4579             incomment = false;
  4580           else if (c == '*' && *dbp == ')') /* within (* *) comments */
  4581             {
  4582               dbp++;
  4583               incomment = false;
  4584             }
  4585           continue;
  4586         }
  4587       else if (inquote)
  4588         {
  4589           if (c == '\'')
  4590             inquote = false;
  4591           continue;
  4592         }
  4593       else
  4594         switch (c)
  4595           {
  4596           case '\'':
  4597             inquote = true;     /* found first quote */
  4598             continue;
  4599           case '{':             /* found open { comment */
  4600             incomment = true;
  4601             continue;
  4602           case '(':
  4603             if (*dbp == '*')    /* found open (* comment */
  4604               {
  4605                 incomment = true;
  4606                 dbp++;
  4607               }
  4608             else if (found_tag) /* found '(' after tag, i.e., parm-list */
  4609               inparms = true;
  4610             continue;
  4611           case ')':             /* end of parms list */
  4612             if (inparms)
  4613               inparms = false;
  4614             continue;
  4615           case ';':
  4616             if (found_tag && !inparms) /* end of proc or fn stmt */
  4617               {
  4618                 verify_tag = true;
  4619                 break;
  4620               }
  4621             continue;
  4622           }
  4623       if (found_tag && verify_tag && (*dbp != ' '))
  4624         {
  4625           /* Check if this is an "extern" declaration. */
  4626           if (*dbp == '\0')
  4627             continue;
  4628           if (lowcase (*dbp) == 'e')
  4629             {
  4630               if (nocase_tail ("extern")) /* superfluous, really! */
  4631                 {
  4632                   found_tag = false;
  4633                   verify_tag = false;
  4634                 }
  4635             }
  4636           else if (lowcase (*dbp) == 'f')
  4637             {
  4638               if (nocase_tail ("forward")) /* check for forward reference */
  4639                 {
  4640                   found_tag = false;
  4641                   verify_tag = false;
  4642                 }
  4643             }
  4644           if (found_tag && verify_tag) /* not external proc, so make tag */
  4645             {
  4646               found_tag = false;
  4647               verify_tag = false;
  4648               make_tag (name, namelen, true,
  4649                         tline.buffer, taglen, save_lineno, save_lcno);
  4650               continue;
  4651             }
  4652         }
  4653       if (get_tagname)          /* grab name of proc or fn */
  4654         {
  4655           char *cp;
  4656 
  4657           if (*dbp == '\0')
  4658             continue;
  4659 
  4660           /* Find block name. */
  4661           for (cp = dbp + 1; *cp != '\0' && !endtoken (*cp); cp++)
  4662             continue;
  4663 
  4664           /* Save all values for later tagging. */
  4665           linebuffer_setlen (&tline, lb.len);
  4666           strcpy (tline.buffer, lb.buffer);
  4667           save_lineno = lineno;
  4668           save_lcno = linecharno;
  4669           name = tline.buffer + (dbp - lb.buffer);
  4670           namelen = cp - dbp;
  4671           taglen = cp - lb.buffer + 1;
  4672 
  4673           dbp = cp;             /* set dbp to e-o-token */
  4674           get_tagname = false;
  4675           found_tag = true;
  4676           continue;
  4677 
  4678           /* And proceed to check for "extern". */
  4679         }
  4680       else if (!incomment && !inquote && !found_tag)
  4681         {
  4682           /* Check for proc/fn keywords. */
  4683           switch (lowcase (c))
  4684             {
  4685             case 'p':
  4686               if (nocase_tail ("rocedure")) /* c = 'p', dbp has advanced */
  4687                 get_tagname = true;
  4688               continue;
  4689             case 'f':
  4690               if (nocase_tail ("unction"))
  4691                 get_tagname = true;
  4692               continue;
  4693             }
  4694         }
  4695     } /* while not eof */
  4696 
  4697   free (tline.buffer);
  4698 }
  4699 
  4700 
  4701 /*
  4702  * Lisp tag functions
  4703  *  look for (def or (DEF, quote or QUOTE
  4704  */
  4705 
  4706 static void L_getit (void);
  4707 
  4708 static void
  4709 L_getit (void)
  4710 {
  4711   if (*dbp == '\'')             /* Skip prefix quote */
  4712     dbp++;
  4713   else if (*dbp == '(')
  4714   {
  4715     dbp++;
  4716     /* Try to skip "(quote " */
  4717     if (!LOOKING_AT (dbp, "quote") && !LOOKING_AT (dbp, "QUOTE"))
  4718       /* Ok, then skip "(" before name in (defstruct (foo)) */
  4719       dbp = skip_spaces (dbp);
  4720   }
  4721   get_tag (dbp, NULL);
  4722 }
  4723 
  4724 static void
  4725 Lisp_functions (FILE *inf)
  4726 {
  4727   LOOP_ON_INPUT_LINES (inf, lb, dbp)
  4728     {
  4729       if (dbp[0] != '(')
  4730         continue;
  4731 
  4732       /* "(defvar foo)" is a declaration rather than a definition.  */
  4733       if (! declarations)
  4734         {
  4735           char *p = dbp + 1;
  4736           if (LOOKING_AT (p, "defvar"))
  4737             {
  4738               p = skip_name (p); /* past var name */
  4739               p = skip_spaces (p);
  4740               if (*p == ')')
  4741                 continue;
  4742             }
  4743         }
  4744 
  4745       if (strneq (dbp + 1, "cl-", 3) || strneq (dbp + 1, "CL-", 3))
  4746         dbp += 3;
  4747 
  4748       if (strneq (dbp+1, "def", 3) || strneq (dbp+1, "DEF", 3))
  4749         {
  4750           dbp = skip_non_spaces (dbp);
  4751           dbp = skip_spaces (dbp);
  4752           L_getit ();
  4753         }
  4754       else
  4755         {
  4756           /* Check for (foo::defmumble name-defined ... */
  4757           do
  4758             dbp++;
  4759           while (!notinname (*dbp) && *dbp != ':');
  4760           if (*dbp == ':')
  4761             {
  4762               do
  4763                 dbp++;
  4764               while (*dbp == ':');
  4765 
  4766               if (strneq (dbp, "def", 3) || strneq (dbp, "DEF", 3))
  4767                 {
  4768                   dbp = skip_non_spaces (dbp);
  4769                   dbp = skip_spaces (dbp);
  4770                   L_getit ();
  4771                 }
  4772             }
  4773         }
  4774     }
  4775 }
  4776 
  4777 
  4778 /*
  4779  * Lua script language parsing
  4780  * Original code by David A. Capello <dacap@users.sourceforge.net> (2004)
  4781  *
  4782  *  "function" and "local function" are tags if they start at column 1.
  4783  */
  4784 static void
  4785 Lua_functions (FILE *inf)
  4786 {
  4787   register char *bp;
  4788 
  4789   LOOP_ON_INPUT_LINES (inf, lb, bp)
  4790     {
  4791       if (bp[0] != 'f' && bp[0] != 'l')
  4792         continue;
  4793 
  4794       (void)LOOKING_AT (bp, "local"); /* skip possible "local" */
  4795 
  4796       if (LOOKING_AT (bp, "function"))
  4797         get_tag (bp, NULL);
  4798     }
  4799 }
  4800 
  4801 
  4802 /*
  4803  * PostScript tags
  4804  * Just look for lines where the first character is '/'
  4805  * Also look at "defineps" for PSWrap
  4806  * Ideas by:
  4807  *   Richard Mlynarik <mly@adoc.xerox.com> (1997)
  4808  *   Masatake Yamato <masata-y@is.aist-nara.ac.jp> (1999)
  4809  */
  4810 static void
  4811 PS_functions (FILE *inf)
  4812 {
  4813   register char *bp, *ep;
  4814 
  4815   LOOP_ON_INPUT_LINES (inf, lb, bp)
  4816     {
  4817       if (bp[0] == '/')
  4818         {
  4819           for (ep = bp+1;
  4820                *ep != '\0' && *ep != ' ' && *ep != '{';
  4821                ep++)
  4822             continue;
  4823           make_tag (bp, ep - bp, true,
  4824                     lb.buffer, ep - lb.buffer + 1, lineno, linecharno);
  4825         }
  4826       else if (LOOKING_AT (bp, "defineps"))
  4827         get_tag (bp, NULL);
  4828     }
  4829 }
  4830 
  4831 
  4832 /*
  4833  * Forth tags
  4834  * Ignore anything after \ followed by space or in ( )
  4835  * Look for words defined by :
  4836  * Look for constant, code, create, defer, value, and variable
  4837  * OBP extensions:  Look for buffer:, field,
  4838  * Ideas by Eduardo Horvath <eeh@netbsd.org> (2004)
  4839  */
  4840 static void
  4841 Forth_words (FILE *inf)
  4842 {
  4843   register char *bp;
  4844 
  4845   LOOP_ON_INPUT_LINES (inf, lb, bp)
  4846     while ((bp = skip_spaces (bp))[0] != '\0')
  4847       if (bp[0] == '\\' && iswhite (bp[1]))
  4848         break;                  /* read next line */
  4849       else if (bp[0] == '(' && iswhite (bp[1]))
  4850         do                      /* skip to ) or eol */
  4851           bp++;
  4852         while (*bp != ')' && *bp != '\0');
  4853       else if ((bp[0] == ':' && iswhite (bp[1]) && bp++)
  4854                || LOOKING_AT_NOCASE (bp, "constant")
  4855                || LOOKING_AT_NOCASE (bp, "code")
  4856                || LOOKING_AT_NOCASE (bp, "create")
  4857                || LOOKING_AT_NOCASE (bp, "defer")
  4858                || LOOKING_AT_NOCASE (bp, "value")
  4859                || LOOKING_AT_NOCASE (bp, "variable")
  4860                || LOOKING_AT_NOCASE (bp, "buffer:")
  4861                || LOOKING_AT_NOCASE (bp, "field"))
  4862         get_tag (skip_spaces (bp), NULL); /* Yay!  A definition! */
  4863       else
  4864         bp = skip_non_spaces (bp);
  4865 }
  4866 
  4867 
  4868 /*
  4869  * Scheme tag functions
  4870  * look for (def... xyzzy
  4871  *          (def... (xyzzy
  4872  *          (def ... ((...(xyzzy ....
  4873  *          (set! xyzzy
  4874  * Original code by Ken Haase (1985?)
  4875  */
  4876 static void
  4877 Scheme_functions (FILE *inf)
  4878 {
  4879   register char *bp;
  4880 
  4881   LOOP_ON_INPUT_LINES (inf, lb, bp)
  4882     {
  4883       if (strneq (bp, "(def", 4) || strneq (bp, "(DEF", 4))
  4884         {
  4885           bp = skip_non_spaces (bp+4);
  4886           /* Skip over open parens and white space.  Don't continue past
  4887              '\0'. */
  4888           while (*bp && notinname (*bp))
  4889             bp++;
  4890           get_tag (bp, NULL);
  4891         }
  4892       if (LOOKING_AT (bp, "(SET!") || LOOKING_AT (bp, "(set!"))
  4893         get_tag (bp, NULL);
  4894     }
  4895 }
  4896 
  4897 
  4898 /* Find tags in TeX and LaTeX input files.  */
  4899 
  4900 /* TEX_toktab is a table of TeX control sequences that define tags.
  4901  * Each entry records one such control sequence.
  4902  *
  4903  * Original code from who knows whom.
  4904  * Ideas by:
  4905  *   Stefan Monnier (2002)
  4906  */
  4907 
  4908 static linebuffer *TEX_toktab = NULL; /* Table with tag tokens */
  4909 
  4910 /* Default set of control sequences to put into TEX_toktab.
  4911    The value of environment var TEXTAGS is prepended to this.  */
  4912 static const char *TEX_defenv = "\
  4913 :chapter:section:subsection:subsubsection:eqno:label:ref:cite:bibitem\
  4914 :part:appendix:entry:index:def\
  4915 :newcommand:renewcommand:newenvironment:renewenvironment";
  4916 
  4917 static void TEX_mode (FILE *);
  4918 static void TEX_decode_env (const char *, const char *);
  4919 
  4920 static char TEX_esc = '\\';
  4921 static char TEX_opgrp = '{';
  4922 static char TEX_clgrp = '}';
  4923 
  4924 /*
  4925  * TeX/LaTeX scanning loop.
  4926  */
  4927 static void
  4928 TeX_commands (FILE *inf)
  4929 {
  4930   char *cp;
  4931   linebuffer *key;
  4932 
  4933   /* Select either \ or ! as escape character.  */
  4934   TEX_mode (inf);
  4935 
  4936   /* Initialize token table once from environment. */
  4937   if (TEX_toktab == NULL)
  4938     TEX_decode_env ("TEXTAGS", TEX_defenv);
  4939 
  4940   LOOP_ON_INPUT_LINES (inf, lb, cp)
  4941     {
  4942       /* Look at each TEX keyword in line. */
  4943       for (;;)
  4944         {
  4945           /* Look for a TEX escape. */
  4946           while (*cp++ != TEX_esc)
  4947             if (cp[-1] == '\0' || cp[-1] == '%')
  4948               goto tex_next_line;
  4949 
  4950           for (key = TEX_toktab; key->buffer != NULL; key++)
  4951             if (strneq (cp, key->buffer, key->len))
  4952               {
  4953                 char *p;
  4954                 int namelen, linelen;
  4955                 bool opgrp = false;
  4956 
  4957                 cp = skip_spaces (cp + key->len);
  4958                 if (*cp == TEX_opgrp)
  4959                   {
  4960                     opgrp = true;
  4961                     cp++;
  4962                   }
  4963                 for (p = cp;
  4964                      (!iswhite (*p) && *p != '#' &&
  4965                       *p != TEX_opgrp && *p != TEX_clgrp);
  4966                      p++)
  4967                   continue;
  4968                 namelen = p - cp;
  4969                 linelen = lb.len;
  4970                 if (!opgrp || *p == TEX_clgrp)
  4971                   {
  4972                     while (*p != '\0' && *p != TEX_opgrp && *p != TEX_clgrp)
  4973                       p++;
  4974                     linelen = p - lb.buffer + 1;
  4975                   }
  4976                 make_tag (cp, namelen, true,
  4977                           lb.buffer, linelen, lineno, linecharno);
  4978                 goto tex_next_line; /* We only tag a line once */
  4979               }
  4980         }
  4981     tex_next_line:
  4982       ;
  4983     }
  4984 }
  4985 
  4986 #define TEX_LESC '\\'
  4987 #define TEX_SESC '!'
  4988 
  4989 /* Figure out whether TeX's escapechar is '\\' or '!' and set grouping
  4990    chars accordingly. */
  4991 static void
  4992 TEX_mode (FILE *inf)
  4993 {
  4994   int c;
  4995 
  4996   while ((c = getc (inf)) != EOF)
  4997     {
  4998       /* Skip to next line if we hit the TeX comment char. */
  4999       if (c == '%')
  5000         while (c != '\n' && c != EOF)
  5001           c = getc (inf);
  5002       else if (c == TEX_LESC || c == TEX_SESC )
  5003         break;
  5004     }
  5005 
  5006   if (c == TEX_LESC)
  5007     {
  5008       TEX_esc = TEX_LESC;
  5009       TEX_opgrp = '{';
  5010       TEX_clgrp = '}';
  5011     }
  5012   else
  5013     {
  5014       TEX_esc = TEX_SESC;
  5015       TEX_opgrp = '<';
  5016       TEX_clgrp = '>';
  5017     }
  5018   /* If the input file is compressed, inf is a pipe, and rewind may fail.
  5019      No attempt is made to correct the situation. */
  5020   rewind (inf);
  5021 }
  5022 
  5023 /* Read environment and prepend it to the default string.
  5024    Build token table. */
  5025 static void
  5026 TEX_decode_env (const char *evarname, const char *defenv)
  5027 {
  5028   register const char *env, *p;
  5029   int i, len;
  5030 
  5031   /* Append default string to environment. */
  5032   env = getenv (evarname);
  5033   if (!env)
  5034     env = defenv;
  5035   else
  5036     env = concat (env, defenv, "");
  5037 
  5038   /* Allocate a token table */
  5039   for (len = 1, p = env; p;)
  5040     if ((p = strchr (p, ':')) && *++p != '\0')
  5041       len++;
  5042   TEX_toktab = xnew (len, linebuffer);
  5043 
  5044   /* Unpack environment string into token table. Be careful about */
  5045   /* zero-length strings (leading ':', "::" and trailing ':') */
  5046   for (i = 0; *env != '\0';)
  5047     {
  5048       p = strchr (env, ':');
  5049       if (!p)                   /* End of environment string. */
  5050         p = env + strlen (env);
  5051       if (p - env > 0)
  5052         {                       /* Only non-zero strings. */
  5053           TEX_toktab[i].buffer = savenstr (env, p - env);
  5054           TEX_toktab[i].len = p - env;
  5055           i++;
  5056         }
  5057       if (*p)
  5058         env = p + 1;
  5059       else
  5060         {
  5061           TEX_toktab[i].buffer = NULL; /* Mark end of table. */
  5062           TEX_toktab[i].len = 0;
  5063           break;
  5064         }
  5065     }
  5066 }
  5067 
  5068 
  5069 /* Texinfo support.  Dave Love, Mar. 2000.  */
  5070 static void
  5071 Texinfo_nodes (FILE *inf)
  5072 {
  5073   char *cp, *start;
  5074   LOOP_ON_INPUT_LINES (inf, lb, cp)
  5075     if (LOOKING_AT (cp, "@node"))
  5076       {
  5077         start = cp;
  5078         while (*cp != '\0' && *cp != ',')
  5079           cp++;
  5080         make_tag (start, cp - start, true,
  5081                   lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  5082       }
  5083 }
  5084 
  5085 
  5086 /*
  5087  * HTML support.
  5088  * Contents of <title>, <h1>, <h2>, <h3> are tags.
  5089  * Contents of <a name=xxx> are tags with name xxx.
  5090  *
  5091  * Francesco Potortì, 2002.
  5092  */
  5093 static void
  5094 HTML_labels (FILE *inf)
  5095 {
  5096   bool getnext = false;         /* next text outside of HTML tags is a tag */
  5097   bool skiptag = false;         /* skip to the end of the current HTML tag */
  5098   bool intag = false;           /* inside an html tag, looking for ID= */
  5099   bool inanchor = false;        /* when INTAG, is an anchor, look for NAME= */
  5100   char *end;
  5101 
  5102 
  5103   linebuffer_setlen (&token_name, 0); /* no name in buffer */
  5104 
  5105   LOOP_ON_INPUT_LINES (inf, lb, dbp)
  5106     for (;;)                    /* loop on the same line */
  5107       {
  5108         if (skiptag)            /* skip HTML tag */
  5109           {
  5110             while (*dbp != '\0' && *dbp != '>')
  5111               dbp++;
  5112             if (*dbp == '>')
  5113               {
  5114                 dbp += 1;
  5115                 skiptag = false;
  5116                 continue;       /* look on the same line */
  5117               }
  5118             break;              /* go to next line */
  5119           }
  5120 
  5121         else if (intag) /* look for "name=" or "id=" */
  5122           {
  5123             while (*dbp != '\0' && *dbp != '>'
  5124                    && lowcase (*dbp) != 'n' && lowcase (*dbp) != 'i')
  5125               dbp++;
  5126             if (*dbp == '\0')
  5127               break;            /* go to next line */
  5128             if (*dbp == '>')
  5129               {
  5130                 dbp += 1;
  5131                 intag = false;
  5132                 continue;       /* look on the same line */
  5133               }
  5134             if ((inanchor && LOOKING_AT_NOCASE (dbp, "name="))
  5135                 || LOOKING_AT_NOCASE (dbp, "id="))
  5136               {
  5137                 bool quoted = (dbp[0] == '"');
  5138 
  5139                 if (quoted)
  5140                   for (end = ++dbp; *end != '\0' && *end != '"'; end++)
  5141                     continue;
  5142                 else
  5143                   for (end = dbp; *end != '\0' && intoken (*end); end++)
  5144                     continue;
  5145                 linebuffer_setlen (&token_name, end - dbp);
  5146                 memcpy (token_name.buffer, dbp, end - dbp);
  5147                 token_name.buffer[end - dbp] = '\0';
  5148 
  5149                 dbp = end;
  5150                 intag = false;  /* we found what we looked for */
  5151                 skiptag = true; /* skip to the end of the tag */
  5152                 getnext = true; /* then grab the text */
  5153                 continue;       /* look on the same line */
  5154               }
  5155             dbp += 1;
  5156           }
  5157 
  5158         else if (getnext)       /* grab next tokens and tag them */
  5159           {
  5160             dbp = skip_spaces (dbp);
  5161             if (*dbp == '\0')
  5162               break;            /* go to next line */
  5163             if (*dbp == '<')
  5164               {
  5165                 intag = true;
  5166                 inanchor = (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]));
  5167                 continue;       /* look on the same line */
  5168               }
  5169 
  5170             for (end = dbp + 1; *end != '\0' && *end != '<'; end++)
  5171               continue;
  5172             make_tag (token_name.buffer, token_name.len, true,
  5173                       dbp, end - dbp, lineno, linecharno);
  5174             linebuffer_setlen (&token_name, 0); /* no name in buffer */
  5175             getnext = false;
  5176             break;              /* go to next line */
  5177           }
  5178 
  5179         else                    /* look for an interesting HTML tag */
  5180           {
  5181             while (*dbp != '\0' && *dbp != '<')
  5182               dbp++;
  5183             if (*dbp == '\0')
  5184               break;            /* go to next line */
  5185             intag = true;
  5186             if (lowcase (dbp[1]) == 'a' && !intoken (dbp[2]))
  5187               {
  5188                 inanchor = true;
  5189                 continue;       /* look on the same line */
  5190               }
  5191             else if (LOOKING_AT_NOCASE (dbp, "<title>")
  5192                      || LOOKING_AT_NOCASE (dbp, "<h1>")
  5193                      || LOOKING_AT_NOCASE (dbp, "<h2>")
  5194                      || LOOKING_AT_NOCASE (dbp, "<h3>"))
  5195               {
  5196                 intag = false;
  5197                 getnext = true;
  5198                 continue;       /* look on the same line */
  5199               }
  5200             dbp += 1;
  5201           }
  5202       }
  5203 }
  5204 
  5205 
  5206 /*
  5207  * Prolog support
  5208  *
  5209  * Assumes that the predicate or rule starts at column 0.
  5210  * Only the first clause of a predicate or rule is added.
  5211  * Original code by Sunichirou Sugou (1989)
  5212  * Rewritten by Anders Lindgren (1996)
  5213  */
  5214 static size_t prolog_pr (char *, char *);
  5215 static void prolog_skip_comment (linebuffer *, FILE *);
  5216 static size_t prolog_atom (char *, size_t);
  5217 
  5218 static void
  5219 Prolog_functions (FILE *inf)
  5220 {
  5221   char *cp, *last;
  5222   size_t len;
  5223   size_t allocated;
  5224 
  5225   allocated = 0;
  5226   len = 0;
  5227   last = NULL;
  5228 
  5229   LOOP_ON_INPUT_LINES (inf, lb, cp)
  5230     {
  5231       if (cp[0] == '\0')        /* Empty line */
  5232         continue;
  5233       else if (iswhite (cp[0])) /* Not a predicate */
  5234         continue;
  5235       else if (cp[0] == '/' && cp[1] == '*')    /* comment. */
  5236         prolog_skip_comment (&lb, inf);
  5237       else if ((len = prolog_pr (cp, last)) > 0)
  5238         {
  5239           /* Predicate or rule.  Store the function name so that we
  5240              only generate a tag for the first clause.  */
  5241           if (last == NULL)
  5242             last = xnew (len + 1, char);
  5243           else if (len + 1 > allocated)
  5244             xrnew (last, len + 1, char);
  5245           allocated = len + 1;
  5246           memcpy (last, cp, len);
  5247           last[len] = '\0';
  5248         }
  5249     }
  5250   free (last);
  5251 }
  5252 
  5253 
  5254 static void
  5255 prolog_skip_comment (linebuffer *plb, FILE *inf)
  5256 {
  5257   char *cp;
  5258 
  5259   do
  5260     {
  5261       for (cp = plb->buffer; *cp != '\0'; cp++)
  5262         if (cp[0] == '*' && cp[1] == '/')
  5263           return;
  5264       readline (plb, inf);
  5265     }
  5266   while (!feof (inf));
  5267 }
  5268 
  5269 /*
  5270  * A predicate or rule definition is added if it matches:
  5271  *     <beginning of line><Prolog Atom><whitespace>(
  5272  * or  <beginning of line><Prolog Atom><whitespace>:-
  5273  *
  5274  * It is added to the tags database if it doesn't match the
  5275  * name of the previous clause header.
  5276  *
  5277  * Return the size of the name of the predicate or rule, or 0 if no
  5278  * header was found.
  5279  */
  5280 static size_t
  5281 prolog_pr (char *s, char *last)
  5282 
  5283                                 /* Name of last clause. */
  5284 {
  5285   size_t pos;
  5286   size_t len;
  5287 
  5288   pos = prolog_atom (s, 0);
  5289   if (! pos)
  5290     return 0;
  5291 
  5292   len = pos;
  5293   pos = skip_spaces (s + pos) - s;
  5294 
  5295   if ((s[pos] == '.'
  5296        || (s[pos] == '(' && (pos += 1))
  5297        || (s[pos] == ':' && s[pos + 1] == '-' && (pos += 2)))
  5298       && (last == NULL          /* save only the first clause */
  5299           || len != strlen (last)
  5300           || !strneq (s, last, len)))
  5301         {
  5302           make_tag (s, len, true, s, pos, lineno, linecharno);
  5303           return len;
  5304         }
  5305   else
  5306     return 0;
  5307 }
  5308 
  5309 /*
  5310  * Consume a Prolog atom.
  5311  * Return the number of bytes consumed, or 0 if there was an error.
  5312  *
  5313  * A prolog atom, in this context, could be one of:
  5314  * - An alphanumeric sequence, starting with a lower case letter.
  5315  * - A quoted arbitrary string. Single quotes can escape themselves.
  5316  *   Backslash quotes everything.
  5317  */
  5318 static size_t
  5319 prolog_atom (char *s, size_t pos)
  5320 {
  5321   size_t origpos;
  5322 
  5323   origpos = pos;
  5324 
  5325   if (ISLOWER (s[pos]) || (s[pos] == '_'))
  5326     {
  5327       /* The atom is unquoted. */
  5328       pos++;
  5329       while (ISALNUM (s[pos]) || (s[pos] == '_'))
  5330         {
  5331           pos++;
  5332         }
  5333       return pos - origpos;
  5334     }
  5335   else if (s[pos] == '\'')
  5336     {
  5337       pos++;
  5338 
  5339       for (;;)
  5340         {
  5341           if (s[pos] == '\'')
  5342             {
  5343               pos++;
  5344               if (s[pos] != '\'')
  5345                 break;
  5346               pos++;            /* A double quote */
  5347             }
  5348           else if (s[pos] == '\0')
  5349             /* Multiline quoted atoms are ignored. */
  5350             return 0;
  5351           else if (s[pos] == '\\')
  5352             {
  5353               if (s[pos+1] == '\0')
  5354                 return 0;
  5355               pos += 2;
  5356             }
  5357           else
  5358             pos++;
  5359         }
  5360       return pos - origpos;
  5361     }
  5362   else
  5363     return 0;
  5364 }
  5365 
  5366 
  5367 /*
  5368  * Support for Erlang
  5369  *
  5370  * Generates tags for functions, defines, and records.
  5371  * Assumes that Erlang functions start at column 0.
  5372  * Original code by Anders Lindgren (1996)
  5373  */
  5374 static int erlang_func (char *, char *);
  5375 static void erlang_attribute (char *);
  5376 static int erlang_atom (char *);
  5377 
  5378 static void
  5379 Erlang_functions (FILE *inf)
  5380 {
  5381   char *cp, *last;
  5382   int len;
  5383   int allocated;
  5384 
  5385   allocated = 0;
  5386   len = 0;
  5387   last = NULL;
  5388 
  5389   LOOP_ON_INPUT_LINES (inf, lb, cp)
  5390     {
  5391       if (cp[0] == '\0')        /* Empty line */
  5392         continue;
  5393       else if (iswhite (cp[0])) /* Not function nor attribute */
  5394         continue;
  5395       else if (cp[0] == '%')    /* comment */
  5396         continue;
  5397       else if (cp[0] == '"')    /* Sometimes, strings start in column one */
  5398         continue;
  5399       else if (cp[0] == '-')    /* attribute, e.g. "-define" */
  5400         {
  5401           erlang_attribute (cp);
  5402           if (last != NULL)
  5403             {
  5404               free (last);
  5405               last = NULL;
  5406             }
  5407         }
  5408       else if ((len = erlang_func (cp, last)) > 0)
  5409         {
  5410           /*
  5411            * Function.  Store the function name so that we only
  5412            * generates a tag for the first clause.
  5413            */
  5414           if (last == NULL)
  5415             last = xnew (len + 1, char);
  5416           else if (len + 1 > allocated)
  5417             xrnew (last, len + 1, char);
  5418           allocated = len + 1;
  5419           memcpy (last, cp, len);
  5420           last[len] = '\0';
  5421         }
  5422     }
  5423   free (last);
  5424 }
  5425 
  5426 
  5427 /*
  5428  * A function definition is added if it matches:
  5429  *     <beginning of line><Erlang Atom><whitespace>(
  5430  *
  5431  * It is added to the tags database if it doesn't match the
  5432  * name of the previous clause header.
  5433  *
  5434  * Return the size of the name of the function, or 0 if no function
  5435  * was found.
  5436  */
  5437 static int
  5438 erlang_func (char *s, char *last)
  5439 
  5440                                 /* Name of last clause. */
  5441 {
  5442   int pos;
  5443   int len;
  5444 
  5445   pos = erlang_atom (s);
  5446   if (pos < 1)
  5447     return 0;
  5448 
  5449   len = pos;
  5450   pos = skip_spaces (s + pos) - s;
  5451 
  5452   /* Save only the first clause. */
  5453   if (s[pos++] == '('
  5454       && (last == NULL
  5455           || len != (int)strlen (last)
  5456           || !strneq (s, last, len)))
  5457         {
  5458           make_tag (s, len, true, s, pos, lineno, linecharno);
  5459           return len;
  5460         }
  5461 
  5462   return 0;
  5463 }
  5464 
  5465 
  5466 /*
  5467  * Handle attributes.  Currently, tags are generated for defines
  5468  * and records.
  5469  *
  5470  * They are on the form:
  5471  * -define(foo, bar).
  5472  * -define(Foo(M, N), M+N).
  5473  * -record(graph, {vtab = notable, cyclic = true}).
  5474  */
  5475 static void
  5476 erlang_attribute (char *s)
  5477 {
  5478   char *cp = s;
  5479 
  5480   if ((LOOKING_AT (cp, "-define") || LOOKING_AT (cp, "-record"))
  5481       && *cp++ == '(')
  5482     {
  5483       int len = erlang_atom (skip_spaces (cp));
  5484       if (len > 0)
  5485         make_tag (cp, len, true, s, cp + len - s, lineno, linecharno);
  5486     }
  5487   return;
  5488 }
  5489 
  5490 
  5491 /*
  5492  * Consume an Erlang atom (or variable).
  5493  * Return the number of bytes consumed, or -1 if there was an error.
  5494  */
  5495 static int
  5496 erlang_atom (char *s)
  5497 {
  5498   int pos = 0;
  5499 
  5500   if (ISALPHA (s[pos]) || s[pos] == '_')
  5501     {
  5502       /* The atom is unquoted. */
  5503       do
  5504         pos++;
  5505       while (ISALNUM (s[pos]) || s[pos] == '_');
  5506     }
  5507   else if (s[pos] == '\'')
  5508     {
  5509       for (pos++; s[pos] != '\''; pos++)
  5510         if (s[pos] == '\0'      /* multiline quoted atoms are ignored */
  5511             || (s[pos] == '\\' && s[++pos] == '\0'))
  5512           return 0;
  5513       pos++;
  5514     }
  5515 
  5516   return pos;
  5517 }
  5518 
  5519 
  5520 static char *scan_separators (char *);
  5521 static void add_regex (char *, language *);
  5522 static char *substitute (char *, char *, struct re_registers *);
  5523 
  5524 /*
  5525  * Take a string like "/blah/" and turn it into "blah", verifying
  5526  * that the first and last characters are the same, and handling
  5527  * quoted separator characters.  Actually, stops on the occurrence of
  5528  * an unquoted separator.  Also process \t, \n, etc. and turn into
  5529  * appropriate characters. Works in place.  Null terminates name string.
  5530  * Returns pointer to terminating separator, or NULL for
  5531  * unterminated regexps.
  5532  */
  5533 static char *
  5534 scan_separators (char *name)
  5535 {
  5536   char sep = name[0];
  5537   char *copyto = name;
  5538   bool quoted = false;
  5539 
  5540   for (++name; *name != '\0'; ++name)
  5541     {
  5542       if (quoted)
  5543         {
  5544           switch (*name)
  5545             {
  5546             case 'a': *copyto++ = '\007'; break; /* BEL (bell)           */
  5547             case 'b': *copyto++ = '\b'; break;   /* BS (back space)      */
  5548             case 'd': *copyto++ = 0177; break;   /* DEL (delete)         */
  5549             case 'e': *copyto++ = 033; break;    /* ESC (delete)         */
  5550             case 'f': *copyto++ = '\f'; break;   /* FF (form feed)       */
  5551             case 'n': *copyto++ = '\n'; break;   /* NL (new line)        */
  5552             case 'r': *copyto++ = '\r'; break;   /* CR (carriage return) */
  5553             case 't': *copyto++ = '\t'; break;   /* TAB (horizontal tab) */
  5554             case 'v': *copyto++ = '\v'; break;   /* VT (vertical tab)    */
  5555             default:
  5556               if (*name == sep)
  5557                 *copyto++ = sep;
  5558               else
  5559                 {
  5560                   /* Something else is quoted, so preserve the quote. */
  5561                   *copyto++ = '\\';
  5562                   *copyto++ = *name;
  5563                 }
  5564               break;
  5565             }
  5566           quoted = false;
  5567         }
  5568       else if (*name == '\\')
  5569         quoted = true;
  5570       else if (*name == sep)
  5571         break;
  5572       else
  5573         *copyto++ = *name;
  5574     }
  5575   if (*name != sep)
  5576     name = NULL;                /* signal unterminated regexp */
  5577 
  5578   /* Terminate copied string. */
  5579   *copyto = '\0';
  5580   return name;
  5581 }
  5582 
  5583 /* Look at the argument of --regex or --no-regex and do the right
  5584    thing.  Same for each line of a regexp file. */
  5585 static void
  5586 analyze_regex (char *regex_arg)
  5587 {
  5588   if (regex_arg == NULL)
  5589     {
  5590       free_regexps ();          /* --no-regex: remove existing regexps */
  5591       return;
  5592     }
  5593 
  5594   /* A real --regexp option or a line in a regexp file. */
  5595   switch (regex_arg[0])
  5596     {
  5597       /* Comments in regexp file or null arg to --regex. */
  5598     case '\0':
  5599     case ' ':
  5600     case '\t':
  5601       break;
  5602 
  5603       /* Read a regex file.  This is recursive and may result in a
  5604          loop, which will stop when the file descriptors are exhausted. */
  5605     case '@':
  5606       {
  5607         FILE *regexfp;
  5608         linebuffer regexbuf;
  5609         char *regexfile = regex_arg + 1;
  5610 
  5611         /* regexfile is a file containing regexps, one per line. */
  5612         regexfp = fopen (regexfile, "r" FOPEN_BINARY);
  5613         if (regexfp == NULL)
  5614           pfatal (regexfile);
  5615         linebuffer_init (&regexbuf);
  5616         while (readline_internal (&regexbuf, regexfp) > 0)
  5617           analyze_regex (regexbuf.buffer);
  5618         free (regexbuf.buffer);
  5619         fclose (regexfp);
  5620       }
  5621       break;
  5622 
  5623       /* Regexp to be used for a specific language only. */
  5624     case '{':
  5625       {
  5626         language *lang;
  5627         char *lang_name = regex_arg + 1;
  5628         char *cp;
  5629 
  5630         for (cp = lang_name; *cp != '}'; cp++)
  5631           if (*cp == '\0')
  5632             {
  5633               error ("unterminated language name in regex: %s", regex_arg);
  5634               return;
  5635             }
  5636         *cp++ = '\0';
  5637         lang = get_language_from_langname (lang_name);
  5638         if (lang == NULL)
  5639           return;
  5640         add_regex (cp, lang);
  5641       }
  5642       break;
  5643 
  5644       /* Regexp to be used for any language. */
  5645     default:
  5646       add_regex (regex_arg, NULL);
  5647       break;
  5648     }
  5649 }
  5650 
  5651 /* Separate the regexp pattern, compile it,
  5652    and care for optional name and modifiers. */
  5653 static void
  5654 add_regex (char *regexp_pattern, language *lang)
  5655 {
  5656   static struct re_pattern_buffer zeropattern;
  5657   char sep, *pat, *name, *modifiers;
  5658   char empty = '\0';
  5659   const char *err;
  5660   struct re_pattern_buffer *patbuf;
  5661   regexp *rp;
  5662   bool
  5663     force_explicit_name = true, /* do not use implicit tag names */
  5664     ignore_case = false,        /* case is significant */
  5665     multi_line = false,         /* matches are done one line at a time */
  5666     single_line = false;        /* dot does not match newline */
  5667 
  5668 
  5669   if (strlen (regexp_pattern) < 3)
  5670     {
  5671       error ("null regexp");
  5672       return;
  5673     }
  5674   sep = regexp_pattern[0];
  5675   name = scan_separators (regexp_pattern);
  5676   if (name == NULL)
  5677     {
  5678       error ("%s: unterminated regexp", regexp_pattern);
  5679       return;
  5680     }
  5681   if (name[1] == sep)
  5682     {
  5683       error ("null name for regexp \"%s\"", regexp_pattern);
  5684       return;
  5685     }
  5686   modifiers = scan_separators (name);
  5687   if (modifiers == NULL)        /* no terminating separator --> no name */
  5688     {
  5689       modifiers = name;
  5690       name = &empty;
  5691     }
  5692   else
  5693     modifiers += 1;             /* skip separator */
  5694 
  5695   /* Parse regex modifiers. */
  5696   for (; modifiers[0] != '\0'; modifiers++)
  5697     switch (modifiers[0])
  5698       {
  5699       case 'N':
  5700         if (modifiers == name)
  5701           error ("forcing explicit tag name but no name, ignoring");
  5702         force_explicit_name = true;
  5703         break;
  5704       case 'i':
  5705         ignore_case = true;
  5706         break;
  5707       case 's':
  5708         single_line = true;
  5709         /* FALLTHRU */
  5710       case 'm':
  5711         multi_line = true;
  5712         need_filebuf = true;
  5713         break;
  5714       default:
  5715         error ("invalid regexp modifier `%c', ignoring", modifiers[0]);
  5716         break;
  5717       }
  5718 
  5719   patbuf = xnew (1, struct re_pattern_buffer);
  5720   *patbuf = zeropattern;
  5721   if (ignore_case)
  5722     {
  5723       static char lc_trans[CHARS];
  5724       int i;
  5725       for (i = 0; i < CHARS; i++)
  5726         lc_trans[i] = lowcase (i);
  5727       patbuf->translate = lc_trans;     /* translation table to fold case  */
  5728     }
  5729 
  5730   if (multi_line)
  5731     pat = concat ("^", regexp_pattern, ""); /* anchor to beginning of line */
  5732   else
  5733     pat = regexp_pattern;
  5734 
  5735   if (single_line)
  5736     re_set_syntax (RE_SYNTAX_EMACS | RE_DOT_NEWLINE);
  5737   else
  5738     re_set_syntax (RE_SYNTAX_EMACS);
  5739 
  5740   err = re_compile_pattern (pat, strlen (pat), patbuf);
  5741   if (multi_line)
  5742     free (pat);
  5743   if (err != NULL)
  5744     {
  5745       error ("%s while compiling pattern", err);
  5746       return;
  5747     }
  5748 
  5749   rp = p_head;
  5750   p_head = xnew (1, regexp);
  5751   p_head->pattern = savestr (regexp_pattern);
  5752   p_head->p_next = rp;
  5753   p_head->lang = lang;
  5754   p_head->pat = patbuf;
  5755   p_head->name = savestr (name);
  5756   p_head->error_signaled = false;
  5757   p_head->force_explicit_name = force_explicit_name;
  5758   p_head->ignore_case = ignore_case;
  5759   p_head->multi_line = multi_line;
  5760 }
  5761 
  5762 /*
  5763  * Do the substitutions indicated by the regular expression and
  5764  * arguments.
  5765  */
  5766 static char *
  5767 substitute (char *in, char *out, struct re_registers *regs)
  5768 {
  5769   char *result, *t;
  5770   int size, dig, diglen;
  5771 
  5772   result = NULL;
  5773   size = strlen (out);
  5774 
  5775   /* Pass 1: figure out how much to allocate by finding all \N strings. */
  5776   if (out[size - 1] == '\\')
  5777     fatal ("pattern error in \"%s\"", out);
  5778   for (t = strchr (out, '\\');
  5779        t != NULL;
  5780        t = strchr (t + 2, '\\'))
  5781     if (ISDIGIT (t[1]))
  5782       {
  5783         dig = t[1] - '0';
  5784         diglen = regs->end[dig] - regs->start[dig];
  5785         size += diglen - 2;
  5786       }
  5787     else
  5788       size -= 1;
  5789 
  5790   /* Allocate space and do the substitutions. */
  5791   assert (size >= 0);
  5792   result = xnew (size + 1, char);
  5793 
  5794   for (t = result; *out != '\0'; out++)
  5795     if (*out == '\\' && ISDIGIT (*++out))
  5796       {
  5797         dig = *out - '0';
  5798         diglen = regs->end[dig] - regs->start[dig];
  5799         memcpy (t, in + regs->start[dig], diglen);
  5800         t += diglen;
  5801       }
  5802     else
  5803       *t++ = *out;
  5804   *t = '\0';
  5805 
  5806   assert (t <= result + size);
  5807   assert (t - result == (int)strlen (result));
  5808 
  5809   return result;
  5810 }
  5811 
  5812 /* Deallocate all regexps. */
  5813 static void
  5814 free_regexps (void)
  5815 {
  5816   regexp *rp;
  5817   while (p_head != NULL)
  5818     {
  5819       rp = p_head->p_next;
  5820       free (p_head->pattern);
  5821       free (p_head->name);
  5822       free (p_head);
  5823       p_head = rp;
  5824     }
  5825   return;
  5826 }
  5827 
  5828 /*
  5829  * Reads the whole file as a single string from `filebuf' and looks for
  5830  * multi-line regular expressions, creating tags on matches.
  5831  * readline already dealt with normal regexps.
  5832  *
  5833  * Idea by Ben Wing <ben@666.com> (2002).
  5834  */
  5835 static void
  5836 regex_tag_multiline (void)
  5837 {
  5838   char *buffer = filebuf.buffer;
  5839   regexp *rp;
  5840   char *name;
  5841 
  5842   for (rp = p_head; rp != NULL; rp = rp->p_next)
  5843     {
  5844       int match = 0;
  5845 
  5846       if (!rp->multi_line)
  5847         continue;               /* skip normal regexps */
  5848 
  5849       /* Generic initializations before parsing file from memory. */
  5850       lineno = 1;               /* reset global line number */
  5851       charno = 0;               /* reset global char number */
  5852       linecharno = 0;           /* reset global char number of line start */
  5853 
  5854       /* Only use generic regexps or those for the current language. */
  5855       if (rp->lang != NULL && rp->lang != curfdp->lang)
  5856         continue;
  5857 
  5858       while (match >= 0 && match < filebuf.len)
  5859         {
  5860           match = re_search (rp->pat, buffer, filebuf.len, charno,
  5861                              filebuf.len - match, &rp->regs);
  5862           switch (match)
  5863             {
  5864             case -2:
  5865               /* Some error. */
  5866               if (!rp->error_signaled)
  5867                 {
  5868                   error ("regexp stack overflow while matching \"%s\"",
  5869                          rp->pattern);
  5870                   rp->error_signaled = true;
  5871                 }
  5872               break;
  5873             case -1:
  5874               /* No match. */
  5875               break;
  5876             default:
  5877               if (match == rp->regs.end[0])
  5878                 {
  5879                   if (!rp->error_signaled)
  5880                     {
  5881                       error ("regexp matches the empty string: \"%s\"",
  5882                              rp->pattern);
  5883                       rp->error_signaled = true;
  5884                     }
  5885                   match = -3;   /* exit from while loop */
  5886                   break;
  5887                 }
  5888 
  5889               /* Match occurred.  Construct a tag. */
  5890               while (charno < rp->regs.end[0])
  5891                 if (buffer[charno++] == '\n')
  5892                   lineno++, linecharno = charno;
  5893               name = rp->name;
  5894               if (name[0] == '\0')
  5895                 name = NULL;
  5896               else /* make a named tag */
  5897                 name = substitute (buffer, rp->name, &rp->regs);
  5898               if (rp->force_explicit_name)
  5899                 /* Force explicit tag name, if a name is there. */
  5900                 pfnote (name, true, buffer + linecharno,
  5901                         charno - linecharno + 1, lineno, linecharno);
  5902               else
  5903                 make_tag (name, strlen (name), true, buffer + linecharno,
  5904                           charno - linecharno + 1, lineno, linecharno);
  5905               break;
  5906             }
  5907         }
  5908     }
  5909 }
  5910 
  5911 
  5912 static bool
  5913 nocase_tail (const char *cp)
  5914 {
  5915   register int len = 0;
  5916 
  5917   while (*cp != '\0' && lowcase (*cp) == lowcase (dbp[len]))
  5918     cp++, len++;
  5919   if (*cp == '\0' && !intoken (dbp[len]))
  5920     {
  5921       dbp += len;
  5922       return true;
  5923     }
  5924   return false;
  5925 }
  5926 
  5927 static void
  5928 get_tag (register char *bp, char **namepp)
  5929 {
  5930   register char *cp = bp;
  5931 
  5932   if (*bp != '\0')
  5933     {
  5934       /* Go till you get to white space or a syntactic break */
  5935       for (cp = bp + 1; !notinname (*cp); cp++)
  5936         continue;
  5937       make_tag (bp, cp - bp, true,
  5938                 lb.buffer, cp - lb.buffer + 1, lineno, linecharno);
  5939     }
  5940 
  5941   if (namepp != NULL)
  5942     *namepp = savenstr (bp, cp - bp);
  5943 }
  5944 
  5945 /*
  5946  * Read a line of text from `stream' into `lbp', excluding the
  5947  * newline or CR-NL, if any.  Return the number of characters read from
  5948  * `stream', which is the length of the line including the newline.
  5949  *
  5950  * On DOS or Windows we do not count the CR character, if any before the
  5951  * NL, in the returned length; this mirrors the behavior of Emacs on those
  5952  * platforms (for text files, it translates CR-NL to NL as it reads in the
  5953  * file).
  5954  *
  5955  * If multi-line regular expressions are requested, each line read is
  5956  * appended to `filebuf'.
  5957  */
  5958 static long
  5959 readline_internal (linebuffer *lbp, register FILE *stream)
  5960 {
  5961   char *buffer = lbp->buffer;
  5962   register char *p = lbp->buffer;
  5963   register char *pend;
  5964   int chars_deleted;
  5965 
  5966   pend = p + lbp->size;         /* Separate to avoid 386/IX compiler bug.  */
  5967 
  5968   for (;;)
  5969     {
  5970       register int c = getc (stream);
  5971       if (p == pend)
  5972         {
  5973           /* We're at the end of linebuffer: expand it. */
  5974           lbp->size *= 2;
  5975           xrnew (buffer, lbp->size, char);
  5976           p += buffer - lbp->buffer;
  5977           pend = buffer + lbp->size;
  5978           lbp->buffer = buffer;
  5979         }
  5980       if (c == EOF)
  5981         {
  5982           *p = '\0';
  5983           chars_deleted = 0;
  5984           break;
  5985         }
  5986       if (c == '\n')
  5987         {
  5988           if (p > buffer && p[-1] == '\r')
  5989             {
  5990               p -= 1;
  5991 #ifdef DOS_NT
  5992              /* Assume CRLF->LF translation will be performed by Emacs
  5993                 when loading this file, so CRs won't appear in the buffer.
  5994                 It would be cleaner to compensate within Emacs;
  5995                 however, Emacs does not know how many CRs were deleted
  5996                 before any given point in the file.  */
  5997               chars_deleted = 1;
  5998 #else
  5999               chars_deleted = 2;
  6000 #endif
  6001             }
  6002           else
  6003             {
  6004               chars_deleted = 1;
  6005             }
  6006           *p = '\0';
  6007           break;
  6008         }
  6009       *p++ = c;
  6010     }
  6011   lbp->len = p - buffer;
  6012 
  6013   if (need_filebuf              /* we need filebuf for multi-line regexps */
  6014       && chars_deleted > 0)     /* not at EOF */
  6015     {
  6016       while (filebuf.size <= filebuf.len + lbp->len + 1) /* +1 for \n */
  6017         {
  6018           /* Expand filebuf. */
  6019           filebuf.size *= 2;
  6020           xrnew (filebuf.buffer, filebuf.size, char);
  6021         }
  6022       memcpy (filebuf.buffer + filebuf.len, lbp->buffer, lbp->len);
  6023       filebuf.len += lbp->len;
  6024       filebuf.buffer[filebuf.len++] = '\n';
  6025       filebuf.buffer[filebuf.len] = '\0';
  6026     }
  6027 
  6028   return lbp->len + chars_deleted;
  6029 }
  6030 
  6031 /*
  6032  * Like readline_internal, above, but in addition try to match the
  6033  * input line against relevant regular expressions and manage #line
  6034  * directives.
  6035  */
  6036 static void
  6037 readline (linebuffer *lbp, FILE *stream)
  6038 {
  6039   long result;
  6040 
  6041   linecharno = charno;          /* update global char number of line start */
  6042   result = readline_internal (lbp, stream); /* read line */
  6043   lineno += 1;                  /* increment global line number */
  6044   charno += result;             /* increment global char number */
  6045 
  6046   /* Honor #line directives. */
  6047   if (!no_line_directive)
  6048     {
  6049       static bool discard_until_line_directive;
  6050 
  6051       /* Check whether this is a #line directive. */
  6052       if (result > 12 && strneq (lbp->buffer, "#line ", 6))
  6053         {
  6054           unsigned int lno;
  6055           int start = 0;
  6056 
  6057           if (sscanf (lbp->buffer, "#line %u \"%n", &lno, &start) >= 1
  6058               && start > 0)     /* double quote character found */
  6059             {
  6060               char *endp = lbp->buffer + start;
  6061 
  6062               while ((endp = strchr (endp, '"')) != NULL
  6063                      && endp[-1] == '\\')
  6064                 endp++;
  6065               if (endp != NULL)
  6066                 /* Ok, this is a real #line directive.  Let's deal with it. */
  6067                 {
  6068                   char *taggedabsname;  /* absolute name of original file */
  6069                   char *taggedfname;    /* name of original file as given */
  6070                   char *name;           /* temp var */
  6071 
  6072                   discard_until_line_directive = false; /* found it */
  6073                   name = lbp->buffer + start;
  6074                   *endp = '\0';
  6075                   canonicalize_filename (name);
  6076                   taggedabsname = absolute_filename (name, tagfiledir);
  6077                   if (filename_is_absolute (name)
  6078                       || filename_is_absolute (curfdp->infname))
  6079                     taggedfname = savestr (taggedabsname);
  6080                   else
  6081                     taggedfname = relative_filename (taggedabsname,tagfiledir);
  6082 
  6083                   if (streq (curfdp->taggedfname, taggedfname))
  6084                     /* The #line directive is only a line number change.  We
  6085                        deal with this afterwards. */
  6086                     free (taggedfname);
  6087                   else
  6088                     /* The tags following this #line directive should be
  6089                        attributed to taggedfname.  In order to do this, set
  6090                        curfdp accordingly. */
  6091                     {
  6092                       fdesc *fdp; /* file description pointer */
  6093 
  6094                       /* Go look for a file description already set up for the
  6095                          file indicated in the #line directive.  If there is
  6096                          one, use it from now until the next #line
  6097                          directive. */
  6098                       for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
  6099                         if (streq (fdp->infname, curfdp->infname)
  6100                             && streq (fdp->taggedfname, taggedfname))
  6101                           /* If we remove the second test above (after the &&)
  6102                              then all entries pertaining to the same file are
  6103                              coalesced in the tags file.  If we use it, then
  6104                              entries pertaining to the same file but generated
  6105                              from different files (via #line directives) will
  6106                              go into separate sections in the tags file.  These
  6107                              alternatives look equivalent.  The first one
  6108                              destroys some apparently useless information. */
  6109                           {
  6110                             curfdp = fdp;
  6111                             free (taggedfname);
  6112                             break;
  6113                           }
  6114                       /* Else, if we already tagged the real file, skip all
  6115                          input lines until the next #line directive. */
  6116                       if (fdp == NULL) /* not found */
  6117                         for (fdp = fdhead; fdp != NULL; fdp = fdp->next)
  6118                           if (streq (fdp->infabsname, taggedabsname))
  6119                             {
  6120                               discard_until_line_directive = true;
  6121                               free (taggedfname);
  6122                               break;
  6123                             }
  6124                       /* Else create a new file description and use that from
  6125                          now on, until the next #line directive. */
  6126                       if (fdp == NULL) /* not found */
  6127                         {
  6128                           fdp = fdhead;
  6129                           fdhead = xnew (1, fdesc);
  6130                           *fdhead = *curfdp; /* copy curr. file description */
  6131                           fdhead->next = fdp;
  6132                           fdhead->infname = savestr (curfdp->infname);
  6133                           fdhead->infabsname = savestr (curfdp->infabsname);
  6134                           fdhead->infabsdir = savestr (curfdp->infabsdir);
  6135                           fdhead->taggedfname = taggedfname;
  6136                           fdhead->usecharno = false;
  6137                           fdhead->prop = NULL;
  6138                           fdhead->written = false;
  6139                           curfdp = fdhead;
  6140                         }
  6141                     }
  6142                   free (taggedabsname);
  6143                   lineno = lno - 1;
  6144                   readline (lbp, stream);
  6145                   return;
  6146                 } /* if a real #line directive */
  6147             } /* if #line is followed by a number */
  6148         } /* if line begins with "#line " */
  6149 
  6150       /* If we are here, no #line directive was found. */
  6151       if (discard_until_line_directive)
  6152         {
  6153           if (result > 0)
  6154             {
  6155               /* Do a tail recursion on ourselves, thus discarding the contents
  6156                  of the line buffer. */
  6157               readline (lbp, stream);
  6158               return;
  6159             }
  6160           /* End of file. */
  6161           discard_until_line_directive = false;
  6162           return;
  6163         }
  6164     } /* if #line directives should be considered */
  6165 
  6166   {
  6167     int match;
  6168     regexp *rp;
  6169     char *name;
  6170 
  6171     /* Match against relevant regexps. */
  6172     if (lbp->len > 0)
  6173       for (rp = p_head; rp != NULL; rp = rp->p_next)
  6174         {
  6175           /* Only use generic regexps or those for the current language.
  6176              Also do not use multiline regexps, which is the job of
  6177              regex_tag_multiline. */
  6178           if ((rp->lang != NULL && rp->lang != fdhead->lang)
  6179               || rp->multi_line)
  6180             continue;
  6181 
  6182           match = re_match (rp->pat, lbp->buffer, lbp->len, 0, &rp->regs);
  6183           switch (match)
  6184             {
  6185             case -2:
  6186               /* Some error. */
  6187               if (!rp->error_signaled)
  6188                 {
  6189                   error ("regexp stack overflow while matching \"%s\"",
  6190                          rp->pattern);
  6191                   rp->error_signaled = true;
  6192                 }
  6193               break;
  6194             case -1:
  6195               /* No match. */
  6196               break;
  6197             case 0:
  6198               /* Empty string matched. */
  6199               if (!rp->error_signaled)
  6200                 {
  6201                   error ("regexp matches the empty string: \"%s\"", rp->pattern);
  6202                   rp->error_signaled = true;
  6203                 }
  6204               break;
  6205             default:
  6206               /* Match occurred.  Construct a tag. */
  6207               name = rp->name;
  6208               if (name[0] == '\0')
  6209                 name = NULL;
  6210               else /* make a named tag */
  6211                 name = substitute (lbp->buffer, rp->name, &rp->regs);
  6212               if (rp->force_explicit_name)
  6213                 /* Force explicit tag name, if a name is there. */
  6214                 pfnote (name, true, lbp->buffer, match, lineno, linecharno);
  6215               else
  6216                 make_tag (name, strlen (name), true,
  6217                           lbp->buffer, match, lineno, linecharno);
  6218               break;
  6219             }
  6220         }
  6221   }
  6222 }
  6223 
  6224 
  6225 /*
  6226  * Return a pointer to a space of size strlen(cp)+1 allocated
  6227  * with xnew where the string CP has been copied.
  6228  */
  6229 static char *
  6230 savestr (const char *cp)
  6231 {
  6232   return savenstr (cp, strlen (cp));
  6233 }
  6234 
  6235 /*
  6236  * Return a pointer to a space of size LEN+1 allocated with xnew where
  6237  * the string CP has been copied for at most the first LEN characters.
  6238  */
  6239 static char *
  6240 savenstr (const char *cp, int len)
  6241 {
  6242   char *dp = xnew (len + 1, char);
  6243   dp[len] = '\0';
  6244   return memcpy (dp, cp, len);
  6245 }
  6246 
  6247 /* Skip spaces (end of string is not space), return new pointer. */
  6248 static char *
  6249 skip_spaces (char *cp)
  6250 {
  6251   while (iswhite (*cp))
  6252     cp++;
  6253   return cp;
  6254 }
  6255 
  6256 /* Skip non spaces, except end of string, return new pointer. */
  6257 static char *
  6258 skip_non_spaces (char *cp)
  6259 {
  6260   while (*cp != '\0' && !iswhite (*cp))
  6261     cp++;
  6262   return cp;
  6263 }
  6264 
  6265 /* Skip any chars in the "name" class.*/
  6266 static char *
  6267 skip_name (char *cp)
  6268 {
  6269   /* '\0' is a notinname() so loop stops there too */
  6270   while (! notinname (*cp))
  6271     cp++;
  6272   return cp;
  6273 }
  6274 
  6275 /* Print error message and exit.  */
  6276 void
  6277 fatal (const char *s1, const char *s2)
  6278 {
  6279   error (s1, s2);
  6280   exit (EXIT_FAILURE);
  6281 }
  6282 
  6283 static void
  6284 pfatal (const char *s1)
  6285 {
  6286   perror (s1);
  6287   exit (EXIT_FAILURE);
  6288 }
  6289 
  6290 static void
  6291 suggest_asking_for_help (void)
  6292 {
  6293   fprintf (stderr, "\tTry `%s --help' for a complete list of options.\n",
  6294            progname);
  6295   exit (EXIT_FAILURE);
  6296 }
  6297 
  6298 /* Output a diagnostic with printf-style FORMAT and args.  */
  6299 static void
  6300 error (const char *format, ...)
  6301 {
  6302   va_list ap;
  6303   va_start (ap, format);
  6304   fprintf (stderr, "%s: ", progname);
  6305   vfprintf (stderr, format, ap);
  6306   fprintf (stderr, "\n");
  6307   va_end (ap);
  6308 }
  6309 
  6310 /* Return a newly-allocated string whose contents
  6311    concatenate those of s1, s2, s3.  */
  6312 static char *
  6313 concat (const char *s1, const char *s2, const char *s3)
  6314 {
  6315   int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
  6316   char *result = xnew (len1 + len2 + len3 + 1, char);
  6317 
  6318   strcpy (result, s1);
  6319   strcpy (result + len1, s2);
  6320   strcpy (result + len1 + len2, s3);
  6321 
  6322   return result;
  6323 }
  6324 
  6325 
  6326 /* Does the same work as the system V getcwd, but does not need to
  6327    guess the buffer size in advance. */
  6328 static char *
  6329 etags_getcwd (void)
  6330 {
  6331   int bufsize = 200;
  6332   char *path = xnew (bufsize, char);
  6333 
  6334   while (getcwd (path, bufsize) == NULL)
  6335     {
  6336       if (errno != ERANGE)
  6337         pfatal ("getcwd");
  6338       bufsize *= 2;
  6339       free (path);
  6340       path = xnew (bufsize, char);
  6341     }
  6342 
  6343   canonicalize_filename (path);
  6344   return path;
  6345 }
  6346 
  6347 /* Return a newly allocated string containing the file name of FILE
  6348    relative to the absolute directory DIR (which should end with a slash). */
  6349 static char *
  6350 relative_filename (char *file, char *dir)
  6351 {
  6352   char *fp, *dp, *afn, *res;
  6353   int i;
  6354 
  6355   /* Find the common root of file and dir (with a trailing slash). */
  6356   afn = absolute_filename (file, cwd);
  6357   fp = afn;
  6358   dp = dir;
  6359   while (*fp++ == *dp++)
  6360     continue;
  6361   fp--, dp--;                   /* back to the first differing char */
  6362 #ifdef DOS_NT
  6363   if (fp == afn && afn[0] != '/') /* cannot build a relative name */
  6364     return afn;
  6365 #endif
  6366   do                            /* look at the equal chars until '/' */
  6367     fp--, dp--;
  6368   while (*fp != '/');
  6369 
  6370   /* Build a sequence of "../" strings for the resulting relative file name. */
  6371   i = 0;
  6372   while ((dp = strchr (dp + 1, '/')) != NULL)
  6373     i += 1;
  6374   res = xnew (3*i + strlen (fp + 1) + 1, char);
  6375   char *z = res;
  6376   while (i-- > 0)
  6377     z = stpcpy (z, "../");
  6378 
  6379   /* Add the file name relative to the common root of file and dir. */
  6380   strcpy (z, fp + 1);
  6381   free (afn);
  6382 
  6383   return res;
  6384 }
  6385 
  6386 /* Return a newly allocated string containing the absolute file name
  6387    of FILE given DIR (which should end with a slash). */
  6388 static char *
  6389 absolute_filename (char *file, char *dir)
  6390 {
  6391   char *slashp, *cp, *res;
  6392 
  6393   if (filename_is_absolute (file))
  6394     res = savestr (file);
  6395 #ifdef DOS_NT
  6396   /* We don't support non-absolute file names with a drive
  6397      letter, like `d:NAME' (it's too much hassle).  */
  6398   else if (file[1] == ':')
  6399     fatal ("%s: relative file names with drive letters not supported", file);
  6400 #endif
  6401   else
  6402     res = concat (dir, file, "");
  6403 
  6404   /* Delete the "/dirname/.." and "/." substrings. */
  6405   slashp = strchr (res, '/');
  6406   while (slashp != NULL && slashp[0] != '\0')
  6407     {
  6408       if (slashp[1] == '.')
  6409         {
  6410           if (slashp[2] == '.'
  6411               && (slashp[3] == '/' || slashp[3] == '\0'))
  6412             {
  6413               cp = slashp;
  6414               do
  6415                 cp--;
  6416               while (cp >= res && !filename_is_absolute (cp));
  6417               if (cp < res)
  6418                 cp = slashp;    /* the absolute name begins with "/.." */
  6419 #ifdef DOS_NT
  6420               /* Under MSDOS and NT we get `d:/NAME' as absolute
  6421                  file name, so the luser could say `d:/../NAME'.
  6422                  We silently treat this as `d:/NAME'.  */
  6423               else if (cp[0] != '/')
  6424                 cp = slashp;
  6425 #endif
  6426               memmove (cp, slashp + 3, strlen (slashp + 2));
  6427               slashp = cp;
  6428               continue;
  6429             }
  6430           else if (slashp[2] == '/' || slashp[2] == '\0')
  6431             {
  6432               memmove (slashp, slashp + 2, strlen (slashp + 1));
  6433               continue;
  6434             }
  6435         }
  6436 
  6437       slashp = strchr (slashp + 1, '/');
  6438     }
  6439 
  6440   if (res[0] == '\0')           /* just a safety net: should never happen */
  6441     {
  6442       free (res);
  6443       return savestr ("/");
  6444     }
  6445   else
  6446     return res;
  6447 }
  6448 
  6449 /* Return a newly allocated string containing the absolute
  6450    file name of dir where FILE resides given DIR (which should
  6451    end with a slash). */
  6452 static char *
  6453 absolute_dirname (char *file, char *dir)
  6454 {
  6455   char *slashp, *res;
  6456   char save;
  6457 
  6458   slashp = strrchr (file, '/');
  6459   if (slashp == NULL)
  6460     return savestr (dir);
  6461   save = slashp[1];
  6462   slashp[1] = '\0';
  6463   res = absolute_filename (file, dir);
  6464   slashp[1] = save;
  6465 
  6466   return res;
  6467 }
  6468 
  6469 /* Whether the argument string is an absolute file name.  The argument
  6470    string must have been canonicalized with canonicalize_filename. */
  6471 static bool
  6472 filename_is_absolute (char *fn)
  6473 {
  6474   return (fn[0] == '/'
  6475 #ifdef DOS_NT
  6476           || (ISALPHA (fn[0]) && fn[1] == ':' && fn[2] == '/')
  6477 #endif
  6478           );
  6479 }
  6480 
  6481 /* Downcase DOS drive letter and collapse separators into single slashes.
  6482    Works in place. */
  6483 static void
  6484 canonicalize_filename (register char *fn)
  6485 {
  6486   register char* cp;
  6487   char sep = '/';
  6488 
  6489 #ifdef DOS_NT
  6490   /* Canonicalize drive letter case.  */
  6491 # define ISUPPER(c)     isupper (CHAR (c))
  6492   if (fn[0] != '\0' && fn[1] == ':' && ISUPPER (fn[0]))
  6493     fn[0] = lowcase (fn[0]);
  6494 
  6495   sep = '\\';
  6496 #endif
  6497 
  6498   /* Collapse multiple separators into a single slash. */
  6499   for (cp = fn; *cp != '\0'; cp++, fn++)
  6500     if (*cp == sep)
  6501       {
  6502         *fn = '/';
  6503         while (cp[1] == sep)
  6504           cp++;
  6505       }
  6506     else
  6507       *fn = *cp;
  6508   *fn = '\0';
  6509 }
  6510 
  6511 
  6512 /* Initialize a linebuffer for use. */
  6513 static void
  6514 linebuffer_init (linebuffer *lbp)
  6515 {
  6516   lbp->size = (DEBUG) ? 3 : 200;
  6517   lbp->buffer = xnew (lbp->size, char);
  6518   lbp->buffer[0] = '\0';
  6519   lbp->len = 0;
  6520 }
  6521 
  6522 /* Set the minimum size of a string contained in a linebuffer. */
  6523 static void
  6524 linebuffer_setlen (linebuffer *lbp, int toksize)
  6525 {
  6526   while (lbp->size <= toksize)
  6527     {
  6528       lbp->size *= 2;
  6529       xrnew (lbp->buffer, lbp->size, char);
  6530     }
  6531   lbp->len = toksize;
  6532 }
  6533 
  6534 /* Like malloc but get fatal error if memory is exhausted. */
  6535 static void *
  6536 xmalloc (size_t size)
  6537 {
  6538   void *result = malloc (size);
  6539   if (result == NULL)
  6540     fatal ("virtual memory exhausted", (char *)NULL);
  6541   return result;
  6542 }
  6543 
  6544 static void *
  6545 xrealloc (void *ptr, size_t size)
  6546 {
  6547   void *result = realloc (ptr, size);
  6548   if (result == NULL)
  6549     fatal ("virtual memory exhausted", (char *)NULL);
  6550   return result;
  6551 }
  6552 
  6553 /*
  6554  * Local Variables:
  6555  * indent-tabs-mode: t
  6556  * tab-width: 8
  6557  * fill-column: 79
  6558  * c-font-lock-extra-types: ("FILE" "bool" "language" "linebuffer" "fdesc" "node" "regexp")
  6559  * c-file-style: "gnu"
  6560  * End:
  6561  */
  6562 
  6563 /* etags.c ends here */

/* [<][>][^][v][top][bottom][index][help] */